Implement syncstream (p0053)

This patch implements `std::basic_syncbuf` and `std::basic_osyncstream` as specified in paper p0053r7. ~~For ease of reviewing I am submitting this patch before submitting a patch for `std::basic_osyncstream`. ~~

~~Please note, this patch is not 100% complete. I plan on adding more tests (see comments), specifically I plan on adding tests for multithreading and synchronization.~~

Edit: I decided that it would be far easier for me to keep track of this and make changes that affect both `std::basic_syncbuf` and `std::basic_osyncstream` if both were in one patch.

The patch was originally written by @zoecarver

Implements
- P0053R7 - C++ Synchronized Buffered Ostream
- LWG-3127 basic_osyncstream::rdbuf needs a const_cast
- LWG-3334 basic_osyncstream move assignment and destruction calls basic_syncbuf::emit() twice
- LWG-3570 basic_osyncstream::emit should be an unformatted output function
- LWG-3867 Should std::basic_osyncstream's move assignment operator be noexcept?

Reviewed By: ldionne, #libc

Differential Revision: https://reviews.llvm.org/D67086
This commit is contained in:
Mark de Wever 2023-09-05 20:10:38 +02:00
parent f1b0a54451
commit 7cc72a0a2e
59 changed files with 3772 additions and 27 deletions

View File

@ -286,7 +286,7 @@ Status
--------------------------------------------------- ----------------- --------------------------------------------------- -----------------
``__cpp_lib_string_view`` ``201803L`` ``__cpp_lib_string_view`` ``201803L``
--------------------------------------------------- ----------------- --------------------------------------------------- -----------------
``__cpp_lib_syncbuf`` *unimplemented* ``__cpp_lib_syncbuf`` ``201803L``
--------------------------------------------------- ----------------- --------------------------------------------------- -----------------
``__cpp_lib_three_way_comparison`` *unimplemented* ``__cpp_lib_three_way_comparison`` *unimplemented*
--------------------------------------------------- ----------------- --------------------------------------------------- -----------------

View File

@ -47,6 +47,7 @@ Implemented Papers
- P2443R1 - ``views::chunk_by`` - P2443R1 - ``views::chunk_by``
- P2538R1 - ADL-proof ``std::projected`` - P2538R1 - ADL-proof ``std::projected``
- P2614R2 - Deprecate ``numeric_limits::has_denorm`` - P2614R2 - Deprecate ``numeric_limits::has_denorm``
- P0053R7 - C++ Synchronized Buffered Ostream (in the experimental library)
Improvements and New Features Improvements and New Features

View File

@ -114,7 +114,7 @@
"`3096 <https://wg21.link/LWG3096>`__","``path::lexically_relative``\ is confused by trailing slashes","San Diego","|Complete|","" "`3096 <https://wg21.link/LWG3096>`__","``path::lexically_relative``\ is confused by trailing slashes","San Diego","|Complete|",""
"`3116 <https://wg21.link/LWG3116>`__","``OUTERMOST_ALLOC_TRAITS``\ needs ``remove_reference_t``\ ","San Diego","","" "`3116 <https://wg21.link/LWG3116>`__","``OUTERMOST_ALLOC_TRAITS``\ needs ``remove_reference_t``\ ","San Diego","",""
"`3122 <https://wg21.link/LWG3122>`__","``__cpp_lib_chrono_udls``\ was accidentally dropped","San Diego","|Complete|","" "`3122 <https://wg21.link/LWG3122>`__","``__cpp_lib_chrono_udls``\ was accidentally dropped","San Diego","|Complete|",""
"`3127 <https://wg21.link/LWG3127>`__","``basic_osyncstream::rdbuf``\ needs a ``const_cast``\ ","San Diego","","" "`3127 <https://wg21.link/LWG3127>`__","``basic_osyncstream::rdbuf``\ needs a ``const_cast``\ ","San Diego","|Complete|","18.0"
"`3128 <https://wg21.link/LWG3128>`__","``strstream::rdbuf``\ needs a ``const_cast``\ ","San Diego","|Nothing To Do|","" "`3128 <https://wg21.link/LWG3128>`__","``strstream::rdbuf``\ needs a ``const_cast``\ ","San Diego","|Nothing To Do|",""
"`3129 <https://wg21.link/LWG3129>`__","``regex_token_iterator``\ constructor uses wrong pointer arithmetic","San Diego","","" "`3129 <https://wg21.link/LWG3129>`__","``regex_token_iterator``\ constructor uses wrong pointer arithmetic","San Diego","",""
"`3130 <https://wg21.link/LWG3130>`__","|sect|\ [input.output] needs many ``addressof``\ ","San Diego","","" "`3130 <https://wg21.link/LWG3130>`__","|sect|\ [input.output] needs many ``addressof``\ ","San Diego","",""
@ -254,7 +254,7 @@
"`3330 <https://wg21.link/LWG3330>`__","Include ``<compare>``\ from most library headers","Prague","|Complete|","13.0","|spaceship|" "`3330 <https://wg21.link/LWG3330>`__","Include ``<compare>``\ from most library headers","Prague","|Complete|","13.0","|spaceship|"
"`3331 <https://wg21.link/LWG3331>`__","Define ``totally_ordered/_with``\ in terms of ``partially-ordered-with``\ ","Prague","|Complete|","13.0" "`3331 <https://wg21.link/LWG3331>`__","Define ``totally_ordered/_with``\ in terms of ``partially-ordered-with``\ ","Prague","|Complete|","13.0"
"`3332 <https://wg21.link/LWG3332>`__","Issue in |sect|\ [time.format]","Prague","|Complete|","16.0","|chrono| |format|" "`3332 <https://wg21.link/LWG3332>`__","Issue in |sect|\ [time.format]","Prague","|Complete|","16.0","|chrono| |format|"
"`3334 <https://wg21.link/LWG3334>`__","``basic_osyncstream``\ move assignment and destruction calls ``basic_syncbuf::emit()``\ twice","Prague","","" "`3334 <https://wg21.link/LWG3334>`__","``basic_osyncstream``\ move assignment and destruction calls ``basic_syncbuf::emit()``\ twice","Prague","|Complete|","18.0"
"`3335 <https://wg21.link/LWG3335>`__","Resolve C++20 NB comments US 273 and GB 274","Prague","|Complete|","15.0","|ranges|" "`3335 <https://wg21.link/LWG3335>`__","Resolve C++20 NB comments US 273 and GB 274","Prague","|Complete|","15.0","|ranges|"
"`3338 <https://wg21.link/LWG3338>`__","Rename ``default_constructible``\ to ``default_initializable``\ ","Prague","|Complete|","13.0" "`3338 <https://wg21.link/LWG3338>`__","Rename ``default_constructible``\ to ``default_initializable``\ ","Prague","|Complete|","13.0"
"`3340 <https://wg21.link/LWG3340>`__","Formatting functions should throw on argument/format string mismatch in |sect|\ [format.functions]","Prague","|Complete|","14.0","|format|" "`3340 <https://wg21.link/LWG3340>`__","Formatting functions should throw on argument/format string mismatch in |sect|\ [format.functions]","Prague","|Complete|","14.0","|format|"

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -3,7 +3,7 @@
"`P0674R1 <https://wg21.link/P0674R1>`__","LWG","Extending make_shared to Support Arrays","Toronto","|Complete|","15.0" "`P0674R1 <https://wg21.link/P0674R1>`__","LWG","Extending make_shared to Support Arrays","Toronto","|Complete|","15.0"
"","","","","","","" "","","","","","",""
"`P0020R6 <https://wg21.link/P0020R6>`__","LWG","Floating Point Atomic","Albuquerque","","" "`P0020R6 <https://wg21.link/P0020R6>`__","LWG","Floating Point Atomic","Albuquerque","",""
"`P0053R7 <https://wg21.link/P0053R7>`__","LWG","C++ Synchronized Buffered Ostream","Albuquerque","","" "`P0053R7 <https://wg21.link/P0053R7>`__","LWG","C++ Synchronized Buffered Ostream","Albuquerque","|Complete|","18.0"
"`P0202R3 <https://wg21.link/P0202R3>`__","LWG","Add constexpr modifiers to functions in <algorithm> and <utility> Headers","Albuquerque","|Complete|","12.0" "`P0202R3 <https://wg21.link/P0202R3>`__","LWG","Add constexpr modifiers to functions in <algorithm> and <utility> Headers","Albuquerque","|Complete|","12.0"
"`P0415R1 <https://wg21.link/P0415R1>`__","LWG","Constexpr for ``std::complex``\ ","Albuquerque","|Complete|","16.0" "`P0415R1 <https://wg21.link/P0415R1>`__","LWG","Constexpr for ``std::complex``\ ","Albuquerque","|Complete|","16.0"
"`P0439R0 <https://wg21.link/P0439R0>`__","LWG","Make ``std::memory_order``\ a scoped enumeration","Albuquerque","|Complete|","" "`P0439R0 <https://wg21.link/P0439R0>`__","LWG","Make ``std::memory_order``\ a scoped enumeration","Albuquerque","|Complete|",""

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -122,7 +122,7 @@
`3566 <https://wg21.link/LWG3566>`__,"Constraint recursion for ``operator<=>(optional<T>, U)``","October 2021","|Complete|","17.0","|spaceship|" `3566 <https://wg21.link/LWG3566>`__,"Constraint recursion for ``operator<=>(optional<T>, U)``","October 2021","|Complete|","17.0","|spaceship|"
`3567 <https://wg21.link/LWG3567>`__,"Formatting move-only iterators take two","October 2021","|Complete|","16.0","|format| |ranges|" `3567 <https://wg21.link/LWG3567>`__,"Formatting move-only iterators take two","October 2021","|Complete|","16.0","|format| |ranges|"
`3568 <https://wg21.link/LWG3568>`__,"``basic_istream_view`` needs to initialize ``value_``","October 2021","|Complete|","16.0","|ranges|" `3568 <https://wg21.link/LWG3568>`__,"``basic_istream_view`` needs to initialize ``value_``","October 2021","|Complete|","16.0","|ranges|"
`3570 <https://wg21.link/LWG3570>`__,"``basic_osyncstream::emit`` should be an unformatted output function","October 2021","","" `3570 <https://wg21.link/LWG3570>`__,"``basic_osyncstream::emit`` should be an unformatted output function","October 2021","|Complete|","18.0"
`3571 <https://wg21.link/LWG3571>`__,"``flush_emit`` should set ``badbit`` if the ``emit`` call fails","October 2021","","" `3571 <https://wg21.link/LWG3571>`__,"``flush_emit`` should set ``badbit`` if the ``emit`` call fails","October 2021","",""
`3572 <https://wg21.link/LWG3572>`__,"``copyable-box`` should be fully ``constexpr``","October 2021","|Complete|","14.0","|ranges|" `3572 <https://wg21.link/LWG3572>`__,"``copyable-box`` should be fully ``constexpr``","October 2021","|Complete|","14.0","|ranges|"
`3573 <https://wg21.link/LWG3573>`__,"Missing Throws element for ``basic_string_view(It begin, End end)``","October 2021","|Complete|","14.0" `3573 <https://wg21.link/LWG3573>`__,"Missing Throws element for ``basic_string_view(It begin, End end)``","October 2021","|Complete|","14.0"
@ -275,7 +275,7 @@
"`3857 <https://wg21.link/LWG3857>`__","``basic_string_view`` should allow explicit conversion when only traits vary","February 2023","|Complete|","17.0","" "`3857 <https://wg21.link/LWG3857>`__","``basic_string_view`` should allow explicit conversion when only traits vary","February 2023","|Complete|","17.0",""
"`3860 <https://wg21.link/LWG3860>`__","``range_common_reference_t`` is missing","February 2023","|Complete|","17.0","|ranges|" "`3860 <https://wg21.link/LWG3860>`__","``range_common_reference_t`` is missing","February 2023","|Complete|","17.0","|ranges|"
"`3866 <https://wg21.link/LWG3866>`__","Bad Mandates for ``expected::transform_error`` overloads","February 2023","|Complete|","17.0","" "`3866 <https://wg21.link/LWG3866>`__","Bad Mandates for ``expected::transform_error`` overloads","February 2023","|Complete|","17.0",""
"`3867 <https://wg21.link/LWG3867>`__","Should ``std::basic_osyncstream``'s move assignment operator be ``noexcept``?","February 2023","","","" "`3867 <https://wg21.link/LWG3867>`__","Should ``std::basic_osyncstream``'s move assignment operator be ``noexcept``?","February 2023","|Complete|","18.0",""
"`3441 <https://wg21.link/LWG3441>`__","Misleading note about calls to customization points","February 2023","","","" "`3441 <https://wg21.link/LWG3441>`__","Misleading note about calls to customization points","February 2023","","",""
"`3622 <https://wg21.link/LWG3622>`__","Misspecified transitivity of equivalence in §[unord.req.general]","February 2023","","","" "`3622 <https://wg21.link/LWG3622>`__","Misspecified transitivity of equivalence in §[unord.req.general]","February 2023","","",""
"`3631 <https://wg21.link/LWG3631>`__","``basic_format_arg(T&&)`` should use ``remove_cvref_t<T>`` throughout","February 2023","|Complete|","17.0","" "`3631 <https://wg21.link/LWG3631>`__","``basic_format_arg(T&&)`` should use ``remove_cvref_t<T>`` throughout","February 2023","|Complete|","17.0",""

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -1000,6 +1000,7 @@ set(files
string.h string.h
string_view string_view
strstream strstream
syncstream
system_error system_error
tgmath.h tgmath.h
thread thread

View File

@ -452,6 +452,7 @@
# define _LIBCPP_HAS_NO_INCOMPLETE_PSTL # define _LIBCPP_HAS_NO_INCOMPLETE_PSTL
# define _LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN # define _LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN
# define _LIBCPP_HAS_NO_INCOMPLETE_TZDB # define _LIBCPP_HAS_NO_INCOMPLETE_TZDB
# define _LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM
# endif # endif
// Need to detect which libc we're using if we're on Linux. // Need to detect which libc we're using if we're on Linux.

View File

@ -200,6 +200,9 @@
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
# include <strstream> # include <strstream>
#endif #endif
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
# include <syncstream>
#endif
#include <system_error> #include <system_error>
#include <tgmath.h> #include <tgmath.h>
#if !defined(_LIBCPP_HAS_NO_THREADS) #if !defined(_LIBCPP_HAS_NO_THREADS)

View File

@ -90,6 +90,18 @@ using u8streampos = fpos<char_traits<char8_t>::state_type>; // C++20
using u16streampos = fpos<char_traits<char16_t>::state_type>; using u16streampos = fpos<char_traits<char16_t>::state_type>;
using u32streampos = fpos<char_traits<char32_t>::state_type>; using u32streampos = fpos<char_traits<char32_t>::state_type>;
template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
class basic_syncbuf; // C++20
using syncbuf = basic_syncbuf<char>; // C++20
using wsyncbuf = basic_syncbuf<wchar_t>; // C++20
template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
class basic_osyncstream; // C++20
using osyncstream = basic_osyncstream<char>; // C++20
using wosyncstream = basic_osyncstream<wchar_t>; // C++20
} // std } // std
*/ */
@ -130,6 +142,26 @@ typedef fpos<mbstate_t> u8streampos;
typedef fpos<mbstate_t> u16streampos; typedef fpos<mbstate_t> u16streampos;
typedef fpos<mbstate_t> u32streampos; typedef fpos<mbstate_t> u32streampos;
#if _LIBCPP_STD_VER >= 20
template <class _CharT, class _Traits = char_traits<_CharT>, class _Allocator = allocator<_CharT>>
class basic_syncbuf;
using syncbuf = basic_syncbuf<char>;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using wsyncbuf = basic_syncbuf<wchar_t>;
#endif
template <class _CharT, class _Traits = char_traits<_CharT>, class _Allocator = allocator<_CharT>>
class basic_osyncstream;
using osyncstream = basic_osyncstream<char>;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using wosyncstream = basic_osyncstream<wchar_t>;
#endif
#endif // _LIBCPP_STD_VER >=20
// Include other forward declarations here // Include other forward declarations here
template <class _Tp, class _Alloc = allocator<_Tp> > template <class _Tp, class _Alloc = allocator<_Tp> >
class _LIBCPP_TEMPLATE_VIS vector; class _LIBCPP_TEMPLATE_VIS vector;

View File

@ -1700,6 +1700,8 @@ template <class _Key, class _Tp, class _Compare, class _Allocator>
_Tp& _Tp&
map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k) map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k)
{ {
// TODO investigate this clang-tidy warning.
// NOLINTNEXTLINE(bugprone-use-after-move)
return __tree_.__emplace_unique_key_args(__k, return __tree_.__emplace_unique_key_args(__k,
_VSTD::piecewise_construct, _VSTD::piecewise_construct,
_VSTD::forward_as_tuple(_VSTD::move(__k)), _VSTD::forward_as_tuple(_VSTD::move(__k)),

View File

@ -110,6 +110,7 @@ protected:
#include <__assert> // all public C++ headers provide the assertion handler #include <__assert> // all public C++ headers provide the assertion handler
#include <__config> #include <__config>
#include <__fwd/streambuf.h> #include <__fwd/streambuf.h>
#include <climits>
#include <ios> #include <ios>
#include <iosfwd> #include <iosfwd>
#include <version> #include <version>

510
libcxx/include/syncstream Normal file
View File

@ -0,0 +1,510 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_SYNCSTREAM
#define _LIBCPP_SYNCSTREAM
/*
syncstream synopsis
#include <ostream> // see [ostream.syn]
namespace std {
template<class charT, class traits, class Allocator>
class basic_syncbuf;
// [syncstream.syncbuf.special], specialized algorithms
template<class charT, class traits, class Allocator>
void swap(basic_syncbuf<charT, traits, Allocator>&,
basic_syncbuf<charT, traits, Allocator>&);
using syncbuf = basic_syncbuf<char>;
using wsyncbuf = basic_syncbuf<wchar_t>;
template<class charT, class traits, class Allocator>
class basic_osyncstream;
using osyncstream = basic_osyncstream<char>;
using wosyncstream = basic_osyncstream<wchar_t>;
template<class charT, class traits, class Allocator>
class basic_syncbuf : public basic_streambuf<charT, traits> {
public:
using char_type = charT;
using int_type = typename traits::int_type;
using pos_type = typename traits::pos_type;
using off_type = typename traits::off_type;
using traits_type = traits;
using allocator_type = Allocator;
using streambuf_type = basic_streambuf<charT, traits>;
// [syncstream.syncbuf.cons], construction and destruction
explicit basic_syncbuf(streambuf_type* obuf = nullptr)
: basic_syncbuf(obuf, Allocator()) {}
basic_syncbuf(streambuf_type*, const Allocator&);
basic_syncbuf(basic_syncbuf&&);
~basic_syncbuf();
// [syncstream.syncbuf.assign], assignment and swap
basic_syncbuf& operator=(basic_syncbuf&&);
void swap(basic_syncbuf&);
// [syncstream.syncbuf.members], member functions
bool emit();
streambuf_type* get_wrapped() const noexcept;
allocator_type get_allocator() const noexcept;
void set_emit_on_sync(bool) noexcept;
protected:
// [syncstream.syncbuf.virtuals], overridden virtual functions
int sync() override;
private:
streambuf_type* wrapped; // exposition only
bool emit_on_sync{}; // exposition only
};
// [syncstream.syncbuf.special], specialized algorithms
template<class charT, class traits, class Allocator>
void swap(basic_syncbuf<charT, traits, Allocator>&,
basic_syncbuf<charT, traits, Allocator>&);
template<class charT, class traits, class Allocator>
class basic_osyncstream : public basic_ostream<charT, traits> {
public:
using char_type = charT;
using int_type = typename traits::int_type;
using pos_type = typename traits::pos_type;
using off_type = typename traits::off_type;
using traits_type = traits;
using allocator_type = Allocator;
using streambuf_type = basic_streambuf<charT, traits>;
using syncbuf_type = basic_syncbuf<charT, traits, Allocator>;
// [syncstream.osyncstream.cons], construction and destruction
basic_osyncstream(streambuf_type*, const Allocator&);
explicit basic_osyncstream(streambuf_type* obuf)
: basic_osyncstream(obuf, Allocator()) {}
basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)
: basic_osyncstream(os.rdbuf(), allocator) {}
explicit basic_osyncstream(basic_ostream<charT, traits>& os)
: basic_osyncstream(os, Allocator()) {}
basic_osyncstream(basic_osyncstream&&) noexcept;
~basic_osyncstream();
// [syncstream.osyncstream.assign], assignment
basic_osyncstream& operator=(basic_osyncstream&&);
// [syncstream.osyncstream.members], member functions
void emit();
streambuf_type* get_wrapped() const noexcept;
syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }
private:
syncbuf_type sb; // exposition only
};
}
*/
#include <__config>
#include <__utility/move.h>
#include <iosfwd> // required for declaration of default arguments
#include <string>
#ifndef _LIBCPP_HAS_NO_THREADS
# include <map>
# include <mutex>
# include <shared_mutex>
#endif
// standard-mandated includes
// [syncstream.syn]
#include <ostream>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
// [syncstream.syncbuf.overview]/1
// Class template basic_syncbuf stores character data written to it,
// known as the associated output, into internal buffers allocated
// using the object's allocator. The associated output is transferred
// to the wrapped stream buffer object *wrapped when emit() is called
// or when the basic_syncbuf object is destroyed. Such transfers are
// atomic with respect to transfers by other basic_syncbuf objects
// with the same wrapped stream buffer object.
//
// This helper singleton is used to implement the required
// synchronisation guarantees.
# ifndef _LIBCPP_HAS_NO_THREADS
class __wrapped_streambuf_mutex {
_LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default;
public:
__wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&) = delete;
__wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete;
_LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) {
_LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
unique_lock __lock{__mutex_};
++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count;
}
// pre: __ptr is in __lut_
_LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept {
unique_lock __lock{__mutex_};
auto __it = __get_it(__ptr);
if (__it->second.__count == 1)
__lut_.erase(__it);
else
--__it->second.__count;
}
// TODO
// This function causes emit() aquire two mutexes:
// - __mutex_ shared
// _ __get_it(__ptr)->second.__mutex exclusive
//
// Instead store a pointer to __get_it(__ptr)->second.__mutex when
// calling __inc_reference.
//
// pre: __ptr is in __lut_
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept {
shared_lock __lock{__mutex_};
return lock_guard{__get_it(__ptr)->second.__mutex};
}
// This function is used for testing.
//
// It is allowed to call this function with a non-registered pointer.
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept {
_LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
shared_lock __lock{__mutex_};
auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
return __it != __lut_.end() ? __it->second.__count : 0;
}
[[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept {
static __wrapped_streambuf_mutex __result;
return __result;
}
private:
struct __value {
mutex __mutex;
size_t __count{0};
};
shared_mutex __mutex_;
map<uintptr_t, __value> __lut_;
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept {
_LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
_LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered");
_LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper");
return __it;
}
};
# endif // _LIBCPP_HAS_NO_THREADS
// basic_syncbuf
// The class uses a basic_string<_CharT, _Traits, _Allocator> as
// internal buffer. Per [syncstream.syncbuf.cons]/4
// Remarks: A copy of allocator is used to allocate memory for
// internal buffers holding the associated output.
//
// Therefore the allocator used in the constructor is passed to the
// basic_string. The class does not keep a copy of this allocator.
template <class _CharT, class _Traits, class _Allocator>
class _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> {
public:
using char_type = _CharT;
using traits_type = _Traits;
using int_type = typename traits_type::int_type;
using pos_type = typename traits_type::pos_type;
using off_type = typename traits_type::off_type;
using allocator_type = _Allocator;
using streambuf_type = basic_streambuf<_CharT, _Traits>;
// [syncstream.syncbuf.cons], construction and destruction
_LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf = nullptr)
: basic_syncbuf(__obuf, _Allocator()) {}
_LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc)
: __wrapped_(__obuf), __str_(__alloc) {
__inc_reference();
}
_LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other)
: __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) {
__move_common(__other);
}
_LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() {
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try {
# endif // _LIBCPP_HAS_NO_EXCEPTIONS
emit();
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
} catch (...) {
}
# endif // _LIBCPP_HAS_NO_EXCEPTIONS
__dec_reference();
}
// [syncstream.syncbuf.assign], assignment and swap
_LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) {
// The function is specified to call emit. This call should
// propagate the exception thrown.
emit();
__dec_reference();
__wrapped_ = __other.get_wrapped();
__str_ = std::move(__other.__str_);
__emit_on_sync_ = __other.__emit_on_sync_;
__move_common(__other);
return *this;
}
_LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) {
_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(),
"violates the mandated swap precondition");
basic_syncbuf __tmp(std::move(__other));
__other = std::move(*this);
*this = std::move(__tmp);
}
// [syncstream.syncbuf.members], member functions
_LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }
_LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
_LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
_LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }
protected:
// [syncstream.syncbuf.virtuals], overridden virtual functions
_LIBCPP_HIDE_FROM_ABI_VIRTUAL
int sync() override {
if (__emit_on_sync_ && !emit(true))
return -1;
return 0;
}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL
int_type overflow(int_type __c = traits_type::eof()) override {
if (traits_type::eq_int_type(__c, traits_type::eof()))
return traits_type::not_eof(__c);
if (this->pptr() == this->epptr()) {
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try {
# endif
size_t __size = __str_.size();
__str_.resize(__str_.capacity() + 1);
_LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown");
char_type* __p = static_cast<char_type*>(__str_.data());
this->setp(__p, __p + __str_.size());
this->pbump(__size);
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
} catch (...) {
return traits_type::eof();
}
# endif
}
return this->sputc(traits_type::to_char_type(__c));
}
private:
streambuf_type* __wrapped_;
// TODO Use a more generic buffer.
// That buffer should be light with almost no additional headers. Then
// it can be use here, the __retarget_buffer, and place that use
// the now deprecated get_temporary_buffer
basic_string<_CharT, _Traits, _Allocator> __str_;
bool __emit_on_sync_{false};
_LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {
if (!__wrapped_)
return false;
# ifndef _LIBCPP_HAS_NO_THREADS
lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_);
# endif
bool __result = true;
if (this->pptr() != this->pbase()) {
_LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid");
// The __str_ does not know how much of its buffer is used. This
// information is extracted from the information of the base class.
__result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1);
// Clears the buffer, but keeps the contents (and) size of the
// internal buffer.
this->setp(this->pbase(), this->epptr());
}
if (__flush)
__result &= (__wrapped_->pubsync() != -1);
return __result;
}
_LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) {
// Adjust the put area pointers to our buffer.
char_type* __p = static_cast<char_type*>(__str_.data());
this->setp(__p, __p + __str_.size());
this->pbump(__other.pptr() - __other.pbase());
// Clear __other_ so the destructor will act as a NOP.
__other.setp(nullptr, nullptr);
__other.__wrapped_ = nullptr;
}
_LIBCPP_HIDE_FROM_ABI void __inc_reference() {
# ifndef _LIBCPP_HAS_NO_THREADS
if (__wrapped_)
__wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_);
# endif
}
_LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept {
# ifndef _LIBCPP_HAS_NO_THREADS
if (__wrapped_)
__wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_);
# endif
}
};
using std::syncbuf;
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using std::wsyncbuf;
# endif
// [syncstream.syncbuf.special], specialized algorithms
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_HIDE_FROM_ABI void
swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) {
__lhs.swap(__rhs);
}
// basic_osyncstream
template <class _CharT, class _Traits, class _Allocator>
class _LIBCPP_TEMPLATE_VIS basic_osyncstream : public basic_ostream<_CharT, _Traits> {
public:
using char_type = _CharT;
using traits_type = _Traits;
using int_type = typename traits_type::int_type;
using pos_type = typename traits_type::pos_type;
using off_type = typename traits_type::off_type;
using allocator_type = _Allocator;
using streambuf_type = basic_streambuf<char_type, traits_type>;
using syncbuf_type = basic_syncbuf<char_type, traits_type, allocator_type>;
// [syncstream.osyncstream.cons], construction and destruction
_LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc)
: basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {}
_LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf)
: basic_osyncstream(__obuf, allocator_type()) {}
_LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc)
: basic_osyncstream(__os.rdbuf(), __alloc) {}
_LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
: basic_osyncstream(__os, allocator_type()) {}
_LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept
: basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) {
this->set_rdbuf(std::addressof(__sb_));
}
// [syncstream.osyncstream.assign], assignment
_LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default;
// [syncstream.osyncstream.members], member functions
_LIBCPP_HIDE_FROM_ABI void emit() {
// The basic_ostream::put places the sentry in a try
// catch, this does not match the wording of the standard
// [ostream.unformatted]
// TODO validate other unformatted output functions.
typename basic_ostream<char_type, traits_type>::sentry __s(*this);
if (__s) {
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try {
# endif
if (__sb_.emit() == false)
this->setstate(ios::badbit);
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
} catch (...) {
this->__set_badbit_and_consider_rethrow();
}
# endif
}
}
_LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
_LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
return const_cast<syncbuf_type*>(std::addressof(__sb_));
}
private:
syncbuf_type __sb_;
};
using std::osyncstream;
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using std::wosyncstream;
# endif
#endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP_SYNCSTREAM

View File

@ -401,7 +401,9 @@ __cpp_lib_within_lifetime 202306L <type_traits>
# define __cpp_lib_starts_ends_with 201711L # define __cpp_lib_starts_ends_with 201711L
# undef __cpp_lib_string_view # undef __cpp_lib_string_view
# define __cpp_lib_string_view 201803L # define __cpp_lib_string_view 201803L
// # define __cpp_lib_syncbuf 201803L # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
# define __cpp_lib_syncbuf 201803L
# endif
// # define __cpp_lib_three_way_comparison 201907L // # define __cpp_lib_three_way_comparison 201907L
# define __cpp_lib_to_address 201711L # define __cpp_lib_to_address 201711L
# define __cpp_lib_to_array 201907L # define __cpp_lib_to_array 201907L

View File

@ -148,6 +148,9 @@ module;
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
# include <strstream> # include <strstream>
#endif #endif
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
# include <syncstream>
#endif
#include <system_error> #include <system_error>
#if !defined(_LIBCPP_HAS_NO_THREADS) #if !defined(_LIBCPP_HAS_NO_THREADS)
# include <thread> # include <thread>
@ -189,9 +192,6 @@ module;
#if __has_include(<stdfloat>) #if __has_include(<stdfloat>)
# error "update the header information for <stdfloat> in libcxx/utils/generate_std_cppm_in.py" # error "update the header information for <stdfloat> in libcxx/utils/generate_std_cppm_in.py"
#endif // __has_include(<stdfloat>) #endif // __has_include(<stdfloat>)
#if __has_include(<syncstream>)
# error "update the header information for <syncstream> in libcxx/utils/generate_std_cppm_in.py"
#endif // __has_include(<syncstream>)
#if __has_include(<text_encoding>) #if __has_include(<text_encoding>)
# error "update the header information for <text_encoding> in libcxx/utils/generate_std_cppm_in.py" # error "update the header information for <text_encoding> in libcxx/utils/generate_std_cppm_in.py"
#endif // __has_include(<text_encoding>) #endif // __has_include(<text_encoding>)

View File

@ -16,8 +16,19 @@ export namespace std {
using std::u32streampos; using std::u32streampos;
using std::u8streampos; using std::u8streampos;
using std::basic_osyncstream;
using std::basic_syncbuf;
using std::istreambuf_iterator; using std::istreambuf_iterator;
using std::ostreambuf_iterator; using std::ostreambuf_iterator;
using std::osyncstream;
using std::syncbuf;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using std::wosyncstream;
using std::wsyncbuf;
#endif
using std::fpos; using std::fpos;
} // namespace std } // namespace std

View File

@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
export namespace std { export namespace std {
#if 0 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
using std::basic_syncbuf; using std::basic_syncbuf;
// [syncstream.syncbuf.special], specialized algorithms // [syncstream.syncbuf.special], specialized algorithms
@ -24,5 +24,5 @@ export namespace std {
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using std::wosyncstream; using std::wosyncstream;
# endif # endif
#endif #endif // !defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
} // namespace std } // namespace std

View File

@ -27,3 +27,7 @@
#ifdef _LIBCPP_HAS_NO_INCOMPLETE_TZDB #ifdef _LIBCPP_HAS_NO_INCOMPLETE_TZDB
# error "-fexperimental-library should enable the chrono TZDB" # error "-fexperimental-library should enable the chrono TZDB"
#endif #endif
#ifdef _LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM
# error "-fexperimental-library should enable the syncstream header"
#endif

View File

@ -813,6 +813,7 @@ stop_token limits
stop_token ratio stop_token ratio
stop_token type_traits stop_token type_traits
stop_token version stop_token version
streambuf climits
streambuf cstdint streambuf cstdint
streambuf ios streambuf ios
streambuf iosfwd streambuf iosfwd
@ -859,6 +860,13 @@ string_view version
strstream istream strstream istream
strstream ostream strstream ostream
strstream version strstream version
syncstream cstddef
syncstream iosfwd
syncstream map
syncstream mutex
syncstream ostream
syncstream shared_mutex
syncstream string
system_error cerrno system_error cerrno
system_error compare system_error compare
system_error cstddef system_error cstddef

1 algorithm atomic
813 stop_token ratio
814 stop_token type_traits
815 stop_token version
816 streambuf climits
817 streambuf cstdint
818 streambuf ios
819 streambuf iosfwd
860 strstream istream
861 strstream ostream
862 strstream version
863 syncstream cstddef
864 syncstream iosfwd
865 syncstream map
866 syncstream mutex
867 syncstream ostream
868 syncstream shared_mutex
869 syncstream string
870 system_error cerrno
871 system_error compare
872 system_error cstddef

View File

@ -819,6 +819,7 @@ stop_token limits
stop_token ratio stop_token ratio
stop_token type_traits stop_token type_traits
stop_token version stop_token version
streambuf climits
streambuf cstdint streambuf cstdint
streambuf ios streambuf ios
streambuf iosfwd streambuf iosfwd
@ -865,6 +866,13 @@ string_view version
strstream istream strstream istream
strstream ostream strstream ostream
strstream version strstream version
syncstream cstddef
syncstream iosfwd
syncstream map
syncstream mutex
syncstream ostream
syncstream shared_mutex
syncstream string
system_error cerrno system_error cerrno
system_error compare system_error compare
system_error cstddef system_error cstddef

1 algorithm atomic
819 stop_token ratio
820 stop_token type_traits
821 stop_token version
822 streambuf climits
823 streambuf cstdint
824 streambuf ios
825 streambuf iosfwd
866 strstream istream
867 strstream ostream
868 strstream version
869 syncstream cstddef
870 syncstream iosfwd
871 syncstream map
872 syncstream mutex
873 syncstream ostream
874 syncstream shared_mutex
875 syncstream string
876 system_error cerrno
877 system_error compare
878 system_error cstddef

View File

@ -821,6 +821,7 @@ stop_token limits
stop_token ratio stop_token ratio
stop_token type_traits stop_token type_traits
stop_token version stop_token version
streambuf climits
streambuf cstdint streambuf cstdint
streambuf ios streambuf ios
streambuf iosfwd streambuf iosfwd
@ -867,6 +868,13 @@ string_view version
strstream istream strstream istream
strstream ostream strstream ostream
strstream version strstream version
syncstream cstddef
syncstream iosfwd
syncstream map
syncstream mutex
syncstream ostream
syncstream shared_mutex
syncstream string
system_error cerrno system_error cerrno
system_error compare system_error compare
system_error cstddef system_error cstddef

1 algorithm atomic
821 stop_token ratio
822 stop_token type_traits
823 stop_token version
824 streambuf climits
825 streambuf cstdint
826 streambuf ios
827 streambuf iosfwd
868 strstream istream
869 strstream ostream
870 strstream version
871 syncstream cstddef
872 syncstream iosfwd
873 syncstream map
874 syncstream mutex
875 syncstream ostream
876 syncstream shared_mutex
877 syncstream string
878 system_error cerrno
879 system_error compare
880 system_error cstddef

View File

@ -821,6 +821,7 @@ stop_token limits
stop_token ratio stop_token ratio
stop_token type_traits stop_token type_traits
stop_token version stop_token version
streambuf climits
streambuf cstdint streambuf cstdint
streambuf ios streambuf ios
streambuf iosfwd streambuf iosfwd
@ -867,6 +868,13 @@ string_view version
strstream istream strstream istream
strstream ostream strstream ostream
strstream version strstream version
syncstream cstddef
syncstream iosfwd
syncstream map
syncstream mutex
syncstream ostream
syncstream shared_mutex
syncstream string
system_error cerrno system_error cerrno
system_error compare system_error compare
system_error cstddef system_error cstddef

1 algorithm atomic
821 stop_token ratio
822 stop_token type_traits
823 stop_token version
824 streambuf climits
825 streambuf cstdint
826 streambuf ios
827 streambuf iosfwd
868 strstream istream
869 strstream ostream
870 strstream version
871 syncstream cstddef
872 syncstream iosfwd
873 syncstream map
874 syncstream mutex
875 syncstream ostream
876 syncstream shared_mutex
877 syncstream string
878 system_error cerrno
879 system_error compare
880 system_error cstddef

View File

@ -826,6 +826,7 @@ stop_token limits
stop_token ratio stop_token ratio
stop_token type_traits stop_token type_traits
stop_token version stop_token version
streambuf climits
streambuf cstdint streambuf cstdint
streambuf ios streambuf ios
streambuf iosfwd streambuf iosfwd
@ -872,6 +873,13 @@ string_view version
strstream istream strstream istream
strstream ostream strstream ostream
strstream version strstream version
syncstream cstddef
syncstream iosfwd
syncstream map
syncstream mutex
syncstream ostream
syncstream shared_mutex
syncstream string
system_error cerrno system_error cerrno
system_error compare system_error compare
system_error cstddef system_error cstddef

1 algorithm atomic
826 stop_token ratio
827 stop_token type_traits
828 stop_token version
829 streambuf climits
830 streambuf cstdint
831 streambuf ios
832 streambuf iosfwd
873 strstream istream
874 strstream ostream
875 strstream version
876 syncstream cstddef
877 syncstream iosfwd
878 syncstream map
879 syncstream mutex
880 syncstream ostream
881 syncstream shared_mutex
882 syncstream string
883 system_error cerrno
884 system_error compare
885 system_error cstddef

View File

@ -564,6 +564,7 @@ stop_token ctime
stop_token limits stop_token limits
stop_token ratio stop_token ratio
stop_token version stop_token version
streambuf climits
streambuf ios streambuf ios
streambuf iosfwd streambuf iosfwd
streambuf version streambuf version
@ -597,6 +598,13 @@ string_view version
strstream istream strstream istream
strstream ostream strstream ostream
strstream version strstream version
syncstream cstddef
syncstream iosfwd
syncstream map
syncstream mutex
syncstream ostream
syncstream shared_mutex
syncstream string
system_error cerrno system_error cerrno
system_error compare system_error compare
system_error cstddef system_error cstddef

1 algorithm climits
564 stop_token limits
565 stop_token ratio
566 stop_token version
567 streambuf climits
568 streambuf ios
569 streambuf iosfwd
570 streambuf version
598 strstream istream
599 strstream ostream
600 strstream version
601 syncstream cstddef
602 syncstream iosfwd
603 syncstream map
604 syncstream mutex
605 syncstream ostream
606 syncstream shared_mutex
607 syncstream string
608 system_error cerrno
609 system_error compare
610 system_error cstddef

View File

@ -564,6 +564,7 @@ stop_token ctime
stop_token limits stop_token limits
stop_token ratio stop_token ratio
stop_token version stop_token version
streambuf climits
streambuf ios streambuf ios
streambuf iosfwd streambuf iosfwd
streambuf version streambuf version
@ -597,6 +598,13 @@ string_view version
strstream istream strstream istream
strstream ostream strstream ostream
strstream version strstream version
syncstream cstddef
syncstream iosfwd
syncstream map
syncstream mutex
syncstream ostream
syncstream shared_mutex
syncstream string
system_error cerrno system_error cerrno
system_error compare system_error compare
system_error cstddef system_error cstddef

1 algorithm climits
564 stop_token limits
565 stop_token ratio
566 stop_token version
567 streambuf climits
568 streambuf ios
569 streambuf iosfwd
570 streambuf version
598 strstream istream
599 strstream ostream
600 strstream version
601 syncstream cstddef
602 syncstream iosfwd
603 syncstream map
604 syncstream mutex
605 syncstream ostream
606 syncstream shared_mutex
607 syncstream string
608 system_error cerrno
609 system_error compare
610 system_error cstddef

View File

@ -0,0 +1,101 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// basic_osyncstream& operator=(basic_osyncstream&& rhs);
#include <syncstream>
#include <sstream>
#include <cassert>
#include "test_macros.h"
#include "test_allocator.h"
template <class CharT, bool propagate>
static void test() {
using Traits = std::char_traits<CharT>;
using Allocator = std::conditional_t<propagate, other_allocator<CharT>, test_allocator<CharT>>;
static_assert(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value == propagate);
using OS = std::basic_osyncstream<CharT, Traits, Allocator>;
std::basic_stringbuf<CharT, Traits, Allocator> base1;
std::basic_stringbuf<CharT, Traits, Allocator> base2;
{
OS out1{&base1, Allocator{42}};
assert(out1.get_wrapped() == &base1);
typename OS::syncbuf_type* sb1 = out1.rdbuf();
assert(sb1->get_wrapped() == &base1);
assert(sb1->get_allocator().get_data() == 42);
out1 << CharT('A');
static_assert(!noexcept(out1.operator=(std::move(out1)))); // LWG-3867
OS out2{&base2, Allocator{99}};
out2 << CharT('Z');
// Validate the data is still in the syncbuf and not in the stringbuf.
assert(base1.str().empty());
assert(base2.str().empty());
out2 = std::move(out1);
// Since sb2 is overwritten by the move its data should be in its stringbuf.
assert(base1.str().empty());
assert(base2.str().size() == 1);
assert(base2.str()[0] == CharT('Z'));
assert(out2.get_wrapped() == &base1);
typename OS::syncbuf_type* sb2 = out2.rdbuf();
assert(sb2->get_wrapped() == &base1);
if constexpr (std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value)
assert(sb2->get_allocator().get_data() == 42);
else
assert(sb2->get_allocator().get_data() == 99);
assert(out1.get_wrapped() == nullptr);
assert(sb1->get_wrapped() == nullptr);
// The data written to 2 will be stored in sb1. The write happens after the destruction.
out2 << CharT('B');
assert(base1.str().empty());
}
assert(base1.str().size() == 2);
assert(base1.str()[0] == CharT('A'));
assert(base1.str()[1] == CharT('B'));
assert(base2.str().size() == 1);
assert(base2.str()[0] == CharT('Z'));
}
template <class CharT>
static void test() {
test<CharT, true>();
test<CharT, false>();
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,45 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// void emit();
#include <syncstream>
#include <sstream>
#include <cassert>
#include "test_macros.h"
template <class CharT>
void test() {
using OS = std::basic_osyncstream<CharT>;
using SS = std::basic_ostringstream<CharT>;
CharT c = 'f';
SS ss;
OS out(ss);
out << c;
assert(ss.str().empty());
out.emit();
assert(ss.str()[0] == c);
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
}

View File

@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// streambuf_type* get_wrapped() const noexcept;
#include <syncstream>
#include <sstream>
#include <cassert>
#include "test_macros.h"
template <class CharT>
void test() {
std::basic_stringbuf<CharT> base;
const std::basic_osyncstream<CharT> out{&base};
assert(out.get_wrapped() == &base);
ASSERT_NOEXCEPT(out.get_wrapped());
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// syncbuf_type* rdbuf() const noexcept
#include <syncstream>
#include <sstream>
#include <cassert>
#include "test_macros.h"
template <class CharT>
void test() {
const std::basic_osyncstream<CharT> out{nullptr};
assert(out.rdbuf() != nullptr);
ASSERT_NOEXCEPT(out.rdbuf());
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,135 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// basic_osyncstream(basic_osyncstream&&) noexcept;
// TODO Why is this noexcept?
// Does the reasoning for https://cplusplus.github.io/LWG/issue3867 not hold true here?
#include <cassert>
#include <sstream>
#include <syncstream>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using OS = std::basic_osyncstream<CharT>;
using W = std::basic_syncbuf<CharT>;
const std::allocator<CharT> alloc;
{
OS os = {OS{nullptr, alloc}};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == alloc);
ASSERT_NOEXCEPT(OS{std::move(os)});
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os = {OS{&w, alloc}};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>>;
using W = std::basic_stringbuf<CharT, constexpr_char_traits<CharT>>;
const std::allocator<CharT> alloc;
{
OS os = {OS{nullptr, alloc}};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == alloc);
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os = {OS{&w, alloc}};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
using W = std::basic_stringbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
const test_allocator<CharT> alloc;
{
OS os = {OS{nullptr, alloc}};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == alloc);
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os = {OS{&w, alloc}};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,114 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// basic_osyncstream(basic_ostream& os, const Allocator& allocator);
#include <cassert>
#include <concepts>
#include <syncstream>
#include <sstream>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using OS = std::basic_osyncstream<CharT>;
using W = std::basic_ostringstream<CharT>;
const std::allocator<CharT> alloc;
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
{
OS os = {w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 1);
#endif
assert(os.get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>>;
using W = std::basic_ostringstream<CharT, constexpr_char_traits<CharT>>;
const std::allocator<CharT> alloc;
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
{
OS os = {w.rdbuf(), alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 1);
#endif
assert(os.get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
using W = std::basic_ostringstream<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
const test_allocator<CharT> alloc;
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
{
OS os = {w.rdbuf(), alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 1);
#endif
assert(os.get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
}
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,120 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// explicit basic_osyncstream(basic_ostream& os);
#include <cassert>
#include <concepts>
#include <syncstream>
#include <sstream>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using OS = std::basic_osyncstream<CharT>;
using W = std::basic_ostringstream<CharT>;
static_assert(!std::convertible_to<std::basic_ostream<CharT>&, OS>);
static_assert(std::constructible_from<OS, std::basic_ostream<CharT>&>);
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
{
OS os{w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 1);
#endif
assert(os.get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_allocator() == std::allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>>;
using W = std::basic_ostringstream<CharT, constexpr_char_traits<CharT>>;
static_assert(!std::convertible_to<std::basic_ostream<CharT, constexpr_char_traits<CharT>>&, OS>);
static_assert(std::constructible_from<OS, std::basic_ostream<CharT, constexpr_char_traits<CharT>>&>);
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
{
OS os{w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 1);
#endif
assert(os.get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_allocator() == std::allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
using W = std::basic_ostringstream<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
static_assert(!std::convertible_to<std::basic_ostream<CharT, constexpr_char_traits<CharT>>&, OS>);
static_assert(std::constructible_from<OS, std::basic_ostream<CharT, constexpr_char_traits<CharT>>&>);
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
{
OS os{w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 1);
#endif
assert(os.get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_wrapped() == w.rdbuf());
assert(os.rdbuf()->get_allocator() == test_allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(w.rdbuf()) == 0);
#endif
}
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,132 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// basic_osyncstream(streambuf_type* os, const Allocator& allocator);
#include <cassert>
#include <concepts>
#include <syncstream>
#include <sstream>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using OS = std::basic_osyncstream<CharT>;
using W = std::basic_stringbuf<CharT>;
const std::allocator<CharT> alloc;
{
OS os = {nullptr, alloc};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == alloc);
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os = {&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>>;
using W = std::basic_stringbuf<CharT, constexpr_char_traits<CharT>>;
const std::allocator<CharT> alloc;
{
OS os = {nullptr, alloc};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == alloc);
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os = {&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
using W = std::basic_stringbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
const test_allocator<CharT> alloc;
{
OS os = {nullptr, alloc};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == alloc);
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os = {&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,140 @@
//==----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// explicit basic_osyncstream(streambuf_type* os);
#include <cassert>
#include <concepts>
#include <syncstream>
#include <sstream>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using OS = std::basic_osyncstream<CharT>;
using W = std::basic_stringbuf<CharT>;
static_assert(!std::convertible_to<std::basic_syncbuf<CharT>*, OS>);
static_assert(std::constructible_from<OS, std::basic_syncbuf<CharT>*>);
{
OS os{nullptr};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == std::allocator<CharT>());
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os{&w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == std::allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>>;
using W = std::basic_stringbuf<CharT, constexpr_char_traits<CharT>>;
static_assert(!std::convertible_to<std::basic_syncbuf<CharT, constexpr_char_traits<CharT>>*, OS>);
static_assert(std::constructible_from<OS, std::basic_syncbuf<CharT, constexpr_char_traits<CharT>>*>);
{
OS os{nullptr};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == std::allocator<CharT>());
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os{&w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == std::allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using OS = std::basic_osyncstream<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
using W = std::basic_stringbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
static_assert(
!std::convertible_to<std::basic_syncbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>*, OS>);
static_assert(
std::constructible_from<OS, std::basic_syncbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>*>);
{
OS os{nullptr};
assert(os.get_wrapped() == nullptr);
assert(os.rdbuf()->get_wrapped() == nullptr);
assert(os.rdbuf()->get_allocator() == test_allocator<CharT>());
}
{
W w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
OS os{&w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(os.get_wrapped() == &w);
assert(os.rdbuf()->get_wrapped() == &w);
assert(os.rdbuf()->get_allocator() == test_allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,60 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: no-threads
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// Basic test whether the code works in a threaded environment.
// Using timing the output order should be stable.
// several_threads.pass.cpp tests with more threads.
#include <syncstream>
#include <sstream>
#include <mutex>
#include <thread>
#include <cassert>
#include <iostream>
#include "test_macros.h"
static std::basic_ostringstream<char> ss;
static const char a = 'a';
static const char b = 'b';
static const char c = 'c';
static const char d = 'd';
void f1() {
std::basic_osyncstream<char> out(ss);
out << a;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
out << b;
}
void f2() {
std::basic_osyncstream<char> out(ss);
out << c;
out << d;
}
int main(int, char**) {
std::thread t1(f1);
std::thread t2(f2);
t1.join();
t2.join();
assert(ss.str() == "cdab");
return 0;
}

View File

@ -0,0 +1,144 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: no-threads
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_osyncstream;
// The test writes all elements in test_strings in a random order in ss. Every
// write is done by an osyncstream. This means the output is in random order,
// but the words should be written without interleaving. To increment the
// change of interleaving words are written one character at a time.
#include <cassert>
#include <chrono>
#include <mutex>
#include <sstream>
#include <string>
#include <syncstream>
#include <thread>
#include <unordered_set>
#include <vector>
#include "test_macros.h"
static std::ostringstream ss;
static std::unordered_multiset<std::string> test_strings = {
"C++ ",
"is ",
"a ",
"general-purpose ",
"programming ",
"language ",
"created ",
"by ",
"Bjarne ",
"Stroustrup ",
"as ",
"an ",
"extension ",
"of ",
"the ",
"C ",
"programming ",
"language, ",
"or ",
"C ",
"with ",
"Classes. ",
"The ",
"language ",
"has ",
"expanded ",
"significantly ",
"over ",
"time, ",
"and ",
"modern ",
"C++ ",
"has ",
"object-oriented, ",
"generic, ",
"and ",
"functional ",
"features ",
"in ",
"addition ",
"to ",
"facilities ",
"for ",
"low-level ",
"memory ",
"manipulation. ",
"It ",
"is ",
"almost ",
"always ",
"implemented ",
"as ",
"a ",
"compiled ",
"language, ",
"and ",
"many ",
"vendors ",
"provide ",
"C++ ",
"compilers, ",
"including ",
"the ",
"Free ",
"Software ",
"Foundation, ",
"LLVM, ",
"Microsoft, ",
"Intel, ",
"and ",
"IBM, ",
"so ",
"it ",
"is ",
"available ",
"on ",
"many ",
"platforms."};
void f(std::string text) {
std::osyncstream out(ss);
for (char c : text)
out << c;
}
void test() {
ss = std::basic_ostringstream<char>();
std::vector<std::thread> threads;
for (std::string const& word : test_strings)
threads.push_back(std::thread(f, word));
for (auto& thread : threads)
thread.join();
std::string output = ss.str();
for (const std::string& word : test_strings)
assert(output.find(word) != std::string::npos);
}
int main(int, char**) {
// The more we test, the more likely we catch an error
for (size_t i = 0; i < 1024; ++i)
test();
return 0;
}

View File

@ -0,0 +1,92 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
//
// template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
// class basic_osyncstream : public basic_ostream<charT, traits> {
// public:
// using char_type = charT;
// using int_type = typename traits::int_type;
// using pos_type = typename traits::pos_type;
// using off_type = typename traits::off_type;
// using traits_type = traits;
//
// using allocator_type = Allocator;
// using streambuf_type = basic_streambuf<charT, traits>;
// using syncbuf_type = basic_syncbuf<charT, traits, Allocator>;
#include <syncstream>
#include <concepts>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
static_assert(std::same_as<std::basic_osyncstream<char>,
std::basic_osyncstream<char, std::char_traits<char>, std::allocator<char>>>);
static_assert(std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>>,
std::basic_osyncstream<char, constexpr_char_traits<char>, std::allocator<char>>>);
static_assert(
std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>, test_allocator<char>>::char_type, char>);
static_assert(std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>, test_allocator<char>>::int_type,
constexpr_char_traits<char>::int_type>);
static_assert(std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>, test_allocator<char>>::pos_type,
constexpr_char_traits<char>::pos_type>);
static_assert(std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>, test_allocator<char>>::off_type,
constexpr_char_traits<char>::off_type>);
static_assert(std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>, test_allocator<char>>::traits_type,
constexpr_char_traits<char>>);
static_assert(
std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>, test_allocator<char>>::allocator_type,
test_allocator<char>>);
static_assert(
std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>, test_allocator<char>>::streambuf_type,
std::basic_streambuf<char, constexpr_char_traits<char>>>);
static_assert(
std::same_as<std::basic_osyncstream<char, constexpr_char_traits<char>, test_allocator<char>>::syncbuf_type,
std::basic_syncbuf<char, constexpr_char_traits<char>, test_allocator<char>>>);
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
static_assert(std::same_as<std::basic_osyncstream<wchar_t>,
std::basic_osyncstream<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>>);
static_assert(std::same_as<std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>>,
std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, std::allocator<wchar_t>>>);
static_assert(
std::same_as<std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::char_type,
wchar_t>);
static_assert(
std::same_as<std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::int_type,
constexpr_char_traits<wchar_t>::int_type>);
static_assert(
std::same_as<std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::pos_type,
constexpr_char_traits<wchar_t>::pos_type>);
static_assert(
std::same_as<std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::off_type,
constexpr_char_traits<wchar_t>::off_type>);
static_assert(
std::same_as<std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::traits_type,
constexpr_char_traits<wchar_t>>);
static_assert(std::same_as<
std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::allocator_type,
test_allocator<wchar_t>>);
static_assert(std::same_as<
std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::streambuf_type,
std::basic_streambuf<wchar_t, constexpr_char_traits<wchar_t>>>);
static_assert(
std::same_as<std::basic_osyncstream<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::syncbuf_type,
std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>>);
#endif // TEST_HAS_NO_WIDE_CHARACTERS

View File

@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef TEST_STD_INPUT_OUTPUT_SYNCSTREAM_SYNCBUF_SYNCSTREAM_SYNCBUF_MEMBERS_H
#define TEST_STD_INPUT_OUTPUT_SYNCSTREAM_SYNCBUF_SYNCSTREAM_SYNCBUF_MEMBERS_H
#include <syncstream>
template <class T>
class test_buf : public std::basic_streambuf<T> {
public:
int id;
test_buf(int _id = 0) : id(_id) {}
T* _pptr() { return this->pptr(); }
};
template <class T, class Alloc = std::allocator<T>>
class test_syncbuf : public std::basic_syncbuf<T, std::char_traits<T>, Alloc> {
public:
test_syncbuf(test_buf<T>* buf, Alloc alloc) : std::basic_syncbuf<T, std::char_traits<T>, Alloc>(buf, alloc) {}
void _setp(T* begin, T* end) { return this->setp(begin, end); }
};
template <class T>
struct test_allocator : std::allocator<T> {
int id;
test_allocator(int _id = 0) : id(_id) {}
};
#endif // TEST_STD_INPUT_OUTPUT_SYNCSTREAM_SYNCBUF_SYNCSTREAM_SYNCBUF_MEMBERS_H

View File

@ -0,0 +1,151 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// Tests the inherited function using a custom allocator.
//
// int_type basic_streambuf<charT, traits>::sputc(char_type c);
//
// This test also validates the observable behaviour after move assignment and
// construction. This test uses a small so the underlying string is in short
// mode.
#include <array>
#include <syncstream>
#include <cassert>
#include <sstream>
#include "test_macros.h"
#include "test_allocator.h"
template <class CharT>
void test() {
std::array< CharT, 17> input{
CharT('a'),
CharT('1'),
CharT('+'),
CharT('A'),
CharT('g'),
CharT('0'),
CharT('@'),
CharT('Z'),
CharT('q'),
CharT('8'),
CharT('#'),
CharT('D'),
CharT('t'),
CharT('9'),
CharT('$'),
CharT('A'),
CharT(' ')};
using SyncBuf = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT>>;
{ // Normal
std::basic_string<CharT> expected;
std::basic_stringbuf<CharT> buf;
test_allocator_statistics stats;
test_allocator<CharT> allocator{&stats};
{
SyncBuf sync_buf{&buf, allocator};
for (int i = 0; i < 1024; ++i) {
CharT c = input[i % input.size()];
expected.push_back(c);
typename SyncBuf::int_type ret = sync_buf.sputc(c);
assert(ret == typename SyncBuf::int_type(c));
}
// The synchchronization happens upon destruction of sync_buf.
assert(buf.str().empty());
assert(stats.allocated_size >= 1024);
}
assert(buf.str() == expected);
assert(stats.allocated_size == 0);
}
{ // Move construction
std::basic_stringbuf<CharT> buf;
test_allocator_statistics stats;
test_allocator<CharT> allocator{&stats};
{
SyncBuf sync_buf{&buf, allocator};
CharT c = CharT('4');
typename SyncBuf::int_type ret = sync_buf.sputc(c);
assert(ret == typename SyncBuf::int_type(c));
{
c = CharT('2');
SyncBuf new_sync_buf{std::move(sync_buf)};
ret = new_sync_buf.sputc(c);
assert(ret == typename SyncBuf::int_type(c));
// The synchchronization happens upon destruction of new_sync_buf.
assert(buf.str().empty());
assert(stats.allocated_size >= 2);
}
assert(buf.str().size() == 2);
assert(buf.str()[0] == CharT('4'));
assert(buf.str()[1] == CharT('2'));
assert(stats.allocated_size == 0);
}
assert(buf.str().size() == 2);
assert(buf.str()[0] == CharT('4'));
assert(buf.str()[1] == CharT('2'));
assert(stats.allocated_size == 0);
}
{ // Move assignment non-propagating allocator
std::basic_stringbuf<CharT> buf;
test_allocator_statistics stats;
test_allocator<CharT> allocator{&stats};
static_assert(!std::allocator_traits<test_allocator<CharT>>::propagate_on_container_move_assignment::value);
{
SyncBuf sync_buf{&buf, allocator};
CharT c = CharT('4');
typename SyncBuf::int_type ret = sync_buf.sputc(c);
assert(ret == typename SyncBuf::int_type(c));
{
c = CharT('2');
SyncBuf new_sync_buf;
test_allocator<CharT> a = new_sync_buf.get_allocator();
new_sync_buf = std::move(sync_buf);
assert(new_sync_buf.get_allocator() == a);
ret = new_sync_buf.sputc(c);
assert(ret == typename SyncBuf::int_type(c));
// The synchchronization happens upon destruction of new_sync_buf.
assert(buf.str().empty());
}
assert(buf.str().size() == 2);
assert(buf.str()[0] == CharT('4'));
assert(buf.str()[1] == CharT('2'));
}
assert(buf.str().size() == 2);
assert(buf.str()[0] == CharT('4'));
assert(buf.str()[1] == CharT('2'));
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,134 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// Tests the inherited function using a custom allocator.
//
// streamsize basic_streambuf<charT, traits>::sputc(const char_type* s, streamsize n);
//
// This test also validates the observable behaviour after move assignment and
// construction. This test uses a large buffer so the underlying string is in
// long mode.
#include <array>
#include <syncstream>
#include <cassert>
#include <sstream>
#include "test_macros.h"
#include "test_allocator.h"
template <class CharT>
void test() {
std::array< CharT, 17> input{
CharT('a'),
CharT('1'),
CharT('+'),
CharT('A'),
CharT('g'),
CharT('0'),
CharT('@'),
CharT('Z'),
CharT('q'),
CharT('8'),
CharT('#'),
CharT('D'),
CharT('t'),
CharT('9'),
CharT('$'),
CharT('A'),
CharT(' ')};
std::basic_string<CharT> expected;
for (int i = 0; i < 1024; ++i)
expected.push_back(input[i % input.size()]);
using SyncBuf = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT>>;
{ // Normal
std::basic_stringbuf<CharT> buf;
test_allocator_statistics stats;
test_allocator<CharT> allocator{&stats};
{
SyncBuf sync_buf{&buf, allocator};
std::streamsize ret = sync_buf.sputn(expected.data(), expected.size());
assert(ret == 1024);
// The synchchronization happens upon destruction of sync_buf.
assert(buf.str().empty());
assert(stats.allocated_size >= 1024);
}
assert(buf.str() == expected);
assert(stats.allocated_size == 0);
}
{ // Move construction
std::basic_stringbuf<CharT> buf;
test_allocator_statistics stats;
test_allocator<CharT> allocator{&stats};
{
SyncBuf sync_buf{&buf, allocator};
std::streamsize ret = sync_buf.sputn(expected.data(), expected.size());
assert(ret == 1024);
{
SyncBuf new_sync_buf{std::move(sync_buf)};
ret = new_sync_buf.sputn(expected.data(), expected.size());
assert(ret == 1024);
// The synchchronization happens upon destruction of new_sync_buf.
assert(buf.str().empty());
assert(stats.allocated_size >= 2048);
}
assert(buf.str() == expected + expected);
assert(stats.allocated_size == 0);
}
assert(buf.str() == expected + expected);
assert(stats.allocated_size == 0);
}
{ // Move assignment non-propagating allocator
std::basic_stringbuf<CharT> buf;
test_allocator_statistics stats;
test_allocator<CharT> allocator{&stats};
static_assert(!std::allocator_traits<test_allocator<CharT>>::propagate_on_container_move_assignment::value);
{
SyncBuf sync_buf{&buf, allocator};
std::streamsize ret = sync_buf.sputn(expected.data(), expected.size());
assert(ret == 1024);
{
SyncBuf new_sync_buf;
test_allocator<CharT> a = new_sync_buf.get_allocator();
new_sync_buf = std::move(sync_buf);
assert(new_sync_buf.get_allocator() == a);
ret = new_sync_buf.sputn(expected.data(), expected.size());
assert(ret == 1024);
// The synchchronization happens upon destruction of new_sync_buf.
assert(buf.str().empty());
}
assert(buf.str() == expected + expected);
}
assert(buf.str() == expected + expected);
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// protected:
// [syncstream.syncbuf.virtuals], overridden virtual functions
// int sync() override;
#include <syncstream>
#include <sstream>
#include <ostream>
#include <cassert>
#include "test_macros.h"
template <class CharT>
void test_sync(bool emit_on_sync) {
std::basic_stringbuf<CharT> base;
std::basic_syncbuf<CharT> buff(&base);
std::basic_ostream<CharT> out(&buff);
buff.set_emit_on_sync(emit_on_sync);
out << 'a';
out.flush(); // This is an indirect call to sync.
if (emit_on_sync) {
assert(base.str().size() == 1);
assert(base.str()[0] == CharT('a'));
} else
assert(base.str().empty());
}
int main(int, char**) {
test_sync<char>(true);
test_sync<char>(false);
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_sync<wchar_t>(true);
test_sync<wchar_t>(false);
#endif
return 0;
}

View File

@ -0,0 +1,399 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// basic_syncbuf& operator=(basic_syncbuf&& rhs);
#include <syncstream>
#include <sstream>
#include <cassert>
#include <concepts>
#include "test_macros.h"
template <class T, class propagate>
struct test_allocator : std::allocator<T> {
using propagate_on_container_move_assignment = propagate;
int id{-1};
test_allocator(int _id = -1) : id(_id) {}
test_allocator(test_allocator const& other) = default;
test_allocator(test_allocator&& other) = default;
test_allocator& operator=(const test_allocator& other) = default;
test_allocator& operator=(test_allocator&& other) {
if constexpr (propagate_on_container_move_assignment::value)
id = other.id;
else
id = -1;
return *this;
}
};
template <class T>
class test_buf : public std::basic_streambuf<T> {
public:
int id;
test_buf(int _id = 0) : id(_id) {}
T* _pptr() { return this->pptr(); }
};
template <class T, class Alloc = std::allocator<T>>
class test_syncbuf : public std::basic_syncbuf<T, std::char_traits<T>, Alloc> {
using Base = std::basic_syncbuf<T, std::char_traits<T>, Alloc>;
public:
test_syncbuf() = default;
test_syncbuf(test_buf<T>* buf, Alloc alloc) : Base(buf, alloc) {}
test_syncbuf(typename Base::streambuf_type* buf, Alloc alloc) : Base(buf, alloc) {}
void _setp(T* begin, T* end) { return this->setp(begin, end); }
};
// Helper wrapper to inspect the internal state of the basic_syncbuf
//
// This is used the valiate some standard requirements and libc++
// implementation details.
template <class CharT, class Traits, class Allocator>
class syncbuf_inspector : public std::basic_syncbuf<CharT, Traits, Allocator> {
public:
syncbuf_inspector() = default;
explicit syncbuf_inspector(std::basic_syncbuf<CharT, Traits, Allocator>&& base)
: std::basic_syncbuf<CharT, Traits, Allocator>(std::move(base)) {}
void operator=(std::basic_syncbuf<CharT, Traits, Allocator>&& base) { *this = std::move(base); }
using std::basic_syncbuf<CharT, Traits, Allocator>::pbase;
using std::basic_syncbuf<CharT, Traits, Allocator>::pptr;
using std::basic_syncbuf<CharT, Traits, Allocator>::epptr;
};
template <class CharT>
static void test_assign() {
test_buf<CharT> base;
{ // Test using the real class, propagating allocator.
using BuffT = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT, std::true_type>>;
BuffT buff1(&base, test_allocator<CharT, std::true_type>{42});
buff1.sputc(CharT('A'));
assert(buff1.get_wrapped() != nullptr);
BuffT buff2;
assert(buff2.get_allocator().id == -1);
buff2 = std::move(buff1);
assert(buff1.get_wrapped() == nullptr);
assert(buff2.get_wrapped() == &base);
assert(buff2.get_wrapped() == &base);
assert(buff2.get_allocator().id == 42);
}
{ // Test using the real class, non-propagating allocator.
using BuffT = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT, std::false_type>>;
BuffT buff1(&base, test_allocator<CharT, std::false_type>{42});
buff1.sputc(CharT('A'));
assert(buff1.get_wrapped() != nullptr);
BuffT buff2;
assert(buff2.get_allocator().id == -1);
buff2 = std::move(buff1);
assert(buff1.get_wrapped() == nullptr);
assert(buff2.get_wrapped() == &base);
assert(buff2.get_wrapped() == &base);
assert(buff2.get_allocator().id == -1);
}
{ // Move assignment propagating allocator
// Test using the inspection wrapper.
// Not all these requirements are explicitly in the Standard,
// however the asserts are based on secondary requirements. The
// LIBCPP_ASSERTs are implementation specific.
using BuffT = std::basic_syncbuf<CharT, std::char_traits<CharT>, std::allocator<CharT>>;
using Inspector = syncbuf_inspector<CharT, std::char_traits<CharT>, std::allocator<CharT>>;
Inspector inspector1{BuffT(&base)};
inspector1.sputc(CharT('A'));
assert(inspector1.get_wrapped() != nullptr);
assert(inspector1.pbase() != nullptr);
assert(inspector1.pptr() != nullptr);
assert(inspector1.epptr() != nullptr);
assert(inspector1.pbase() != inspector1.pptr());
assert(inspector1.pptr() - inspector1.pbase() == 1);
[[maybe_unused]] std::streamsize size = inspector1.epptr() - inspector1.pbase();
Inspector inspector2;
inspector2 = std::move(inspector1);
assert(inspector1.get_wrapped() == nullptr);
LIBCPP_ASSERT(inspector1.pbase() == nullptr);
LIBCPP_ASSERT(inspector1.pptr() == nullptr);
LIBCPP_ASSERT(inspector1.epptr() == nullptr);
assert(inspector1.pbase() == inspector1.pptr());
assert(inspector2.get_wrapped() == &base);
LIBCPP_ASSERT(inspector2.pbase() != nullptr);
LIBCPP_ASSERT(inspector2.pptr() != nullptr);
LIBCPP_ASSERT(inspector2.epptr() != nullptr);
assert(inspector2.pptr() - inspector2.pbase() == 1);
LIBCPP_ASSERT(inspector2.epptr() - inspector2.pbase() == size);
}
}
template <class CharT>
static void test_basic() {
{ // Test properties
std::basic_syncbuf<CharT> sync_buf1(nullptr);
std::basic_syncbuf<CharT> sync_buf2(nullptr);
[[maybe_unused]] std::same_as<std::basic_syncbuf<CharT>&> decltype(auto) ret =
sync_buf1.operator=(std::move(sync_buf2));
}
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.sputn(expected.data(), expected.size());
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr1) == 1);
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr2) == 1);
#endif
sync_buf2 = std::move(sync_buf1);
assert(sync_buf2.get_wrapped() == &sstr1);
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr1) == 1);
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr2) == 0);
#endif
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
template <class CharT>
static void test_short_write_after_assign() {
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf2 = std::move(sync_buf1);
sync_buf2.sputc(CharT('Z'));
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
}
assert(sstr1.str().size() == 2);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr1.str()[1] == CharT('Z'));
assert(sstr2.str() == expected);
}
template <class CharT>
static void test_long_write_after_assign() {
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf2 = std::move(sync_buf1);
sync_buf2.sputn(expected.data(), expected.size());
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
}
assert(sstr1.str().size() == 1 + expected.size());
assert(sstr1.str()[0] == CharT('A'));
assert(sstr1.str().substr(1) == expected);
assert(sstr2.str() == expected);
}
template <class CharT>
static void test_emit_on_assign() {
{ // don't emit / don't emit
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.set_emit_on_sync(false);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.set_emit_on_sync(false);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf2 = std::move(sync_buf1);
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
sync_buf2.pubsync();
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
{ // don't emit / do emit
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.set_emit_on_sync(true);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.set_emit_on_sync(false);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf2 = std::move(sync_buf1);
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
sync_buf2.pubsync();
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
{ // do emit / don't emit
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.set_emit_on_sync(false);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.set_emit_on_sync(true);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf2 = std::move(sync_buf1);
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
sync_buf2.pubsync();
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
{ // do emit / do emit
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.set_emit_on_sync(true);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.set_emit_on_sync(true);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf2 = std::move(sync_buf1);
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
sync_buf2.pubsync();
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
}
template <class CharT>
static void test() {
test_assign<CharT>();
test_basic<CharT>();
test_short_write_after_assign<CharT>();
test_long_write_after_assign<CharT>();
test_emit_on_assign<CharT>();
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,274 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// void swap(basic_syncbuf& other) noexcept;
#include <syncstream>
#include <sstream>
#include <cassert>
#include "test_macros.h"
#include <iostream>
template <class CharT>
static void test_basic() {
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.sputn(expected.data(), expected.size());
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr1) == 1);
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr2) == 1);
#endif
sync_buf1.swap(sync_buf2);
assert(sync_buf1.get_wrapped() == &sstr2);
assert(sync_buf2.get_wrapped() == &sstr1);
assert(sstr1.str().empty());
assert(sstr2.str().empty());
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr1) == 1);
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr2) == 1);
#endif
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
template <class CharT>
static void test_short_write_after_swap() {
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf1.swap(sync_buf2);
expected.push_back(sync_buf1.sputc(CharT('B')));
sync_buf2.sputc(CharT('Z'));
assert(sstr1.str().empty());
assert(sstr2.str().empty());
}
assert(sstr1.str().size() == 2);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr1.str()[1] == CharT('Z'));
assert(sstr2.str() == expected);
}
template <class CharT>
static void test_long_write_after_swap() {
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf1.swap(sync_buf2);
sync_buf1.sputn(expected.data(), expected.size());
sync_buf2.sputn(expected.data(), expected.size());
assert(sstr1.str().empty());
assert(sstr2.str().empty());
}
assert(sstr1.str().size() == 1 + expected.size());
assert(sstr1.str()[0] == CharT('A'));
assert(sstr1.str().substr(1) == expected);
assert(sstr2.str() == expected + expected);
}
template <class CharT>
static void test_emit_on_sync() {
{ // false false
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.set_emit_on_sync(false);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.set_emit_on_sync(false);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf1.swap(sync_buf2);
assert(sstr1.str().empty());
assert(sstr2.str().empty());
sync_buf1.pubsync();
assert(sstr1.str().empty());
assert(sstr2.str().empty());
sync_buf2.pubsync();
assert(sstr1.str().empty());
assert(sstr2.str().empty());
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
{ // false true
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.set_emit_on_sync(true);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.set_emit_on_sync(false);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf1.swap(sync_buf2);
assert(sstr1.str().empty());
assert(sstr2.str().empty());
sync_buf1.pubsync();
assert(sstr1.str().empty());
assert(sstr2.str().empty());
sync_buf2.pubsync();
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str().empty());
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
{ // true false
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.set_emit_on_sync(false);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.set_emit_on_sync(true);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf1.swap(sync_buf2);
assert(sstr1.str().empty());
assert(sstr2.str().empty());
sync_buf1.pubsync();
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
sync_buf2.pubsync();
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
{ // true true
std::basic_stringbuf<CharT> sstr1;
std::basic_stringbuf<CharT> sstr2;
std::basic_string<CharT> expected(42, CharT('*')); // a long string
{
std::basic_syncbuf<CharT> sync_buf1(&sstr1);
sync_buf1.set_emit_on_sync(true);
sync_buf1.sputc(CharT('A')); // a short string
std::basic_syncbuf<CharT> sync_buf2(&sstr2);
sync_buf2.set_emit_on_sync(true);
sync_buf2.sputn(expected.data(), expected.size());
sync_buf1.swap(sync_buf2);
assert(sstr1.str().empty());
assert(sstr2.str().empty());
sync_buf1.pubsync();
assert(sstr1.str().empty());
assert(sstr2.str() == expected);
sync_buf2.pubsync();
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
assert(sstr1.str().size() == 1);
assert(sstr1.str()[0] == CharT('A'));
assert(sstr2.str() == expected);
}
}
template <class CharT>
static void test() {
test_basic<CharT>();
test_emit_on_sync<CharT>();
test_short_write_after_swap<CharT>();
test_long_write_after_swap<CharT>();
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,60 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// basic_syncbuf();
#include <cassert>
#include <concepts>
#include <syncstream>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using Buf = std::basic_syncbuf<CharT>;
static_assert(std::default_initializable<Buf>);
Buf buf;
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == std::allocator<CharT>());
}
{
using Buf = std::basic_syncbuf<CharT, constexpr_char_traits<CharT>>;
static_assert(std::default_initializable<Buf>);
Buf buf;
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == std::allocator<CharT>());
}
{
using Buf = std::basic_syncbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
static_assert(std::default_initializable<Buf>);
Buf buf;
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == test_allocator<CharT>());
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,136 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// basic_syncbuf(basic_syncbuf&& other);
#include <syncstream>
#include <cassert>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using Buf = std::basic_syncbuf<CharT>;
const std::allocator<CharT> alloc;
{
Buf b1{nullptr, alloc};
Buf b2{std::move(b1)};
assert(b2.get_wrapped() == nullptr);
assert(b2.get_allocator() == alloc);
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf b1{&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
Buf b2{std::move(b1)};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(b2.get_wrapped() == &w);
assert(b2.get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using Buf = std::basic_syncbuf<CharT, constexpr_char_traits<CharT>>;
const std::allocator<CharT> alloc;
{
Buf b1{nullptr, alloc};
Buf b2{std::move(b1)};
assert(b2.get_wrapped() == nullptr);
assert(b2.get_allocator() == alloc);
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf b1{&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
Buf b2{std::move(b1)};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(b2.get_wrapped() == &w);
assert(b2.get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using Buf = std::basic_syncbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
test_allocator<CharT> alloc{42};
{
Buf b1{nullptr, alloc};
Buf b2{std::move(b1)};
assert(b2.get_wrapped() == nullptr);
assert(b2.get_allocator() == alloc);
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf b1{&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
Buf b2{std::move(b1)};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(b2.get_wrapped() == &w);
assert(b2.get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,119 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// basic_syncbuf(streambuf_type* obuf, const Allocator&);
#include <cassert>
#include <concepts>
#include <syncstream>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using Buf = std::basic_syncbuf<CharT>;
const std::allocator<CharT> alloc;
{
Buf buf = {nullptr, alloc};
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == alloc);
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf buf = {&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(buf.get_wrapped() == &w);
assert(buf.get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using Buf = std::basic_syncbuf<CharT, constexpr_char_traits<CharT>>;
const std::allocator<CharT> alloc;
{
Buf buf = {nullptr, alloc};
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == alloc);
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf buf{&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(buf.get_wrapped() == &w);
assert(buf.get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using Buf = std::basic_syncbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
test_allocator<CharT> alloc{42};
{
Buf buf = {nullptr, alloc};
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == alloc);
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf buf{&w, alloc};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(buf.get_wrapped() == &w);
assert(buf.get_allocator() == alloc);
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,128 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// explicit basic_syncbuf(streambuf_type* obuf);
#include <cassert>
#include <concepts>
#include <syncstream>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
template <class CharT>
void test() {
{
using Buf = std::basic_syncbuf<CharT>;
static_assert(!std::convertible_to<std::basic_streambuf<CharT>*, Buf>);
static_assert(std::constructible_from<Buf, std::basic_streambuf<CharT>*>);
{
Buf buf{nullptr};
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == std::allocator<CharT>());
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf buf{&w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(buf.get_wrapped() == &w);
assert(buf.get_allocator() == std::allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using Buf = std::basic_syncbuf<CharT, constexpr_char_traits<CharT>>;
static_assert(!std::convertible_to<std::basic_streambuf<CharT, constexpr_char_traits<CharT>>*, Buf>);
static_assert(std::constructible_from<Buf, std::basic_streambuf<CharT, constexpr_char_traits<CharT>>*>);
{
Buf buf{nullptr};
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == std::allocator<CharT>());
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf buf{&w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(buf.get_wrapped() == &w);
assert(buf.get_allocator() == std::allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
{
using Buf = std::basic_syncbuf<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>;
static_assert(!std::convertible_to<std::basic_streambuf<CharT, constexpr_char_traits<CharT>>*, Buf>);
static_assert(std::constructible_from<Buf, std::basic_streambuf<CharT, constexpr_char_traits<CharT>>*>);
{
Buf buf{nullptr};
assert(buf.get_wrapped() == nullptr);
assert(buf.get_allocator() == test_allocator<CharT>());
}
{
Buf w;
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
{
Buf buf{&w};
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 1);
#endif
assert(buf.get_wrapped() == &w);
assert(buf.get_allocator() == test_allocator<CharT>());
}
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&w) == 0);
#endif
}
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,54 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// ~basic_syncbuf();
#include <syncstream>
#include <cassert>
#include "../helpers.h"
#include "test_macros.h"
template <class CharT>
void test() {
// We do this because we want to be able to use CharT
CharT arr[3] = {'a', 'b', 'c'};
CharT* ptr = arr;
test_buf<CharT> base;
const std::allocator<CharT> alloc;
{
test_syncbuf<CharT> buf(&base, alloc);
buf._setp(ptr, ptr + 3);
assert(base._pptr() == nullptr);
// The destructor calls buf.emit();
}
CharT* pptr = base._pptr();
while (pptr) {
assert(*pptr++ == *ptr++);
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,52 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// bool emit();
#include <syncstream>
#include <cassert>
#include "../helpers.h"
#include "test_macros.h"
template <class CharT>
void test() {
// We do this because we want to be able to use CharT
CharT arr[3] = {'a', 'b', 'c'};
CharT* ptr = arr;
test_buf<CharT> base;
const std::allocator<CharT> alloc;
test_syncbuf<CharT> buff(&base, alloc);
buff._setp(ptr, ptr + 3);
assert(base._pptr() == nullptr);
buff.emit();
CharT* pptr = base._pptr();
while (pptr) {
assert(*pptr++ == *ptr++);
}
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// allocator_type get_allocator() const noexcept;
#include <syncstream>
#include <cassert>
#include "test_macros.h"
#include "../helpers.h"
template <class T>
void test_get_allocator() {
test_buf<T> base;
test_allocator<T> alloc(42);
const test_syncbuf<T, test_allocator<T>> buff(&base, alloc);
assert(buff.get_allocator().id == 42);
ASSERT_NOEXCEPT(buff.get_allocator());
}
int main(int, char**) {
test_get_allocator<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_get_allocator<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,44 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// streambuf_type* get_wrapped() const noexcept;
#include <syncstream>
#include <concepts>
#include <cassert>
#include "../helpers.h"
#include "test_macros.h"
template <class T>
void test() {
test_buf<T> base(42);
const std::allocator<T> alloc;
const test_syncbuf<T> buff(&base, alloc);
std::same_as<std::basic_streambuf<T>*> auto wrapped = buff.get_wrapped();
assert(static_cast<test_buf<T>*>(wrapped)->id == 42);
ASSERT_NOEXCEPT(buff.get_wrapped());
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template <class charT, class traits, class Allocator>
// class basic_syncbuf;
// void set_emit_on_sync(bool) noexcept;
#include <syncstream>
#include <cassert>
#include "test_macros.h"
#include "../helpers.h"
template <class T>
void test_set_emit_on_sync() {
// set_emit_on_sync tested in sync, which is called by pubsync. The assign
// and swap test use this.
test_syncbuf<T, std::allocator<T>> buff(nullptr, std::allocator<T>());
ASSERT_NOEXCEPT(buff.set_emit_on_sync(false));
buff.set_emit_on_sync(false); // Validates the function can be called.
}
int main(int, char**) {
test_set_emit_on_sync<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_set_emit_on_sync<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template<class charT, class traits, class Allocator>
// void swap(basic_syncbuf<charT, traits, Allocator>&,
// basic_syncbuf<charT, traits, Allocator>&);
#include <syncstream>
#include <cassert>
#include "test_macros.h"
template <class CharT>
void test() {
std::basic_syncbuf<CharT> base1;
std::basic_syncbuf<CharT> base2;
std::basic_syncbuf<CharT> buff1(&base1);
std::basic_syncbuf<CharT> buff2(&base2);
std::swap(buff1, buff2);
assert(buff1.get_wrapped() == &base2);
assert(buff2.get_wrapped() == &base1);
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View File

@ -0,0 +1,84 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-experimental-syncstream
// <syncstream>
// template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
// class basic_syncbuf {
//
// public:
// using char_type = charT;
// using int_type = typename traits::int_type;
// using pos_type = typename traits::pos_type;
// using off_type = typename traits::off_type;
// using traits_type = traits;
// using allocator_type = Allocator;
//
// using streambuf_type = basic_streambuf<charT, traits>;
//
// ...
#include <syncstream>
#include <concepts>
#include "test_macros.h"
#include "constexpr_char_traits.h"
#include "test_allocator.h"
static_assert(
std::same_as<std::basic_syncbuf<char>, std::basic_syncbuf<char, std::char_traits<char>, std::allocator<char>>>);
static_assert(std::same_as<std::basic_syncbuf<char, constexpr_char_traits<char>>,
std::basic_syncbuf<char, constexpr_char_traits<char>, std::allocator<char>>>);
static_assert(
std::same_as<std::basic_syncbuf<char, constexpr_char_traits<char>, test_allocator<char>>::char_type, char>);
static_assert(std::same_as<std::basic_syncbuf<char, constexpr_char_traits<char>, test_allocator<char>>::int_type,
constexpr_char_traits<char>::int_type>);
static_assert(std::same_as<std::basic_syncbuf<char, constexpr_char_traits<char>, test_allocator<char>>::pos_type,
constexpr_char_traits<char>::pos_type>);
static_assert(std::same_as<std::basic_syncbuf<char, constexpr_char_traits<char>, test_allocator<char>>::off_type,
constexpr_char_traits<char>::off_type>);
static_assert(std::same_as<std::basic_syncbuf<char, constexpr_char_traits<char>, test_allocator<char>>::traits_type,
constexpr_char_traits<char>>);
static_assert(std::same_as<std::basic_syncbuf<char, constexpr_char_traits<char>, test_allocator<char>>::allocator_type,
test_allocator<char>>);
static_assert(std::same_as<std::basic_syncbuf<char, constexpr_char_traits<char>, test_allocator<char>>::streambuf_type,
std::basic_streambuf<char, constexpr_char_traits<char>>>);
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
static_assert(std::same_as<std::basic_syncbuf<wchar_t>,
std::basic_syncbuf<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>>);
static_assert(std::same_as<std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>>,
std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, std::allocator<wchar_t>>>);
static_assert(
std::same_as<std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::char_type,
wchar_t>);
static_assert(
std::same_as<std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::int_type,
constexpr_char_traits<wchar_t>::int_type>);
static_assert(
std::same_as<std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::pos_type,
constexpr_char_traits<wchar_t>::pos_type>);
static_assert(
std::same_as<std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::off_type,
constexpr_char_traits<wchar_t>::off_type>);
static_assert(
std::same_as<std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::traits_type,
constexpr_char_traits<wchar_t>>);
static_assert(
std::same_as<std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::allocator_type,
test_allocator<wchar_t>>);
static_assert(
std::same_as<std::basic_syncbuf<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>::streambuf_type,
std::basic_streambuf<wchar_t, constexpr_char_traits<wchar_t>>>);
#endif // TEST_HAS_NO_WIDE_CHARACTERS

View File

@ -0,0 +1,91 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// WARNING: This test was generated by generate_feature_test_macro_components.py
// and should not be edited manually.
//
// clang-format off
// UNSUPPORTED: no-localization
// <syncstream>
// Test the feature test macros defined by <syncstream>
/* Constant Value
__cpp_lib_syncbuf 201803L [C++20]
*/
#include <syncstream>
#include "test_macros.h"
#if TEST_STD_VER < 14
# ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined before c++20"
# endif
#elif TEST_STD_VER == 14
# ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined before c++20"
# endif
#elif TEST_STD_VER == 17
# ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined before c++20"
# endif
#elif TEST_STD_VER == 20
# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
# ifndef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should be defined in c++20"
# endif
# if __cpp_lib_syncbuf != 201803L
# error "__cpp_lib_syncbuf should have the value 201803L in c++20"
# endif
# else
# ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined when the requirement '!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)' is not met!"
# endif
# endif
#elif TEST_STD_VER == 23
# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
# ifndef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should be defined in c++23"
# endif
# if __cpp_lib_syncbuf != 201803L
# error "__cpp_lib_syncbuf should have the value 201803L in c++23"
# endif
# else
# ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined when the requirement '!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)' is not met!"
# endif
# endif
#elif TEST_STD_VER > 23
# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
# ifndef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should be defined in c++26"
# endif
# if __cpp_lib_syncbuf != 201803L
# error "__cpp_lib_syncbuf should have the value 201803L in c++26"
# endif
# else
# ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined when the requirement '!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)' is not met!"
# endif
# endif
#endif // TEST_STD_VER > 23

View File

@ -3822,16 +3822,16 @@
# error "__cpp_lib_submdspan should not be defined before c++26" # error "__cpp_lib_submdspan should not be defined before c++26"
# endif # endif
# if !defined(_LIBCPP_VERSION) # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
# ifndef __cpp_lib_syncbuf # ifndef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should be defined in c++20" # error "__cpp_lib_syncbuf should be defined in c++20"
# endif # endif
# if __cpp_lib_syncbuf != 201803L # if __cpp_lib_syncbuf != 201803L
# error "__cpp_lib_syncbuf should have the value 201803L in c++20" # error "__cpp_lib_syncbuf should have the value 201803L in c++20"
# endif # endif
# else // _LIBCPP_VERSION # else
# ifdef __cpp_lib_syncbuf # ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined because it is unimplemented in libc++!" # error "__cpp_lib_syncbuf should not be defined when the requirement '!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)' is not met!"
# endif # endif
# endif # endif
@ -5294,16 +5294,16 @@
# error "__cpp_lib_submdspan should not be defined before c++26" # error "__cpp_lib_submdspan should not be defined before c++26"
# endif # endif
# if !defined(_LIBCPP_VERSION) # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
# ifndef __cpp_lib_syncbuf # ifndef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should be defined in c++23" # error "__cpp_lib_syncbuf should be defined in c++23"
# endif # endif
# if __cpp_lib_syncbuf != 201803L # if __cpp_lib_syncbuf != 201803L
# error "__cpp_lib_syncbuf should have the value 201803L in c++23" # error "__cpp_lib_syncbuf should have the value 201803L in c++23"
# endif # endif
# else // _LIBCPP_VERSION # else
# ifdef __cpp_lib_syncbuf # ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined because it is unimplemented in libc++!" # error "__cpp_lib_syncbuf should not be defined when the requirement '!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)' is not met!"
# endif # endif
# endif # endif
@ -6868,16 +6868,16 @@
# endif # endif
# endif # endif
# if !defined(_LIBCPP_VERSION) # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
# ifndef __cpp_lib_syncbuf # ifndef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should be defined in c++26" # error "__cpp_lib_syncbuf should be defined in c++26"
# endif # endif
# if __cpp_lib_syncbuf != 201803L # if __cpp_lib_syncbuf != 201803L
# error "__cpp_lib_syncbuf should have the value 201803L in c++26" # error "__cpp_lib_syncbuf should have the value 201803L in c++26"
# endif # endif
# else // _LIBCPP_VERSION # else
# ifdef __cpp_lib_syncbuf # ifdef __cpp_lib_syncbuf
# error "__cpp_lib_syncbuf should not be defined because it is unimplemented in libc++!" # error "__cpp_lib_syncbuf should not be defined when the requirement '!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)' is not met!"
# endif # endif
# endif # endif

View File

@ -29,8 +29,9 @@ TEST_CONSTEXPR_CXX20 inline typename std::allocator_traits<Alloc>::size_type all
struct test_allocator_statistics { struct test_allocator_statistics {
int time_to_throw = 0; int time_to_throw = 0;
int throw_after = INT_MAX; int throw_after = INT_MAX;
int count = 0; int count = 0; // the number of active instances
int alloc_count = 0; int alloc_count = 0; // the number of allocations not deallocating
int allocated_size = 0; // the size of allocated elements
int construct_count = 0; // the number of times that ::construct was called int construct_count = 0; // the number of times that ::construct was called
int destroy_count = 0; // the number of times that ::destroy was called int destroy_count = 0; // the number of times that ::destroy was called
int copied = 0; int copied = 0;
@ -42,6 +43,7 @@ struct test_allocator_statistics {
count = 0; count = 0;
time_to_throw = 0; time_to_throw = 0;
alloc_count = 0; alloc_count = 0;
allocated_size = 0;
construct_count = 0; construct_count = 0;
destroy_count = 0; destroy_count = 0;
throw_after = INT_MAX; throw_after = INT_MAX;
@ -155,14 +157,17 @@ public:
TEST_THROW(std::bad_alloc()); TEST_THROW(std::bad_alloc());
++stats_->time_to_throw; ++stats_->time_to_throw;
++stats_->alloc_count; ++stats_->alloc_count;
stats_->allocated_size += n;
} }
return std::allocator<value_type>().allocate(n); return std::allocator<value_type>().allocate(n);
} }
TEST_CONSTEXPR_CXX14 void deallocate(pointer p, size_type s) { TEST_CONSTEXPR_CXX14 void deallocate(pointer p, size_type s) {
assert(data_ != test_alloc_base::destructed_value); assert(data_ != test_alloc_base::destructed_value);
if (stats_ != nullptr) if (stats_ != nullptr) {
--stats_->alloc_count; --stats_->alloc_count;
stats_->allocated_size -= s;
}
std::allocator<value_type>().deallocate(p, s); std::allocator<value_type>().deallocate(p, s);
} }
@ -275,6 +280,7 @@ public:
} }
TEST_CONSTEXPR_CXX14 friend bool operator!=(const other_allocator& x, const other_allocator& y) { return !(x == y); } TEST_CONSTEXPR_CXX14 friend bool operator!=(const other_allocator& x, const other_allocator& y) { return !(x == y); }
TEST_CONSTEXPR int get_data() const { return data_; }
typedef std::true_type propagate_on_container_copy_assignment; typedef std::true_type propagate_on_container_copy_assignment;
typedef std::true_type propagate_on_container_move_assignment; typedef std::true_type propagate_on_container_move_assignment;

View File

@ -1023,7 +1023,8 @@ feature_test_macros = [
"name": "__cpp_lib_syncbuf", "name": "__cpp_lib_syncbuf",
"values": {"c++20": 201803}, "values": {"c++20": 201803},
"headers": ["syncstream"], "headers": ["syncstream"],
"unimplemented": True, "test_suite_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)",
"libcxx_guard": "!defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)",
}, },
{ {
"name": "__cpp_lib_text_encoding", "name": "__cpp_lib_text_encoding",
@ -1180,6 +1181,7 @@ lit_markup = {
"semaphore": ["UNSUPPORTED: no-threads"], "semaphore": ["UNSUPPORTED: no-threads"],
"shared_mutex": ["UNSUPPORTED: no-threads"], "shared_mutex": ["UNSUPPORTED: no-threads"],
"sstream": ["UNSUPPORTED: no-localization"], "sstream": ["UNSUPPORTED: no-localization"],
"syncstream": ["UNSUPPORTED: no-localization"],
"stdatomic.h": ["UNSUPPORTED: no-threads"], "stdatomic.h": ["UNSUPPORTED: no-threads"],
"stop_token": ["UNSUPPORTED: no-threads"], "stop_token": ["UNSUPPORTED: no-threads"],
"thread": ["UNSUPPORTED: no-threads"], "thread": ["UNSUPPORTED: no-threads"],

View File

@ -30,6 +30,7 @@ header_restrictions = {
"sstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)", "sstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
"streambuf": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)", "streambuf": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
"strstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)", "strstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
"syncstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
# headers with #error directives # headers with #error directives
"barrier": "!defined(_LIBCPP_HAS_NO_THREADS)", "barrier": "!defined(_LIBCPP_HAS_NO_THREADS)",
@ -92,6 +93,7 @@ lit_header_restrictions = {
"stop_token": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17", "stop_token": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17",
"streambuf": "// UNSUPPORTED: no-localization", "streambuf": "// UNSUPPORTED: no-localization",
"strstream": "// UNSUPPORTED: no-localization", "strstream": "// UNSUPPORTED: no-localization",
"syncstream": "// UNSUPPORTED: no-localization",
"thread": "// UNSUPPORTED: no-threads, c++03", "thread": "// UNSUPPORTED: no-threads, c++03",
"wchar.h": "// UNSUPPORTED: no-wide-characters", "wchar.h": "// UNSUPPORTED: no-wide-characters",
"wctype.h": "// UNSUPPORTED: no-wide-characters", "wctype.h": "// UNSUPPORTED: no-wide-characters",
@ -127,7 +129,7 @@ mandatory_inclusions = {
"stack": ["compare", "initializer_list"], "stack": ["compare", "initializer_list"],
"string_view": ["compare"], "string_view": ["compare"],
"string": ["compare", "initializer_list"], "string": ["compare", "initializer_list"],
# TODO "syncstream": ["ostream"], "syncstream": ["ostream"],
"system_error": ["compare"], "system_error": ["compare"],
"tgmath.h": ["cmath", "complex"], "tgmath.h": ["cmath", "complex"],
"thread": ["compare"], "thread": ["compare"],
@ -156,7 +158,6 @@ headers_not_available = [
"spanstream", "spanstream",
"stacktrace", "stacktrace",
"stdfloat", "stdfloat",
"syncstream",
"text_encoding", "text_encoding",
] ]

View File

@ -267,6 +267,7 @@ DEFAULT_PARAMETERS = [
AddFeature("libcpp-has-no-incomplete-pstl"), AddFeature("libcpp-has-no-incomplete-pstl"),
AddFeature("libcpp-has-no-experimental-stop_token"), AddFeature("libcpp-has-no-experimental-stop_token"),
AddFeature("libcpp-has-no-incomplete-tzdb"), AddFeature("libcpp-has-no-incomplete-tzdb"),
AddFeature("libcpp-has-no-experimental-syncstream"),
], ],
), ),
Parameter( Parameter(