15f757f3fSDimitry Andric// -*- C++ -*- 25f757f3fSDimitry Andric//===----------------------------------------------------------------------===// 35f757f3fSDimitry Andric// 45f757f3fSDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 55f757f3fSDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 65f757f3fSDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 75f757f3fSDimitry Andric// 85f757f3fSDimitry Andric//===----------------------------------------------------------------------===// 95f757f3fSDimitry Andric 105f757f3fSDimitry Andric#ifndef _LIBCPP_SYNCSTREAM 115f757f3fSDimitry Andric#define _LIBCPP_SYNCSTREAM 125f757f3fSDimitry Andric 135f757f3fSDimitry Andric/* 145f757f3fSDimitry Andric syncstream synopsis 155f757f3fSDimitry Andric 165f757f3fSDimitry Andric#include <ostream> // see [ostream.syn] 175f757f3fSDimitry Andric 185f757f3fSDimitry Andricnamespace std { 195f757f3fSDimitry Andric template<class charT, class traits, class Allocator> 205f757f3fSDimitry Andric class basic_syncbuf; 215f757f3fSDimitry Andric 225f757f3fSDimitry Andric // [syncstream.syncbuf.special], specialized algorithms 235f757f3fSDimitry Andric template<class charT, class traits, class Allocator> 245f757f3fSDimitry Andric void swap(basic_syncbuf<charT, traits, Allocator>&, 255f757f3fSDimitry Andric basic_syncbuf<charT, traits, Allocator>&); 265f757f3fSDimitry Andric 275f757f3fSDimitry Andric using syncbuf = basic_syncbuf<char>; 285f757f3fSDimitry Andric using wsyncbuf = basic_syncbuf<wchar_t>; 295f757f3fSDimitry Andric 305f757f3fSDimitry Andric template<class charT, class traits, class Allocator> 315f757f3fSDimitry Andric class basic_osyncstream; 325f757f3fSDimitry Andric 335f757f3fSDimitry Andric using osyncstream = basic_osyncstream<char>; 345f757f3fSDimitry Andric using wosyncstream = basic_osyncstream<wchar_t>; 355f757f3fSDimitry Andric 365f757f3fSDimitry Andric template<class charT, class traits, class Allocator> 375f757f3fSDimitry Andric class basic_syncbuf : public basic_streambuf<charT, traits> { 385f757f3fSDimitry Andric public: 395f757f3fSDimitry Andric using char_type = charT; 405f757f3fSDimitry Andric using int_type = typename traits::int_type; 415f757f3fSDimitry Andric using pos_type = typename traits::pos_type; 425f757f3fSDimitry Andric using off_type = typename traits::off_type; 435f757f3fSDimitry Andric using traits_type = traits; 445f757f3fSDimitry Andric using allocator_type = Allocator; 455f757f3fSDimitry Andric 465f757f3fSDimitry Andric using streambuf_type = basic_streambuf<charT, traits>; 475f757f3fSDimitry Andric 485f757f3fSDimitry Andric // [syncstream.syncbuf.cons], construction and destruction 495f757f3fSDimitry Andric explicit basic_syncbuf(streambuf_type* obuf = nullptr) 505f757f3fSDimitry Andric : basic_syncbuf(obuf, Allocator()) {} 515f757f3fSDimitry Andric basic_syncbuf(streambuf_type*, const Allocator&); 525f757f3fSDimitry Andric basic_syncbuf(basic_syncbuf&&); 535f757f3fSDimitry Andric ~basic_syncbuf(); 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric // [syncstream.syncbuf.assign], assignment and swap 565f757f3fSDimitry Andric basic_syncbuf& operator=(basic_syncbuf&&); 575f757f3fSDimitry Andric void swap(basic_syncbuf&); 585f757f3fSDimitry Andric 595f757f3fSDimitry Andric // [syncstream.syncbuf.members], member functions 605f757f3fSDimitry Andric bool emit(); 615f757f3fSDimitry Andric streambuf_type* get_wrapped() const noexcept; 625f757f3fSDimitry Andric allocator_type get_allocator() const noexcept; 635f757f3fSDimitry Andric void set_emit_on_sync(bool) noexcept; 645f757f3fSDimitry Andric 655f757f3fSDimitry Andric protected: 665f757f3fSDimitry Andric // [syncstream.syncbuf.virtuals], overridden virtual functions 675f757f3fSDimitry Andric int sync() override; 685f757f3fSDimitry Andric 695f757f3fSDimitry Andric private: 705f757f3fSDimitry Andric streambuf_type* wrapped; // exposition only 715f757f3fSDimitry Andric bool emit_on_sync{}; // exposition only 725f757f3fSDimitry Andric }; 735f757f3fSDimitry Andric 745f757f3fSDimitry Andric // [syncstream.syncbuf.special], specialized algorithms 755f757f3fSDimitry Andric template<class charT, class traits, class Allocator> 765f757f3fSDimitry Andric void swap(basic_syncbuf<charT, traits, Allocator>&, 775f757f3fSDimitry Andric basic_syncbuf<charT, traits, Allocator>&); 785f757f3fSDimitry Andric 795f757f3fSDimitry Andric template<class charT, class traits, class Allocator> 805f757f3fSDimitry Andric class basic_osyncstream : public basic_ostream<charT, traits> { 815f757f3fSDimitry Andric public: 825f757f3fSDimitry Andric using char_type = charT; 835f757f3fSDimitry Andric using int_type = typename traits::int_type; 845f757f3fSDimitry Andric using pos_type = typename traits::pos_type; 855f757f3fSDimitry Andric using off_type = typename traits::off_type; 865f757f3fSDimitry Andric using traits_type = traits; 875f757f3fSDimitry Andric 885f757f3fSDimitry Andric using allocator_type = Allocator; 895f757f3fSDimitry Andric using streambuf_type = basic_streambuf<charT, traits>; 905f757f3fSDimitry Andric using syncbuf_type = basic_syncbuf<charT, traits, Allocator>; 915f757f3fSDimitry Andric 925f757f3fSDimitry Andric // [syncstream.osyncstream.cons], construction and destruction 935f757f3fSDimitry Andric basic_osyncstream(streambuf_type*, const Allocator&); 945f757f3fSDimitry Andric explicit basic_osyncstream(streambuf_type* obuf) 955f757f3fSDimitry Andric : basic_osyncstream(obuf, Allocator()) {} 965f757f3fSDimitry Andric basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator) 975f757f3fSDimitry Andric : basic_osyncstream(os.rdbuf(), allocator) {} 985f757f3fSDimitry Andric explicit basic_osyncstream(basic_ostream<charT, traits>& os) 995f757f3fSDimitry Andric : basic_osyncstream(os, Allocator()) {} 1005f757f3fSDimitry Andric basic_osyncstream(basic_osyncstream&&) noexcept; 1015f757f3fSDimitry Andric ~basic_osyncstream(); 1025f757f3fSDimitry Andric 1035f757f3fSDimitry Andric // [syncstream.osyncstream.assign], assignment 1045f757f3fSDimitry Andric basic_osyncstream& operator=(basic_osyncstream&&); 1055f757f3fSDimitry Andric 1065f757f3fSDimitry Andric // [syncstream.osyncstream.members], member functions 1075f757f3fSDimitry Andric void emit(); 1085f757f3fSDimitry Andric streambuf_type* get_wrapped() const noexcept; 1095f757f3fSDimitry Andric syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); } 1105f757f3fSDimitry Andric 1115f757f3fSDimitry Andric private: 1125f757f3fSDimitry Andric syncbuf_type sb; // exposition only 1135f757f3fSDimitry Andric }; 1145f757f3fSDimitry Andric} 1155f757f3fSDimitry Andric 1165f757f3fSDimitry Andric*/ 1175f757f3fSDimitry Andric 1185f757f3fSDimitry Andric#include <__config> 1195f757f3fSDimitry Andric#include <__utility/move.h> 120*0fca6ea1SDimitry Andric#include <ios> 1215f757f3fSDimitry Andric#include <iosfwd> // required for declaration of default arguments 122*0fca6ea1SDimitry Andric#include <streambuf> 1235f757f3fSDimitry Andric#include <string> 1245f757f3fSDimitry Andric 1255f757f3fSDimitry Andric#ifndef _LIBCPP_HAS_NO_THREADS 1265f757f3fSDimitry Andric# include <map> 1275f757f3fSDimitry Andric# include <mutex> 1285f757f3fSDimitry Andric# include <shared_mutex> 1295f757f3fSDimitry Andric#endif 1305f757f3fSDimitry Andric 1315f757f3fSDimitry Andric// standard-mandated includes 1325f757f3fSDimitry Andric 1335f757f3fSDimitry Andric// [syncstream.syn] 1345f757f3fSDimitry Andric#include <ostream> 1355f757f3fSDimitry Andric 1365f757f3fSDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 1375f757f3fSDimitry Andric# pragma GCC system_header 1385f757f3fSDimitry Andric#endif 1395f757f3fSDimitry Andric 1405f757f3fSDimitry Andric_LIBCPP_PUSH_MACROS 1415f757f3fSDimitry Andric#include <__undef_macros> 1425f757f3fSDimitry Andric 1435f757f3fSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD 1445f757f3fSDimitry Andric 1455f757f3fSDimitry Andric#if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM) 1465f757f3fSDimitry Andric 1475f757f3fSDimitry Andric// [syncstream.syncbuf.overview]/1 1485f757f3fSDimitry Andric// Class template basic_syncbuf stores character data written to it, 1495f757f3fSDimitry Andric// known as the associated output, into internal buffers allocated 1505f757f3fSDimitry Andric// using the object's allocator. The associated output is transferred 1515f757f3fSDimitry Andric// to the wrapped stream buffer object *wrapped when emit() is called 1525f757f3fSDimitry Andric// or when the basic_syncbuf object is destroyed. Such transfers are 1535f757f3fSDimitry Andric// atomic with respect to transfers by other basic_syncbuf objects 1545f757f3fSDimitry Andric// with the same wrapped stream buffer object. 1555f757f3fSDimitry Andric// 1565f757f3fSDimitry Andric// This helper singleton is used to implement the required 1575f757f3fSDimitry Andric// synchronisation guarantees. 1585f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_THREADS 1595f757f3fSDimitry Andricclass __wrapped_streambuf_mutex { 1605f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default; 1615f757f3fSDimitry Andric 1625f757f3fSDimitry Andricpublic: 1635f757f3fSDimitry Andric __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&) = delete; 1645f757f3fSDimitry Andric __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete; 1655f757f3fSDimitry Andric 1665f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) { 1675f757f3fSDimitry Andric _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to"); 1685f757f3fSDimitry Andric unique_lock __lock{__mutex_}; 1695f757f3fSDimitry Andric ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count; 1705f757f3fSDimitry Andric } 1715f757f3fSDimitry Andric 1725f757f3fSDimitry Andric // pre: __ptr is in __lut_ 1735f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept { 1745f757f3fSDimitry Andric unique_lock __lock{__mutex_}; 1755f757f3fSDimitry Andric 1765f757f3fSDimitry Andric auto __it = __get_it(__ptr); 1775f757f3fSDimitry Andric if (__it->second.__count == 1) 1785f757f3fSDimitry Andric __lut_.erase(__it); 1795f757f3fSDimitry Andric else 1805f757f3fSDimitry Andric --__it->second.__count; 1815f757f3fSDimitry Andric } 1825f757f3fSDimitry Andric 1835f757f3fSDimitry Andric // TODO 1845f757f3fSDimitry Andric // This function causes emit() aquire two mutexes: 1855f757f3fSDimitry Andric // - __mutex_ shared 1865f757f3fSDimitry Andric // _ __get_it(__ptr)->second.__mutex exclusive 1875f757f3fSDimitry Andric // 1885f757f3fSDimitry Andric // Instead store a pointer to __get_it(__ptr)->second.__mutex when 1895f757f3fSDimitry Andric // calling __inc_reference. 1905f757f3fSDimitry Andric // 1915f757f3fSDimitry Andric // pre: __ptr is in __lut_ 1925f757f3fSDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept { 1935f757f3fSDimitry Andric shared_lock __lock{__mutex_}; 1945f757f3fSDimitry Andric return lock_guard{__get_it(__ptr)->second.__mutex}; 1955f757f3fSDimitry Andric } 1965f757f3fSDimitry Andric 1975f757f3fSDimitry Andric // This function is used for testing. 1985f757f3fSDimitry Andric // 1995f757f3fSDimitry Andric // It is allowed to call this function with a non-registered pointer. 2005f757f3fSDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept { 2015f757f3fSDimitry Andric _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to"); 2025f757f3fSDimitry Andric shared_lock __lock{__mutex_}; 2035f757f3fSDimitry Andric 2045f757f3fSDimitry Andric auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr)); 2055f757f3fSDimitry Andric return __it != __lut_.end() ? __it->second.__count : 0; 2065f757f3fSDimitry Andric } 2075f757f3fSDimitry Andric 2085f757f3fSDimitry Andric [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept { 2095f757f3fSDimitry Andric static __wrapped_streambuf_mutex __result; 2105f757f3fSDimitry Andric return __result; 2115f757f3fSDimitry Andric } 2125f757f3fSDimitry Andric 2135f757f3fSDimitry Andricprivate: 2145f757f3fSDimitry Andric struct __value { 2155f757f3fSDimitry Andric mutex __mutex; 2165f757f3fSDimitry Andric size_t __count{0}; 2175f757f3fSDimitry Andric }; 2185f757f3fSDimitry Andric 2195f757f3fSDimitry Andric shared_mutex __mutex_; 2205f757f3fSDimitry Andric map<uintptr_t, __value> __lut_; 2215f757f3fSDimitry Andric 2225f757f3fSDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept { 2235f757f3fSDimitry Andric _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to"); 2245f757f3fSDimitry Andric 2255f757f3fSDimitry Andric auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr)); 2265f757f3fSDimitry Andric _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered"); 2275f757f3fSDimitry Andric _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper"); 2285f757f3fSDimitry Andric return __it; 2295f757f3fSDimitry Andric } 2305f757f3fSDimitry Andric}; 2315f757f3fSDimitry Andric# endif // _LIBCPP_HAS_NO_THREADS 2325f757f3fSDimitry Andric 2335f757f3fSDimitry Andric// basic_syncbuf 2345f757f3fSDimitry Andric 2355f757f3fSDimitry Andric// The class uses a basic_string<_CharT, _Traits, _Allocator> as 2365f757f3fSDimitry Andric// internal buffer. Per [syncstream.syncbuf.cons]/4 2375f757f3fSDimitry Andric// Remarks: A copy of allocator is used to allocate memory for 2385f757f3fSDimitry Andric// internal buffers holding the associated output. 2395f757f3fSDimitry Andric// 2405f757f3fSDimitry Andric// Therefore the allocator used in the constructor is passed to the 2415f757f3fSDimitry Andric// basic_string. The class does not keep a copy of this allocator. 2425f757f3fSDimitry Andrictemplate <class _CharT, class _Traits, class _Allocator> 2435f757f3fSDimitry Andricclass _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> { 2445f757f3fSDimitry Andricpublic: 2455f757f3fSDimitry Andric using char_type = _CharT; 2465f757f3fSDimitry Andric using traits_type = _Traits; 2475f757f3fSDimitry Andric using int_type = typename traits_type::int_type; 2485f757f3fSDimitry Andric using pos_type = typename traits_type::pos_type; 2495f757f3fSDimitry Andric using off_type = typename traits_type::off_type; 2505f757f3fSDimitry Andric using allocator_type = _Allocator; 2515f757f3fSDimitry Andric 2525f757f3fSDimitry Andric using streambuf_type = basic_streambuf<_CharT, _Traits>; 2535f757f3fSDimitry Andric 2545f757f3fSDimitry Andric // [syncstream.syncbuf.cons], construction and destruction 2555f757f3fSDimitry Andric 2565f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf = nullptr) 2575f757f3fSDimitry Andric : basic_syncbuf(__obuf, _Allocator()) {} 2585f757f3fSDimitry Andric 2595f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc) 2605f757f3fSDimitry Andric : __wrapped_(__obuf), __str_(__alloc) { 2615f757f3fSDimitry Andric __inc_reference(); 2625f757f3fSDimitry Andric } 2635f757f3fSDimitry Andric 2645f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other) 2655f757f3fSDimitry Andric : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) { 2665f757f3fSDimitry Andric __move_common(__other); 2675f757f3fSDimitry Andric } 2685f757f3fSDimitry Andric 2695f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() { 2705f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 2715f757f3fSDimitry Andric try { 2725f757f3fSDimitry Andric# endif // _LIBCPP_HAS_NO_EXCEPTIONS 2735f757f3fSDimitry Andric emit(); 2745f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 2755f757f3fSDimitry Andric } catch (...) { 2765f757f3fSDimitry Andric } 2775f757f3fSDimitry Andric# endif // _LIBCPP_HAS_NO_EXCEPTIONS 2785f757f3fSDimitry Andric __dec_reference(); 2795f757f3fSDimitry Andric } 2805f757f3fSDimitry Andric 2815f757f3fSDimitry Andric // [syncstream.syncbuf.assign], assignment and swap 2825f757f3fSDimitry Andric 2835f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) { 2845f757f3fSDimitry Andric // The function is specified to call emit. This call should 2855f757f3fSDimitry Andric // propagate the exception thrown. 2865f757f3fSDimitry Andric emit(); 2875f757f3fSDimitry Andric __dec_reference(); 2885f757f3fSDimitry Andric 2895f757f3fSDimitry Andric __wrapped_ = __other.get_wrapped(); 2905f757f3fSDimitry Andric __str_ = std::move(__other.__str_); 2915f757f3fSDimitry Andric __emit_on_sync_ = __other.__emit_on_sync_; 2925f757f3fSDimitry Andric 2935f757f3fSDimitry Andric __move_common(__other); 2945f757f3fSDimitry Andric 2955f757f3fSDimitry Andric return *this; 2965f757f3fSDimitry Andric } 2975f757f3fSDimitry Andric 2985f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) { 2995f757f3fSDimitry Andric _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( 3005f757f3fSDimitry Andric allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(), 3015f757f3fSDimitry Andric "violates the mandated swap precondition"); 3025f757f3fSDimitry Andric 3035f757f3fSDimitry Andric basic_syncbuf __tmp(std::move(__other)); 3045f757f3fSDimitry Andric __other = std::move(*this); 3055f757f3fSDimitry Andric *this = std::move(__tmp); 3065f757f3fSDimitry Andric } 3075f757f3fSDimitry Andric 3085f757f3fSDimitry Andric // [syncstream.syncbuf.members], member functions 3095f757f3fSDimitry Andric 3105f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); } 3115f757f3fSDimitry Andric 3125f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; } 3135f757f3fSDimitry Andric 3145f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); } 3155f757f3fSDimitry Andric 3165f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; } 3175f757f3fSDimitry Andric 3185f757f3fSDimitry Andricprotected: 3195f757f3fSDimitry Andric // [syncstream.syncbuf.virtuals], overridden virtual functions 3205f757f3fSDimitry Andric 3215f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI_VIRTUAL 3225f757f3fSDimitry Andric int sync() override { 3235f757f3fSDimitry Andric if (__emit_on_sync_ && !emit(true)) 3245f757f3fSDimitry Andric return -1; 3255f757f3fSDimitry Andric return 0; 3265f757f3fSDimitry Andric } 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI_VIRTUAL 3295f757f3fSDimitry Andric int_type overflow(int_type __c = traits_type::eof()) override { 3305f757f3fSDimitry Andric if (traits_type::eq_int_type(__c, traits_type::eof())) 3315f757f3fSDimitry Andric return traits_type::not_eof(__c); 3325f757f3fSDimitry Andric 3335f757f3fSDimitry Andric if (this->pptr() == this->epptr()) { 3345f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 3355f757f3fSDimitry Andric try { 3365f757f3fSDimitry Andric# endif 3375f757f3fSDimitry Andric size_t __size = __str_.size(); 3385f757f3fSDimitry Andric __str_.resize(__str_.capacity() + 1); 3395f757f3fSDimitry Andric _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown"); 3405f757f3fSDimitry Andric 3415f757f3fSDimitry Andric char_type* __p = static_cast<char_type*>(__str_.data()); 3425f757f3fSDimitry Andric this->setp(__p, __p + __str_.size()); 3435f757f3fSDimitry Andric this->pbump(__size); 3445f757f3fSDimitry Andric 3455f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 3465f757f3fSDimitry Andric } catch (...) { 3475f757f3fSDimitry Andric return traits_type::eof(); 3485f757f3fSDimitry Andric } 3495f757f3fSDimitry Andric# endif 3505f757f3fSDimitry Andric } 3515f757f3fSDimitry Andric 3525f757f3fSDimitry Andric return this->sputc(traits_type::to_char_type(__c)); 3535f757f3fSDimitry Andric } 3545f757f3fSDimitry Andric 3555f757f3fSDimitry Andricprivate: 3565f757f3fSDimitry Andric streambuf_type* __wrapped_; 3575f757f3fSDimitry Andric 3585f757f3fSDimitry Andric // TODO Use a more generic buffer. 3595f757f3fSDimitry Andric // That buffer should be light with almost no additional headers. Then 3605f757f3fSDimitry Andric // it can be use here, the __retarget_buffer, and place that use 3615f757f3fSDimitry Andric // the now deprecated get_temporary_buffer 3625f757f3fSDimitry Andric 3635f757f3fSDimitry Andric basic_string<_CharT, _Traits, _Allocator> __str_; 3645f757f3fSDimitry Andric bool __emit_on_sync_{false}; 3655f757f3fSDimitry Andric 3665f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) { 3675f757f3fSDimitry Andric if (!__wrapped_) 3685f757f3fSDimitry Andric return false; 3695f757f3fSDimitry Andric 3705f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_THREADS 3715f757f3fSDimitry Andric lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_); 3725f757f3fSDimitry Andric# endif 3735f757f3fSDimitry Andric 3745f757f3fSDimitry Andric bool __result = true; 3755f757f3fSDimitry Andric if (this->pptr() != this->pbase()) { 3765f757f3fSDimitry Andric _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid"); 3775f757f3fSDimitry Andric 3785f757f3fSDimitry Andric // The __str_ does not know how much of its buffer is used. This 3795f757f3fSDimitry Andric // information is extracted from the information of the base class. 3805f757f3fSDimitry Andric __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1); 3815f757f3fSDimitry Andric // Clears the buffer, but keeps the contents (and) size of the 3825f757f3fSDimitry Andric // internal buffer. 3835f757f3fSDimitry Andric this->setp(this->pbase(), this->epptr()); 3845f757f3fSDimitry Andric } 3855f757f3fSDimitry Andric 3865f757f3fSDimitry Andric if (__flush) 3875f757f3fSDimitry Andric __result &= (__wrapped_->pubsync() != -1); 3885f757f3fSDimitry Andric 3895f757f3fSDimitry Andric return __result; 3905f757f3fSDimitry Andric } 3915f757f3fSDimitry Andric 3925f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) { 3935f757f3fSDimitry Andric // Adjust the put area pointers to our buffer. 3945f757f3fSDimitry Andric char_type* __p = static_cast<char_type*>(__str_.data()); 3955f757f3fSDimitry Andric this->setp(__p, __p + __str_.size()); 3965f757f3fSDimitry Andric this->pbump(__other.pptr() - __other.pbase()); 3975f757f3fSDimitry Andric 3985f757f3fSDimitry Andric // Clear __other_ so the destructor will act as a NOP. 3995f757f3fSDimitry Andric __other.setp(nullptr, nullptr); 4005f757f3fSDimitry Andric __other.__wrapped_ = nullptr; 4015f757f3fSDimitry Andric } 4025f757f3fSDimitry Andric 4035f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __inc_reference() { 4045f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_THREADS 4055f757f3fSDimitry Andric if (__wrapped_) 4065f757f3fSDimitry Andric __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_); 4075f757f3fSDimitry Andric# endif 4085f757f3fSDimitry Andric } 4095f757f3fSDimitry Andric 4105f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept { 4115f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_THREADS 4125f757f3fSDimitry Andric if (__wrapped_) 4135f757f3fSDimitry Andric __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_); 4145f757f3fSDimitry Andric# endif 4155f757f3fSDimitry Andric } 4165f757f3fSDimitry Andric}; 4175f757f3fSDimitry Andric 4185f757f3fSDimitry Andricusing std::syncbuf; 4195f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 4205f757f3fSDimitry Andricusing std::wsyncbuf; 4215f757f3fSDimitry Andric# endif 4225f757f3fSDimitry Andric 4235f757f3fSDimitry Andric// [syncstream.syncbuf.special], specialized algorithms 4245f757f3fSDimitry Andrictemplate <class _CharT, class _Traits, class _Allocator> 4255f757f3fSDimitry Andric_LIBCPP_HIDE_FROM_ABI void 4265f757f3fSDimitry Andricswap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) { 4275f757f3fSDimitry Andric __lhs.swap(__rhs); 4285f757f3fSDimitry Andric} 4295f757f3fSDimitry Andric 4305f757f3fSDimitry Andric// basic_osyncstream 4315f757f3fSDimitry Andric 4325f757f3fSDimitry Andrictemplate <class _CharT, class _Traits, class _Allocator> 4335f757f3fSDimitry Andricclass _LIBCPP_TEMPLATE_VIS basic_osyncstream : public basic_ostream<_CharT, _Traits> { 4345f757f3fSDimitry Andricpublic: 4355f757f3fSDimitry Andric using char_type = _CharT; 4365f757f3fSDimitry Andric using traits_type = _Traits; 4375f757f3fSDimitry Andric using int_type = typename traits_type::int_type; 4385f757f3fSDimitry Andric using pos_type = typename traits_type::pos_type; 4395f757f3fSDimitry Andric using off_type = typename traits_type::off_type; 4405f757f3fSDimitry Andric 4415f757f3fSDimitry Andric using allocator_type = _Allocator; 4425f757f3fSDimitry Andric using streambuf_type = basic_streambuf<char_type, traits_type>; 4435f757f3fSDimitry Andric using syncbuf_type = basic_syncbuf<char_type, traits_type, allocator_type>; 4445f757f3fSDimitry Andric 4455f757f3fSDimitry Andric // [syncstream.osyncstream.cons], construction and destruction 4465f757f3fSDimitry Andric 4475f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc) 4485f757f3fSDimitry Andric : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {} 4495f757f3fSDimitry Andric 4505f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf) 4515f757f3fSDimitry Andric : basic_osyncstream(__obuf, allocator_type()) {} 4525f757f3fSDimitry Andric 4535f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc) 4545f757f3fSDimitry Andric : basic_osyncstream(__os.rdbuf(), __alloc) {} 4555f757f3fSDimitry Andric 4565f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os) 4575f757f3fSDimitry Andric : basic_osyncstream(__os, allocator_type()) {} 4585f757f3fSDimitry Andric 4595f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept 4605f757f3fSDimitry Andric : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) { 4615f757f3fSDimitry Andric this->set_rdbuf(std::addressof(__sb_)); 4625f757f3fSDimitry Andric } 4635f757f3fSDimitry Andric 4645f757f3fSDimitry Andric // [syncstream.osyncstream.assign], assignment 4655f757f3fSDimitry Andric 4665f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default; 4675f757f3fSDimitry Andric 4685f757f3fSDimitry Andric // [syncstream.osyncstream.members], member functions 4695f757f3fSDimitry Andric 4705f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void emit() { 4715f757f3fSDimitry Andric // The basic_ostream::put places the sentry in a try 4725f757f3fSDimitry Andric // catch, this does not match the wording of the standard 4735f757f3fSDimitry Andric // [ostream.unformatted] 4745f757f3fSDimitry Andric // TODO validate other unformatted output functions. 4755f757f3fSDimitry Andric typename basic_ostream<char_type, traits_type>::sentry __s(*this); 4765f757f3fSDimitry Andric if (__s) { 4775f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 4785f757f3fSDimitry Andric try { 4795f757f3fSDimitry Andric# endif 4805f757f3fSDimitry Andric 4815f757f3fSDimitry Andric if (__sb_.emit() == false) 4825f757f3fSDimitry Andric this->setstate(ios::badbit); 4835f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 4845f757f3fSDimitry Andric } catch (...) { 4855f757f3fSDimitry Andric this->__set_badbit_and_consider_rethrow(); 4865f757f3fSDimitry Andric } 4875f757f3fSDimitry Andric# endif 4885f757f3fSDimitry Andric } 4895f757f3fSDimitry Andric } 4905f757f3fSDimitry Andric 4915f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); } 4925f757f3fSDimitry Andric 4935f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept { 4945f757f3fSDimitry Andric return const_cast<syncbuf_type*>(std::addressof(__sb_)); 4955f757f3fSDimitry Andric } 4965f757f3fSDimitry Andric 4975f757f3fSDimitry Andricprivate: 4985f757f3fSDimitry Andric syncbuf_type __sb_; 4995f757f3fSDimitry Andric}; 5005f757f3fSDimitry Andric 5015f757f3fSDimitry Andricusing std::osyncstream; 5025f757f3fSDimitry Andric# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 5035f757f3fSDimitry Andricusing std::wosyncstream; 5045f757f3fSDimitry Andric# endif 5055f757f3fSDimitry Andric 5065f757f3fSDimitry Andric#endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM) 5075f757f3fSDimitry Andric 5085f757f3fSDimitry Andric_LIBCPP_END_NAMESPACE_STD 5095f757f3fSDimitry Andric 5105f757f3fSDimitry Andric_LIBCPP_POP_MACROS 5115f757f3fSDimitry Andric 5125f757f3fSDimitry Andric#endif // _LIBCPP_SYNCSTREAM 513