Add constructors to stringbuf, stringstream, istringstream, and ostringstream, and a matching overload of str(sv) in each, that take anything convertible to a string_view where the existing functions take a string.
libstdc++-v3/ChangeLog: P2495R3 stringstream to init from string_view-ish * include/std/sstream: full implementation, really just decls, requires clause and plumbing. * include/std/bits/version.def, .h: new preprocessor symbol __cpp_lib_sstream_from_string_view. * testsuite/27_io/basic_stringbuf/cons/char/3.cc: New tests. * testsuite/27_io/basic_istringstream/cons/char/2.cc: New tests. * testsuite/27_io/basic_ostringstream/cons/char/4.cc: New tests. * testsuite/27_io/basic_stringstream/cons/char/2.cc: New tests. --- libstdc++-v3/ChangeLog | 11 + libstdc++-v3/include/bits/version.def | 11 +- libstdc++-v3/include/bits/version.h | 10 + libstdc++-v3/include/std/sstream | 181 +++++++++++++-- .../27_io/basic_istringstream/cons/char/2.cc | 193 ++++++++++++++++ .../27_io/basic_ostringstream/cons/char/4.cc | 193 ++++++++++++++++ .../27_io/basic_stringbuf/cons/char/3.cc | 216 ++++++++++++++++++ .../27_io/basic_stringstream/cons/char/2.cc | 194 ++++++++++++++++ 8 files changed, 990 insertions(+), 19 deletions(-) create mode 100644 libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc create mode 100644 libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc create mode 100644 libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc create mode 100644 libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b45f8c2c7a5..ac0ff4a386f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -41,6 +41,17 @@ PR libstdc++/119246 * include/std/format: Updated check for _GLIBCXX_FORMAT_F128. +2025-05-14 Nathan Myers <nmy...@redhat.com> + P2495R3 stringstream to init from string_view-ish + * include/std/sstream: full implementation, really just + decls, requires clause and plumbing. + * include/std/bits/version.def, .h: new preprocessor symbol + __cpp_lib_sstream_from_string_view. + * testsuite/27_io/basic_stringbuf/cons/char/3.cc: New tests. + * testsuite/27_io/basic_istringstream/cons/char/2.cc: New tests. + * testsuite/27_io/basic_ostringstream/cons/char/4.cc: New tests. + * testsuite/27_io/basic_stringstream/cons/char/2.cc: New tests. + 2025-05-14 Tomasz KamiĆski <tkami...@redhat.com> PR libstdc++/119125 diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 6ca148f0488..567c56b4117 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -649,7 +649,7 @@ ftms = { }; values = { v = 1; - /* For when there's no gthread. */ + // For when there is no gthread. cxxmin = 17; hosted = yes; gthread = no; @@ -1961,6 +1961,15 @@ ftms = { }; }; +ftms = { + name = sstream_from_string_view; + values = { + v = 202302; + cxxmin = 26; + hosted = yes; + }; +}; + // Standard test specifications. stds[97] = ">= 199711L"; stds[03] = ">= 199711L"; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 48a090c14a3..5d1beb83a25 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -2193,4 +2193,14 @@ #endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */ #undef __glibcxx_want_modules +#if !defined(__cpp_lib_sstream_from_string_view) +# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED +# define __glibcxx_sstream_from_string_view 202302L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_sstream_from_string_view) +# define __cpp_lib_sstream_from_string_view 202302L +# endif +# endif +#endif /* !defined(__cpp_lib_sstream_from_string_view) && defined(__glibcxx_want_sstream_from_string_view) */ +#undef __glibcxx_want_sstream_from_string_view + #undef __glibcxx_want_all diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream index ad0c16a91e8..9b2b0eb53fc 100644 --- a/libstdc++-v3/include/std/sstream +++ b/libstdc++-v3/include/std/sstream @@ -38,9 +38,14 @@ #endif #include <bits/requires_hosted.h> // iostream +#include <bits/version.h> #include <istream> #include <ostream> +#ifdef __cpp_lib_sstream_from_string_view +# include <type_traits> // is_convertible_v +#endif + #include <bits/alloc_traits.h> // allocator_traits, __allocator_like #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI @@ -52,8 +57,6 @@ # define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]] #endif - - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -159,6 +162,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer explicit basic_stringbuf(const allocator_type& __a) : basic_stringbuf(ios_base::in | std::ios_base::out, __a) @@ -197,7 +201,35 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 | ios_base::out) : basic_stringbuf(__s, __mode, allocator_type{}) { } +#endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + explicit + basic_stringbuf(const _Tp& __t, ios_base::openmode __mode = ios_base::in | ios_base::out) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_stringbuf(__t, __mode, allocator_type{}) + { } + + template<typename _Tp> + basic_stringbuf(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_stringbuf(__t, ios_base::in | ios_base::out, __a) + { } + template<typename _Tp> + basic_stringbuf(const _Tp& __t, ios_base::openmode __mode, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_stringbuf(__mode, __a) + { + basic_string_view<_CharT, _Traits> __sv{__t}; + _M_string = __sv; + _M_stringbuf_init(__mode); + } +#endif // C++26 + +#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a) : basic_stringbuf(std::move(__rhs), __a, __xfer_bufptrs(__rhs, this)) { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); } @@ -262,6 +294,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -317,6 +350,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -335,6 +369,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } #endif +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + { + basic_string_view<_CharT, _Traits> __sv{__t}; + _M_string = __sv; + _M_stringbuf_init(_M_mode); + } +#endif // C++26 + protected: // Common initialization code goes here. void @@ -521,6 +567,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer + // The move constructor initializes an __xfer_bufptrs temporary then // delegates to this constructor to performs moves during its lifetime. basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a, @@ -584,7 +632,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_istringstream() : __istream_type(), _M_stringbuf(ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -601,7 +649,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_istringstream(ios_base::openmode __mode) : __istream_type(), _M_stringbuf(__mode | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -620,7 +668,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_istringstream(const __string_type& __str, ios_base::openmode __mode = ios_base::in) : __istream_type(), _M_stringbuf(__str, __mode | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -637,9 +685,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_istringstream(basic_istringstream&& __rhs) : __istream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __istream_type::set_rdbuf(&_M_stringbuf); } + { __istream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_istringstream(ios_base::openmode __mode, const allocator_type& __a) : __istream_type(), _M_stringbuf(__mode | ios_base::in, __a) { this->init(std::__addressof(_M_stringbuf)); } @@ -667,10 +716,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_istringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str, ios_base::openmode __mode = ios_base::in) +#ifdef __cpp_lib_sstream_from_string_view + requires (!is_same_v<_SAlloc, allocator_type>) +#endif // C++26 : basic_istringstream(__str, __mode, allocator_type()) { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit basic_istringstream(const _Tp& __t, ios_base::openmode __mode = ios_base::in) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_istringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_istringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_istringstream(__t, ios_base::in, __a) + { } + + template <typename _Tp> + basic_istringstream(const _Tp& __t, ios_base::openmode __mode, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : __istream_type(), _M_stringbuf(__t, __mode | ios_base::in, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_istringstream& @@ -702,7 +774,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -716,6 +788,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -747,6 +820,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -758,6 +832,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; @@ -812,7 +894,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_ostringstream() : __ostream_type(), _M_stringbuf(ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -829,7 +911,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_ostringstream(ios_base::openmode __mode) : __ostream_type(), _M_stringbuf(__mode | ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -848,7 +930,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_ostringstream(const __string_type& __str, ios_base::openmode __mode = ios_base::out) : __ostream_type(), _M_stringbuf(__str, __mode | ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -865,9 +947,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_ostringstream(basic_ostringstream&& __rhs) : __ostream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __ostream_type::set_rdbuf(&_M_stringbuf); } + { __ostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_ostringstream(ios_base::openmode __mode, const allocator_type& __a) : __ostream_type(), _M_stringbuf(__mode | ios_base::out, __a) { this->init(std::__addressof(_M_stringbuf)); } @@ -899,6 +982,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit basic_ostringstream(const _Tp& __t, ios_base::openmode __mode = ios_base::out) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_ostringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_ostringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_ostringstream(__t, ios_base::out, __a) + { } + + template <typename _Tp> + basic_ostringstream(const _Tp& __t, ios_base::openmode __mode, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : __ostream_type(), _M_stringbuf(__t, __mode | ios_base::out, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_ostringstream& @@ -930,7 +1033,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -944,6 +1047,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -975,6 +1079,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -986,6 +1091,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; @@ -1040,7 +1153,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_stringstream() : __iostream_type(), _M_stringbuf(ios_base::out | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -1055,7 +1168,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_stringstream(ios_base::openmode __m) : __iostream_type(), _M_stringbuf(__m) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -1072,7 +1185,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_stringstream(const __string_type& __str, ios_base::openmode __m = ios_base::out | ios_base::in) : __iostream_type(), _M_stringbuf(__str, __m) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -1089,12 +1202,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_stringstream(basic_stringstream&& __rhs) : __iostream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __iostream_type::set_rdbuf(&_M_stringbuf); } + { __iostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_stringstream(ios_base::openmode __mode, const allocator_type& __a) : __iostream_type(), _M_stringbuf(__mode, __a) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } explicit basic_stringstream(__string_type&& __str, @@ -1125,6 +1239,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit basic_stringstream(const _Tp& __t, + ios_base::openmode __mode = ios_base::in | ios_base::out) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_stringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_stringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : basic_stringstream(__t, ios_base::in | ios_base::out, __a) + { } + + template <typename _Tp> + basic_stringstream(const _Tp& __t, ios_base::openmode __mode, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : __iostream_type(), _M_stringbuf(__t, __mode, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_stringstream& @@ -1156,7 +1291,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -1170,6 +1305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -1201,6 +1337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -1212,6 +1349,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; #if __cplusplus >= 201103L diff --git a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc new file mode 100644 index 00000000000..4c27ad2ea07 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc @@ -0,0 +1,193 @@ +// C++26 [istringstream.general] + +// { dg-do run { target c++26 } } +// { dg-require-effective-target cxx11_abi } + +#include <sstream> +#include <string> +#include <string_view> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> + +// Check C++26 P2495 istringstream ctors and members str(s) that accept a +// string_view, or anything convertible to a string_view, in place of a +// string object. Mostly just verify plumbing. + +struct convertible_to_string_view { + std::string s; + operator std::string_view() const { return s; } +}; + +const std::string str("This is a test string"); +convertible_to_string_view cstr{str}; // a copy +const convertible_to_string_view ccstr{str}; // another copy + +template <typename istringstream = std::basic_istringstream<char>> +void +test01() +{ + // Test C++26 constructor and str(s) taking a generalized string_view + + static_assert(! requires { istringstream(1); }, + "istringstream ctor should reject what cannot be converted to a string_view"); + static_assert(! requires { istringstream().str(1); }, + "istringstream::str(s) should reject what cannot be converted to a string_view"); + + static_assert(!std::is_convertible_v<std::string_view, std::istringstream>, + "istringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const std::string_view, std::istringstream>, + "istringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<convertible_to_string_view, std::istringstream>, + "istringstream(convertible_to_string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const convertible_to_string_view, std::istringstream>, + "istringstream(convertible_to_string_view, ios::openmode) is explicit"); + + { + std::istringstream istr(cstr); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + } + { + std::istringstream istr(ccstr); + VERIFY( istr.str() == ccstr.s ); + VERIFY( istr.get() == ccstr.s[0] ); + } + { + std::istringstream istr(cstr, std::ios_base::in); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } + { + std::istringstream istr(cstr, std::ios_base::out); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } +} + +void +test02() +{ + // Test C++26 constructors taking string views using different allocators + + using alloc_type = __gnu_test::tracker_allocator<char>; + using str_type = std::basic_string<char, std::char_traits<char>, alloc_type>; + + auto const mode = std::ios_base::in | std::ios_base::out; + + { + // template <typename T> + // basic_istringstream(const T&, ios_base::openmode, const allocator_type&) + + std::istringstream::allocator_type a; + { + std::istringstream istr(cstr, mode, a); // ={} checks for non-explicit ctor + VERIFY( istr.str() == cstr.s ); + } + { + std::istringstream istr(cstr, std::ios::in, a); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } + { + std::istringstream istr(cstr, std::ios::out, a); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } + } + + { + // template <typename T> + // basic_istringstream(const T&, ios_base::openmode) + { + std::istringstream istr(cstr, mode); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } + { + std::istringstream istr(cstr, std::ios::in); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } + { + std::istringstream istr(cstr, std::ios::out); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } + } + + { + // template <typename T> + // explicit + // basic_istringstream(const T&, ios_base::openmode = ios_base::in) + + std::istringstream istr(cstr); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } +} + +// A minimal allocator with no default constructor +template<typename T> + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> + { + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; + NoDefaultCons() = delete; + NoDefaultCons(int) { } + }; + +template<typename Alloc, typename C = typename Alloc::value_type> + using istringstream_with_alloc + = std::basic_istringstream<C, std::char_traits<C>, Alloc>; + +void test03() +{ + NoDefaultCons<char> a{1}; + { + istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, a); + VERIFY( std::string_view{istr.str()} == cstr ); + VERIFY( istr.get() == cstr.s[0] ); + } + { + istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, std::ios::in, a); + VERIFY( std::string_view{istr.str()} == cstr ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } + { + istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, std::ios::out, a); + VERIFY( std::string_view{istr.str()} == cstr ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } +} + +void test04() +{ + { + std::istringstream istr; + istr.str( cstr ); + VERIFY( istr.str() == cstr.s ); + } + { + std::istringstream istr; + istr.str( ccstr ); + VERIFY( istr.str() == ccstr.s ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc new file mode 100644 index 00000000000..1ca27dfbfa5 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc @@ -0,0 +1,193 @@ +// C++26 [ostringstream.general] + +// { dg-do run { target c++26 } } +// { dg-require-effective-target cxx11_abi } + +#include <sstream> +#include <string> +#include <string_view> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> + +// Check C++26 P2495 ostringstream ctors and members str(s) that accept a +// string_view, or anything convertible to a string_view, in place of a +// string object. Mostly just verify plumbing. + +struct convertible_to_string_view { + std::string s; + operator std::string_view() const { return s; } +}; + +const std::string str("This is a test string"); +convertible_to_string_view cstr{str}; // a copy +const convertible_to_string_view ccstr{str}; // another copy + +template <typename ostringstream = std::basic_ostringstream<char>> +void +test01() +{ + // Test C++26 constructor and str(s) taking a generalized string_view + + static_assert(! requires { ostringstream(1); }, + "ostringstream ctor should reject what cannot be converted to a string_view"); + static_assert(! requires { ostringstream().str(1); }, + "ostringstream::str(s) should reject what cannot be converted to a string_view"); + + static_assert(!std::is_convertible_v<std::string_view, std::ostringstream>, + "ostringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const std::string_view, std::ostringstream>, + "ostringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<convertible_to_string_view, std::ostringstream>, + "ostringstream(convertible_to_string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const convertible_to_string_view, std::ostringstream>, + "ostringstream(convertible_to_string_view, ios::openmode) is explicit"); + + { + std::ostringstream ostrstr(cstr); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() ); + } + { + std::ostringstream ostrstr(ccstr); + VERIFY( ostrstr.str() == ccstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() ); + } + { + std::ostringstream ostrstr(cstr, std::ios_base::in); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } + { + std::ostringstream ostrstr(cstr, std::ios_base::out); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() ); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } +} + +void +test02() +{ + // Test C++26 constructors taking string views using different allocators + + using alloc_type = __gnu_test::tracker_allocator<char>; + using str_type = std::basic_string<char, std::char_traits<char>, alloc_type>; + + auto const mode = std::ios_base::in | std::ios_base::out; + + { + std::ostringstream::allocator_type a; + // template <typename T> + // basic_ostringstream(const T&, ios_base::openmode, const allocator_type&) + { + std::ostringstream ostrstr(cstr, mode, a); // ={} checks for non-explicit ctor + VERIFY( ostrstr.str() == cstr.s ); + } + { + std::ostringstream ostrstr(cstr, std::ios::in, a); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } + { + std::ostringstream ostrstr(cstr, std::ios::out, a); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() ); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } + } + + { + // template <typename T> + // basic_ostringstream(const T&, ios_base::openmode) + { + std::ostringstream ostrstr(cstr, mode); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('Y').good() ); + } + { + std::ostringstream ostrstr(cstr, std::ios::in); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('X').good() ); + } + { + std::ostringstream ostrstr(cstr, std::ios::out); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() ); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } + } + + { + // template <typename T> + // explicit + // basic_ostringstream(const T&, ios_base::openmode = ios_base::out) + + std::ostringstream ostrstr(cstr); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() ); + VERIFY( ostrstr.put('Y').good() ); + } +} + +// A minimal allocator with no default constructor +template<typename T> + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> + { + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; + NoDefaultCons() = delete; + NoDefaultCons(int) { } + }; + +template<typename Alloc, typename C = typename Alloc::value_type> + using ostringstream_with_alloc + = std::basic_ostringstream<C, std::char_traits<C>, Alloc>; + +void test03() +{ + NoDefaultCons<char> a{1}; + { + ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, a); + VERIFY( std::string_view{ostrstr.str()} == cstr ); + VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() ); + VERIFY( ostrstr.put('X').good() ); + } + { + ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, std::ios::in, a); + VERIFY( std::string_view{ostrstr.str()} == cstr ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('X').good() ); + } + { + ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, std::ios::out, a); + VERIFY( std::string_view{ostrstr.str()} == cstr ); + VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() ); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } +} + +void test04() +{ + { + std::ostringstream ostrstr; + ostrstr.str(cstr); + VERIFY( ostrstr.str() == cstr.s ); + } + { + std::ostringstream ostrstr; + ostrstr.str(ccstr); + VERIFY( ostrstr.str() == ccstr.s ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc new file mode 100644 index 00000000000..35f544c1201 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc @@ -0,0 +1,216 @@ +// C++26 31.8.2.1 [stringbuf.general] + +// { dg-do run { target c++26 } } +// { dg-require-effective-target cxx11_abi } + +#include <sstream> +#include <string> +#include <string_view> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> + +// Check C++26 P2495 stringbuf ctors and members str(s) that accept a +// string_view, or anything convertible to a string_view, in place of a +// string object. + +struct convertible_to_string_view { + std::string s; + operator std::string_view() const { return s; } +}; + +struct convertible_to_both { + std::string s; + operator std::string_view() const { return s; } + operator std::string() const { return s; } +}; + +const std::string str("This is a test string"); +convertible_to_string_view cstr{str}; // a copy +const convertible_to_string_view ccstr{str}; // another copy +convertible_to_both bcstr{str}; + +template <typename stringbuf = std::basic_stringbuf<char>> +void +test01() +{ + // Test C++26 constructor and str(s) taking a generalized string_view + + static_assert(! requires { stringbuf(1); }, + "stringbuf ctor should reject what cannot be converted to a string_view"); + static_assert(! requires { stringbuf().str(1); }, + "stringbuf::str(s) should reject what cannot be converted to a string_view"); + + static_assert(!std::is_convertible_v<std::string_view, std::stringbuf>, + "stringbuf(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const std::string_view, std::stringbuf>, + "stringbuf(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<convertible_to_string_view, std::stringbuf>, + "stringbuf(convertible_to_string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const convertible_to_string_view, std::stringbuf>, + "stringbuf(convertible_to_string_view, ios::openmode) is explicit"); + + { + std::stringbuf sbuf(cstr); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + } + { // check from a const source object + std::stringbuf sbuf(ccstr); + VERIFY( sbuf.str() == ccstr.s ); + VERIFY( sbuf.sgetc() == ccstr.s[0] ); + } + { // check from a type that has conversions to both std::string + // and std::string_view + std::stringbuf sbuf(bcstr); + VERIFY( sbuf.str() == bcstr.s ); + VERIFY( sbuf.sgetc() == ccstr.s[0] ); + } + { + std::stringbuf sbuf(cstr, std::ios_base::in); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); + } + { + std::stringbuf sbuf(ccstr, std::ios_base::in); + VERIFY( sbuf.str() == ccstr.s ); + VERIFY( sbuf.sgetc() == ccstr.s[0] ); + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); + } + { + std::stringbuf sbuf(cstr, std::ios_base::out); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sputc('Y') == 'Y' ); + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); + } + { + std::stringbuf sbuf(ccstr, std::ios_base::out); + VERIFY( sbuf.str() == ccstr.s ); + VERIFY( sbuf.sputc('Y') == 'Y' ); + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); + } +} + +void +test02() +{ + // Test C++26 constructors taking string views using different allocators + + using alloc_type = __gnu_test::tracker_allocator<char>; + using str_type = std::basic_string<char, std::char_traits<char>, alloc_type>; + + auto const mode = std::ios_base::in | std::ios_base::out; + + { + // template <typename T> + // basic_stringbuf(const T&, ios_base::openmode, const allocator_type&) + + std::stringbuf::allocator_type a; + { + std::stringbuf sbuf(cstr, mode, a); // ={} checks for non-explicit ctor + VERIFY( sbuf.str() == cstr.s ); + } + { + std::stringbuf sbuf(cstr, std::ios::in, a); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); + } + + { + std::stringbuf sbuf(cstr, std::ios::out, a); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sputc('X') == 'X' ); + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); + } + } + + { + // template <typename T> + // basic_stringbuf(const T&, ios_base::openmode) + { + std::stringbuf sbuf(cstr, mode); + VERIFY( sbuf.str() == cstr.s ); + } + { + std::stringbuf sbuf(cstr, std::ios::in); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); + } + { + std::stringbuf sbuf(cstr, std::ios::out); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sputc('X') == 'X' ); + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); + } + } + + { + // template <typename T> + // explicit + // basic_stringbuf(const T&, ios_base::openmode = ios_base::in|ios_base::out) + + std::stringbuf sbuf(cstr); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + } +} + +// A minimal allocator with no default constructor +template<typename T> + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> + { + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; + NoDefaultCons() = delete; + NoDefaultCons(int) { } + }; + +template<typename Alloc, typename C = typename Alloc::value_type> + using stringbuf_with_alloc + = std::basic_stringbuf<C, std::char_traits<C>, Alloc>; + +void test03() +{ + NoDefaultCons<char> a{1}; + { + stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, a); + VERIFY( std::string_view{sbuf.str()} == cstr ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + } + { + stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, std::ios::in, a); + VERIFY( std::string_view{sbuf.str()} == cstr ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); + } + { + stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, std::ios::out, a); + VERIFY( std::string_view{sbuf.str()} == cstr ); + VERIFY( sbuf.sputc('X') == 'X' ); + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); + } +} + +void test04() +{ + { + std::stringbuf sbuf; + sbuf.str(cstr); + VERIFY( sbuf.str() == cstr.s ); + } + { + std::stringbuf sbuf; + sbuf.str(ccstr); + VERIFY( sbuf.str() == ccstr.s ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc new file mode 100644 index 00000000000..06fab33a382 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc @@ -0,0 +1,194 @@ +// C++26 31.8.2.1 [stringstream.general] + +// { dg-do run { target c++26 } } +// { dg-require-effective-target cxx11_abi } + +#include <sstream> +#include <string> +#include <string_view> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> + +// Check C++26 P2495 stringstream ctors and members str(s) that accept a +// string_view, or anything convertible to a string_view, in place of a +// string object. Mostly just verify plumbing. + +struct convertible_to_string_view { + std::string s; + operator std::string_view() const { return s; } +}; + +const std::string str("This is a test string"); +convertible_to_string_view cstr{str}; // a copy +const convertible_to_string_view ccstr{str}; // another copy + +template <typename stringstream = std::basic_stringstream<char>> +void +test01() +{ + // Test C++26 constructor and str(s) taking a generalized string_view + + static_assert(! requires { stringstream(1); }, + "stringstream ctor should reject what cannot be converted to a string_view"); + static_assert(! requires { stringstream().str(1); }, + "stringstream::str(s) should reject what cannot be converted to a string_view"); + + static_assert(!std::is_convertible_v<std::string_view, std::stringstream>, + "stringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const std::string_view, std::stringstream>, + "stringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<convertible_to_string_view, std::stringstream>, + "stringstream(convertible_to_string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const convertible_to_string_view, std::stringstream>, + "stringstream(convertible_to_string_view, ios::openmode) is explicit"); + + { + std::stringstream strstr(cstr); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + } + { + std::stringstream strstr(ccstr); + VERIFY( strstr.str() == ccstr.s ); + VERIFY( strstr.get() == ccstr.s[0] ); + } + { + std::stringstream strstr(cstr, std::ios_base::in); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); + } + { + std::stringstream strstr(cstr, std::ios_base::out); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.put('Y').good() ); + VERIFY( strstr.get() == std::stringbuf::traits_type::eof()); + } +} + +void +test02() +{ + // Test C++26 constructors taking string views using different allocators + + using alloc_type = __gnu_test::tracker_allocator<char>; + using str_type = std::basic_string<char, std::char_traits<char>, alloc_type>; + + auto const mode = std::ios_base::in | std::ios_base::out; + + { + // template <typename T> + // basic_stringstream(const T&, ios_base::openmode, const allocator_type&) + + std::stringstream::allocator_type a; + { + std::stringstream strstr(cstr, mode, a); // ={} checks for non-explicit ctor + VERIFY( strstr.str() == cstr.s ); + } + { + std::stringstream strstr(cstr, std::ios::in, a); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); + } + { + std::stringstream strstr(cstr, std::ios::out, a); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.put('X').good() ); + VERIFY( strstr.get() == std::stringbuf::traits_type::eof()); + } + } + + { + // template <typename T> + // basic_stringstream(const T&, ios_base::openmode) + + { + std::stringstream strstr(cstr, mode); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').good() ); + } + { + std::stringstream strstr(cstr, std::ios::in); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); + } + { + std::stringstream strstr(cstr, std::ios::out); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.put('X').good() ); + VERIFY( strstr.get() == std::stringbuf::traits_type::eof()); + } + } + + { + // template <typename T> + // explicit + // basic_stringstream(const T&, ios_base::openmode = ios_base::in|ios_base::out) + + std::stringstream strstr(cstr); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').good() ); + } +} + +// A minimal allocator with no default constructor +template<typename T> + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> + { + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; + NoDefaultCons() = delete; + NoDefaultCons(int) { } + }; + +template<typename Alloc, typename C = typename Alloc::value_type> + using stringstream_with_alloc + = std::basic_stringstream<C, std::char_traits<C>, Alloc>; + +void test03() +{ + NoDefaultCons<char> a{1}; + { + stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, a); + VERIFY( std::string_view{strstr.str()} == cstr ); + VERIFY( strstr.get() == cstr.s[0] ); + } + { + stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, std::ios::in, a); + VERIFY( std::string_view{strstr.str()} == cstr ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); + } + { + stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, std::ios::out, a); + VERIFY( std::string_view{strstr.str()} == cstr ); + VERIFY( strstr.put('X').good() ); + VERIFY( strstr.get() == std::stringbuf::traits_type::eof()); + } +} + +void test04() +{ + { + std::stringstream strstr; + strstr.str( cstr ); + VERIFY( strstr.str() == cstr.s ); + } + { + std::stringstream strstr; + strstr.str( ccstr ); + VERIFY( strstr.str() == ccstr.s ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} -- 2.49.0