Back to home page

EIC code displayed by LXR

 
 

    


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