- 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.
#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)
{ }
{ _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
}
#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.
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>
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>
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>
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,
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&);
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,
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()
}
}
+// 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();
}
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()
}
}
+// 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();
}
// 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>
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;
}
// 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 } }
#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);
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>;
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;
test02();
test03();
test04();
- return 0;
}
// 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>
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;
}
// 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 } }
#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>;
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;
test02();
test03();
test04();
- return 0;
}
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()
{
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();
}