On Tue, 20 May 2025 at 09:10, Tomasz Kaminski <tkami...@redhat.com> wrote: > > > > On Mon, May 19, 2025 at 11:28 PM Nathan Myers <n...@cantrip.org> wrote: > In the title, we usually put link to bugzilla PR119741 in your case, not the > paper. > Then link the paper in commit descritpion.
Right. When there's no bugzilla I'll sometimes put the paper number in parens, e.g. in https://gcc.gnu.org/g:91f4550e1700 which has this summary: libstdc++: Move std::monostate to <utility> for C++26 (P0472R2) But the paper number should not be in square brackets, that should be reserved for a bugzilla PR number if there is one (and for this feature, we do have a bugzilla PR). > >> 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. > > > After you put bugzilla number, git gcc-verify will suggest you to add > following node: > <tab>PR libstdc++/119741 > >> >> >> libstdc++-v3/ChangeLog: >> >> P2495R3 stringstream to init from string_view-ish > > We usually put only the change files here. Did git gcc-verify accepted it. >> >> * 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. >> + > > Changelogs are now automatically generated from commit messages, so you do not > need to edit this file. >> >> 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) > > Any reason for not initializing _M_string(t, __a) directly here, string has > string_view constructor. More importantly, it has a "convertible to string_view" constructor, which matches the constraint on _Tp here. So it does look like we can just construct _M_string directly from __t and __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 > > Standard have same constraint of ostringstream > (https://eel.is/c++draft/string.streams#ostringstream.cons-6): > Constraints: is_same_v<SAlloc,Allocator> is false. > Do we miss some library issue? P2495R3 adds this to basic_istringstream with this note: [DRAFTING NOTE: Drive-by fix, this adds a missing constraint present in stringstream and ostringstream.] The constraints were added elsewhere by P0408 so I missed adding those constraints in https://gcc.gnu.org/g:95cb0fc8c51841 Nathan, could you please add that same !is_same_v constraint to the basic_stringbuf, basic_ostringstream and basic_stringstream constructors as part of this patch? > >> : 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>; > > I would use __gnu_test::uneq_allocator<>, as it have state (int), that is > checked in equality in VERIFY. > >> >> + 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 >>