diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2020-11-05 12:16:13 +0000 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2020-11-05 13:31:32 +0000 |
commit | 432258be4f2cf4f0970f106db319e3dbab4ab13d (patch) | |
tree | 1c1c9d60c27e86527efb1ebce7cea15358519af1 | |
parent | cbc3f0bcc0e6dba4be2873f7ed7b63de6f8fc524 (diff) | |
download | gcc-432258be4f2cf4f0970f106db319e3dbab4ab13d.zip gcc-432258be4f2cf4f0970f106db319e3dbab4ab13d.tar.gz gcc-432258be4f2cf4f0970f106db319e3dbab4ab13d.tar.bz2 |
libstdc++: Fix new <sstream> constructors
- Add a missing 'explicit' to a basic_stringbuf constructor.
- Set up the get/put area pointers in the constructor from strings using
different allocator types.
- Remove public basic_stringbuf::__sv_type alias.
- Do not construct temporary basic_string objects with a
default-constructed allocator.
Also, change which basic_string constructor is used, as a minor
compile-time optimization. Constructing from a basic_string_view
requires more work from the compiler, so just use a pointer and length.
libstdc++-v3/ChangeLog:
* include/std/sstream (basic_stringbuf(const allocator_type&):
Add explicit.
(basic_stringbuf(const basic_string<C,T,SA>&, openmode, const A&)):
Call _M_stringbuf_init. Construct _M_string from pointer and length
to avoid constraint checks for string view.
(basic_stringbuf::view()): Make __sv_type alias local to the
function.
(basic_istringstream(const basic_string<C,T,SA>&, openmode, const A&)):
Pass string to _M_streambuf instead of constructing a temporary
with the wrong allocator.
(basic_ostringstream(const basic_string<C,T,SA>&, openmode, const A&)):
Likewise.
(basic_stringstream(const basic_string<C,T,SA>&, openmode, const A&)):
Likewise.
* src/c++20/sstream-inst.cc: Use string_view and wstring_view
typedefs in explicit instantiations.
* testsuite/27_io/basic_istringstream/cons/char/1.cc: Add more
tests for constructors.
* testsuite/27_io/basic_ostringstream/cons/char/1.cc: Likewise.
* testsuite/27_io/basic_stringbuf/cons/char/1.cc: Likewise.
* testsuite/27_io/basic_stringbuf/cons/char/2.cc: Likewise.
* testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc: Likewise.
* testsuite/27_io/basic_stringbuf/cons/wchar_t/2.cc: Likewise.
* testsuite/27_io/basic_stringstream/cons/char/1.cc: Likewise.
9 files changed, 451 insertions, 55 deletions
diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream index 276badf..437e2ba 100644 --- a/libstdc++-v3/include/std/sstream +++ b/libstdc++-v3/include/std/sstream @@ -166,8 +166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #endif #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI - using __sv_type = basic_string_view<char_type, traits_type>; - + explicit basic_stringbuf(const allocator_type& __a) : basic_stringbuf(ios_base::in | std::ios_base::out, __a) { } @@ -185,18 +184,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { _M_stringbuf_init(__mode); } template<typename _SAlloc> - basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s, - const allocator_type& __a) - : basic_stringbuf(__s, ios_base::in | std::ios_base::out, __a) - { } + basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s, + const allocator_type& __a) + : basic_stringbuf(__s, ios_base::in | std::ios_base::out, __a) + { } template<typename _SAlloc> - basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s, - ios_base::openmode __mode, - const allocator_type& __a) - : __streambuf_type(), _M_mode(__mode), - _M_string(static_cast<__sv_type>(__s), __a) - { } + basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s, + ios_base::openmode __mode, + const allocator_type& __a) + : __streambuf_type(), _M_mode(__mode), + _M_string(__s.data(), __s.size(), __a) + { _M_stringbuf_init(__mode); } template<typename _SAlloc> explicit @@ -258,9 +257,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI - __sv_type + basic_string_view<char_type, traits_type> view() const noexcept { + using __sv_type = basic_string_view<char_type, traits_type>; + if (this->pptr()) { // The current egptr() may not be the actual string end. @@ -598,9 +599,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_istringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str, ios_base::openmode __mode, const allocator_type& __a) - : __istream_type(), - _M_stringbuf(__string_type(__str.data(), __str.size()), - __mode | ios_base::in, __a) + : __istream_type(), _M_stringbuf(__str, __mode | ios_base::in, __a) { this->init(std::__addressof(_M_stringbuf)); } template<typename _SAlloc> @@ -796,9 +795,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_ostringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str, ios_base::openmode __mode, const allocator_type& __a) - : __ostream_type(), - _M_stringbuf(__string_type(__str.data(), __str.size()), - __mode | ios_base::out, __a) + : __ostream_type(), _M_stringbuf(__str, __mode | ios_base::out, __a) { this->init(std::__addressof(_M_stringbuf)); } template<typename _SAlloc> @@ -991,8 +988,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_stringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str, ios_base::openmode __mode, const allocator_type& __a) - : __iostream_type(), - _M_stringbuf(__string_type(__str.data(), __str.size()), __mode, __a) + : __iostream_type(), _M_stringbuf(__str, __mode, __a) { this->init(std::__addressof(_M_stringbuf)); } template<typename _SAlloc> diff --git a/libstdc++-v3/src/c++20/sstream-inst.cc b/libstdc++-v3/src/c++20/sstream-inst.cc index 8c68401..ada3eab 100644 --- a/libstdc++-v3/src/c++20/sstream-inst.cc +++ b/libstdc++-v3/src/c++20/sstream-inst.cc @@ -43,7 +43,7 @@ template basic_stringbuf<char>::basic_stringbuf(basic_stringbuf&&, const allocator_type&); template basic_stringbuf<char>::allocator_type basic_stringbuf<char>::get_allocator() const noexcept; -template basic_stringbuf<char>::__sv_type +template string_view basic_stringbuf<char>::view() const noexcept; template basic_istringstream<char>::basic_istringstream(ios_base::openmode, @@ -68,8 +68,6 @@ template string_view basic_stringstream<char>::view() const noexcept; #ifdef _GLIBCXX_USE_WCHAR_T -using wsv_type = basic_string_view<wchar_t>; - template basic_stringbuf<wchar_t>::basic_stringbuf(const allocator_type&); template basic_stringbuf<wchar_t>::basic_stringbuf(ios_base::openmode, const allocator_type&); @@ -80,7 +78,7 @@ template basic_stringbuf<wchar_t>::basic_stringbuf(basic_stringbuf&&, template basic_stringbuf<wchar_t>::allocator_type basic_stringbuf<wchar_t>::get_allocator() const noexcept; -template basic_istringstream<wchar_t>::__stringbuf_type::__sv_type +template wstring_view basic_stringbuf<wchar_t>::view() const noexcept; template basic_istringstream<wchar_t>::basic_istringstream(ios_base::openmode, diff --git a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/1.cc b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/1.cc index 496aa69..6584b88 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/1.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/1.cc @@ -33,7 +33,7 @@ test01() std::istringstream stm(std::ios_base::in, a); } -auto const cstr = "This is a test"; +auto const cstr = "This is a test string"; void test02() @@ -75,11 +75,44 @@ test03() } } +// 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) { } + }; + +void +test04() +{ + using sstream = std::basic_istringstream<char, std::char_traits<char>, + NoDefaultCons<char>>; + + NoDefaultCons<char> a(1); + const std::string str(cstr); + + sstream ss1(str, a); + VERIFY( ss1.str() == cstr ); + VERIFY( ss1.get() == cstr[0] ); + + sstream ss2(str, std::ios::out, a); + VERIFY( ss2.str() == cstr ); + VERIFY( ss2.get() == cstr[0] ); + + sstream ss3(std::string(str), std::ios::out, a); + VERIFY( ss3.str() == cstr ); + VERIFY( ss3.get() == cstr[0] ); +} + int main() { test01(); test02(); test03(); - return 0; + test04(); } diff --git a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/1.cc b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/1.cc index cba69f8..885949c 100644 --- a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/1.cc +++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/1.cc @@ -33,7 +33,7 @@ test01() std::ostringstream stm(std::ios_base::in, a); } -auto const cstr = "This is a test"; +auto const cstr = "This is a test string"; void test02() @@ -75,11 +75,45 @@ test03() } } +// 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) { } + }; + +void +test04() +{ + using sstream = std::basic_ostringstream<char, std::char_traits<char>, + NoDefaultCons<char>>; + + NoDefaultCons<char> a(1); + const std::string str(cstr); + + sstream ss1(str, a); + VERIFY( ss1.str() == cstr ); + + sstream ss2(str, std::ios::in, a); + VERIFY( ss2.str() == cstr ); + VERIFY( bool(ss2 << "That") ); + VERIFY( ss2.str() == "That is a test string" ); + + sstream ss3(std::string(str), std::ios::ate, a); + VERIFY( ss3.str() == cstr ); + VERIFY( bool(ss3 << "y thing") ); + VERIFY( ss3.str() == "This is a test stringy thing" ); +} + int main() { test01(); test02(); test03(); - return 0; + test04(); } diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/1.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/1.cc index 0e96497..bd17e6d 100644 --- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/1.cc +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/1.cc @@ -17,7 +17,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// 27.7.1.1 basic_stringbuf constructors [lib.stringbuf.cons] +// C++03 27.7.1.1 basic_stringbuf constructors [lib.stringbuf.cons] #include <sstream> #include <testsuite_hooks.h> @@ -30,8 +30,41 @@ void test01() VERIFY( sbuf.check_pointers() ); } -int main() +void test02() +{ + std::stringbuf sbuf; + VERIFY( sbuf.str().empty() ); + + std::stringbuf sbuf1(std::ios::in); + VERIFY( sbuf1.str().empty() ); + + const std::string str = "This is my boomstick!"; + + std::stringbuf sbuf2(str); + VERIFY( sbuf2.str() == str ); + + std::stringbuf sbuf3(str, std::ios::in); + VERIFY( sbuf3.str() == str ); + VERIFY( sbuf3.sgetc() == str[0] ); + VERIFY( sbuf3.sputc('X') == std::stringbuf::traits_type::eof() ); + + std::stringbuf sbuf4(str, std::ios::out); + VERIFY( sbuf4.str() == str ); + VERIFY( sbuf4.sputc('Y') == 'Y' ); + VERIFY( sbuf4.sgetc() == std::stringbuf::traits_type::eof() ); + +#if __cplusplus >= 201103L + static_assert( ! std::is_convertible<std::ios::openmode, std::stringbuf>(), + "stringbuf(ios::openmode) is explicit"); + + static_assert( ! std::is_convertible<const std::string&, std::stringbuf>(), + "stringbuf(string, ios::openmode) is explicit"); +#endif +} + +int main() { test01(); + test02(); return 0; } diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/2.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/2.cc index ce66935..c72ca5c 100644 --- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/2.cc +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/2.cc @@ -15,7 +15,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// 27.7.1.1 basic_stringbuf constructors [lib.stringbuf.cons] +// C++20 29.8.2.2 basic_stringbuf constructors [stringbuf.cons] // { dg-options "-std=gnu++2a" } // { dg-do run { target c++2a } } @@ -26,13 +26,24 @@ #include <testsuite_allocator.h> #include <testsuite_hooks.h> +template<typename Alloc, typename C = typename Alloc::value_type> + using stringbuf_with_alloc + = std::basic_stringbuf<C, std::char_traits<C>, Alloc>; + void test01() { + // Test C++20 constructors taking an allocator but no string. + + static_assert(!std::is_convertible_v<std::allocator<char>, std::stringbuf>, + "stringbuf(const allocator<char>&) is explicit"); + { using alloc_type = __gnu_test::uneq_allocator<char>; - using sbuf_t = std::basic_stringbuf<char, std::char_traits<char>, - alloc_type>; + using sbuf_t = stringbuf_with_alloc<alloc_type>; + + static_assert(!std::is_convertible_v<const alloc_type&, sbuf_t>, + "basic_stringbuf(const basic_stringbuf::allocator_type&) is explicit"); alloc_type aa; sbuf_t sbuf1(aa); @@ -48,29 +59,64 @@ test01() std::stringbuf::allocator_type a; { std::stringbuf sbuf(std::ios_base::in, a); + VERIFY( sbuf.str().empty() ); + + std::stringbuf sbuf2 = {std::ios_base::in, a}; // non-explicit ctor } { std::stringbuf sbuf(a); + VERIFY( sbuf.str().empty() ); } } -auto const cstr = "This is a test"; +auto const cstr = "This is a test string"; void test02() { + // Test C++20 constructor taking an rvalue string + + static_assert(!std::is_convertible_v<std::string, std::stringbuf>, + "stringbuf(string&&, ios::openmode) is explicit"); + std::string s1(cstr); - std::stringbuf sbuf(std::move(s1)); + std::stringbuf sbuf1(std::move(s1)); VERIFY( s1.empty() ); + VERIFY( sbuf1.str() == cstr ); + VERIFY( sbuf1.sgetc() == cstr[0] ); std::string s2(cstr); - VERIFY( sbuf.str() == s2 ); + std::stringbuf sbuf2(std::move(s2), std::ios_base::in); + VERIFY( s2.empty() ); + VERIFY( sbuf2.str() == cstr ); + VERIFY( sbuf2.sgetc() == cstr[0] ); + VERIFY( sbuf2.sputc('X') == std::stringbuf::traits_type::eof() ); + + std::string s3(cstr); + std::stringbuf sbuf3(std::move(s3), std::ios_base::out); + VERIFY( s3.empty() ); + VERIFY( sbuf3.str() == cstr ); + VERIFY( sbuf3.sputc('Y') == 'Y' ); + VERIFY( sbuf3.sgetc() == std::stringbuf::traits_type::eof() ); } +// 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) { } + }; + void test03() { + // Test C++20 constructors taking strings using different allocators + using alloc_type = __gnu_test::tracker_allocator<char>; using str_type = std::basic_string<char, std::char_traits<char>, alloc_type>; @@ -78,28 +124,92 @@ test03() str_type s1(cstr); { + // basic_stringbuf(const basic_string<char, traits_type, SAlloc>&, + // ios_base::openmode, + // const allocator_type&) + std::stringbuf::allocator_type a; - std::stringbuf sbuf(s1, mode, a); + std::stringbuf sbuf = {s1, mode, a}; // ={} checks for non-explicit ctor std::string s2(cstr); VERIFY( sbuf.str() == s2 ); + + std::stringbuf sbuf2 = {std::move(s1), std::ios::in, a}; + VERIFY( sbuf2.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf2.sgetc() == s1[0] ); + VERIFY( sbuf2.sputc('X') == std::stringbuf::traits_type::eof() ); + + std::stringbuf sbuf3 = {std::move(s1), std::ios::out, a}; + VERIFY( sbuf3.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf3.sputc('X') == 'X' ); + VERIFY( sbuf3.sgetc() == std::stringbuf::traits_type::eof() ); } { + // explicit + // basic_stringbuf(const basic_string<char, traits_type, SAlloc>&, + // ios_base::openmode) + std::stringbuf sbuf(s1, mode); std::string s2(cstr); VERIFY( sbuf.str() == s2 ); + + std::stringbuf sbuf2(std::move(s1), std::ios::in); + VERIFY( sbuf2.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf2.sgetc() == s1[0] ); + VERIFY( sbuf2.sputc('X') == std::stringbuf::traits_type::eof() ); + + std::stringbuf sbuf3(std::move(s1), std::ios::out); + VERIFY( sbuf3.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf3.sputc('X') == 'X' ); + VERIFY( sbuf3.sgetc() == std::stringbuf::traits_type::eof() ); } { + // explicit + // basic_stringbuf(const basic_string<char, traits_type, SAlloc>&, + // ios_base::openmode = ios_base::in|ios_base::out) + + static_assert( ! std::is_convertible_v<str_type, std::stringbuf>, + "stringbuf(const basic_string<char, traits_type, SAlloc>&, openmode)" + " is explicit"); + std::stringbuf sbuf(s1); std::string s2(cstr); VERIFY( sbuf.str() == s2 ); + + std::stringbuf sbuf2(std::move(s1)); + VERIFY( sbuf2.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf2.sgetc() == s1[0] ); + } + + { + NoDefaultCons<char> a(1); + stringbuf_with_alloc<NoDefaultCons<char>> sbuf1(s1, a); + VERIFY( sbuf1.str() == cstr ); + VERIFY( sbuf1.sgetc() == s1[0] ); + + stringbuf_with_alloc<NoDefaultCons<char>> sbuf2(s1, std::ios::in, a); + VERIFY( sbuf2.str() == cstr ); + VERIFY( sbuf2.sgetc() == s1[0] ); + VERIFY( sbuf2.sputc('X') == std::stringbuf::traits_type::eof() ); + + stringbuf_with_alloc<NoDefaultCons<char>> sbuf3(s1, std::ios::out, a); + VERIFY( sbuf3.str() == cstr ); + VERIFY( sbuf3.sputc('X') == 'X' ); + VERIFY( sbuf3.sgetc() == std::stringbuf::traits_type::eof() ); } } void test04() { + // Test C++20 allocator-extended move constructor + std::stringbuf sbuf1(cstr); std::stringbuf::allocator_type a; @@ -117,5 +227,4 @@ main() test02(); test03(); test04(); - return 0; } diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc index 7d51744..4e3a2a9 100644 --- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc @@ -17,7 +17,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// 27.7.1.1 basic_stringbuf constructors [lib.stringbuf.cons] +// C++03 27.7.1.1 basic_stringbuf constructors [lib.stringbuf.cons] #include <sstream> #include <testsuite_hooks.h> @@ -30,8 +30,41 @@ void test01() VERIFY( sbuf.check_pointers() ); } -int main() +void test02() +{ + std::wstringbuf sbuf; + VERIFY( sbuf.str().empty() ); + + std::wstringbuf sbuf1(std::wios::in); + VERIFY( sbuf1.str().empty() ); + + const std::wstring str = L"This is my boomstick!"; + + std::wstringbuf sbuf2(str); + VERIFY( sbuf2.str() == str ); + + std::wstringbuf sbuf3(str, std::wios::in); + VERIFY( sbuf3.str() == str ); + VERIFY( sbuf3.sgetc() == str[0] ); + VERIFY( sbuf3.sputc(L'X') == std::wstringbuf::traits_type::eof() ); + + std::wstringbuf sbuf4(str, std::wios::out); + VERIFY( sbuf4.str() == str ); + VERIFY( sbuf4.sputc(L'Y') == L'Y' ); + VERIFY( sbuf4.sgetc() == std::wstringbuf::traits_type::eof() ); + +#if __cplusplus >= 201103L + static_assert( ! std::is_convertible<std::wios::openmode, std::wstringbuf>(), + "wstringbuf(wios::openmode) is explicit"); + + static_assert( ! std::is_convertible<const std::wstring&, std::wstringbuf>(), + "wstringbuf(wstring, wios::openmode) is explicit"); +#endif +} + +int main() { test01(); + test02(); return 0; } diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/2.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/2.cc index e05acc4..4fbbbf3 100644 --- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/2.cc +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/2.cc @@ -15,7 +15,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// 27.7.1.1 basic_stringbuf constructors [lib.stringbuf.cons] +// C++20 29.8.2.2 basic_stringbuf constructors [stringbuf.cons] // { dg-options "-std=gnu++2a" } // { dg-do run { target c++2a } } @@ -26,35 +26,97 @@ #include <testsuite_allocator.h> #include <testsuite_hooks.h> +template<typename Alloc, typename C = typename Alloc::value_type> + using stringbuf_with_alloc + = std::basic_stringbuf<C, std::char_traits<C>, Alloc>; + void test01() { + // Test C++20 constructors taking an allocator but no string. + + static_assert(!std::is_convertible_v<std::allocator<wchar_t>, std::wstringbuf>, + "wstringbuf(const allocator<wchar_t>&) is explicit"); + + { + using alloc_type = __gnu_test::uneq_allocator<wchar_t>; + using sbuf_t = stringbuf_with_alloc<alloc_type>; + + static_assert(!std::is_convertible_v<const alloc_type&, sbuf_t>, + "basic_stringbuf(const basic_stringbuf::allocator_type&) is explicit"); + + alloc_type aa; + sbuf_t sbuf1(aa); + VERIFY( aa == sbuf1.get_allocator() ); + + alloc_type aaa(42); + sbuf_t sbuf2(aaa); + VERIFY( aaa == sbuf2.get_allocator() ); + + VERIFY( sbuf1.get_allocator() != sbuf2.get_allocator() ); + } + std::wstringbuf::allocator_type a; { std::wstringbuf sbuf(std::ios_base::in, a); + VERIFY( sbuf.str().empty() ); + + std::wstringbuf sbuf2 = {std::ios_base::in, a}; // non-explicit ctor } { std::wstringbuf sbuf(a); + VERIFY( sbuf.str().empty() ); } } -auto const cstr = L"This is a test"; +auto const cstr = L"This is a test string"; void test02() { + // Test C++20 constructor taking an rvalue string + + static_assert(!std::is_convertible_v<std::wstring, std::wstringbuf>, + "wstringbuf(wstring&&, ios::openmode) is explicit"); + std::wstring s1(cstr); - std::wstringbuf sbuf(std::move(s1)); + std::wstringbuf sbuf1(std::move(s1)); VERIFY( s1.empty() ); + VERIFY( sbuf1.str() == cstr ); + VERIFY( sbuf1.sgetc() == cstr[0] ); std::wstring s2(cstr); - VERIFY( sbuf.str() == s2 ); + std::wstringbuf sbuf2(std::move(s2), std::ios_base::in); + VERIFY( s2.empty() ); + VERIFY( sbuf2.str() == cstr ); + VERIFY( sbuf2.sgetc() == cstr[0] ); + VERIFY( sbuf2.sputc(L'X') == std::wstringbuf::traits_type::eof() ); + + std::wstring s3(cstr); + std::wstringbuf sbuf3(std::move(s3), std::ios_base::out); + VERIFY( s3.empty() ); + VERIFY( sbuf3.str() == cstr ); + VERIFY( sbuf3.sputc(L'Y') == L'Y' ); + VERIFY( sbuf3.sgetc() == std::wstringbuf::traits_type::eof() ); } +// 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) { } + }; + void test03() { + // Test C++20 constructors taking strings using different allocators + using alloc_type = __gnu_test::tracker_allocator<wchar_t>; using str_type = std::basic_string<wchar_t, std::char_traits<wchar_t>, alloc_type>; @@ -62,28 +124,92 @@ test03() str_type s1(cstr); { + // basic_stringbuf(const basic_string<wchar_t, traits_type, SAlloc>&, + // ios_base::openmode, + // const allocator_type&) + std::wstringbuf::allocator_type a; - std::wstringbuf sbuf(s1, mode, a); + std::wstringbuf sbuf = {s1, mode, a}; // ={} checks for non-explicit ctor std::wstring s2(cstr); VERIFY( sbuf.str() == s2 ); + + std::wstringbuf sbuf2 = {std::move(s1), std::ios::in, a}; + VERIFY( sbuf2.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf2.sgetc() == s1[0] ); + VERIFY( sbuf2.sputc(L'X') == std::wstringbuf::traits_type::eof() ); + + std::wstringbuf sbuf3 = {std::move(s1), std::ios::out, a}; + VERIFY( sbuf3.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf3.sputc(L'X') == L'X' ); + VERIFY( sbuf3.sgetc() == std::wstringbuf::traits_type::eof() ); } { + // explicit + // basic_stringbuf(const basic_string<wchar_t, traits_type, SAlloc>&, + // ios_base::openmode) + std::wstringbuf sbuf(s1, mode); std::wstring s2(cstr); VERIFY( sbuf.str() == s2 ); + + std::wstringbuf sbuf2(std::move(s1), std::ios::in); + VERIFY( sbuf2.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf2.sgetc() == s1[0] ); + VERIFY( sbuf2.sputc(L'X') == std::wstringbuf::traits_type::eof() ); + + std::wstringbuf sbuf3(std::move(s1), std::ios::out); + VERIFY( sbuf3.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf3.sputc(L'X') == L'X' ); + VERIFY( sbuf3.sgetc() == std::wstringbuf::traits_type::eof() ); } { + // explicit + // basic_stringbuf(const basic_string<wchar_t, traits_type, SAlloc>&, + // ios_base::openmode = ios_base::in|ios_base::out) + + static_assert( ! std::is_convertible_v<str_type, std::wstringbuf>, + "wstringbuf(const basic_string<wchar_t, traits_type, SAlloc>&," + " openmode) is explicit"); + std::wstringbuf sbuf(s1); std::wstring s2(cstr); VERIFY( sbuf.str() == s2 ); + + std::wstringbuf sbuf2(std::move(s1)); + VERIFY( sbuf2.str() == s2 ); + VERIFY( s1 == cstr ); // did not move from std::move(s1) + VERIFY( sbuf2.sgetc() == s1[0] ); + } + + { + NoDefaultCons<wchar_t> a(1); + stringbuf_with_alloc<NoDefaultCons<wchar_t>> sbuf1(s1, a); + VERIFY( sbuf1.str() == cstr ); + VERIFY( sbuf1.sgetc() == s1[0] ); + + stringbuf_with_alloc<NoDefaultCons<wchar_t>> sbuf2(s1, std::ios::in, a); + VERIFY( sbuf2.str() == cstr ); + VERIFY( sbuf2.sgetc() == s1[0] ); + VERIFY( sbuf2.sputc(L'X') == std::wstringbuf::traits_type::eof() ); + + stringbuf_with_alloc<NoDefaultCons<wchar_t>> sbuf3(s1, std::ios::out, a); + VERIFY( sbuf3.str() == cstr ); + VERIFY( sbuf3.sputc(L'X') == L'X' ); + VERIFY( sbuf3.sgetc() == std::wstringbuf::traits_type::eof() ); } } void test04() { + // Test C++20 allocator-extended move constructor + std::wstringbuf sbuf1(cstr); std::wstringbuf::allocator_type a; @@ -101,5 +227,4 @@ main() test02(); test03(); test04(); - return 0; } diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/1.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/1.cc index 83a3374..33f2953 100644 --- a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/1.cc +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/1.cc @@ -33,7 +33,7 @@ test01() std::stringstream stm(std::ios_base::in, a); } -auto const cstr = "This is a test"; +auto const cstr = "This is a test string"; void test02() @@ -57,29 +57,64 @@ test03() { std::stringstream::allocator_type a; - std::stringstream sbuf(s1, mode, a); + std::stringstream ss(s1, mode, a); std::string s2(cstr); - VERIFY( sbuf.str() == s2 ); + VERIFY( ss.str() == s2 ); } { - std::stringstream sbuf(s1, mode); + std::stringstream ss(s1, mode); std::string s2(cstr); - VERIFY( sbuf.str() == s2 ); + VERIFY( ss.str() == s2 ); } { - std::stringstream sbuf(s1); + std::stringstream ss(s1); std::string s2(cstr); - VERIFY( sbuf.str() == s2 ); + VERIFY( ss.str() == s2 ); } } +// 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) { } + }; + +void +test04() +{ + using sstream = std::basic_stringstream<char, std::char_traits<char>, + NoDefaultCons<char>>; + + NoDefaultCons<char> a(1); + const std::string str(cstr); + + sstream ss1(str, a); + VERIFY( ss1.str() == cstr ); + VERIFY( ss1.get() == cstr[0] ); + + sstream ss2(str, std::ios::in, a); + VERIFY( ss2.str() == cstr ); + VERIFY( ss2.get() == cstr[0] ); + VERIFY( !bool(ss2 << 1) ); + + sstream ss3(std::string(str), std::ios::out, a); + VERIFY( ss3.str() == cstr ); + VERIFY( bool(ss3 << 1) ); + VERIFY( ss3.get() == std::wstringbuf::traits_type::eof() ); +} + int main() { test01(); test02(); test03(); - return 0; + test04(); } |