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