xref: /llvm-project/libcxx/include/syncstream (revision 24e70e3930724ce499ad05d669bfbc4423c542e0)
17cc72a0aSMark de Wever// -*- C++ -*-
27cc72a0aSMark de Wever//===----------------------------------------------------------------------===//
37cc72a0aSMark de Wever//
47cc72a0aSMark de Wever// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
57cc72a0aSMark de Wever// See https://llvm.org/LICENSE.txt for license information.
67cc72a0aSMark de Wever// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
77cc72a0aSMark de Wever//
87cc72a0aSMark de Wever//===----------------------------------------------------------------------===//
97cc72a0aSMark de Wever
107cc72a0aSMark de Wever#ifndef _LIBCPP_SYNCSTREAM
117cc72a0aSMark de Wever#define _LIBCPP_SYNCSTREAM
127cc72a0aSMark de Wever
137cc72a0aSMark de Wever/*
147cc72a0aSMark de Wever    syncstream synopsis
157cc72a0aSMark de Wever
167cc72a0aSMark de Wever#include <ostream>  // see [ostream.syn]
177cc72a0aSMark de Wever
187cc72a0aSMark de Wevernamespace std {
197cc72a0aSMark de Wever    template<class charT, class traits, class Allocator>
207cc72a0aSMark de Wever    class basic_syncbuf;
217cc72a0aSMark de Wever
227cc72a0aSMark de Wever    // [syncstream.syncbuf.special], specialized algorithms
237cc72a0aSMark de Wever    template<class charT, class traits, class Allocator>
247cc72a0aSMark de Wever      void swap(basic_syncbuf<charT, traits, Allocator>&,
257cc72a0aSMark de Wever                basic_syncbuf<charT, traits, Allocator>&);
267cc72a0aSMark de Wever
277cc72a0aSMark de Wever    using syncbuf = basic_syncbuf<char>;
287cc72a0aSMark de Wever    using wsyncbuf = basic_syncbuf<wchar_t>;
297cc72a0aSMark de Wever
307cc72a0aSMark de Wever    template<class charT, class traits, class Allocator>
317cc72a0aSMark de Wever    class basic_osyncstream;
327cc72a0aSMark de Wever
337cc72a0aSMark de Wever    using osyncstream = basic_osyncstream<char>;
347cc72a0aSMark de Wever    using wosyncstream = basic_osyncstream<wchar_t>;
357cc72a0aSMark de Wever
367cc72a0aSMark de Wever    template<class charT, class traits, class Allocator>
377cc72a0aSMark de Wever    class basic_syncbuf : public basic_streambuf<charT, traits> {
387cc72a0aSMark de Wever    public:
397cc72a0aSMark de Wever        using char_type      = charT;
407cc72a0aSMark de Wever        using int_type       = typename traits::int_type;
417cc72a0aSMark de Wever        using pos_type       = typename traits::pos_type;
427cc72a0aSMark de Wever        using off_type       = typename traits::off_type;
437cc72a0aSMark de Wever        using traits_type    = traits;
447cc72a0aSMark de Wever        using allocator_type = Allocator;
457cc72a0aSMark de Wever
467cc72a0aSMark de Wever        using streambuf_type = basic_streambuf<charT, traits>;
477cc72a0aSMark de Wever
487cc72a0aSMark de Wever        // [syncstream.syncbuf.cons], construction and destruction
49f4ea19b4SMark de Wever        basic_syncbuf()
50f4ea19b4SMark de Wever          : basic_syncbuf(nullptr) {}
51f4ea19b4SMark de Wever        explicit basic_syncbuf(streambuf_type* obuf)
527cc72a0aSMark de Wever          : basic_syncbuf(obuf, Allocator()) {}
537cc72a0aSMark de Wever        basic_syncbuf(streambuf_type*, const Allocator&);
547cc72a0aSMark de Wever        basic_syncbuf(basic_syncbuf&&);
557cc72a0aSMark de Wever        ~basic_syncbuf();
567cc72a0aSMark de Wever
577cc72a0aSMark de Wever        // [syncstream.syncbuf.assign], assignment and swap
587cc72a0aSMark de Wever        basic_syncbuf& operator=(basic_syncbuf&&);
597cc72a0aSMark de Wever        void swap(basic_syncbuf&);
607cc72a0aSMark de Wever
617cc72a0aSMark de Wever        // [syncstream.syncbuf.members], member functions
627cc72a0aSMark de Wever        bool emit();
637cc72a0aSMark de Wever        streambuf_type* get_wrapped() const noexcept;
647cc72a0aSMark de Wever        allocator_type get_allocator() const noexcept;
657cc72a0aSMark de Wever        void set_emit_on_sync(bool) noexcept;
667cc72a0aSMark de Wever
677cc72a0aSMark de Wever    protected:
687cc72a0aSMark de Wever        // [syncstream.syncbuf.virtuals], overridden virtual functions
697cc72a0aSMark de Wever        int sync() override;
707cc72a0aSMark de Wever
717cc72a0aSMark de Wever    private:
727cc72a0aSMark de Wever        streambuf_type* wrapped;    // exposition only
737cc72a0aSMark de Wever        bool emit_on_sync{};        // exposition only
747cc72a0aSMark de Wever    };
757cc72a0aSMark de Wever
767cc72a0aSMark de Wever    // [syncstream.syncbuf.special], specialized algorithms
777cc72a0aSMark de Wever    template<class charT, class traits, class Allocator>
787cc72a0aSMark de Wever    void swap(basic_syncbuf<charT, traits, Allocator>&,
797cc72a0aSMark de Wever              basic_syncbuf<charT, traits, Allocator>&);
807cc72a0aSMark de Wever
817cc72a0aSMark de Wever    template<class charT, class traits, class Allocator>
827cc72a0aSMark de Wever    class basic_osyncstream : public basic_ostream<charT, traits> {
837cc72a0aSMark de Wever    public:
847cc72a0aSMark de Wever        using char_type   = charT;
857cc72a0aSMark de Wever        using int_type    = typename traits::int_type;
867cc72a0aSMark de Wever        using pos_type    = typename traits::pos_type;
877cc72a0aSMark de Wever        using off_type    = typename traits::off_type;
887cc72a0aSMark de Wever        using traits_type = traits;
897cc72a0aSMark de Wever
907cc72a0aSMark de Wever        using allocator_type = Allocator;
917cc72a0aSMark de Wever        using streambuf_type = basic_streambuf<charT, traits>;
927cc72a0aSMark de Wever        using syncbuf_type   = basic_syncbuf<charT, traits, Allocator>;
937cc72a0aSMark de Wever
947cc72a0aSMark de Wever        // [syncstream.osyncstream.cons], construction and destruction
957cc72a0aSMark de Wever        basic_osyncstream(streambuf_type*, const Allocator&);
967cc72a0aSMark de Wever        explicit basic_osyncstream(streambuf_type* obuf)
977cc72a0aSMark de Wever          : basic_osyncstream(obuf, Allocator()) {}
987cc72a0aSMark de Wever        basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)
997cc72a0aSMark de Wever          : basic_osyncstream(os.rdbuf(), allocator) {}
1007cc72a0aSMark de Wever        explicit basic_osyncstream(basic_ostream<charT, traits>& os)
1017cc72a0aSMark de Wever          : basic_osyncstream(os, Allocator()) {}
1027cc72a0aSMark de Wever        basic_osyncstream(basic_osyncstream&&) noexcept;
1037cc72a0aSMark de Wever        ~basic_osyncstream();
1047cc72a0aSMark de Wever
1057cc72a0aSMark de Wever        // [syncstream.osyncstream.assign], assignment
1067cc72a0aSMark de Wever        basic_osyncstream& operator=(basic_osyncstream&&);
1077cc72a0aSMark de Wever
1087cc72a0aSMark de Wever        // [syncstream.osyncstream.members], member functions
1097cc72a0aSMark de Wever        void emit();
1107cc72a0aSMark de Wever        streambuf_type* get_wrapped() const noexcept;
1117cc72a0aSMark de Wever        syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }
1127cc72a0aSMark de Wever
1137cc72a0aSMark de Wever    private:
1147cc72a0aSMark de Wever        syncbuf_type sb;    // exposition only
1157cc72a0aSMark de Wever    };
1167cc72a0aSMark de Wever}
1177cc72a0aSMark de Wever
1187cc72a0aSMark de Wever*/
1197cc72a0aSMark de Wever
120b9a2658aSNikolas Klauser#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
121b9a2658aSNikolas Klauser#  include <__cxx03/syncstream>
122b9a2658aSNikolas Klauser#else
1237cc72a0aSMark de Wever#  include <__config>
12487d56c59SLouis Dionne
125c6f3b7bcSNikolas Klauser#  if _LIBCPP_HAS_LOCALIZATION
12687d56c59SLouis Dionne
1274a8329cdSNikolas Klauser#    include <__mutex/lock_guard.h>
1287cc72a0aSMark de Wever#    include <__utility/move.h>
12917f00620SNikolas Klauser#    include <ios>
1307cc72a0aSMark de Wever#    include <iosfwd> // required for declaration of default arguments
13117f00620SNikolas Klauser#    include <streambuf>
1327cc72a0aSMark de Wever#    include <string>
1337cc72a0aSMark de Wever
134c6f3b7bcSNikolas Klauser#    if _LIBCPP_HAS_THREADS
1357cc72a0aSMark de Wever#      include <map>
1367cc72a0aSMark de Wever#      include <shared_mutex>
1377cc72a0aSMark de Wever#    endif
1387cc72a0aSMark de Wever
1397cc72a0aSMark de Wever// standard-mandated includes
1407cc72a0aSMark de Wever
1417cc72a0aSMark de Wever// [syncstream.syn]
1427cc72a0aSMark de Wever#    include <ostream>
1437cc72a0aSMark de Wever
1447cc72a0aSMark de Wever#    if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1457cc72a0aSMark de Wever#      pragma GCC system_header
1467cc72a0aSMark de Wever#    endif
1477cc72a0aSMark de Wever
1487cc72a0aSMark de Wever_LIBCPP_PUSH_MACROS
1497cc72a0aSMark de Wever#    include <__undef_macros>
1507cc72a0aSMark de Wever
1517cc72a0aSMark de Wever_LIBCPP_BEGIN_NAMESPACE_STD
1527cc72a0aSMark de Wever
153*24e70e39SNikolas Klauser#    if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM
1547cc72a0aSMark de Wever
1557cc72a0aSMark de Wever// [syncstream.syncbuf.overview]/1
1567cc72a0aSMark de Wever//   Class template basic_syncbuf stores character data written to it,
1577cc72a0aSMark de Wever//   known as the associated output, into internal buffers allocated
1587cc72a0aSMark de Wever//   using the object's allocator. The associated output is transferred
1597cc72a0aSMark de Wever//   to the wrapped stream buffer object *wrapped when emit() is called
1607cc72a0aSMark de Wever//   or when the basic_syncbuf object is destroyed. Such transfers are
1617cc72a0aSMark de Wever//   atomic with respect to transfers by other basic_syncbuf objects
1627cc72a0aSMark de Wever//   with the same wrapped stream buffer object.
1637cc72a0aSMark de Wever//
1647cc72a0aSMark de Wever// This helper singleton is used to implement the required
1657cc72a0aSMark de Wever// synchronisation guarantees.
166c6f3b7bcSNikolas Klauser#      if _LIBCPP_HAS_THREADS
1677cc72a0aSMark de Weverclass __wrapped_streambuf_mutex {
1687cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default;
1697cc72a0aSMark de Wever
1707cc72a0aSMark de Weverpublic:
1717cc72a0aSMark de Wever  __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&)            = delete;
1727cc72a0aSMark de Wever  __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete;
1737cc72a0aSMark de Wever
1747cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) {
1757cc72a0aSMark de Wever    _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
1767cc72a0aSMark de Wever    unique_lock __lock{__mutex_};
1777cc72a0aSMark de Wever    ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count;
1787cc72a0aSMark de Wever  }
1797cc72a0aSMark de Wever
1807cc72a0aSMark de Wever  // pre: __ptr is in __lut_
1817cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept {
1827cc72a0aSMark de Wever    unique_lock __lock{__mutex_};
1837cc72a0aSMark de Wever
1847cc72a0aSMark de Wever    auto __it = __get_it(__ptr);
1857cc72a0aSMark de Wever    if (__it->second.__count == 1)
1867cc72a0aSMark de Wever      __lut_.erase(__it);
1877cc72a0aSMark de Wever    else
1887cc72a0aSMark de Wever      --__it->second.__count;
1897cc72a0aSMark de Wever  }
1907cc72a0aSMark de Wever
1917cc72a0aSMark de Wever  // TODO
1927cc72a0aSMark de Wever  // This function causes emit() aquire two mutexes:
1937cc72a0aSMark de Wever  // - __mutex_ shared
1947cc72a0aSMark de Wever  // _ __get_it(__ptr)->second.__mutex exclusive
1957cc72a0aSMark de Wever  //
1967cc72a0aSMark de Wever  // Instead store a pointer to __get_it(__ptr)->second.__mutex when
1977cc72a0aSMark de Wever  // calling __inc_reference.
1987cc72a0aSMark de Wever  //
1997cc72a0aSMark de Wever  // pre: __ptr is in __lut_
2007cc72a0aSMark de Wever  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept {
2017cc72a0aSMark de Wever    shared_lock __lock{__mutex_};
2027cc72a0aSMark de Wever    return lock_guard{__get_it(__ptr)->second.__mutex};
2037cc72a0aSMark de Wever  }
2047cc72a0aSMark de Wever
2057cc72a0aSMark de Wever  // This function is used for testing.
2067cc72a0aSMark de Wever  //
2077cc72a0aSMark de Wever  // It is allowed to call this function with a non-registered pointer.
2087cc72a0aSMark de Wever  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept {
2097cc72a0aSMark de Wever    _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
2107cc72a0aSMark de Wever    shared_lock __lock{__mutex_};
2117cc72a0aSMark de Wever
2127cc72a0aSMark de Wever    auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
2137cc72a0aSMark de Wever    return __it != __lut_.end() ? __it->second.__count : 0;
2147cc72a0aSMark de Wever  }
2157cc72a0aSMark de Wever
2167cc72a0aSMark de Wever  [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept {
2177cc72a0aSMark de Wever    static __wrapped_streambuf_mutex __result;
2187cc72a0aSMark de Wever    return __result;
2197cc72a0aSMark de Wever  }
2207cc72a0aSMark de Wever
2217cc72a0aSMark de Weverprivate:
2227cc72a0aSMark de Wever  struct __value {
2237cc72a0aSMark de Wever    mutex __mutex;
2247cc72a0aSMark de Wever    size_t __count{0};
2257cc72a0aSMark de Wever  };
2267cc72a0aSMark de Wever
2277cc72a0aSMark de Wever  shared_mutex __mutex_;
2287cc72a0aSMark de Wever  map<uintptr_t, __value> __lut_;
2297cc72a0aSMark de Wever
2307cc72a0aSMark de Wever  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept {
2317cc72a0aSMark de Wever    _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
2327cc72a0aSMark de Wever
2337cc72a0aSMark de Wever    auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
2347cc72a0aSMark de Wever    _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered");
2357cc72a0aSMark de Wever    _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper");
2367cc72a0aSMark de Wever    return __it;
2377cc72a0aSMark de Wever  }
2387cc72a0aSMark de Wever};
239c6f3b7bcSNikolas Klauser#      endif // _LIBCPP_HAS_THREADS
2407cc72a0aSMark de Wever
2417cc72a0aSMark de Wever// basic_syncbuf
2427cc72a0aSMark de Wever
2437cc72a0aSMark de Wever// The class uses a basic_string<_CharT, _Traits, _Allocator> as
2447cc72a0aSMark de Wever// internal buffer. Per [syncstream.syncbuf.cons]/4
2457cc72a0aSMark de Wever//   Remarks: A copy of allocator is used to allocate memory for
2467cc72a0aSMark de Wever//   internal buffers holding the associated output.
2477cc72a0aSMark de Wever//
2487cc72a0aSMark de Wever// Therefore the allocator used in the constructor is passed to the
2497cc72a0aSMark de Wever// basic_string. The class does not keep a copy of this allocator.
2507cc72a0aSMark de Wevertemplate <class _CharT, class _Traits, class _Allocator>
2517cc72a0aSMark de Weverclass _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> {
2527cc72a0aSMark de Weverpublic:
2537cc72a0aSMark de Wever  using char_type      = _CharT;
2547cc72a0aSMark de Wever  using traits_type    = _Traits;
2557cc72a0aSMark de Wever  using int_type       = typename traits_type::int_type;
2567cc72a0aSMark de Wever  using pos_type       = typename traits_type::pos_type;
2577cc72a0aSMark de Wever  using off_type       = typename traits_type::off_type;
2587cc72a0aSMark de Wever  using allocator_type = _Allocator;
2597cc72a0aSMark de Wever
2607cc72a0aSMark de Wever  using streambuf_type = basic_streambuf<_CharT, _Traits>;
2617cc72a0aSMark de Wever
2627cc72a0aSMark de Wever  // [syncstream.syncbuf.cons], construction and destruction
2637cc72a0aSMark de Wever
264348e7413SLouis Dionne  _LIBCPP_HIDE_FROM_ABI basic_syncbuf() : basic_syncbuf(nullptr) {}
265f4ea19b4SMark de Wever
266348e7413SLouis Dionne  _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf) : basic_syncbuf(__obuf, _Allocator()) {}
2677cc72a0aSMark de Wever
2687cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc)
2697cc72a0aSMark de Wever      : __wrapped_(__obuf), __str_(__alloc) {
2707cc72a0aSMark de Wever    __inc_reference();
2717cc72a0aSMark de Wever  }
2727cc72a0aSMark de Wever
2737cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other)
2747cc72a0aSMark de Wever      : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) {
2757cc72a0aSMark de Wever    __move_common(__other);
2767cc72a0aSMark de Wever  }
2777cc72a0aSMark de Wever
2787cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() {
279ba87515fSNikolas Klauser#      if _LIBCPP_HAS_EXCEPTIONS
2807cc72a0aSMark de Wever    try {
281ba87515fSNikolas Klauser#      endif // _LIBCPP_HAS_EXCEPTIONS
2827cc72a0aSMark de Wever      emit();
283ba87515fSNikolas Klauser#      if _LIBCPP_HAS_EXCEPTIONS
2847cc72a0aSMark de Wever    } catch (...) {
2857cc72a0aSMark de Wever    }
286ba87515fSNikolas Klauser#      endif // _LIBCPP_HAS_EXCEPTIONS
2877cc72a0aSMark de Wever    __dec_reference();
2887cc72a0aSMark de Wever  }
2897cc72a0aSMark de Wever
2907cc72a0aSMark de Wever  // [syncstream.syncbuf.assign], assignment and swap
2917cc72a0aSMark de Wever
2927cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) {
2937cc72a0aSMark de Wever    // The function is specified to call emit. This call should
2947cc72a0aSMark de Wever    // propagate the exception thrown.
2957cc72a0aSMark de Wever    emit();
2967cc72a0aSMark de Wever    __dec_reference();
2977cc72a0aSMark de Wever
2987cc72a0aSMark de Wever    __wrapped_      = __other.get_wrapped();
2997cc72a0aSMark de Wever    __str_          = std::move(__other.__str_);
3007cc72a0aSMark de Wever    __emit_on_sync_ = __other.__emit_on_sync_;
3017cc72a0aSMark de Wever
3027cc72a0aSMark de Wever    __move_common(__other);
3037cc72a0aSMark de Wever
3047cc72a0aSMark de Wever    return *this;
3057cc72a0aSMark de Wever  }
3067cc72a0aSMark de Wever
3077cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) {
3087cc72a0aSMark de Wever    _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
3097cc72a0aSMark de Wever        allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(),
3107cc72a0aSMark de Wever        "violates the mandated swap precondition");
3117cc72a0aSMark de Wever
3127cc72a0aSMark de Wever    basic_syncbuf __tmp(std::move(__other));
3137cc72a0aSMark de Wever    __other = std::move(*this);
3147cc72a0aSMark de Wever    *this   = std::move(__tmp);
3157cc72a0aSMark de Wever  }
3167cc72a0aSMark de Wever
3177cc72a0aSMark de Wever  // [syncstream.syncbuf.members], member functions
3187cc72a0aSMark de Wever
3197cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }
3207cc72a0aSMark de Wever
3217cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
3227cc72a0aSMark de Wever
3237cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
3247cc72a0aSMark de Wever
3257cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }
3267cc72a0aSMark de Wever
3277cc72a0aSMark de Weverprotected:
3287cc72a0aSMark de Wever  // [syncstream.syncbuf.virtuals], overridden virtual functions
3297cc72a0aSMark de Wever
3307cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI_VIRTUAL
3317cc72a0aSMark de Wever  int sync() override {
3327cc72a0aSMark de Wever    if (__emit_on_sync_ && !emit(true))
3337cc72a0aSMark de Wever      return -1;
3347cc72a0aSMark de Wever    return 0;
3357cc72a0aSMark de Wever  }
3367cc72a0aSMark de Wever
3377cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI_VIRTUAL
3387cc72a0aSMark de Wever  int_type overflow(int_type __c = traits_type::eof()) override {
3397cc72a0aSMark de Wever    if (traits_type::eq_int_type(__c, traits_type::eof()))
3407cc72a0aSMark de Wever      return traits_type::not_eof(__c);
3417cc72a0aSMark de Wever
3427cc72a0aSMark de Wever    if (this->pptr() == this->epptr()) {
343ba87515fSNikolas Klauser#      if _LIBCPP_HAS_EXCEPTIONS
3447cc72a0aSMark de Wever      try {
3457cc72a0aSMark de Wever#      endif
3467cc72a0aSMark de Wever        size_t __size = __str_.size();
3477cc72a0aSMark de Wever        __str_.resize(__str_.capacity() + 1);
3487cc72a0aSMark de Wever        _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown");
3497cc72a0aSMark de Wever
3507cc72a0aSMark de Wever        char_type* __p = static_cast<char_type*>(__str_.data());
3517cc72a0aSMark de Wever        this->setp(__p, __p + __str_.size());
3527cc72a0aSMark de Wever        this->pbump(__size);
3537cc72a0aSMark de Wever
354ba87515fSNikolas Klauser#      if _LIBCPP_HAS_EXCEPTIONS
3557cc72a0aSMark de Wever      } catch (...) {
3567cc72a0aSMark de Wever        return traits_type::eof();
3577cc72a0aSMark de Wever      }
3587cc72a0aSMark de Wever#      endif
3597cc72a0aSMark de Wever    }
3607cc72a0aSMark de Wever
3617cc72a0aSMark de Wever    return this->sputc(traits_type::to_char_type(__c));
3627cc72a0aSMark de Wever  }
3637cc72a0aSMark de Wever
3647cc72a0aSMark de Weverprivate:
3657cc72a0aSMark de Wever  streambuf_type* __wrapped_;
3667cc72a0aSMark de Wever
3677cc72a0aSMark de Wever  // TODO Use a more generic buffer.
3687cc72a0aSMark de Wever  // That buffer should be light with almost no additional headers. Then
3697cc72a0aSMark de Wever  // it can be use here, the __retarget_buffer, and place that use
37094e7c0b0SA. Jiang  // the now removed get_temporary_buffer
3717cc72a0aSMark de Wever
3727cc72a0aSMark de Wever  basic_string<_CharT, _Traits, _Allocator> __str_;
3737cc72a0aSMark de Wever  bool __emit_on_sync_{false};
3747cc72a0aSMark de Wever
3757cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {
3767cc72a0aSMark de Wever    if (!__wrapped_)
3777cc72a0aSMark de Wever      return false;
3787cc72a0aSMark de Wever
379c6f3b7bcSNikolas Klauser#      if _LIBCPP_HAS_THREADS
3807cc72a0aSMark de Wever    lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_);
3817cc72a0aSMark de Wever#      endif
3827cc72a0aSMark de Wever
3837cc72a0aSMark de Wever    bool __result = true;
3847cc72a0aSMark de Wever    if (this->pptr() != this->pbase()) {
3857cc72a0aSMark de Wever      _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid");
3867cc72a0aSMark de Wever
3877cc72a0aSMark de Wever      // The __str_ does not know how much of its buffer is used. This
3887cc72a0aSMark de Wever      // information is extracted from the information of the base class.
3897cc72a0aSMark de Wever      __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1);
3907cc72a0aSMark de Wever      // Clears the buffer, but keeps the contents (and) size of the
3917cc72a0aSMark de Wever      // internal buffer.
3927cc72a0aSMark de Wever      this->setp(this->pbase(), this->epptr());
3937cc72a0aSMark de Wever    }
3947cc72a0aSMark de Wever
3957cc72a0aSMark de Wever    if (__flush)
3967cc72a0aSMark de Wever      __result &= (__wrapped_->pubsync() != -1);
3977cc72a0aSMark de Wever
3987cc72a0aSMark de Wever    return __result;
3997cc72a0aSMark de Wever  }
4007cc72a0aSMark de Wever
4017cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) {
4027cc72a0aSMark de Wever    // Adjust the put area pointers to our buffer.
4037cc72a0aSMark de Wever    char_type* __p = static_cast<char_type*>(__str_.data());
4047cc72a0aSMark de Wever    this->setp(__p, __p + __str_.size());
4057cc72a0aSMark de Wever    this->pbump(__other.pptr() - __other.pbase());
4067cc72a0aSMark de Wever
4077cc72a0aSMark de Wever    // Clear __other_ so the destructor will act as a NOP.
4087cc72a0aSMark de Wever    __other.setp(nullptr, nullptr);
4097cc72a0aSMark de Wever    __other.__wrapped_ = nullptr;
4107cc72a0aSMark de Wever  }
4117cc72a0aSMark de Wever
4127cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI void __inc_reference() {
413c6f3b7bcSNikolas Klauser#      if _LIBCPP_HAS_THREADS
4147cc72a0aSMark de Wever    if (__wrapped_)
4157cc72a0aSMark de Wever      __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_);
4167cc72a0aSMark de Wever#      endif
4177cc72a0aSMark de Wever  }
4187cc72a0aSMark de Wever
4197cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept {
420c6f3b7bcSNikolas Klauser#      if _LIBCPP_HAS_THREADS
4217cc72a0aSMark de Wever    if (__wrapped_)
4227cc72a0aSMark de Wever      __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_);
4237cc72a0aSMark de Wever#      endif
4247cc72a0aSMark de Wever  }
4257cc72a0aSMark de Wever};
4267cc72a0aSMark de Wever
4277cc72a0aSMark de Weverusing std::syncbuf;
428c6f3b7bcSNikolas Klauser#      if _LIBCPP_HAS_WIDE_CHARACTERS
4297cc72a0aSMark de Weverusing std::wsyncbuf;
4307cc72a0aSMark de Wever#      endif
4317cc72a0aSMark de Wever
4327cc72a0aSMark de Wever// [syncstream.syncbuf.special], specialized algorithms
4337cc72a0aSMark de Wevertemplate <class _CharT, class _Traits, class _Allocator>
4347cc72a0aSMark de Wever_LIBCPP_HIDE_FROM_ABI void
4357cc72a0aSMark de Weverswap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) {
4367cc72a0aSMark de Wever  __lhs.swap(__rhs);
4377cc72a0aSMark de Wever}
4387cc72a0aSMark de Wever
4397cc72a0aSMark de Wever// basic_osyncstream
4407cc72a0aSMark de Wever
4417cc72a0aSMark de Wevertemplate <class _CharT, class _Traits, class _Allocator>
4427cc72a0aSMark de Weverclass _LIBCPP_TEMPLATE_VIS basic_osyncstream : public basic_ostream<_CharT, _Traits> {
4437cc72a0aSMark de Weverpublic:
4447cc72a0aSMark de Wever  using char_type   = _CharT;
4457cc72a0aSMark de Wever  using traits_type = _Traits;
4467cc72a0aSMark de Wever  using int_type    = typename traits_type::int_type;
4477cc72a0aSMark de Wever  using pos_type    = typename traits_type::pos_type;
4487cc72a0aSMark de Wever  using off_type    = typename traits_type::off_type;
4497cc72a0aSMark de Wever
4507cc72a0aSMark de Wever  using allocator_type = _Allocator;
4517cc72a0aSMark de Wever  using streambuf_type = basic_streambuf<char_type, traits_type>;
4527cc72a0aSMark de Wever  using syncbuf_type   = basic_syncbuf<char_type, traits_type, allocator_type>;
4537cc72a0aSMark de Wever
4547cc72a0aSMark de Wever  // [syncstream.osyncstream.cons], construction and destruction
4557cc72a0aSMark de Wever
4567cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc)
4577cc72a0aSMark de Wever      : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {}
4587cc72a0aSMark de Wever
4597cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf)
4607cc72a0aSMark de Wever      : basic_osyncstream(__obuf, allocator_type()) {}
4617cc72a0aSMark de Wever
4627cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc)
4637cc72a0aSMark de Wever      : basic_osyncstream(__os.rdbuf(), __alloc) {}
4647cc72a0aSMark de Wever
4657cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
4667cc72a0aSMark de Wever      : basic_osyncstream(__os, allocator_type()) {}
4677cc72a0aSMark de Wever
4687cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept
4697cc72a0aSMark de Wever      : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) {
4707cc72a0aSMark de Wever    this->set_rdbuf(std::addressof(__sb_));
4717cc72a0aSMark de Wever  }
4727cc72a0aSMark de Wever
4737cc72a0aSMark de Wever  // [syncstream.osyncstream.assign], assignment
4747cc72a0aSMark de Wever
4757cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default;
4767cc72a0aSMark de Wever
4777cc72a0aSMark de Wever  // [syncstream.osyncstream.members], member functions
4787cc72a0aSMark de Wever
4797cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI void emit() {
4807cc72a0aSMark de Wever    // The basic_ostream::put places the sentry in a try
4817cc72a0aSMark de Wever    // catch, this does not match the wording of the standard
4827cc72a0aSMark de Wever    // [ostream.unformatted]
4837cc72a0aSMark de Wever    // TODO validate other unformatted output functions.
4847cc72a0aSMark de Wever    typename basic_ostream<char_type, traits_type>::sentry __s(*this);
4857cc72a0aSMark de Wever    if (__s) {
486ba87515fSNikolas Klauser#      if _LIBCPP_HAS_EXCEPTIONS
4877cc72a0aSMark de Wever      try {
4887cc72a0aSMark de Wever#      endif
4897cc72a0aSMark de Wever
4907cc72a0aSMark de Wever        if (__sb_.emit() == false)
4917cc72a0aSMark de Wever          this->setstate(ios::badbit);
492ba87515fSNikolas Klauser#      if _LIBCPP_HAS_EXCEPTIONS
4937cc72a0aSMark de Wever      } catch (...) {
4947cc72a0aSMark de Wever        this->__set_badbit_and_consider_rethrow();
4957cc72a0aSMark de Wever      }
4967cc72a0aSMark de Wever#      endif
4977cc72a0aSMark de Wever    }
4987cc72a0aSMark de Wever  }
4997cc72a0aSMark de Wever
5007cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
5017cc72a0aSMark de Wever
5027cc72a0aSMark de Wever  _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
5037cc72a0aSMark de Wever    return const_cast<syncbuf_type*>(std::addressof(__sb_));
5047cc72a0aSMark de Wever  }
5057cc72a0aSMark de Wever
5067cc72a0aSMark de Weverprivate:
5077cc72a0aSMark de Wever  syncbuf_type __sb_;
5087cc72a0aSMark de Wever};
5097cc72a0aSMark de Wever
5107cc72a0aSMark de Weverusing std::osyncstream;
511c6f3b7bcSNikolas Klauser#      if _LIBCPP_HAS_WIDE_CHARACTERS
5127cc72a0aSMark de Weverusing std::wosyncstream;
5137cc72a0aSMark de Wever#      endif
5147cc72a0aSMark de Wever
515*24e70e39SNikolas Klauser#    endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM
5167cc72a0aSMark de Wever
5177cc72a0aSMark de Wever_LIBCPP_END_NAMESPACE_STD
5187cc72a0aSMark de Wever
5197cc72a0aSMark de Wever_LIBCPP_POP_MACROS
5207cc72a0aSMark de Wever
521c6f3b7bcSNikolas Klauser#  endif // _LIBCPP_HAS_LOCALIZATION
522b9a2658aSNikolas Klauser#endif   // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
52387d56c59SLouis Dionne
5247cc72a0aSMark de Wever#endif // _LIBCPP_SYNCSTREAM
525