Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/c++/v1/syncstream is written in an unsupported language. File is not indexed.

0001 // -*- C++ -*-
0002 //===----------------------------------------------------------------------===//
0003 //
0004 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0005 // See https://llvm.org/LICENSE.txt for license information.
0006 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0007 //
0008 //===----------------------------------------------------------------------===//
0009 
0010 #ifndef _LIBCPP_SYNCSTREAM
0011 #define _LIBCPP_SYNCSTREAM
0012 
0013 /*
0014     syncstream synopsis
0015 
0016 #include <ostream>  // see [ostream.syn]
0017 
0018 namespace std {
0019     template<class charT, class traits, class Allocator>
0020     class basic_syncbuf;
0021 
0022     // [syncstream.syncbuf.special], specialized algorithms
0023     template<class charT, class traits, class Allocator>
0024       void swap(basic_syncbuf<charT, traits, Allocator>&,
0025                 basic_syncbuf<charT, traits, Allocator>&);
0026 
0027     using syncbuf = basic_syncbuf<char>;
0028     using wsyncbuf = basic_syncbuf<wchar_t>;
0029 
0030     template<class charT, class traits, class Allocator>
0031     class basic_osyncstream;
0032 
0033     using osyncstream = basic_osyncstream<char>;
0034     using wosyncstream = basic_osyncstream<wchar_t>;
0035 
0036     template<class charT, class traits, class Allocator>
0037     class basic_syncbuf : public basic_streambuf<charT, traits> {
0038     public:
0039         using char_type      = charT;
0040         using int_type       = typename traits::int_type;
0041         using pos_type       = typename traits::pos_type;
0042         using off_type       = typename traits::off_type;
0043         using traits_type    = traits;
0044         using allocator_type = Allocator;
0045 
0046         using streambuf_type = basic_streambuf<charT, traits>;
0047 
0048         // [syncstream.syncbuf.cons], construction and destruction
0049         basic_syncbuf()
0050           : basic_syncbuf(nullptr) {}
0051         explicit basic_syncbuf(streambuf_type* obuf)
0052           : basic_syncbuf(obuf, Allocator()) {}
0053         basic_syncbuf(streambuf_type*, const Allocator&);
0054         basic_syncbuf(basic_syncbuf&&);
0055         ~basic_syncbuf();
0056 
0057         // [syncstream.syncbuf.assign], assignment and swap
0058         basic_syncbuf& operator=(basic_syncbuf&&);
0059         void swap(basic_syncbuf&);
0060 
0061         // [syncstream.syncbuf.members], member functions
0062         bool emit();
0063         streambuf_type* get_wrapped() const noexcept;
0064         allocator_type get_allocator() const noexcept;
0065         void set_emit_on_sync(bool) noexcept;
0066 
0067     protected:
0068         // [syncstream.syncbuf.virtuals], overridden virtual functions
0069         int sync() override;
0070 
0071     private:
0072         streambuf_type* wrapped;    // exposition only
0073         bool emit_on_sync{};        // exposition only
0074     };
0075 
0076     // [syncstream.syncbuf.special], specialized algorithms
0077     template<class charT, class traits, class Allocator>
0078     void swap(basic_syncbuf<charT, traits, Allocator>&,
0079               basic_syncbuf<charT, traits, Allocator>&);
0080 
0081     template<class charT, class traits, class Allocator>
0082     class basic_osyncstream : public basic_ostream<charT, traits> {
0083     public:
0084         using char_type   = charT;
0085         using int_type    = typename traits::int_type;
0086         using pos_type    = typename traits::pos_type;
0087         using off_type    = typename traits::off_type;
0088         using traits_type = traits;
0089 
0090         using allocator_type = Allocator;
0091         using streambuf_type = basic_streambuf<charT, traits>;
0092         using syncbuf_type   = basic_syncbuf<charT, traits, Allocator>;
0093 
0094         // [syncstream.osyncstream.cons], construction and destruction
0095         basic_osyncstream(streambuf_type*, const Allocator&);
0096         explicit basic_osyncstream(streambuf_type* obuf)
0097           : basic_osyncstream(obuf, Allocator()) {}
0098         basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)
0099           : basic_osyncstream(os.rdbuf(), allocator) {}
0100         explicit basic_osyncstream(basic_ostream<charT, traits>& os)
0101           : basic_osyncstream(os, Allocator()) {}
0102         basic_osyncstream(basic_osyncstream&&) noexcept;
0103         ~basic_osyncstream();
0104 
0105         // [syncstream.osyncstream.assign], assignment
0106         basic_osyncstream& operator=(basic_osyncstream&&);
0107 
0108         // [syncstream.osyncstream.members], member functions
0109         void emit();
0110         streambuf_type* get_wrapped() const noexcept;
0111         syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }
0112 
0113     private:
0114         syncbuf_type sb;    // exposition only
0115     };
0116 }
0117 
0118 */
0119 
0120 #if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
0121 #  include <__cxx03/syncstream>
0122 #else
0123 #  include <__config>
0124 
0125 #  if _LIBCPP_HAS_LOCALIZATION
0126 
0127 #    include <__mutex/lock_guard.h>
0128 #    include <__utility/move.h>
0129 #    include <ios>
0130 #    include <iosfwd> // required for declaration of default arguments
0131 #    include <streambuf>
0132 #    include <string>
0133 
0134 #    if _LIBCPP_HAS_THREADS
0135 #      include <map>
0136 #      include <shared_mutex>
0137 #    endif
0138 
0139 // standard-mandated includes
0140 
0141 // [syncstream.syn]
0142 #    include <ostream>
0143 
0144 #    if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0145 #      pragma GCC system_header
0146 #    endif
0147 
0148 _LIBCPP_PUSH_MACROS
0149 #    include <__undef_macros>
0150 
0151 _LIBCPP_BEGIN_NAMESPACE_STD
0152 
0153 #    if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM
0154 
0155 // [syncstream.syncbuf.overview]/1
0156 //   Class template basic_syncbuf stores character data written to it,
0157 //   known as the associated output, into internal buffers allocated
0158 //   using the object's allocator. The associated output is transferred
0159 //   to the wrapped stream buffer object *wrapped when emit() is called
0160 //   or when the basic_syncbuf object is destroyed. Such transfers are
0161 //   atomic with respect to transfers by other basic_syncbuf objects
0162 //   with the same wrapped stream buffer object.
0163 //
0164 // This helper singleton is used to implement the required
0165 // synchronisation guarantees.
0166 #      if _LIBCPP_HAS_THREADS
0167 class __wrapped_streambuf_mutex {
0168   _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default;
0169 
0170 public:
0171   __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&)            = delete;
0172   __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete;
0173 
0174   _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) {
0175     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
0176     unique_lock __lock{__mutex_};
0177     ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count;
0178   }
0179 
0180   // pre: __ptr is in __lut_
0181   _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept {
0182     unique_lock __lock{__mutex_};
0183 
0184     auto __it = __get_it(__ptr);
0185     if (__it->second.__count == 1)
0186       __lut_.erase(__it);
0187     else
0188       --__it->second.__count;
0189   }
0190 
0191   // TODO
0192   // This function causes emit() aquire two mutexes:
0193   // - __mutex_ shared
0194   // _ __get_it(__ptr)->second.__mutex exclusive
0195   //
0196   // Instead store a pointer to __get_it(__ptr)->second.__mutex when
0197   // calling __inc_reference.
0198   //
0199   // pre: __ptr is in __lut_
0200   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept {
0201     shared_lock __lock{__mutex_};
0202     return lock_guard{__get_it(__ptr)->second.__mutex};
0203   }
0204 
0205   // This function is used for testing.
0206   //
0207   // It is allowed to call this function with a non-registered pointer.
0208   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept {
0209     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
0210     shared_lock __lock{__mutex_};
0211 
0212     auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
0213     return __it != __lut_.end() ? __it->second.__count : 0;
0214   }
0215 
0216   [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept {
0217     static __wrapped_streambuf_mutex __result;
0218     return __result;
0219   }
0220 
0221 private:
0222   struct __value {
0223     mutex __mutex;
0224     size_t __count{0};
0225   };
0226 
0227   shared_mutex __mutex_;
0228   map<uintptr_t, __value> __lut_;
0229 
0230   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept {
0231     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
0232 
0233     auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
0234     _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered");
0235     _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper");
0236     return __it;
0237   }
0238 };
0239 #      endif // _LIBCPP_HAS_THREADS
0240 
0241 // basic_syncbuf
0242 
0243 // The class uses a basic_string<_CharT, _Traits, _Allocator> as
0244 // internal buffer. Per [syncstream.syncbuf.cons]/4
0245 //   Remarks: A copy of allocator is used to allocate memory for
0246 //   internal buffers holding the associated output.
0247 //
0248 // Therefore the allocator used in the constructor is passed to the
0249 // basic_string. The class does not keep a copy of this allocator.
0250 template <class _CharT, class _Traits, class _Allocator>
0251 class _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> {
0252 public:
0253   using char_type      = _CharT;
0254   using traits_type    = _Traits;
0255   using int_type       = typename traits_type::int_type;
0256   using pos_type       = typename traits_type::pos_type;
0257   using off_type       = typename traits_type::off_type;
0258   using allocator_type = _Allocator;
0259 
0260   using streambuf_type = basic_streambuf<_CharT, _Traits>;
0261 
0262   // [syncstream.syncbuf.cons], construction and destruction
0263 
0264   _LIBCPP_HIDE_FROM_ABI basic_syncbuf() : basic_syncbuf(nullptr) {}
0265 
0266   _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf) : basic_syncbuf(__obuf, _Allocator()) {}
0267 
0268   _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc)
0269       : __wrapped_(__obuf), __str_(__alloc) {
0270     __inc_reference();
0271   }
0272 
0273   _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other)
0274       : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) {
0275     __move_common(__other);
0276   }
0277 
0278   _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() {
0279 #      if _LIBCPP_HAS_EXCEPTIONS
0280     try {
0281 #      endif // _LIBCPP_HAS_EXCEPTIONS
0282       emit();
0283 #      if _LIBCPP_HAS_EXCEPTIONS
0284     } catch (...) {
0285     }
0286 #      endif // _LIBCPP_HAS_EXCEPTIONS
0287     __dec_reference();
0288   }
0289 
0290   // [syncstream.syncbuf.assign], assignment and swap
0291 
0292   _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) {
0293     // The function is specified to call emit. This call should
0294     // propagate the exception thrown.
0295     emit();
0296     __dec_reference();
0297 
0298     __wrapped_      = __other.get_wrapped();
0299     __str_          = std::move(__other.__str_);
0300     __emit_on_sync_ = __other.__emit_on_sync_;
0301 
0302     __move_common(__other);
0303 
0304     return *this;
0305   }
0306 
0307   _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) {
0308     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
0309         allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(),
0310         "violates the mandated swap precondition");
0311 
0312     basic_syncbuf __tmp(std::move(__other));
0313     __other = std::move(*this);
0314     *this   = std::move(__tmp);
0315   }
0316 
0317   // [syncstream.syncbuf.members], member functions
0318 
0319   _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }
0320 
0321   _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
0322 
0323   _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
0324 
0325   _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }
0326 
0327 protected:
0328   // [syncstream.syncbuf.virtuals], overridden virtual functions
0329 
0330   _LIBCPP_HIDE_FROM_ABI_VIRTUAL
0331   int sync() override {
0332     if (__emit_on_sync_ && !emit(true))
0333       return -1;
0334     return 0;
0335   }
0336 
0337   _LIBCPP_HIDE_FROM_ABI_VIRTUAL
0338   int_type overflow(int_type __c = traits_type::eof()) override {
0339     if (traits_type::eq_int_type(__c, traits_type::eof()))
0340       return traits_type::not_eof(__c);
0341 
0342     if (this->pptr() == this->epptr()) {
0343 #      if _LIBCPP_HAS_EXCEPTIONS
0344       try {
0345 #      endif
0346         size_t __size = __str_.size();
0347         __str_.resize(__str_.capacity() + 1);
0348         _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown");
0349 
0350         char_type* __p = static_cast<char_type*>(__str_.data());
0351         this->setp(__p, __p + __str_.size());
0352         this->pbump(__size);
0353 
0354 #      if _LIBCPP_HAS_EXCEPTIONS
0355       } catch (...) {
0356         return traits_type::eof();
0357       }
0358 #      endif
0359     }
0360 
0361     return this->sputc(traits_type::to_char_type(__c));
0362   }
0363 
0364 private:
0365   streambuf_type* __wrapped_;
0366 
0367   // TODO Use a more generic buffer.
0368   // That buffer should be light with almost no additional headers. Then
0369   // it can be use here, the __retarget_buffer, and place that use
0370   // the now removed get_temporary_buffer
0371 
0372   basic_string<_CharT, _Traits, _Allocator> __str_;
0373   bool __emit_on_sync_{false};
0374 
0375   _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {
0376     if (!__wrapped_)
0377       return false;
0378 
0379 #      if _LIBCPP_HAS_THREADS
0380     lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_);
0381 #      endif
0382 
0383     bool __result = true;
0384     if (this->pptr() != this->pbase()) {
0385       _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid");
0386 
0387       // The __str_ does not know how much of its buffer is used. This
0388       // information is extracted from the information of the base class.
0389       __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1);
0390       // Clears the buffer, but keeps the contents (and) size of the
0391       // internal buffer.
0392       this->setp(this->pbase(), this->epptr());
0393     }
0394 
0395     if (__flush)
0396       __result &= (__wrapped_->pubsync() != -1);
0397 
0398     return __result;
0399   }
0400 
0401   _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) {
0402     // Adjust the put area pointers to our buffer.
0403     char_type* __p = static_cast<char_type*>(__str_.data());
0404     this->setp(__p, __p + __str_.size());
0405     this->pbump(__other.pptr() - __other.pbase());
0406 
0407     // Clear __other_ so the destructor will act as a NOP.
0408     __other.setp(nullptr, nullptr);
0409     __other.__wrapped_ = nullptr;
0410   }
0411 
0412   _LIBCPP_HIDE_FROM_ABI void __inc_reference() {
0413 #      if _LIBCPP_HAS_THREADS
0414     if (__wrapped_)
0415       __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_);
0416 #      endif
0417   }
0418 
0419   _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept {
0420 #      if _LIBCPP_HAS_THREADS
0421     if (__wrapped_)
0422       __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_);
0423 #      endif
0424   }
0425 };
0426 
0427 using std::syncbuf;
0428 #      if _LIBCPP_HAS_WIDE_CHARACTERS
0429 using std::wsyncbuf;
0430 #      endif
0431 
0432 // [syncstream.syncbuf.special], specialized algorithms
0433 template <class _CharT, class _Traits, class _Allocator>
0434 _LIBCPP_HIDE_FROM_ABI void
0435 swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) {
0436   __lhs.swap(__rhs);
0437 }
0438 
0439 // basic_osyncstream
0440 
0441 template <class _CharT, class _Traits, class _Allocator>
0442 class _LIBCPP_TEMPLATE_VIS basic_osyncstream : public basic_ostream<_CharT, _Traits> {
0443 public:
0444   using char_type   = _CharT;
0445   using traits_type = _Traits;
0446   using int_type    = typename traits_type::int_type;
0447   using pos_type    = typename traits_type::pos_type;
0448   using off_type    = typename traits_type::off_type;
0449 
0450   using allocator_type = _Allocator;
0451   using streambuf_type = basic_streambuf<char_type, traits_type>;
0452   using syncbuf_type   = basic_syncbuf<char_type, traits_type, allocator_type>;
0453 
0454   // [syncstream.osyncstream.cons], construction and destruction
0455 
0456   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc)
0457       : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {}
0458 
0459   _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf)
0460       : basic_osyncstream(__obuf, allocator_type()) {}
0461 
0462   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc)
0463       : basic_osyncstream(__os.rdbuf(), __alloc) {}
0464 
0465   _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
0466       : basic_osyncstream(__os, allocator_type()) {}
0467 
0468   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept
0469       : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) {
0470     this->set_rdbuf(std::addressof(__sb_));
0471   }
0472 
0473   // [syncstream.osyncstream.assign], assignment
0474 
0475   _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default;
0476 
0477   // [syncstream.osyncstream.members], member functions
0478 
0479   _LIBCPP_HIDE_FROM_ABI void emit() {
0480     // The basic_ostream::put places the sentry in a try
0481     // catch, this does not match the wording of the standard
0482     // [ostream.unformatted]
0483     // TODO validate other unformatted output functions.
0484     typename basic_ostream<char_type, traits_type>::sentry __s(*this);
0485     if (__s) {
0486 #      if _LIBCPP_HAS_EXCEPTIONS
0487       try {
0488 #      endif
0489 
0490         if (__sb_.emit() == false)
0491           this->setstate(ios::badbit);
0492 #      if _LIBCPP_HAS_EXCEPTIONS
0493       } catch (...) {
0494         this->__set_badbit_and_consider_rethrow();
0495       }
0496 #      endif
0497     }
0498   }
0499 
0500   _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
0501 
0502   _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
0503     return const_cast<syncbuf_type*>(std::addressof(__sb_));
0504   }
0505 
0506 private:
0507   syncbuf_type __sb_;
0508 };
0509 
0510 using std::osyncstream;
0511 #      if _LIBCPP_HAS_WIDE_CHARACTERS
0512 using std::wosyncstream;
0513 #      endif
0514 
0515 #    endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM
0516 
0517 _LIBCPP_END_NAMESPACE_STD
0518 
0519 _LIBCPP_POP_MACROS
0520 
0521 #  endif // _LIBCPP_HAS_LOCALIZATION
0522 #endif   // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
0523 
0524 #endif // _LIBCPP_SYNCSTREAM