// String based streams -*- C++ -*-
-// Copyright (C) 1997-2020 Free Software Foundation, Inc.
+// Copyright (C) 1997-2024 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
#pragma GCC system_header
+#include <bits/requires_hosted.h> // iostream
+
#include <istream>
#include <ostream>
+#include <bits/alloc_traits.h> // allocator_traits, __allocator_like
+
+#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_LVAL_REF_QUAL &
+# define _GLIBCXX_SSTREAM_ALWAYS_INLINE
+#else
+# define _GLIBCXX_LVAL_REF_QUAL
+// For symbols that are not exported from libstdc++.so for the COW string ABI.
+# define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]]
+#endif
+
+
namespace std _GLIBCXX_VISIBILITY(default)
{
class basic_stringbuf : public basic_streambuf<_CharT, _Traits>
{
struct __xfer_bufptrs;
+
+#if __cplusplus >= 201103L
+ using allocator_traits = std::allocator_traits<_Alloc>;
+ using _Noexcept_swap
+ = __or_<typename allocator_traits::propagate_on_container_swap,
+ typename allocator_traits::is_always_equal>;
+#endif
+
public:
// Types:
typedef _CharT char_type;
: basic_stringbuf(std::move(__rhs), __xfer_bufptrs(__rhs, this))
{ __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); }
- // 27.8.2.2 Assign and swap:
-
- basic_stringbuf&
- operator=(const basic_stringbuf&) = delete;
-
- basic_stringbuf&
- operator=(basic_stringbuf&& __rhs)
- {
- __xfer_bufptrs __st{__rhs, this};
- const __streambuf_type& __base = __rhs;
- __streambuf_type::operator=(__base);
- this->pubimbue(__rhs.getloc());
- _M_mode = __rhs._M_mode;
- _M_string = std::move(__rhs._M_string);
- __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0);
- return *this;
- }
-
- void
- swap(basic_stringbuf& __rhs)
- {
- __xfer_bufptrs __l_st{*this, std::__addressof(__rhs)};
- __xfer_bufptrs __r_st{__rhs, this};
- __streambuf_type& __base = __rhs;
- __streambuf_type::swap(__base);
- __rhs.pubimbue(this->pubimbue(__rhs.getloc()));
- std::swap(_M_mode, __rhs._M_mode);
- std::swap(_M_string, __rhs._M_string);
- }
-#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)
{ }
explicit
basic_stringbuf(__string_type&& __s,
- ios_base::openmode __mode = ios_base::in
- | ios_base::out )
+ ios_base::openmode __mode = ios_base::in
+ | ios_base::out)
: __streambuf_type(), _M_mode(__mode), _M_string(std::move(__s))
{ _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
basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s,
- ios_base::openmode __mode = ios_base::in
+ ios_base::openmode __mode = ios_base::in
| ios_base::out)
: basic_stringbuf(__s, __mode, allocator_type{})
{ }
allocator_type get_allocator() const noexcept
{ return _M_string.get_allocator(); }
-#endif
+#endif // C++20
+
+ // 27.8.2.2 Assign and swap:
+
+ basic_stringbuf&
+ operator=(const basic_stringbuf&) = delete;
+
+ basic_stringbuf&
+ operator=(basic_stringbuf&& __rhs)
+ {
+ __xfer_bufptrs __st{__rhs, this};
+ const __streambuf_type& __base = __rhs;
+ __streambuf_type::operator=(__base);
+ this->pubimbue(__rhs.getloc());
+ _M_mode = __rhs._M_mode;
+ _M_string = std::move(__rhs._M_string);
+ __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0);
+ return *this;
+ }
+
+ void
+ swap(basic_stringbuf& __rhs) noexcept(_Noexcept_swap::value)
+ {
+ __xfer_bufptrs __l_st{*this, std::__addressof(__rhs)};
+ __xfer_bufptrs __r_st{__rhs, this};
+ __streambuf_type& __base = __rhs;
+ __streambuf_type::swap(__base);
+ __rhs.pubimbue(this->pubimbue(__rhs.getloc()));
+ std::swap(_M_mode, __rhs._M_mode);
+ std::swap(_M_string, __rhs._M_string); // XXX not exception safe
+ }
+#endif // C++11
+
+ // Getters and setters:
- // Get and set:
/**
* @brief Copying out the string buffer.
* @return A copy of one of the underlying sequences.
* is equal to the output sequence.</em> [27.7.1.2]/1
*/
__string_type
- str() const
+ str() const _GLIBCXX_LVAL_REF_QUAL
{
__string_type __ret(_M_string.get_allocator());
- if (char_type* __pptr = this->pptr())
- {
- char_type* __egptr = this->egptr();
- // The current egptr() may not be the actual string end.
- if (!__egptr || __pptr > __egptr)
- __ret.assign(this->pbase(), __pptr);
- else
- __ret.assign(this->pbase(), __egptr);
- }
+ if (char_type* __hi = _M_high_mark())
+ __ret.assign(this->pbase(), __hi);
else
__ret = _M_string;
return __ret;
}
+#if __cplusplus > 201703L
+#if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_concepts
+ template<__allocator_like _SAlloc>
+ basic_string<_CharT, _Traits, _SAlloc>
+ str(const _SAlloc& __sa) const
+ {
+ auto __sv = view();
+ return { __sv.data(), __sv.size(), __sa };
+ }
+#endif
+
+ __string_type
+ str() &&
+ {
+ if (char_type* __hi = _M_high_mark())
+ {
+ // Set length to end of character sequence and add null terminator.
+ _M_string._M_set_length(_M_high_mark() - this->pbase());
+ }
+ auto __str = std::move(_M_string);
+ _M_string.clear();
+ _M_sync(_M_string.data(), 0, 0);
+ return __str;
+ }
+#endif // cxx11 ABI
+
+ _GLIBCXX_SSTREAM_ALWAYS_INLINE
+ basic_string_view<char_type, traits_type>
+ view() const noexcept
+ {
+ if (char_type* __hi = _M_high_mark())
+ return { this->pbase(), __hi };
+ else
+ return _M_string;
+ }
+#endif // C++20
+
/**
* @brief Setting a new buffer.
* @param __s The string to use as a new sequence.
}
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
- __sv_type
- view() const noexcept
+#if __cpp_concepts
+ template<__allocator_like _SAlloc>
+ requires (!is_same_v<_SAlloc, _Alloc>)
+ void
+ str(const basic_string<_CharT, _Traits, _SAlloc>& __s)
+ {
+ _M_string.assign(__s.data(), __s.size());
+ _M_stringbuf_init(_M_mode);
+ }
+#endif
+
+ void
+ str(__string_type&& __s)
{
- if (this->pptr())
- {
- // The current egptr() may not be the actual string end.
- if (this->pptr() > this->egptr())
- return __sv_type(this->pbase(), this->pptr());
- else
- return __sv_type(this->pbase(), this->egptr());
- }
- else
- return static_cast<__sv_type>(_M_string);
+ _M_string = std::move(__s);
+ _M_stringbuf_init(_M_mode);
}
#endif
void
_M_update_egptr()
{
- const bool __testin = _M_mode & ios_base::in;
- if (this->pptr() && this->pptr() > this->egptr())
+ if (char_type* __pptr = this->pptr())
{
- if (__testin)
- this->setg(this->eback(), this->gptr(), this->pptr());
- else
- this->setg(this->pptr(), this->pptr(), this->pptr());
+ char_type* __egptr = this->egptr();
+ if (!__egptr || __pptr > __egptr)
+ {
+ if (_M_mode & ios_base::in)
+ this->setg(this->eback(), this->gptr(), __pptr);
+ else
+ this->setg(__pptr, __pptr, __pptr);
+ }
}
}
_M_pbump(char_type* __pbeg, char_type* __pend, off_type __off);
private:
+ // Return a pointer to the end of the underlying character sequence.
+ // This might not be the same character as _M_string.end() because
+ // basic_stringbuf::overflow might have written to unused capacity
+ // in _M_string without updating its length.
+ __attribute__((__always_inline__))
+ char_type*
+ _M_high_mark() const _GLIBCXX_NOEXCEPT
+ {
+ if (char_type* __pptr = this->pptr())
+ {
+ char_type* __egptr = this->egptr();
+ if (!__egptr || __pptr > __egptr)
+ return __pptr; // Underlying sequence is [pbase, pptr).
+ else
+ return __egptr; // Underlying sequence is [pbase, egptr).
+ }
+ return 0; // Underlying character sequence is just _M_string.
+ }
+
#if __cplusplus >= 201103L
#if _GLIBCXX_USE_CXX11_ABI
// This type captures the state of the gptr / pptr pointers as offsets
_M_poff[0] = __from.pbase() - __str;
_M_poff[1] = __from.pptr() - __from.pbase();
_M_poff[2] = __from.epptr() - __str;
- if (__from.pptr() > __end)
+ if (!__end || __from.pptr() > __end)
__end = __from.pptr();
}
_M_mode(__rhs._M_mode), _M_string(std::move(__rhs._M_string), __a)
{ }
#endif
-#endif
+#endif // C++11
};
_M_stringbuf(std::move(__rhs._M_stringbuf))
{ __istream_type::set_rdbuf(&_M_stringbuf); }
- // 27.8.3.2 Assign and swap:
-
- basic_istringstream&
- operator=(const basic_istringstream&) = delete;
-
- basic_istringstream&
- operator=(basic_istringstream&& __rhs)
- {
- __istream_type::operator=(std::move(__rhs));
- _M_stringbuf = std::move(__rhs._M_stringbuf);
- return *this;
- }
-
- void
- swap(basic_istringstream& __rhs)
- {
- __istream_type::swap(__rhs);
- _M_stringbuf.swap(__rhs._M_stringbuf);
- }
-#endif
-
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
basic_istringstream(ios_base::openmode __mode, const allocator_type& __a)
: __istream_type(), _M_stringbuf(__mode | ios_base::in, __a)
explicit
basic_istringstream(__string_type&& __str,
- ios_base::openmode __mode = ios_base::in )
+ ios_base::openmode __mode = ios_base::in)
: __istream_type(), _M_stringbuf(std::move(__str), __mode | ios_base::in)
{ this->init(std::__addressof(_M_stringbuf)); }
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>
explicit
basic_istringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
- ios_base::openmode __mode = ios_base::in)
+ ios_base::openmode __mode = ios_base::in)
: basic_istringstream(__str, __mode, allocator_type())
{ }
-#endif
+#endif // C++20
+
+ // 27.8.3.2 Assign and swap:
+
+ basic_istringstream&
+ operator=(const basic_istringstream&) = delete;
+
+ basic_istringstream&
+ operator=(basic_istringstream&& __rhs)
+ {
+ __istream_type::operator=(std::move(__rhs));
+ _M_stringbuf = std::move(__rhs._M_stringbuf);
+ return *this;
+ }
+
+ void
+ swap(basic_istringstream& __rhs)
+ {
+ __istream_type::swap(__rhs);
+ _M_stringbuf.swap(__rhs._M_stringbuf);
+ }
+#endif // C++11
// Members:
/**
* @return @c rdbuf()->str()
*/
__string_type
- str() const
+ str() const _GLIBCXX_LVAL_REF_QUAL
{ return _M_stringbuf.str(); }
+#if __cplusplus > 201703L
+#if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_concepts
+ template<__allocator_like _SAlloc>
+ basic_string<_CharT, _Traits, _SAlloc>
+ str(const _SAlloc& __sa) const
+ { return _M_stringbuf.str(__sa); }
+#endif
+
+ __string_type
+ str() &&
+ { return std::move(_M_stringbuf).str(); }
+#endif // cxx11 ABI
+
+ _GLIBCXX_SSTREAM_ALWAYS_INLINE
+ basic_string_view<char_type, traits_type>
+ view() const noexcept
+ { return _M_stringbuf.view(); }
+#endif // C++20
+
/**
* @brief Setting a new buffer.
* @param __s The string to use as a new sequence.
{ _M_stringbuf.str(__s); }
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
- basic_string_view<char_type, traits_type>
- view() const noexcept
- { return _M_stringbuf.view(); }
+#if __cpp_concepts
+ template<__allocator_like _SAlloc>
+ requires (!is_same_v<_SAlloc, _Alloc>)
+ void
+ str(const basic_string<_CharT, _Traits, _SAlloc>& __s)
+ { _M_stringbuf.str(__s); }
+#endif
+
+ void
+ str(__string_type&& __s)
+ { _M_stringbuf.str(std::move(__s)); }
#endif
};
_M_stringbuf(std::move(__rhs._M_stringbuf))
{ __ostream_type::set_rdbuf(&_M_stringbuf); }
- // 27.8.3.2 Assign and swap:
-
- basic_ostringstream&
- operator=(const basic_ostringstream&) = delete;
-
- basic_ostringstream&
- operator=(basic_ostringstream&& __rhs)
- {
- __ostream_type::operator=(std::move(__rhs));
- _M_stringbuf = std::move(__rhs._M_stringbuf);
- return *this;
- }
-
- void
- swap(basic_ostringstream& __rhs)
- {
- __ostream_type::swap(__rhs);
- _M_stringbuf.swap(__rhs._M_stringbuf);
- }
-#endif
-
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
basic_ostringstream(ios_base::openmode __mode, const allocator_type& __a)
: __ostream_type(), _M_stringbuf(__mode | ios_base::out, __a)
explicit
basic_ostringstream(__string_type&& __str,
- ios_base::openmode __mode = ios_base::out )
+ ios_base::openmode __mode = ios_base::out)
: __ostream_type(), _M_stringbuf(std::move(__str), __mode | ios_base::out)
{ this->init(std::__addressof(_M_stringbuf)); }
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>
explicit
basic_ostringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
- ios_base::openmode __mode = ios_base::out)
+ ios_base::openmode __mode = ios_base::out)
: basic_ostringstream(__str, __mode, allocator_type())
{ }
-#endif
+#endif // C++20
+
+ // 27.8.3.2 Assign and swap:
+
+ basic_ostringstream&
+ operator=(const basic_ostringstream&) = delete;
+
+ basic_ostringstream&
+ operator=(basic_ostringstream&& __rhs)
+ {
+ __ostream_type::operator=(std::move(__rhs));
+ _M_stringbuf = std::move(__rhs._M_stringbuf);
+ return *this;
+ }
+
+ void
+ swap(basic_ostringstream& __rhs)
+ {
+ __ostream_type::swap(__rhs);
+ _M_stringbuf.swap(__rhs._M_stringbuf);
+ }
+#endif // C++11
// Members:
/**
* @return @c rdbuf()->str()
*/
__string_type
- str() const
+ str() const _GLIBCXX_LVAL_REF_QUAL
{ return _M_stringbuf.str(); }
+#if __cplusplus > 201703L
+#if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_concepts
+ template<__allocator_like _SAlloc>
+ basic_string<_CharT, _Traits, _SAlloc>
+ str(const _SAlloc& __sa) const
+ { return _M_stringbuf.str(__sa); }
+#endif
+
+ __string_type
+ str() &&
+ { return std::move(_M_stringbuf).str(); }
+#endif // cxx11 ABI
+
+ _GLIBCXX_SSTREAM_ALWAYS_INLINE
+ basic_string_view<char_type, traits_type>
+ view() const noexcept
+ { return _M_stringbuf.view(); }
+#endif // C++20
+
/**
* @brief Setting a new buffer.
* @param __s The string to use as a new sequence.
{ _M_stringbuf.str(__s); }
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
- basic_string_view<char_type, traits_type>
- view() const noexcept
- { return _M_stringbuf.view(); }
+#if __cpp_concepts
+ template<__allocator_like _SAlloc>
+ requires (!is_same_v<_SAlloc, _Alloc>)
+ void
+ str(const basic_string<_CharT, _Traits, _SAlloc>& __s)
+ { _M_stringbuf.str(__s); }
+#endif
+
+ void
+ str(__string_type&& __s)
+ { _M_stringbuf.str(std::move(__s)); }
#endif
};
_M_stringbuf(std::move(__rhs._M_stringbuf))
{ __iostream_type::set_rdbuf(&_M_stringbuf); }
- // 27.8.3.2 Assign and swap:
-
- basic_stringstream&
- operator=(const basic_stringstream&) = delete;
-
- basic_stringstream&
- operator=(basic_stringstream&& __rhs)
- {
- __iostream_type::operator=(std::move(__rhs));
- _M_stringbuf = std::move(__rhs._M_stringbuf);
- return *this;
- }
-
- void
- swap(basic_stringstream& __rhs)
- {
- __iostream_type::swap(__rhs);
- _M_stringbuf.swap(__rhs._M_stringbuf);
- }
-#endif
-
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
basic_stringstream(ios_base::openmode __mode, const allocator_type& __a)
: __iostream_type(), _M_stringbuf(__mode, __a)
explicit
basic_stringstream(__string_type&& __str,
- ios_base::openmode __mode = ios_base::out
+ ios_base::openmode __mode = ios_base::in
| ios_base::out)
: __iostream_type(), _M_stringbuf(std::move(__str), __mode)
{ 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)
+ ios_base::openmode __mode,
+ const allocator_type& __a)
+ : __iostream_type(), _M_stringbuf(__str, __mode, __a)
{ this->init(std::__addressof(_M_stringbuf)); }
template<typename _SAlloc>
explicit
basic_stringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
- ios_base::openmode __mode = ios_base::in
+ ios_base::openmode __mode = ios_base::in
| ios_base::out)
: basic_stringstream(__str, __mode, allocator_type())
{ }
-#endif
+#endif // C++20
+
+ // 27.8.3.2 Assign and swap:
+
+ basic_stringstream&
+ operator=(const basic_stringstream&) = delete;
+
+ basic_stringstream&
+ operator=(basic_stringstream&& __rhs)
+ {
+ __iostream_type::operator=(std::move(__rhs));
+ _M_stringbuf = std::move(__rhs._M_stringbuf);
+ return *this;
+ }
+
+ void
+ swap(basic_stringstream& __rhs)
+ {
+ __iostream_type::swap(__rhs);
+ _M_stringbuf.swap(__rhs._M_stringbuf);
+ }
+#endif // C++11
// Members:
/**
* @return @c rdbuf()->str()
*/
__string_type
- str() const
+ str() const _GLIBCXX_LVAL_REF_QUAL
{ return _M_stringbuf.str(); }
+#if __cplusplus > 201703L
+#if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_concepts
+ template<__allocator_like _SAlloc>
+ basic_string<_CharT, _Traits, _SAlloc>
+ str(const _SAlloc& __sa) const
+ { return _M_stringbuf.str(__sa); }
+#endif
+
+ __string_type
+ str() &&
+ { return std::move(_M_stringbuf).str(); }
+#endif // cxx11 ABI
+
+ _GLIBCXX_SSTREAM_ALWAYS_INLINE
+ basic_string_view<char_type, traits_type>
+ view() const noexcept
+ { return _M_stringbuf.view(); }
+#endif // C++20
+
/**
* @brief Setting a new buffer.
* @param __s The string to use as a new sequence.
{ _M_stringbuf.str(__s); }
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
- basic_string_view<char_type, traits_type>
- view() const noexcept
- { return _M_stringbuf.view(); }
+#if __cpp_concepts
+ template<__allocator_like _SAlloc>
+ requires (!is_same_v<_SAlloc, _Alloc>)
+ void
+ str(const basic_string<_CharT, _Traits, _SAlloc>& __s)
+ { _M_stringbuf.str(__s); }
+#endif
+
+ void
+ str(__string_type&& __s)
+ { _M_stringbuf.str(std::move(__s)); }
#endif
};
inline void
swap(basic_stringbuf<_CharT, _Traits, _Allocator>& __x,
basic_stringbuf<_CharT, _Traits, _Allocator>& __y)
+ noexcept(noexcept(__x.swap(__y)))
{ __x.swap(__y); }
/// Swap specialization for istringstreams.
swap(basic_stringstream<_CharT, _Traits, _Allocator>& __x,
basic_stringstream<_CharT, _Traits, _Allocator>& __y)
{ __x.swap(__y); }
-#endif
+#endif // C++11
_GLIBCXX_END_NAMESPACE_CXX11
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
+#undef _GLIBCXX_SSTREAM_ALWAYS_INLINE
+#undef _GLIBCXX_LVAL_REF_QUAL
+
#include <bits/sstream.tcc>
#endif /* _GLIBCXX_SSTREAM */