Reverted. (was Re: [PATCH v4] libstdc++: stringstream ctors from string_view [PR119741])
Nathan Myers
ncm@cantrip.org
Thu Jun 5 03:23:03 GMT 2025
On 6/4/25 20:30, H.J. Lu wrote:
> On Wed, Jun 4, 2025 at 8:02 PM Jonathan Wakely <jwakely@redhat.com> wrote:
>>
>> On Thu, 29 May 2025 at 20:30, Nathan Myers <ncm@cantrip.org> wrote:
>>>
>>> Change in V4:
>>> * Rename tests to string_view.cc
>>> * Adapt tests to cons/wchar_t directories
>>> * Define symbol __cpp_lib_sstream_from_string_view as 202406
>>> * Define symbol __glibcxx_want_sstream_from_string_view before version.h
>>> * Include version.h after other includes
>>> * No include type_traits
>>> * Drive-by comment moved to commit message
>>> * Each `explicit` on its own line
>>> * Run tests even when using old COW string
>>>
>>> Change in V3:
>>> * Comment that p2495 specifies a drive-by constraint omitted as redundant
>>> * Adjust whitespace to fit in 80 columns
>>>
>>> Change in V2:
>>> * Apply all review comments
>>> * Remove redundant drive-by "requires" on ctor from string allocator arg
>>> * Check allocators are plumbed through
>>
>> Looks great now, thanks for iterating on it.
>>
>> Please push to trunk (you'll probably need to rebase first, which will
>> have a merge conflict in bits/version.h but just regenerating it again
>> will resolve that).
>
> On Fedora 42/x86-64, I got
>
> FAIL: 27_io/basic_istringstream/cons/wchar_t/string_view.cc
> -std=gnu++17 (test for excess errors)
> Excess errors:
> /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39:
> error: 'requires' only available with '-std=c++20' or '-fconcepts'
> [-Wtemplate-body]
> /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39:
> error: expected ',' before '{' token [-Wtemplate-body]
> /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39:
> warning: 'static_assert' with non-string message only available with
> '-std=c++2c' or '-std=gnu++2c' [-Wc++26-extensions]
> /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39:
> error: expected primary-expression before '{' token [-Wtemplate-body]
> /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39:
> error: expected ')' before '{' token [-Wtemplate-body]
> /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:41:
> error: 'requires' only available with '-std=c++20' or '-fconcepts'
> [-Wtemplate-body]
> /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:41:
> error: expected ',' before '{' token [-Wtemplate-body]
Reverted a31e76a2643.
>>> -- >8 --
>>>
>>> Implement PR libstdc++/119741 (P2495R3).
>>> 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 in places where the existing ctors and function take a string.
>>> Note this change omits the constraint applied to the istringstream constructor
>>> from string cited as a "drive-by" in P2495R3, as we have determined it is
>>> redundant.
>>>
>>> libstdc++-v3/ChangeLog:
>>>
>>> PR libstdc++/119741
>>> * include/std/sstream: full implementation, really just
>>> decls, requires clause and plumbing.
>>> * include/bits/version.def, include/bits/version.h:
>>> new preprocessor symbol
>>> __cpp_lib_sstream_from_string_view.
>>> * testsuite/27_io/basic_stringbuf/cons/char/string_view.cc:
>>> New tests.
>>> * testsuite/27_io/basic_istringstream/cons/char/string_view.cc:
>>> New tests.
>>> * testsuite/27_io/basic_ostringstream/cons/char/string_view.cc:
>>> New tests.
>>> * testsuite/27_io/basic_stringstream/cons/char/string_view.cc:
>>> New tests.
>>> * testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc:
>>> New tests.
>>> * testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc:
>>> New tests.
>>> * testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc:
>>> New tests.
>>> * testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc:
>>> New tests.
>>> ---
>>> libstdc++-v3/include/bits/version.def | 11 +-
>>> libstdc++-v3/include/bits/version.h | 10 +
>>> libstdc++-v3/include/std/sstream | 198 +++++++++++++++--
>>> .../cons/char/string_view.cc | 195 +++++++++++++++++
>>> .../cons/wchar_t/string_view.cc | 3 +
>>> .../cons/char/string_view.cc | 194 +++++++++++++++++
>>> .../cons/wchar_t/string_view.cc | 3 +
>>> .../basic_stringbuf/cons/char/string_view.cc | 205 ++++++++++++++++++
>>> .../cons/wchar_t/string_view.cc | 3 +
>>> .../cons/char/string_view.cc | 204 +++++++++++++++++
>>> .../cons/wchar_t/string_view.cc | 3 +
>>> 11 files changed, 1010 insertions(+), 19 deletions(-)
>>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc
>>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc
>>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc
>>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc
>>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc
>>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc
>>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc
>>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc
>>>
>>> diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
>>> index 282667eabda..53bf72d95c2 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;
>>> @@ -1945,6 +1945,15 @@ ftms = {
>>> };
>>> };
>>>
>>> +ftms = {
>>> + name = sstream_from_string_view;
>>> + values = {
>>> + v = 202306;
>>> + 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 bb7c0479c72..0b932183e5b 100644
>>> --- a/libstdc++-v3/include/bits/version.h
>>> +++ b/libstdc++-v3/include/bits/version.h
>>> @@ -2174,4 +2174,14 @@
>>> #endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */
>>> #undef __glibcxx_want_modules
>>>
>>> +#if !defined(__cpp_lib_sstream_from_string_view)
>>> +# if (__cplusplus >= 202306L) && _GLIBCXX_HOSTED
>>> +# define __glibcxx_sstream_from_string_view 202306L
>>> +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_sstream_from_string_view)
>>> +# define __cpp_lib_sstream_from_string_view 202306L
>>> +# 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..edef599bd6f 100644
>>> --- a/libstdc++-v3/include/std/sstream
>>> +++ b/libstdc++-v3/include/std/sstream
>>> @@ -41,8 +41,12 @@
>>>
>>> #include <istream>
>>> #include <ostream>
>>> +
>>> #include <bits/alloc_traits.h> // allocator_traits, __allocator_like
>>>
>>> +#define __glibcxx_want_sstream_from_string_view
>>> +#include <bits/version.h>
>>> +
>>> #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>>> # define _GLIBCXX_LVAL_REF_QUAL &
>>> # define _GLIBCXX_SSTREAM_ALWAYS_INLINE
>>> @@ -52,8 +56,6 @@
>>> # define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]]
>>> #endif
>>>
>>> -
>>> -
>>> namespace std _GLIBCXX_VISIBILITY(default)
>>> {
>>> _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>> @@ -159,6 +161,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 +200,36 @@ _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>>)
>>> + : _M_string(__t, __a)
>>> + { _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,19 @@ _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 +568,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 +633,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 +650,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 +669,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 +686,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)); }
>>> @@ -671,6 +721,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>> { }
>>> #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 +778,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 +792,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 +824,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 +836,15 @@ _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 +899,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 +916,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 +935,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 +952,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 +987,32 @@ _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 +1044,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 +1058,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 +1090,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 +1102,15 @@ _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 +1165,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 +1180,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 +1197,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 +1214,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 +1251,31 @@ _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 +1307,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 +1321,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 +1353,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 +1365,15 @@ _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/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc
>>> new file mode 100644
>>> index 00000000000..27f65aa9437
>>> --- /dev/null
>>> +++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc
>>> @@ -0,0 +1,195 @@
>>> +// C++26 [istringstream.general]
>>> +
>>> +// { dg-do run { target c++26 } }
>>> +
>>> +#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.
>>> +
>>> +#ifndef C
>>> +# define C char
>>> +# define L(a) a
>>> +#endif
>>> +
>>> +using string = std::basic_string<C>;
>>> +using string_view = std::basic_string_view<C>;
>>> +using istringstream = std::basic_istringstream<C>;
>>> +
>>> +struct convertible_to_string_view {
>>> + string s;
>>> + operator string_view() const { return s; }
>>> +};
>>> +
>>> +const string str(L("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<C>>
>>> +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<string_view, istringstream>,
>>> + "istringstream(string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<const string_view, istringstream>,
>>> + "istringstream(string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<convertible_to_string_view, istringstream>,
>>> + "istringstream(convertible_to_string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<const convertible_to_string_view, istringstream>,
>>> + "istringstream(convertible_to_string_view, ios::openmode) is explicit");
>>> +
>>> + {
>>> + istringstream istr(cstr);
>>> + VERIFY( istr.str() == cstr.s );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + }
>>> + {
>>> + istringstream istr(ccstr);
>>> + VERIFY( istr.str() == ccstr.s );
>>> + VERIFY( istr.get() == ccstr.s[0] );
>>> + }
>>> + {
>>> + istringstream istr(cstr, std::ios_base::in);
>>> + VERIFY( istr.str() == cstr.s );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>>> + }
>>> + {
>>> + 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 various C++26 constructors taking string views
>>> + // and mix of other arguments
>>> +
>>> + auto const mode = std::ios_base::in | std::ios_base::out;
>>> +
>>> + {
>>> + // template <typename T>
>>> + // basic_istringstream(const T&, ios_base::openmode, const allocator_type&)
>>> +
>>> + istringstream::allocator_type a;
>>> + {
>>> + istringstream istr(cstr, mode, a); // ={} checks for non-explicit ctor
>>> + VERIFY( istr.str() == cstr.s );
>>> + }
>>> + {
>>> + istringstream istr(cstr, std::ios::in, a);
>>> + VERIFY( istr.str() == cstr.s );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>>> + }
>>> + {
>>> + 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)
>>> + {
>>> + istringstream istr(cstr, mode);
>>> + VERIFY( istr.str() == cstr.s );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + VERIFY( istr.rdbuf()->sputc('X') == 'X' );
>>> + }
>>> + {
>>> + istringstream istr(cstr, std::ios::in);
>>> + VERIFY( istr.str() == cstr.s );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>>> + }
>>> + {
>>> + 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)
>>> +
>>> + istringstream istr(cstr);
>>> + VERIFY( istr.str() == cstr.s );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>>> + }
>>> +}
>>> +
>>> +using alloc_type = __gnu_test::uneq_allocator<C>;
>>> +
>>> +template<typename Alloc, typename CC = typename Alloc::value_type>
>>> + using istringstream_with_alloc
>>> + = std::basic_istringstream<CC, std::char_traits<CC>, Alloc>;
>>> +
>>> +void test03()
>>> +{
>>> + alloc_type a{1};
>>> + {
>>> + istringstream_with_alloc<alloc_type> istr(cstr, a);
>>> + VERIFY( istr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{istr.str()} == cstr );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + }
>>> + {
>>> + istringstream_with_alloc<alloc_type> istr(cstr, std::ios::in, a);
>>> + VERIFY( istr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{istr.str()} == cstr );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>>> + }
>>> + {
>>> + istringstream_with_alloc<alloc_type> istr(cstr, std::ios::out, a);
>>> + VERIFY( istr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{istr.str()} == cstr );
>>> + VERIFY( istr.get() == cstr.s[0] );
>>> + VERIFY( istr.rdbuf()->sputc('X') == 'X' );
>>> + }
>>> +}
>>> +
>>> +void test04()
>>> +{
>>> + {
>>> + istringstream istr;
>>> + istr.str( cstr );
>>> + VERIFY( istr.str() == cstr.s );
>>> + }
>>> + {
>>> + 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_istringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc
>>> new file mode 100644
>>> index 00000000000..cfb73c4c510
>>> --- /dev/null
>>> +++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc
>>> @@ -0,0 +1,3 @@
>>> +#define C wchar_t
>>> +#define L(a) L##a
>>> +#include "../char/string_view.cc"
>>> diff --git a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc
>>> new file mode 100644
>>> index 00000000000..731e97e4aa2
>>> --- /dev/null
>>> +++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc
>>> @@ -0,0 +1,194 @@
>>> +// C++26 [ostringstream.general]
>>> +
>>> +// { dg-do run { target c++26 } }
>>> +
>>> +#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.
>>> +
>>> +#ifndef C
>>> +# define C char
>>> +# define L(a) a
>>> +#endif
>>> +
>>> +using string = std::basic_string<C>;
>>> +using string_view = std::basic_string_view<C>;
>>> +using ostringstream = std::basic_ostringstream<C>;
>>> +
>>> +struct convertible_to_string_view {
>>> + string s;
>>> + operator string_view() const { return s; }
>>> +};
>>> +
>>> +const string str(L("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<C>>
>>> +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<string_view, ostringstream>,
>>> + "ostringstream(string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<const string_view, ostringstream>,
>>> + "ostringstream(string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<convertible_to_string_view, ostringstream>,
>>> + "ostringstream(convertible_to_string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<const convertible_to_string_view, ostringstream>,
>>> + "ostringstream(convertible_to_string_view, ios::openmode) is explicit");
>>> +
>>> + {
>>> + ostringstream ostrstr(cstr);
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
>>> + }
>>> + {
>>> + ostringstream ostrstr(ccstr);
>>> + VERIFY( ostrstr.str() == ccstr.s );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
>>> + }
>>> + {
>>> + 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 );
>>> + }
>>> + {
>>> + ostringstream ostrstr(cstr, std::ios_base::out);
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
>>> + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>>> + }
>>> +}
>>> +
>>> +void
>>> +test02()
>>> +{
>>> + // Test plumbing of C++26 various constructors taking string views
>>> +
>>> + auto const mode = std::ios_base::in | std::ios_base::out;
>>> +
>>> + {
>>> + ostringstream::allocator_type a;
>>> + // template <typename T>
>>> + // basic_ostringstream(const T&, ios_base::openmode, const allocator_type&)
>>> + {
>>> + ostringstream ostrstr(cstr, mode, a); // ={} checks for non-explicit ctor
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + }
>>> + {
>>> + 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 );
>>> + }
>>> + {
>>> + ostringstream ostrstr(cstr, std::ios::out, a);
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
>>> + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>>> + }
>>> + }
>>> +
>>> + {
>>> + // template <typename T>
>>> + // basic_ostringstream(const T&, ios_base::openmode)
>>> + {
>>> + ostringstream ostrstr(cstr, mode);
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
>>> + VERIFY( ostrstr.put('Y').good() );
>>> + }
>>> + {
>>> + ostringstream ostrstr(cstr, std::ios::in);
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
>>> + VERIFY( ostrstr.put('X').good() );
>>> + }
>>> + {
>>> + ostringstream ostrstr(cstr, std::ios::out);
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
>>> + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>>> + }
>>> + }
>>> +
>>> + {
>>> + // template <typename T>
>>> + // explicit
>>> + // basic_ostringstream(const T&, ios_base::openmode = ios_base::out)
>>> +
>>> + ostringstream ostrstr(cstr);
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
>>> + VERIFY( ostrstr.put('Y').good() );
>>> + }
>>> +}
>>> +
>>> +using alloc_type = __gnu_test::uneq_allocator<C>;
>>> +
>>> +template<typename Alloc, typename CC = typename Alloc::value_type>
>>> + using ostringstream_with_alloc
>>> + = std::basic_ostringstream<CC, std::char_traits<CC>, Alloc>;
>>> +
>>> +void test03()
>>> +{
>>> + alloc_type a{1};
>>> + {
>>> + ostringstream_with_alloc<alloc_type> ostrstr(cstr, a);
>>> + VERIFY( ostrstr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{ostrstr.str()} == cstr );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
>>> + VERIFY( ostrstr.put('X').good() );
>>> + }
>>> + {
>>> + ostringstream_with_alloc<alloc_type> ostrstr(cstr, std::ios::in, a);
>>> + VERIFY( ostrstr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{ostrstr.str()} == cstr );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
>>> + VERIFY( ostrstr.put('X').good() );
>>> + }
>>> + {
>>> + ostringstream_with_alloc<alloc_type> ostrstr(cstr, std::ios::out, a);
>>> + VERIFY( ostrstr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{ostrstr.str()} == cstr );
>>> + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
>>> + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>>> + }
>>> +}
>>> +
>>> +void test04()
>>> +{
>>> + {
>>> + ostringstream ostrstr;
>>> + ostrstr.str(cstr);
>>> + VERIFY( ostrstr.str() == cstr.s );
>>> + }
>>> + {
>>> + 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_ostringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc
>>> new file mode 100644
>>> index 00000000000..cfb73c4c510
>>> --- /dev/null
>>> +++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc
>>> @@ -0,0 +1,3 @@
>>> +#define C wchar_t
>>> +#define L(a) L##a
>>> +#include "../char/string_view.cc"
>>> diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc
>>> new file mode 100644
>>> index 00000000000..7843269c48f
>>> --- /dev/null
>>> +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc
>>> @@ -0,0 +1,205 @@
>>> +// C++26 31.8.2.1 [stringbuf.general]
>>> +
>>> +// { dg-do run { target c++26 } }
>>> +
>>> +#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.
>>> +
>>> +#ifndef C
>>> +# define C char
>>> +# define L(a) a
>>> +#endif
>>> +
>>> +using string = std::basic_string<C>;
>>> +using string_view = std::basic_string_view<C>;
>>> +using stringbuf = std::basic_stringbuf<C>;
>>> +
>>> +struct convertible_to_string_view {
>>> + string s;
>>> + operator string_view() const { return s; }
>>> +};
>>> +
>>> +const string str(L("This is a test string"));
>>> +convertible_to_string_view cstr{str}; // a copy
>>> +const convertible_to_string_view ccstr{str}; // another copy
>>> +
>>> +template <typename stringbuf = std::basic_stringbuf<C>>
>>> +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<string_view, stringbuf>,
>>> + "stringbuf(string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<const string_view, stringbuf>,
>>> + "stringbuf(string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<convertible_to_string_view, stringbuf>,
>>> + "stringbuf(convertible_to_string_view, ios::openmode) is explicit");
>>> + static_assert(
>>> + !std::is_convertible_v<const convertible_to_string_view, stringbuf>,
>>> + "stringbuf(convertible_to_string_view, ios::openmode) is explicit");
>>> +
>>> + {
>>> + stringbuf sbuf(cstr);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + VERIFY( sbuf.sgetc() == cstr.s[0] );
>>> + }
>>> + {
>>> + stringbuf sbuf(ccstr);
>>> + VERIFY( sbuf.str() == ccstr.s );
>>> + VERIFY( sbuf.sgetc() == ccstr.s[0] );
>>> + }
>>> + {
>>> + stringbuf sbuf(cstr, std::ios_base::in);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + VERIFY( sbuf.sgetc() == cstr.s[0] );
>>> + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
>>> + }
>>> + {
>>> + stringbuf sbuf(ccstr, std::ios_base::in);
>>> + VERIFY( sbuf.str() == ccstr.s );
>>> + VERIFY( sbuf.sgetc() == ccstr.s[0] );
>>> + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
>>> + }
>>> + {
>>> + stringbuf sbuf(cstr, std::ios_base::out);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + VERIFY( sbuf.sputc('Y') == 'Y' );
>>> + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
>>> + }
>>> + {
>>> + stringbuf sbuf(ccstr, std::ios_base::out);
>>> + VERIFY( sbuf.str() == ccstr.s );
>>> + VERIFY( sbuf.sputc('Y') == 'Y' );
>>> + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
>>> + }
>>> +}
>>> +
>>> +void
>>> +test02()
>>> +{
>>> + // Test C++26 constructors taking string views using different allocators
>>> +
>>> + auto const mode = std::ios_base::in | std::ios_base::out;
>>> +
>>> + {
>>> + // template <typename T>
>>> + // basic_stringbuf(const T&, ios_base::openmode, const allocator_type&)
>>> +
>>> + stringbuf::allocator_type a;
>>> + {
>>> + stringbuf sbuf(cstr, mode, a); // ={} checks for non-explicit ctor
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + }
>>> + {
>>> + stringbuf sbuf(cstr, std::ios::in, a);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + VERIFY( sbuf.sgetc() == cstr.s[0] );
>>> + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
>>> + }
>>> +
>>> + {
>>> + stringbuf sbuf(cstr, std::ios::out, a);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + VERIFY( sbuf.sputc('X') == 'X' );
>>> + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
>>> + }
>>> + }
>>> +
>>> + {
>>> + // template <typename T>
>>> + // basic_stringbuf(const T&, ios_base::openmode)
>>> + {
>>> + stringbuf sbuf(cstr, mode);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + }
>>> + {
>>> + stringbuf sbuf(cstr, std::ios::in);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + VERIFY( sbuf.sgetc() == cstr.s[0] );
>>> + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
>>> + }
>>> + {
>>> + stringbuf sbuf(cstr, std::ios::out);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + VERIFY( sbuf.sputc('X') == 'X' );
>>> + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
>>> + }
>>> + }
>>> +
>>> + {
>>> + // template <typename T>
>>> + // explicit
>>> + // basic_stringbuf(const T&, ios_base::openmode = ios_base::in|ios_base::out)
>>> +
>>> + stringbuf sbuf(cstr);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + VERIFY( sbuf.sgetc() == cstr.s[0] );
>>> + }
>>> +}
>>> +
>>> +using alloc_type = __gnu_test::uneq_allocator<C>;
>>> +
>>> +template<typename Alloc, typename CC = typename Alloc::value_type>
>>> + using stringbuf_with_alloc
>>> + = std::basic_stringbuf<CC, std::char_traits<CC>, Alloc>;
>>> +
>>> +void test03()
>>> +{
>>> + alloc_type a{1};
>>> + {
>>> + stringbuf_with_alloc<alloc_type> sbuf(cstr, a);
>>> + VERIFY( sbuf.get_allocator() == a );
>>> + VERIFY( string_view{sbuf.str()} == cstr );
>>> + VERIFY( sbuf.sgetc() == cstr.s[0] );
>>> + }
>>> + {
>>> + stringbuf_with_alloc<alloc_type> sbuf(cstr, std::ios::in, a);
>>> + VERIFY( sbuf.get_allocator() == a );
>>> + VERIFY( string_view{sbuf.str()} == cstr );
>>> + VERIFY( sbuf.sgetc() == cstr.s[0] );
>>> + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
>>> + }
>>> + {
>>> + stringbuf_with_alloc<alloc_type> sbuf(cstr, std::ios::out, a);
>>> + VERIFY( sbuf.get_allocator() == a );
>>> + VERIFY( string_view{sbuf.str()} == cstr );
>>> + VERIFY( sbuf.sputc('X') == 'X' );
>>> + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
>>> + }
>>> +}
>>> +
>>> +void test04()
>>> +{
>>> + {
>>> + stringbuf sbuf;
>>> + sbuf.str(cstr);
>>> + VERIFY( sbuf.str() == cstr.s );
>>> + }
>>> + {
>>> + 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_stringbuf/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc
>>> new file mode 100644
>>> index 00000000000..cfb73c4c510
>>> --- /dev/null
>>> +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc
>>> @@ -0,0 +1,3 @@
>>> +#define C wchar_t
>>> +#define L(a) L##a
>>> +#include "../char/string_view.cc"
>>> diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc
>>> new file mode 100644
>>> index 00000000000..72085230442
>>> --- /dev/null
>>> +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc
>>> @@ -0,0 +1,204 @@
>>> +// C++26 31.8.2.1 [stringstream.general]
>>> +
>>> +// { dg-do run { target c++26 } }
>>> +
>>> +#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.
>>> +
>>> +#ifndef C
>>> +# define C char
>>> +# define L(a) a
>>> +#endif
>>> +
>>> +using string = std::basic_string<C>;
>>> +using string_view = std::basic_string_view<C>;
>>> +using stringstream = std::basic_stringstream<C>;
>>> +
>>> +struct convertible_to_string_view {
>>> + string s;
>>> + operator string_view() const { return s; }
>>> +};
>>> +
>>> +const string str(L("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<C>>
>>> +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<string_view, stringstream>,
>>> + "stringstream(string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<const string_view, stringstream>,
>>> + "stringstream(string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<convertible_to_string_view, stringstream>,
>>> + "stringstream(convertible_to_string_view, ios::openmode) is explicit");
>>> + static_assert(!std::is_convertible_v<const convertible_to_string_view, stringstream>,
>>> + "stringstream(convertible_to_string_view, ios::openmode) is explicit");
>>> +
>>> + {
>>> + stringstream strstr(cstr);
>>> + VERIFY( strstr.str() == cstr.s );
>>> + VERIFY( strstr.get() == cstr.s[0] );
>>> + }
>>> + {
>>> + stringstream strstr(ccstr);
>>> + VERIFY( strstr.str() == ccstr.s );
>>> + VERIFY( strstr.get() == ccstr.s[0] );
>>> + }
>>> + {
>>> + 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 );
>>> + }
>>> + {
>>> + stringstream strstr(cstr, std::ios_base::out);
>>> + VERIFY( strstr.str() == cstr.s );
>>> + VERIFY( strstr.put('Y').good() );
>>> + VERIFY( strstr.get() == stringstream::traits_type::eof());
>>> + }
>>> +}
>>> +
>>> +void
>>> +test02()
>>> +{
>>> + // Test C++26 various constructors taking string views
>>> +
>>> + auto const mode = std::ios_base::in | std::ios_base::out;
>>> +
>>> + {
>>> + // template <typename T>
>>> + // basic_stringstream(const T&, ios_base::openmode, const allocator_type&)
>>> +
>>> + stringstream::allocator_type a;
>>> + {
>>> + stringstream strstr(cstr, mode, a); // ={} checks for non-explicit ctor
>>> + VERIFY( strstr.str() == cstr.s );
>>> + }
>>> + {
>>> + 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 );
>>> + }
>>> + {
>>> + stringstream strstr(cstr, std::ios::out, a);
>>> + VERIFY( strstr.str() == cstr.s );
>>> + VERIFY( strstr.put('X').good() );
>>> + VERIFY( strstr.get() == stringstream::traits_type::eof());
>>> + }
>>> + }
>>> +
>>> + {
>>> + // template <typename T>
>>> + // basic_stringstream(const T&, ios_base::openmode)
>>> +
>>> + {
>>> + stringstream strstr(cstr, mode);
>>> + VERIFY( strstr.str() == cstr.s );
>>> + VERIFY( strstr.get() == cstr.s[0] );
>>> + VERIFY( strstr.put('X').good() );
>>> + }
>>> + {
>>> + stringstream strstr(cstr, std::ios::in);
>>> + VERIFY( strstr.str() == cstr.s );
>>> + VERIFY( strstr.get() == cstr.s[0] );
>>> + VERIFY( strstr.put('X').rdstate() == strstr.badbit );
>>> + }
>>> + {
>>> + stringstream strstr(cstr, std::ios::out);
>>> + VERIFY( strstr.str() == cstr.s );
>>> + VERIFY( strstr.put('X').good() );
>>> + VERIFY( strstr.get() == stringstream::traits_type::eof());
>>> + }
>>> + }
>>> +
>>> + {
>>> + // template <typename T>
>>> + // explicit
>>> + // basic_stringstream(const T&, ios_base::openmode = ios_base::in|ios_base::out)
>>> +
>>> + 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) { }
>>> + };
>>> +
>>> +using alloc_type = __gnu_test::uneq_allocator<C>;
>>> +
>>> +template<typename Alloc, typename CC = typename Alloc::value_type>
>>> + using stringstream_with_alloc
>>> + = std::basic_stringstream<CC, std::char_traits<CC>, Alloc>;
>>> +
>>> +void test03()
>>> +{
>>> + alloc_type a{1};
>>> + {
>>> + stringstream_with_alloc<alloc_type> strstr(cstr, a);
>>> + VERIFY( strstr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{strstr.str()} == cstr );
>>> + VERIFY( strstr.get() == cstr.s[0] );
>>> + }
>>> + {
>>> + stringstream_with_alloc<alloc_type> strstr(cstr, std::ios::in, a);
>>> + VERIFY( strstr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{strstr.str()} == cstr );
>>> + VERIFY( strstr.get() == cstr.s[0] );
>>> + VERIFY( strstr.put('X').rdstate() == strstr.badbit );
>>> + }
>>> + {
>>> + stringstream_with_alloc<alloc_type> strstr(cstr, std::ios::out, a);
>>> + VERIFY( strstr.rdbuf()->get_allocator() == a );
>>> + VERIFY( string_view{strstr.str()} == cstr );
>>> + VERIFY( strstr.put('X').good() );
>>> + VERIFY( strstr.get() == stringstream::traits_type::eof());
>>> + }
>>> +}
>>> +
>>> +void test04()
>>> +{
>>> + {
>>> + stringstream strstr;
>>> + strstr.str( cstr );
>>> + VERIFY( strstr.str() == cstr.s );
>>> + }
>>> + {
>>> + stringstream strstr;
>>> + strstr.str( ccstr );
>>> + VERIFY( strstr.str() == ccstr.s );
>>> + }
>>> +}
>>> +
>>> +int
>>> +main()
>>> +{
>>> + test01();
>>> + test02();
>>> + test03();
>>> + test04();
>>> +}
>>> diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc
>>> new file mode 100644
>>> index 00000000000..cfb73c4c510
>>> --- /dev/null
>>> +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc
>>> @@ -0,0 +1,3 @@
>>> +#define C wchar_t
>>> +#define L(a) L##a
>>> +#include "../char/string_view.cc"
>>> --
>>> 2.49.0
>>>
>>
>
>
More information about the Libstdc++
mailing list