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