brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.3 KiB · 1f7605e Raw
524 lines · plain
1// -*- C++ -*-2//===----------------------------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP_SYNCSTREAM11#define _LIBCPP_SYNCSTREAM12 13/*14    syncstream synopsis15 16#include <ostream>  // see [ostream.syn]17 18namespace std {19    template<class charT, class traits, class Allocator>20    class basic_syncbuf;21 22    // [syncstream.syncbuf.special], specialized algorithms23    template<class charT, class traits, class Allocator>24      void swap(basic_syncbuf<charT, traits, Allocator>&,25                basic_syncbuf<charT, traits, Allocator>&);26 27    using syncbuf = basic_syncbuf<char>;28    using wsyncbuf = basic_syncbuf<wchar_t>;29 30    template<class charT, class traits, class Allocator>31    class basic_osyncstream;32 33    using osyncstream = basic_osyncstream<char>;34    using wosyncstream = basic_osyncstream<wchar_t>;35 36    template<class charT, class traits, class Allocator>37    class basic_syncbuf : public basic_streambuf<charT, traits> {38    public:39        using char_type      = charT;40        using int_type       = typename traits::int_type;41        using pos_type       = typename traits::pos_type;42        using off_type       = typename traits::off_type;43        using traits_type    = traits;44        using allocator_type = Allocator;45 46        using streambuf_type = basic_streambuf<charT, traits>;47 48        // [syncstream.syncbuf.cons], construction and destruction49        basic_syncbuf()50          : basic_syncbuf(nullptr) {}51        explicit basic_syncbuf(streambuf_type* obuf)52          : basic_syncbuf(obuf, Allocator()) {}53        basic_syncbuf(streambuf_type*, const Allocator&);54        basic_syncbuf(basic_syncbuf&&);55        ~basic_syncbuf();56 57        // [syncstream.syncbuf.assign], assignment and swap58        basic_syncbuf& operator=(basic_syncbuf&&);59        void swap(basic_syncbuf&);60 61        // [syncstream.syncbuf.members], member functions62        bool emit();63        streambuf_type* get_wrapped() const noexcept;64        allocator_type get_allocator() const noexcept;65        void set_emit_on_sync(bool) noexcept;66 67    protected:68        // [syncstream.syncbuf.virtuals], overridden virtual functions69        int sync() override;70 71    private:72        streambuf_type* wrapped;    // exposition only73        bool emit_on_sync{};        // exposition only74    };75 76    // [syncstream.syncbuf.special], specialized algorithms77    template<class charT, class traits, class Allocator>78    void swap(basic_syncbuf<charT, traits, Allocator>&,79              basic_syncbuf<charT, traits, Allocator>&);80 81    template<class charT, class traits, class Allocator>82    class basic_osyncstream : public basic_ostream<charT, traits> {83    public:84        using char_type   = charT;85        using int_type    = typename traits::int_type;86        using pos_type    = typename traits::pos_type;87        using off_type    = typename traits::off_type;88        using traits_type = traits;89 90        using allocator_type = Allocator;91        using streambuf_type = basic_streambuf<charT, traits>;92        using syncbuf_type   = basic_syncbuf<charT, traits, Allocator>;93 94        // [syncstream.osyncstream.cons], construction and destruction95        basic_osyncstream(streambuf_type*, const Allocator&);96        explicit basic_osyncstream(streambuf_type* obuf)97          : basic_osyncstream(obuf, Allocator()) {}98        basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)99          : basic_osyncstream(os.rdbuf(), allocator) {}100        explicit basic_osyncstream(basic_ostream<charT, traits>& os)101          : basic_osyncstream(os, Allocator()) {}102        basic_osyncstream(basic_osyncstream&&) noexcept;103        ~basic_osyncstream();104 105        // [syncstream.osyncstream.assign], assignment106        basic_osyncstream& operator=(basic_osyncstream&&);107 108        // [syncstream.osyncstream.members], member functions109        void emit();110        streambuf_type* get_wrapped() const noexcept;111        syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }112 113    private:114        syncbuf_type sb;    // exposition only115    };116}117 118*/119 120#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)121#  include <__cxx03/__config>122#else123#  include <__config>124 125// standard-mandated includes126 127// [syncstream.syn]128#  include <ostream>129 130#  if _LIBCPP_HAS_LOCALIZATION131 132#    include <__mutex/lock_guard.h>133#    include <__utility/move.h>134#    include <ios>135#    include <iosfwd> // required for declaration of default arguments136#    include <streambuf>137#    include <string>138#    if _LIBCPP_HAS_THREADS139#      include <map>140#      include <shared_mutex>141#    endif142 143#    if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)144#      pragma GCC system_header145#    endif146 147_LIBCPP_PUSH_MACROS148#    include <__undef_macros>149 150_LIBCPP_BEGIN_NAMESPACE_STD151 152#    if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM153 154// [syncstream.syncbuf.overview]/1155//   Class template basic_syncbuf stores character data written to it,156//   known as the associated output, into internal buffers allocated157//   using the object's allocator. The associated output is transferred158//   to the wrapped stream buffer object *wrapped when emit() is called159//   or when the basic_syncbuf object is destroyed. Such transfers are160//   atomic with respect to transfers by other basic_syncbuf objects161//   with the same wrapped stream buffer object.162//163// This helper singleton is used to implement the required164// synchronisation guarantees.165#      if _LIBCPP_HAS_THREADS166class __wrapped_streambuf_mutex {167  _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default;168 169public:170  __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&)            = delete;171  __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete;172 173  _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) {174    _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");175    unique_lock __lock{__mutex_};176    ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count;177  }178 179  // pre: __ptr is in __lut_180  _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept {181    unique_lock __lock{__mutex_};182 183    auto __it = __get_it(__ptr);184    if (__it->second.__count == 1)185      __lut_.erase(__it);186    else187      --__it->second.__count;188  }189 190  // TODO191  // This function causes emit() aquire two mutexes:192  // - __mutex_ shared193  // _ __get_it(__ptr)->second.__mutex exclusive194  //195  // Instead store a pointer to __get_it(__ptr)->second.__mutex when196  // calling __inc_reference.197  //198  // pre: __ptr is in __lut_199  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept {200    shared_lock __lock{__mutex_};201    return lock_guard{__get_it(__ptr)->second.__mutex};202  }203 204  // This function is used for testing.205  //206  // It is allowed to call this function with a non-registered pointer.207  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept {208    _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");209    shared_lock __lock{__mutex_};210 211    auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));212    return __it != __lut_.end() ? __it->second.__count : 0;213  }214 215  [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept {216    static __wrapped_streambuf_mutex __result;217    return __result;218  }219 220private:221  struct __value {222    mutex __mutex;223    size_t __count{0};224  };225 226  shared_mutex __mutex_;227  map<uintptr_t, __value> __lut_;228 229  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept {230    _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");231 232    auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));233    _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered");234    _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper");235    return __it;236  }237};238#      endif // _LIBCPP_HAS_THREADS239 240// basic_syncbuf241 242// The class uses a basic_string<_CharT, _Traits, _Allocator> as243// internal buffer. Per [syncstream.syncbuf.cons]/4244//   Remarks: A copy of allocator is used to allocate memory for245//   internal buffers holding the associated output.246//247// Therefore the allocator used in the constructor is passed to the248// basic_string. The class does not keep a copy of this allocator.249template <class _CharT, class _Traits, class _Allocator>250class basic_syncbuf : public basic_streambuf<_CharT, _Traits> {251public:252  using char_type      = _CharT;253  using traits_type    = _Traits;254  using int_type       = typename traits_type::int_type;255  using pos_type       = typename traits_type::pos_type;256  using off_type       = typename traits_type::off_type;257  using allocator_type = _Allocator;258 259  using streambuf_type = basic_streambuf<_CharT, _Traits>;260 261  // [syncstream.syncbuf.cons], construction and destruction262 263  _LIBCPP_HIDE_FROM_ABI basic_syncbuf() : basic_syncbuf(nullptr) {}264 265  _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf) : basic_syncbuf(__obuf, _Allocator()) {}266 267  _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc)268      : __wrapped_(__obuf), __str_(__alloc) {269    __inc_reference();270  }271 272  _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other)273      : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) {274    __move_common(__other);275  }276 277  _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() {278#      if _LIBCPP_HAS_EXCEPTIONS279    try {280#      endif // _LIBCPP_HAS_EXCEPTIONS281      emit();282#      if _LIBCPP_HAS_EXCEPTIONS283    } catch (...) {284    }285#      endif // _LIBCPP_HAS_EXCEPTIONS286    __dec_reference();287  }288 289  // [syncstream.syncbuf.assign], assignment and swap290 291  _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) {292    // The function is specified to call emit. This call should293    // propagate the exception thrown.294    emit();295    __dec_reference();296 297    __wrapped_      = __other.get_wrapped();298    __str_          = std::move(__other.__str_);299    __emit_on_sync_ = __other.__emit_on_sync_;300 301    __move_common(__other);302 303    return *this;304  }305 306  _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) {307    _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(308        allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(),309        "violates the mandated swap precondition");310 311    basic_syncbuf __tmp(std::move(__other));312    __other = std::move(*this);313    *this   = std::move(__tmp);314  }315 316  // [syncstream.syncbuf.members], member functions317 318  _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }319 320  _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }321 322  _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }323 324  _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }325 326protected:327  // [syncstream.syncbuf.virtuals], overridden virtual functions328 329  _LIBCPP_HIDE_FROM_ABI_VIRTUAL330  int sync() override {331    if (__emit_on_sync_ && !emit(true))332      return -1;333    return 0;334  }335 336  _LIBCPP_HIDE_FROM_ABI_VIRTUAL337  int_type overflow(int_type __c = traits_type::eof()) override {338    if (traits_type::eq_int_type(__c, traits_type::eof()))339      return traits_type::not_eof(__c);340 341    if (this->pptr() == this->epptr()) {342#      if _LIBCPP_HAS_EXCEPTIONS343      try {344#      endif345        size_t __size = __str_.size();346        __str_.resize(__str_.capacity() + 1);347        _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown");348 349        char_type* __p = static_cast<char_type*>(__str_.data());350        this->setp(__p, __p + __str_.size());351        this->pbump(__size);352 353#      if _LIBCPP_HAS_EXCEPTIONS354      } catch (...) {355        return traits_type::eof();356      }357#      endif358    }359 360    return this->sputc(traits_type::to_char_type(__c));361  }362 363private:364  streambuf_type* __wrapped_;365 366  // TODO Use a more generic buffer.367  // That buffer should be light with almost no additional headers. Then368  // it can be use here, the __retarget_buffer, and place that use369  // the now removed get_temporary_buffer370 371  basic_string<_CharT, _Traits, _Allocator> __str_;372  bool __emit_on_sync_{false};373 374  _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {375    if (!__wrapped_)376      return false;377 378#      if _LIBCPP_HAS_THREADS379    lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_);380#      endif381 382    bool __result = true;383    if (this->pptr() != this->pbase()) {384      _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid");385 386      // The __str_ does not know how much of its buffer is used. This387      // information is extracted from the information of the base class.388      __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1);389      // Clears the buffer, but keeps the contents (and) size of the390      // internal buffer.391      this->setp(this->pbase(), this->epptr());392    }393 394    if (__flush)395      __result &= (__wrapped_->pubsync() != -1);396 397    return __result;398  }399 400  _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) {401    // Adjust the put area pointers to our buffer.402    char_type* __p = static_cast<char_type*>(__str_.data());403    this->setp(__p, __p + __str_.size());404    this->pbump(__other.pptr() - __other.pbase());405 406    // Clear __other_ so the destructor will act as a NOP.407    __other.setp(nullptr, nullptr);408    __other.__wrapped_ = nullptr;409  }410 411  _LIBCPP_HIDE_FROM_ABI void __inc_reference() {412#      if _LIBCPP_HAS_THREADS413    if (__wrapped_)414      __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_);415#      endif416  }417 418  _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept {419#      if _LIBCPP_HAS_THREADS420    if (__wrapped_)421      __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_);422#      endif423  }424};425 426using std::syncbuf;427#      if _LIBCPP_HAS_WIDE_CHARACTERS428using std::wsyncbuf;429#      endif430 431// [syncstream.syncbuf.special], specialized algorithms432template <class _CharT, class _Traits, class _Allocator>433_LIBCPP_HIDE_FROM_ABI void434swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) {435  __lhs.swap(__rhs);436}437 438// basic_osyncstream439 440template <class _CharT, class _Traits, class _Allocator>441class basic_osyncstream : public basic_ostream<_CharT, _Traits> {442public:443  using char_type   = _CharT;444  using traits_type = _Traits;445  using int_type    = typename traits_type::int_type;446  using pos_type    = typename traits_type::pos_type;447  using off_type    = typename traits_type::off_type;448 449  using allocator_type = _Allocator;450  using streambuf_type = basic_streambuf<char_type, traits_type>;451  using syncbuf_type   = basic_syncbuf<char_type, traits_type, allocator_type>;452 453  // [syncstream.osyncstream.cons], construction and destruction454 455  _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc)456      : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {}457 458  _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf)459      : basic_osyncstream(__obuf, allocator_type()) {}460 461  _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc)462      : basic_osyncstream(__os.rdbuf(), __alloc) {}463 464  _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)465      : basic_osyncstream(__os, allocator_type()) {}466 467  _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept468      : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) {469    this->set_rdbuf(std::addressof(__sb_));470  }471 472  // [syncstream.osyncstream.assign], assignment473 474  _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default;475 476  // [syncstream.osyncstream.members], member functions477 478  _LIBCPP_HIDE_FROM_ABI void emit() {479    // The basic_ostream::put places the sentry in a try480    // catch, this does not match the wording of the standard481    // [ostream.unformatted]482    // TODO validate other unformatted output functions.483    typename basic_ostream<char_type, traits_type>::sentry __s(*this);484    if (__s) {485#      if _LIBCPP_HAS_EXCEPTIONS486      try {487#      endif488 489        if (__sb_.emit() == false)490          this->setstate(ios::badbit);491#      if _LIBCPP_HAS_EXCEPTIONS492      } catch (...) {493        this->__set_badbit_and_consider_rethrow();494      }495#      endif496    }497  }498 499  _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }500 501  _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {502    return const_cast<syncbuf_type*>(std::addressof(__sb_));503  }504 505private:506  syncbuf_type __sb_;507};508 509using std::osyncstream;510#      if _LIBCPP_HAS_WIDE_CHARACTERS511using std::wosyncstream;512#      endif513 514#    endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM515 516_LIBCPP_END_NAMESPACE_STD517 518_LIBCPP_POP_MACROS519 520#  endif // _LIBCPP_HAS_LOCALIZATION521#endif   // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)522 523#endif // _LIBCPP_SYNCSTREAM524