1*c9157d92SDimitry Andric// -*- C++ -*- 2*c9157d92SDimitry Andric//===----------------------------------------------------------------------===// 3*c9157d92SDimitry Andric// 4*c9157d92SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5*c9157d92SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 6*c9157d92SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7*c9157d92SDimitry Andric// 8*c9157d92SDimitry Andric//===----------------------------------------------------------------------===// 9*c9157d92SDimitry Andric 10*c9157d92SDimitry Andric#ifndef _LIBCPP_SYNCSTREAM 11*c9157d92SDimitry Andric#define _LIBCPP_SYNCSTREAM 12*c9157d92SDimitry Andric 13*c9157d92SDimitry Andric/* 14*c9157d92SDimitry Andric syncstream synopsis 15*c9157d92SDimitry Andric 16*c9157d92SDimitry Andric#include <ostream> // see [ostream.syn] 17*c9157d92SDimitry Andric 18*c9157d92SDimitry Andricnamespace std { 19*c9157d92SDimitry Andric template<class charT, class traits, class Allocator> 20*c9157d92SDimitry Andric class basic_syncbuf; 21*c9157d92SDimitry Andric 22*c9157d92SDimitry Andric // [syncstream.syncbuf.special], specialized algorithms 23*c9157d92SDimitry Andric template<class charT, class traits, class Allocator> 24*c9157d92SDimitry Andric void swap(basic_syncbuf<charT, traits, Allocator>&, 25*c9157d92SDimitry Andric basic_syncbuf<charT, traits, Allocator>&); 26*c9157d92SDimitry Andric 27*c9157d92SDimitry Andric using syncbuf = basic_syncbuf<char>; 28*c9157d92SDimitry Andric using wsyncbuf = basic_syncbuf<wchar_t>; 29*c9157d92SDimitry Andric 30*c9157d92SDimitry Andric template<class charT, class traits, class Allocator> 31*c9157d92SDimitry Andric class basic_osyncstream; 32*c9157d92SDimitry Andric 33*c9157d92SDimitry Andric using osyncstream = basic_osyncstream<char>; 34*c9157d92SDimitry Andric using wosyncstream = basic_osyncstream<wchar_t>; 35*c9157d92SDimitry Andric 36*c9157d92SDimitry Andric template<class charT, class traits, class Allocator> 37*c9157d92SDimitry Andric class basic_syncbuf : public basic_streambuf<charT, traits> { 38*c9157d92SDimitry Andric public: 39*c9157d92SDimitry Andric using char_type = charT; 40*c9157d92SDimitry Andric using int_type = typename traits::int_type; 41*c9157d92SDimitry Andric using pos_type = typename traits::pos_type; 42*c9157d92SDimitry Andric using off_type = typename traits::off_type; 43*c9157d92SDimitry Andric using traits_type = traits; 44*c9157d92SDimitry Andric using allocator_type = Allocator; 45*c9157d92SDimitry Andric 46*c9157d92SDimitry Andric using streambuf_type = basic_streambuf<charT, traits>; 47*c9157d92SDimitry Andric 48*c9157d92SDimitry Andric // [syncstream.syncbuf.cons], construction and destruction 49*c9157d92SDimitry Andric explicit basic_syncbuf(streambuf_type* obuf = nullptr) 50*c9157d92SDimitry Andric : basic_syncbuf(obuf, Allocator()) {} 51*c9157d92SDimitry Andric basic_syncbuf(streambuf_type*, const Allocator&); 52*c9157d92SDimitry Andric basic_syncbuf(basic_syncbuf&&); 53*c9157d92SDimitry Andric ~basic_syncbuf(); 54*c9157d92SDimitry Andric 55*c9157d92SDimitry Andric // [syncstream.syncbuf.assign], assignment and swap 56*c9157d92SDimitry Andric basic_syncbuf& operator=(basic_syncbuf&&); 57*c9157d92SDimitry Andric void swap(basic_syncbuf&); 58*c9157d92SDimitry Andric 59*c9157d92SDimitry Andric // [syncstream.syncbuf.members], member functions 60*c9157d92SDimitry Andric bool emit(); 61*c9157d92SDimitry Andric streambuf_type* get_wrapped() const noexcept; 62*c9157d92SDimitry Andric allocator_type get_allocator() const noexcept; 63*c9157d92SDimitry Andric void set_emit_on_sync(bool) noexcept; 64*c9157d92SDimitry Andric 65*c9157d92SDimitry Andric protected: 66*c9157d92SDimitry Andric // [syncstream.syncbuf.virtuals], overridden virtual functions 67*c9157d92SDimitry Andric int sync() override; 68*c9157d92SDimitry Andric 69*c9157d92SDimitry Andric private: 70*c9157d92SDimitry Andric streambuf_type* wrapped; // exposition only 71*c9157d92SDimitry Andric bool emit_on_sync{}; // exposition only 72*c9157d92SDimitry Andric }; 73*c9157d92SDimitry Andric 74*c9157d92SDimitry Andric // [syncstream.syncbuf.special], specialized algorithms 75*c9157d92SDimitry Andric template<class charT, class traits, class Allocator> 76*c9157d92SDimitry Andric void swap(basic_syncbuf<charT, traits, Allocator>&, 77*c9157d92SDimitry Andric basic_syncbuf<charT, traits, Allocator>&); 78*c9157d92SDimitry Andric 79*c9157d92SDimitry Andric template<class charT, class traits, class Allocator> 80*c9157d92SDimitry Andric class basic_osyncstream : public basic_ostream<charT, traits> { 81*c9157d92SDimitry Andric public: 82*c9157d92SDimitry Andric using char_type = charT; 83*c9157d92SDimitry Andric using int_type = typename traits::int_type; 84*c9157d92SDimitry Andric using pos_type = typename traits::pos_type; 85*c9157d92SDimitry Andric using off_type = typename traits::off_type; 86*c9157d92SDimitry Andric using traits_type = traits; 87*c9157d92SDimitry Andric 88*c9157d92SDimitry Andric using allocator_type = Allocator; 89*c9157d92SDimitry Andric using streambuf_type = basic_streambuf<charT, traits>; 90*c9157d92SDimitry Andric using syncbuf_type = basic_syncbuf<charT, traits, Allocator>; 91*c9157d92SDimitry Andric 92*c9157d92SDimitry Andric // [syncstream.osyncstream.cons], construction and destruction 93*c9157d92SDimitry Andric basic_osyncstream(streambuf_type*, const Allocator&); 94*c9157d92SDimitry Andric explicit basic_osyncstream(streambuf_type* obuf) 95*c9157d92SDimitry Andric : basic_osyncstream(obuf, Allocator()) {} 96*c9157d92SDimitry Andric basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator) 97*c9157d92SDimitry Andric : basic_osyncstream(os.rdbuf(), allocator) {} 98*c9157d92SDimitry Andric explicit basic_osyncstream(basic_ostream<charT, traits>& os) 99*c9157d92SDimitry Andric : basic_osyncstream(os, Allocator()) {} 100*c9157d92SDimitry Andric basic_osyncstream(basic_osyncstream&&) noexcept; 101*c9157d92SDimitry Andric ~basic_osyncstream(); 102*c9157d92SDimitry Andric 103*c9157d92SDimitry Andric // [syncstream.osyncstream.assign], assignment 104*c9157d92SDimitry Andric basic_osyncstream& operator=(basic_osyncstream&&); 105*c9157d92SDimitry Andric 106*c9157d92SDimitry Andric // [syncstream.osyncstream.members], member functions 107*c9157d92SDimitry Andric void emit(); 108*c9157d92SDimitry Andric streambuf_type* get_wrapped() const noexcept; 109*c9157d92SDimitry Andric syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); } 110*c9157d92SDimitry Andric 111*c9157d92SDimitry Andric private: 112*c9157d92SDimitry Andric syncbuf_type sb; // exposition only 113*c9157d92SDimitry Andric }; 114*c9157d92SDimitry Andric} 115*c9157d92SDimitry Andric 116*c9157d92SDimitry Andric*/ 117*c9157d92SDimitry Andric 118*c9157d92SDimitry Andric#include <__config> 119*c9157d92SDimitry Andric#include <__utility/move.h> 120*c9157d92SDimitry Andric#include <iosfwd> // required for declaration of default arguments 121*c9157d92SDimitry Andric#include <string> 122*c9157d92SDimitry Andric 123*c9157d92SDimitry Andric#ifndef _LIBCPP_HAS_NO_THREADS 124*c9157d92SDimitry Andric# include <map> 125*c9157d92SDimitry Andric# include <mutex> 126*c9157d92SDimitry Andric# include <shared_mutex> 127*c9157d92SDimitry Andric#endif 128*c9157d92SDimitry Andric 129*c9157d92SDimitry Andric// standard-mandated includes 130*c9157d92SDimitry Andric 131*c9157d92SDimitry Andric// [syncstream.syn] 132*c9157d92SDimitry Andric#include <ostream> 133*c9157d92SDimitry Andric 134*c9157d92SDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 135*c9157d92SDimitry Andric# pragma GCC system_header 136*c9157d92SDimitry Andric#endif 137*c9157d92SDimitry Andric 138*c9157d92SDimitry Andric_LIBCPP_PUSH_MACROS 139*c9157d92SDimitry Andric#include <__undef_macros> 140*c9157d92SDimitry Andric 141*c9157d92SDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD 142*c9157d92SDimitry Andric 143*c9157d92SDimitry Andric#if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM) 144*c9157d92SDimitry Andric 145*c9157d92SDimitry Andric// [syncstream.syncbuf.overview]/1 146*c9157d92SDimitry Andric// Class template basic_syncbuf stores character data written to it, 147*c9157d92SDimitry Andric// known as the associated output, into internal buffers allocated 148*c9157d92SDimitry Andric// using the object's allocator. The associated output is transferred 149*c9157d92SDimitry Andric// to the wrapped stream buffer object *wrapped when emit() is called 150*c9157d92SDimitry Andric// or when the basic_syncbuf object is destroyed. Such transfers are 151*c9157d92SDimitry Andric// atomic with respect to transfers by other basic_syncbuf objects 152*c9157d92SDimitry Andric// with the same wrapped stream buffer object. 153*c9157d92SDimitry Andric// 154*c9157d92SDimitry Andric// This helper singleton is used to implement the required 155*c9157d92SDimitry Andric// synchronisation guarantees. 156*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_THREADS 157*c9157d92SDimitry Andricclass __wrapped_streambuf_mutex { 158*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default; 159*c9157d92SDimitry Andric 160*c9157d92SDimitry Andricpublic: 161*c9157d92SDimitry Andric __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&) = delete; 162*c9157d92SDimitry Andric __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete; 163*c9157d92SDimitry Andric 164*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) { 165*c9157d92SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to"); 166*c9157d92SDimitry Andric unique_lock __lock{__mutex_}; 167*c9157d92SDimitry Andric ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count; 168*c9157d92SDimitry Andric } 169*c9157d92SDimitry Andric 170*c9157d92SDimitry Andric // pre: __ptr is in __lut_ 171*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept { 172*c9157d92SDimitry Andric unique_lock __lock{__mutex_}; 173*c9157d92SDimitry Andric 174*c9157d92SDimitry Andric auto __it = __get_it(__ptr); 175*c9157d92SDimitry Andric if (__it->second.__count == 1) 176*c9157d92SDimitry Andric __lut_.erase(__it); 177*c9157d92SDimitry Andric else 178*c9157d92SDimitry Andric --__it->second.__count; 179*c9157d92SDimitry Andric } 180*c9157d92SDimitry Andric 181*c9157d92SDimitry Andric // TODO 182*c9157d92SDimitry Andric // This function causes emit() aquire two mutexes: 183*c9157d92SDimitry Andric // - __mutex_ shared 184*c9157d92SDimitry Andric // _ __get_it(__ptr)->second.__mutex exclusive 185*c9157d92SDimitry Andric // 186*c9157d92SDimitry Andric // Instead store a pointer to __get_it(__ptr)->second.__mutex when 187*c9157d92SDimitry Andric // calling __inc_reference. 188*c9157d92SDimitry Andric // 189*c9157d92SDimitry Andric // pre: __ptr is in __lut_ 190*c9157d92SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept { 191*c9157d92SDimitry Andric shared_lock __lock{__mutex_}; 192*c9157d92SDimitry Andric return lock_guard{__get_it(__ptr)->second.__mutex}; 193*c9157d92SDimitry Andric } 194*c9157d92SDimitry Andric 195*c9157d92SDimitry Andric // This function is used for testing. 196*c9157d92SDimitry Andric // 197*c9157d92SDimitry Andric // It is allowed to call this function with a non-registered pointer. 198*c9157d92SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept { 199*c9157d92SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to"); 200*c9157d92SDimitry Andric shared_lock __lock{__mutex_}; 201*c9157d92SDimitry Andric 202*c9157d92SDimitry Andric auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr)); 203*c9157d92SDimitry Andric return __it != __lut_.end() ? __it->second.__count : 0; 204*c9157d92SDimitry Andric } 205*c9157d92SDimitry Andric 206*c9157d92SDimitry Andric [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept { 207*c9157d92SDimitry Andric static __wrapped_streambuf_mutex __result; 208*c9157d92SDimitry Andric return __result; 209*c9157d92SDimitry Andric } 210*c9157d92SDimitry Andric 211*c9157d92SDimitry Andricprivate: 212*c9157d92SDimitry Andric struct __value { 213*c9157d92SDimitry Andric mutex __mutex; 214*c9157d92SDimitry Andric size_t __count{0}; 215*c9157d92SDimitry Andric }; 216*c9157d92SDimitry Andric 217*c9157d92SDimitry Andric shared_mutex __mutex_; 218*c9157d92SDimitry Andric map<uintptr_t, __value> __lut_; 219*c9157d92SDimitry Andric 220*c9157d92SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept { 221*c9157d92SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to"); 222*c9157d92SDimitry Andric 223*c9157d92SDimitry Andric auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr)); 224*c9157d92SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered"); 225*c9157d92SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper"); 226*c9157d92SDimitry Andric return __it; 227*c9157d92SDimitry Andric } 228*c9157d92SDimitry Andric}; 229*c9157d92SDimitry Andric# endif // _LIBCPP_HAS_NO_THREADS 230*c9157d92SDimitry Andric 231*c9157d92SDimitry Andric// basic_syncbuf 232*c9157d92SDimitry Andric 233*c9157d92SDimitry Andric// The class uses a basic_string<_CharT, _Traits, _Allocator> as 234*c9157d92SDimitry Andric// internal buffer. Per [syncstream.syncbuf.cons]/4 235*c9157d92SDimitry Andric// Remarks: A copy of allocator is used to allocate memory for 236*c9157d92SDimitry Andric// internal buffers holding the associated output. 237*c9157d92SDimitry Andric// 238*c9157d92SDimitry Andric// Therefore the allocator used in the constructor is passed to the 239*c9157d92SDimitry Andric// basic_string. The class does not keep a copy of this allocator. 240*c9157d92SDimitry Andrictemplate <class _CharT, class _Traits, class _Allocator> 241*c9157d92SDimitry Andricclass _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> { 242*c9157d92SDimitry Andricpublic: 243*c9157d92SDimitry Andric using char_type = _CharT; 244*c9157d92SDimitry Andric using traits_type = _Traits; 245*c9157d92SDimitry Andric using int_type = typename traits_type::int_type; 246*c9157d92SDimitry Andric using pos_type = typename traits_type::pos_type; 247*c9157d92SDimitry Andric using off_type = typename traits_type::off_type; 248*c9157d92SDimitry Andric using allocator_type = _Allocator; 249*c9157d92SDimitry Andric 250*c9157d92SDimitry Andric using streambuf_type = basic_streambuf<_CharT, _Traits>; 251*c9157d92SDimitry Andric 252*c9157d92SDimitry Andric // [syncstream.syncbuf.cons], construction and destruction 253*c9157d92SDimitry Andric 254*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf = nullptr) 255*c9157d92SDimitry Andric : basic_syncbuf(__obuf, _Allocator()) {} 256*c9157d92SDimitry Andric 257*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc) 258*c9157d92SDimitry Andric : __wrapped_(__obuf), __str_(__alloc) { 259*c9157d92SDimitry Andric __inc_reference(); 260*c9157d92SDimitry Andric } 261*c9157d92SDimitry Andric 262*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other) 263*c9157d92SDimitry Andric : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) { 264*c9157d92SDimitry Andric __move_common(__other); 265*c9157d92SDimitry Andric } 266*c9157d92SDimitry Andric 267*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() { 268*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 269*c9157d92SDimitry Andric try { 270*c9157d92SDimitry Andric# endif // _LIBCPP_HAS_NO_EXCEPTIONS 271*c9157d92SDimitry Andric emit(); 272*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 273*c9157d92SDimitry Andric } catch (...) { 274*c9157d92SDimitry Andric } 275*c9157d92SDimitry Andric# endif // _LIBCPP_HAS_NO_EXCEPTIONS 276*c9157d92SDimitry Andric __dec_reference(); 277*c9157d92SDimitry Andric } 278*c9157d92SDimitry Andric 279*c9157d92SDimitry Andric // [syncstream.syncbuf.assign], assignment and swap 280*c9157d92SDimitry Andric 281*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) { 282*c9157d92SDimitry Andric // The function is specified to call emit. This call should 283*c9157d92SDimitry Andric // propagate the exception thrown. 284*c9157d92SDimitry Andric emit(); 285*c9157d92SDimitry Andric __dec_reference(); 286*c9157d92SDimitry Andric 287*c9157d92SDimitry Andric __wrapped_ = __other.get_wrapped(); 288*c9157d92SDimitry Andric __str_ = std::move(__other.__str_); 289*c9157d92SDimitry Andric __emit_on_sync_ = __other.__emit_on_sync_; 290*c9157d92SDimitry Andric 291*c9157d92SDimitry Andric __move_common(__other); 292*c9157d92SDimitry Andric 293*c9157d92SDimitry Andric return *this; 294*c9157d92SDimitry Andric } 295*c9157d92SDimitry Andric 296*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) { 297*c9157d92SDimitry Andric _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( 298*c9157d92SDimitry Andric allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(), 299*c9157d92SDimitry Andric "violates the mandated swap precondition"); 300*c9157d92SDimitry Andric 301*c9157d92SDimitry Andric basic_syncbuf __tmp(std::move(__other)); 302*c9157d92SDimitry Andric __other = std::move(*this); 303*c9157d92SDimitry Andric *this = std::move(__tmp); 304*c9157d92SDimitry Andric } 305*c9157d92SDimitry Andric 306*c9157d92SDimitry Andric // [syncstream.syncbuf.members], member functions 307*c9157d92SDimitry Andric 308*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); } 309*c9157d92SDimitry Andric 310*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; } 311*c9157d92SDimitry Andric 312*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); } 313*c9157d92SDimitry Andric 314*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; } 315*c9157d92SDimitry Andric 316*c9157d92SDimitry Andricprotected: 317*c9157d92SDimitry Andric // [syncstream.syncbuf.virtuals], overridden virtual functions 318*c9157d92SDimitry Andric 319*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI_VIRTUAL 320*c9157d92SDimitry Andric int sync() override { 321*c9157d92SDimitry Andric if (__emit_on_sync_ && !emit(true)) 322*c9157d92SDimitry Andric return -1; 323*c9157d92SDimitry Andric return 0; 324*c9157d92SDimitry Andric } 325*c9157d92SDimitry Andric 326*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI_VIRTUAL 327*c9157d92SDimitry Andric int_type overflow(int_type __c = traits_type::eof()) override { 328*c9157d92SDimitry Andric if (traits_type::eq_int_type(__c, traits_type::eof())) 329*c9157d92SDimitry Andric return traits_type::not_eof(__c); 330*c9157d92SDimitry Andric 331*c9157d92SDimitry Andric if (this->pptr() == this->epptr()) { 332*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 333*c9157d92SDimitry Andric try { 334*c9157d92SDimitry Andric# endif 335*c9157d92SDimitry Andric size_t __size = __str_.size(); 336*c9157d92SDimitry Andric __str_.resize(__str_.capacity() + 1); 337*c9157d92SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown"); 338*c9157d92SDimitry Andric 339*c9157d92SDimitry Andric char_type* __p = static_cast<char_type*>(__str_.data()); 340*c9157d92SDimitry Andric this->setp(__p, __p + __str_.size()); 341*c9157d92SDimitry Andric this->pbump(__size); 342*c9157d92SDimitry Andric 343*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 344*c9157d92SDimitry Andric } catch (...) { 345*c9157d92SDimitry Andric return traits_type::eof(); 346*c9157d92SDimitry Andric } 347*c9157d92SDimitry Andric# endif 348*c9157d92SDimitry Andric } 349*c9157d92SDimitry Andric 350*c9157d92SDimitry Andric return this->sputc(traits_type::to_char_type(__c)); 351*c9157d92SDimitry Andric } 352*c9157d92SDimitry Andric 353*c9157d92SDimitry Andricprivate: 354*c9157d92SDimitry Andric streambuf_type* __wrapped_; 355*c9157d92SDimitry Andric 356*c9157d92SDimitry Andric // TODO Use a more generic buffer. 357*c9157d92SDimitry Andric // That buffer should be light with almost no additional headers. Then 358*c9157d92SDimitry Andric // it can be use here, the __retarget_buffer, and place that use 359*c9157d92SDimitry Andric // the now deprecated get_temporary_buffer 360*c9157d92SDimitry Andric 361*c9157d92SDimitry Andric basic_string<_CharT, _Traits, _Allocator> __str_; 362*c9157d92SDimitry Andric bool __emit_on_sync_{false}; 363*c9157d92SDimitry Andric 364*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) { 365*c9157d92SDimitry Andric if (!__wrapped_) 366*c9157d92SDimitry Andric return false; 367*c9157d92SDimitry Andric 368*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_THREADS 369*c9157d92SDimitry Andric lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_); 370*c9157d92SDimitry Andric# endif 371*c9157d92SDimitry Andric 372*c9157d92SDimitry Andric bool __result = true; 373*c9157d92SDimitry Andric if (this->pptr() != this->pbase()) { 374*c9157d92SDimitry Andric _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid"); 375*c9157d92SDimitry Andric 376*c9157d92SDimitry Andric // The __str_ does not know how much of its buffer is used. This 377*c9157d92SDimitry Andric // information is extracted from the information of the base class. 378*c9157d92SDimitry Andric __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1); 379*c9157d92SDimitry Andric // Clears the buffer, but keeps the contents (and) size of the 380*c9157d92SDimitry Andric // internal buffer. 381*c9157d92SDimitry Andric this->setp(this->pbase(), this->epptr()); 382*c9157d92SDimitry Andric } 383*c9157d92SDimitry Andric 384*c9157d92SDimitry Andric if (__flush) 385*c9157d92SDimitry Andric __result &= (__wrapped_->pubsync() != -1); 386*c9157d92SDimitry Andric 387*c9157d92SDimitry Andric return __result; 388*c9157d92SDimitry Andric } 389*c9157d92SDimitry Andric 390*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) { 391*c9157d92SDimitry Andric // Adjust the put area pointers to our buffer. 392*c9157d92SDimitry Andric char_type* __p = static_cast<char_type*>(__str_.data()); 393*c9157d92SDimitry Andric this->setp(__p, __p + __str_.size()); 394*c9157d92SDimitry Andric this->pbump(__other.pptr() - __other.pbase()); 395*c9157d92SDimitry Andric 396*c9157d92SDimitry Andric // Clear __other_ so the destructor will act as a NOP. 397*c9157d92SDimitry Andric __other.setp(nullptr, nullptr); 398*c9157d92SDimitry Andric __other.__wrapped_ = nullptr; 399*c9157d92SDimitry Andric } 400*c9157d92SDimitry Andric 401*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __inc_reference() { 402*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_THREADS 403*c9157d92SDimitry Andric if (__wrapped_) 404*c9157d92SDimitry Andric __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_); 405*c9157d92SDimitry Andric# endif 406*c9157d92SDimitry Andric } 407*c9157d92SDimitry Andric 408*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept { 409*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_THREADS 410*c9157d92SDimitry Andric if (__wrapped_) 411*c9157d92SDimitry Andric __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_); 412*c9157d92SDimitry Andric# endif 413*c9157d92SDimitry Andric } 414*c9157d92SDimitry Andric}; 415*c9157d92SDimitry Andric 416*c9157d92SDimitry Andricusing std::syncbuf; 417*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 418*c9157d92SDimitry Andricusing std::wsyncbuf; 419*c9157d92SDimitry Andric# endif 420*c9157d92SDimitry Andric 421*c9157d92SDimitry Andric// [syncstream.syncbuf.special], specialized algorithms 422*c9157d92SDimitry Andrictemplate <class _CharT, class _Traits, class _Allocator> 423*c9157d92SDimitry Andric_LIBCPP_HIDE_FROM_ABI void 424*c9157d92SDimitry Andricswap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) { 425*c9157d92SDimitry Andric __lhs.swap(__rhs); 426*c9157d92SDimitry Andric} 427*c9157d92SDimitry Andric 428*c9157d92SDimitry Andric// basic_osyncstream 429*c9157d92SDimitry Andric 430*c9157d92SDimitry Andrictemplate <class _CharT, class _Traits, class _Allocator> 431*c9157d92SDimitry Andricclass _LIBCPP_TEMPLATE_VIS basic_osyncstream : public basic_ostream<_CharT, _Traits> { 432*c9157d92SDimitry Andricpublic: 433*c9157d92SDimitry Andric using char_type = _CharT; 434*c9157d92SDimitry Andric using traits_type = _Traits; 435*c9157d92SDimitry Andric using int_type = typename traits_type::int_type; 436*c9157d92SDimitry Andric using pos_type = typename traits_type::pos_type; 437*c9157d92SDimitry Andric using off_type = typename traits_type::off_type; 438*c9157d92SDimitry Andric 439*c9157d92SDimitry Andric using allocator_type = _Allocator; 440*c9157d92SDimitry Andric using streambuf_type = basic_streambuf<char_type, traits_type>; 441*c9157d92SDimitry Andric using syncbuf_type = basic_syncbuf<char_type, traits_type, allocator_type>; 442*c9157d92SDimitry Andric 443*c9157d92SDimitry Andric // [syncstream.osyncstream.cons], construction and destruction 444*c9157d92SDimitry Andric 445*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc) 446*c9157d92SDimitry Andric : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {} 447*c9157d92SDimitry Andric 448*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf) 449*c9157d92SDimitry Andric : basic_osyncstream(__obuf, allocator_type()) {} 450*c9157d92SDimitry Andric 451*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc) 452*c9157d92SDimitry Andric : basic_osyncstream(__os.rdbuf(), __alloc) {} 453*c9157d92SDimitry Andric 454*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os) 455*c9157d92SDimitry Andric : basic_osyncstream(__os, allocator_type()) {} 456*c9157d92SDimitry Andric 457*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept 458*c9157d92SDimitry Andric : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) { 459*c9157d92SDimitry Andric this->set_rdbuf(std::addressof(__sb_)); 460*c9157d92SDimitry Andric } 461*c9157d92SDimitry Andric 462*c9157d92SDimitry Andric // [syncstream.osyncstream.assign], assignment 463*c9157d92SDimitry Andric 464*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default; 465*c9157d92SDimitry Andric 466*c9157d92SDimitry Andric // [syncstream.osyncstream.members], member functions 467*c9157d92SDimitry Andric 468*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI void emit() { 469*c9157d92SDimitry Andric // The basic_ostream::put places the sentry in a try 470*c9157d92SDimitry Andric // catch, this does not match the wording of the standard 471*c9157d92SDimitry Andric // [ostream.unformatted] 472*c9157d92SDimitry Andric // TODO validate other unformatted output functions. 473*c9157d92SDimitry Andric typename basic_ostream<char_type, traits_type>::sentry __s(*this); 474*c9157d92SDimitry Andric if (__s) { 475*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 476*c9157d92SDimitry Andric try { 477*c9157d92SDimitry Andric# endif 478*c9157d92SDimitry Andric 479*c9157d92SDimitry Andric if (__sb_.emit() == false) 480*c9157d92SDimitry Andric this->setstate(ios::badbit); 481*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_EXCEPTIONS 482*c9157d92SDimitry Andric } catch (...) { 483*c9157d92SDimitry Andric this->__set_badbit_and_consider_rethrow(); 484*c9157d92SDimitry Andric } 485*c9157d92SDimitry Andric# endif 486*c9157d92SDimitry Andric } 487*c9157d92SDimitry Andric } 488*c9157d92SDimitry Andric 489*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); } 490*c9157d92SDimitry Andric 491*c9157d92SDimitry Andric _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept { 492*c9157d92SDimitry Andric return const_cast<syncbuf_type*>(std::addressof(__sb_)); 493*c9157d92SDimitry Andric } 494*c9157d92SDimitry Andric 495*c9157d92SDimitry Andricprivate: 496*c9157d92SDimitry Andric syncbuf_type __sb_; 497*c9157d92SDimitry Andric}; 498*c9157d92SDimitry Andric 499*c9157d92SDimitry Andricusing std::osyncstream; 500*c9157d92SDimitry Andric# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 501*c9157d92SDimitry Andricusing std::wosyncstream; 502*c9157d92SDimitry Andric# endif 503*c9157d92SDimitry Andric 504*c9157d92SDimitry Andric#endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM) 505*c9157d92SDimitry Andric 506*c9157d92SDimitry Andric_LIBCPP_END_NAMESPACE_STD 507*c9157d92SDimitry Andric 508*c9157d92SDimitry Andric_LIBCPP_POP_MACROS 509*c9157d92SDimitry Andric 510*c9157d92SDimitry Andric#endif // _LIBCPP_SYNCSTREAM 511