syncstream 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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-exception
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #ifndef _LIBCPP_SYNCSTREAM
  10. #define _LIBCPP_SYNCSTREAM
  11. /*
  12. syncstream synopsis
  13. #include <ostream> // see [ostream.syn]
  14. namespace std {
  15. template<class charT, class traits, class Allocator>
  16. class basic_syncbuf;
  17. // [syncstream.syncbuf.special], specialized algorithms
  18. template<class charT, class traits, class Allocator>
  19. void swap(basic_syncbuf<charT, traits, Allocator>&,
  20. basic_syncbuf<charT, traits, Allocator>&);
  21. using syncbuf = basic_syncbuf<char>;
  22. using wsyncbuf = basic_syncbuf<wchar_t>;
  23. template<class charT, class traits, class Allocator>
  24. class basic_osyncstream;
  25. using osyncstream = basic_osyncstream<char>;
  26. using wosyncstream = basic_osyncstream<wchar_t>;
  27. template<class charT, class traits, class Allocator>
  28. class basic_syncbuf : public basic_streambuf<charT, traits> {
  29. public:
  30. using char_type = charT;
  31. using int_type = typename traits::int_type;
  32. using pos_type = typename traits::pos_type;
  33. using off_type = typename traits::off_type;
  34. using traits_type = traits;
  35. using allocator_type = Allocator;
  36. using streambuf_type = basic_streambuf<charT, traits>;
  37. // [syncstream.syncbuf.cons], construction and destruction
  38. explicit basic_syncbuf(streambuf_type* obuf = nullptr)
  39. : basic_syncbuf(obuf, Allocator()) {}
  40. basic_syncbuf(streambuf_type*, const Allocator&);
  41. basic_syncbuf(basic_syncbuf&&);
  42. ~basic_syncbuf();
  43. // [syncstream.syncbuf.assign], assignment and swap
  44. basic_syncbuf& operator=(basic_syncbuf&&);
  45. void swap(basic_syncbuf&);
  46. // [syncstream.syncbuf.members], member functions
  47. bool emit();
  48. streambuf_type* get_wrapped() const noexcept;
  49. allocator_type get_allocator() const noexcept;
  50. void set_emit_on_sync(bool) noexcept;
  51. protected:
  52. // [syncstream.syncbuf.virtuals], overridden virtual functions
  53. int sync() override;
  54. private:
  55. streambuf_type* wrapped; // exposition only
  56. bool emit_on_sync{}; // exposition only
  57. };
  58. // [syncstream.syncbuf.special], specialized algorithms
  59. template<class charT, class traits, class Allocator>
  60. void swap(basic_syncbuf<charT, traits, Allocator>&,
  61. basic_syncbuf<charT, traits, Allocator>&);
  62. template<class charT, class traits, class Allocator>
  63. class basic_osyncstream : public basic_ostream<charT, traits> {
  64. public:
  65. using char_type = charT;
  66. using int_type = typename traits::int_type;
  67. using pos_type = typename traits::pos_type;
  68. using off_type = typename traits::off_type;
  69. using traits_type = traits;
  70. using allocator_type = Allocator;
  71. using streambuf_type = basic_streambuf<charT, traits>;
  72. using syncbuf_type = basic_syncbuf<charT, traits, Allocator>;
  73. // [syncstream.osyncstream.cons], construction and destruction
  74. basic_osyncstream(streambuf_type*, const Allocator&);
  75. explicit basic_osyncstream(streambuf_type* obuf)
  76. : basic_osyncstream(obuf, Allocator()) {}
  77. basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)
  78. : basic_osyncstream(os.rdbuf(), allocator) {}
  79. explicit basic_osyncstream(basic_ostream<charT, traits>& os)
  80. : basic_osyncstream(os, Allocator()) {}
  81. basic_osyncstream(basic_osyncstream&&) noexcept;
  82. ~basic_osyncstream();
  83. // [syncstream.osyncstream.assign], assignment
  84. basic_osyncstream& operator=(basic_osyncstream&&);
  85. // [syncstream.osyncstream.members], member functions
  86. void emit();
  87. streambuf_type* get_wrapped() const noexcept;
  88. syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }
  89. private:
  90. syncbuf_type sb; // exposition only
  91. };
  92. }
  93. */
  94. #include <__config>
  95. #include <__utility/move.h>
  96. #include <iosfwd> // required for declaration of default arguments
  97. #include <string>
  98. #ifndef _LIBCPP_HAS_NO_THREADS
  99. # include <map>
  100. # include <mutex>
  101. # include <shared_mutex>
  102. #endif
  103. // standard-mandated includes
  104. // [syncstream.syn]
  105. #include <ostream>
  106. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  107. # pragma GCC system_header
  108. #endif
  109. _LIBCPP_PUSH_MACROS
  110. #include <__undef_macros>
  111. _LIBCPP_BEGIN_NAMESPACE_STD
  112. #if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
  113. // [syncstream.syncbuf.overview]/1
  114. // Class template basic_syncbuf stores character data written to it,
  115. // known as the associated output, into internal buffers allocated
  116. // using the object's allocator. The associated output is transferred
  117. // to the wrapped stream buffer object *wrapped when emit() is called
  118. // or when the basic_syncbuf object is destroyed. Such transfers are
  119. // atomic with respect to transfers by other basic_syncbuf objects
  120. // with the same wrapped stream buffer object.
  121. //
  122. // This helper singleton is used to implement the required
  123. // synchronisation guarantees.
  124. # ifndef _LIBCPP_HAS_NO_THREADS
  125. class __wrapped_streambuf_mutex {
  126. _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default;
  127. public:
  128. __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&) = delete;
  129. __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete;
  130. _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) {
  131. _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
  132. unique_lock __lock{__mutex_};
  133. ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count;
  134. }
  135. // pre: __ptr is in __lut_
  136. _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept {
  137. unique_lock __lock{__mutex_};
  138. auto __it = __get_it(__ptr);
  139. if (__it->second.__count == 1)
  140. __lut_.erase(__it);
  141. else
  142. --__it->second.__count;
  143. }
  144. // TODO
  145. // This function causes emit() aquire two mutexes:
  146. // - __mutex_ shared
  147. // _ __get_it(__ptr)->second.__mutex exclusive
  148. //
  149. // Instead store a pointer to __get_it(__ptr)->second.__mutex when
  150. // calling __inc_reference.
  151. //
  152. // pre: __ptr is in __lut_
  153. [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept {
  154. shared_lock __lock{__mutex_};
  155. return lock_guard{__get_it(__ptr)->second.__mutex};
  156. }
  157. // This function is used for testing.
  158. //
  159. // It is allowed to call this function with a non-registered pointer.
  160. [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept {
  161. _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
  162. shared_lock __lock{__mutex_};
  163. auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
  164. return __it != __lut_.end() ? __it->second.__count : 0;
  165. }
  166. [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept {
  167. static __wrapped_streambuf_mutex __result;
  168. return __result;
  169. }
  170. private:
  171. struct __value {
  172. mutex __mutex;
  173. size_t __count{0};
  174. };
  175. shared_mutex __mutex_;
  176. map<uintptr_t, __value> __lut_;
  177. [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept {
  178. _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
  179. auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
  180. _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered");
  181. _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper");
  182. return __it;
  183. }
  184. };
  185. # endif // _LIBCPP_HAS_NO_THREADS
  186. // basic_syncbuf
  187. // The class uses a basic_string<_CharT, _Traits, _Allocator> as
  188. // internal buffer. Per [syncstream.syncbuf.cons]/4
  189. // Remarks: A copy of allocator is used to allocate memory for
  190. // internal buffers holding the associated output.
  191. //
  192. // Therefore the allocator used in the constructor is passed to the
  193. // basic_string. The class does not keep a copy of this allocator.
  194. template <class _CharT, class _Traits, class _Allocator>
  195. class _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> {
  196. public:
  197. using char_type = _CharT;
  198. using traits_type = _Traits;
  199. using int_type = typename traits_type::int_type;
  200. using pos_type = typename traits_type::pos_type;
  201. using off_type = typename traits_type::off_type;
  202. using allocator_type = _Allocator;
  203. using streambuf_type = basic_streambuf<_CharT, _Traits>;
  204. // [syncstream.syncbuf.cons], construction and destruction
  205. _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf = nullptr)
  206. : basic_syncbuf(__obuf, _Allocator()) {}
  207. _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc)
  208. : __wrapped_(__obuf), __str_(__alloc) {
  209. __inc_reference();
  210. }
  211. _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other)
  212. : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) {
  213. __move_common(__other);
  214. }
  215. _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() {
  216. # ifndef _LIBCPP_HAS_NO_EXCEPTIONS
  217. try {
  218. # endif // _LIBCPP_HAS_NO_EXCEPTIONS
  219. emit();
  220. # ifndef _LIBCPP_HAS_NO_EXCEPTIONS
  221. } catch (...) {
  222. }
  223. # endif // _LIBCPP_HAS_NO_EXCEPTIONS
  224. __dec_reference();
  225. }
  226. // [syncstream.syncbuf.assign], assignment and swap
  227. _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) {
  228. // The function is specified to call emit. This call should
  229. // propagate the exception thrown.
  230. emit();
  231. __dec_reference();
  232. __wrapped_ = __other.get_wrapped();
  233. __str_ = std::move(__other.__str_);
  234. __emit_on_sync_ = __other.__emit_on_sync_;
  235. __move_common(__other);
  236. return *this;
  237. }
  238. _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) {
  239. _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
  240. allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(),
  241. "violates the mandated swap precondition");
  242. basic_syncbuf __tmp(std::move(__other));
  243. __other = std::move(*this);
  244. *this = std::move(__tmp);
  245. }
  246. // [syncstream.syncbuf.members], member functions
  247. _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }
  248. _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
  249. _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
  250. _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }
  251. protected:
  252. // [syncstream.syncbuf.virtuals], overridden virtual functions
  253. _LIBCPP_HIDE_FROM_ABI_VIRTUAL
  254. int sync() override {
  255. if (__emit_on_sync_ && !emit(true))
  256. return -1;
  257. return 0;
  258. }
  259. _LIBCPP_HIDE_FROM_ABI_VIRTUAL
  260. int_type overflow(int_type __c = traits_type::eof()) override {
  261. if (traits_type::eq_int_type(__c, traits_type::eof()))
  262. return traits_type::not_eof(__c);
  263. if (this->pptr() == this->epptr()) {
  264. # ifndef _LIBCPP_HAS_NO_EXCEPTIONS
  265. try {
  266. # endif
  267. size_t __size = __str_.size();
  268. __str_.resize(__str_.capacity() + 1);
  269. _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown");
  270. char_type* __p = static_cast<char_type*>(__str_.data());
  271. this->setp(__p, __p + __str_.size());
  272. this->pbump(__size);
  273. # ifndef _LIBCPP_HAS_NO_EXCEPTIONS
  274. } catch (...) {
  275. return traits_type::eof();
  276. }
  277. # endif
  278. }
  279. return this->sputc(traits_type::to_char_type(__c));
  280. }
  281. private:
  282. streambuf_type* __wrapped_;
  283. // TODO Use a more generic buffer.
  284. // That buffer should be light with almost no additional headers. Then
  285. // it can be use here, the __retarget_buffer, and place that use
  286. // the now deprecated get_temporary_buffer
  287. basic_string<_CharT, _Traits, _Allocator> __str_;
  288. bool __emit_on_sync_{false};
  289. _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {
  290. if (!__wrapped_)
  291. return false;
  292. # ifndef _LIBCPP_HAS_NO_THREADS
  293. lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_);
  294. # endif
  295. bool __result = true;
  296. if (this->pptr() != this->pbase()) {
  297. _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid");
  298. // The __str_ does not know how much of its buffer is used. This
  299. // information is extracted from the information of the base class.
  300. __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1);
  301. // Clears the buffer, but keeps the contents (and) size of the
  302. // internal buffer.
  303. this->setp(this->pbase(), this->epptr());
  304. }
  305. if (__flush)
  306. __result &= (__wrapped_->pubsync() != -1);
  307. return __result;
  308. }
  309. _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) {
  310. // Adjust the put area pointers to our buffer.
  311. char_type* __p = static_cast<char_type*>(__str_.data());
  312. this->setp(__p, __p + __str_.size());
  313. this->pbump(__other.pptr() - __other.pbase());
  314. // Clear __other_ so the destructor will act as a NOP.
  315. __other.setp(nullptr, nullptr);
  316. __other.__wrapped_ = nullptr;
  317. }
  318. _LIBCPP_HIDE_FROM_ABI void __inc_reference() {
  319. # ifndef _LIBCPP_HAS_NO_THREADS
  320. if (__wrapped_)
  321. __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_);
  322. # endif
  323. }
  324. _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept {
  325. # ifndef _LIBCPP_HAS_NO_THREADS
  326. if (__wrapped_)
  327. __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_);
  328. # endif
  329. }
  330. };
  331. using std::syncbuf;
  332. # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
  333. using std::wsyncbuf;
  334. # endif
  335. // [syncstream.syncbuf.special], specialized algorithms
  336. template <class _CharT, class _Traits, class _Allocator>
  337. _LIBCPP_HIDE_FROM_ABI void
  338. swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) {
  339. __lhs.swap(__rhs);
  340. }
  341. // basic_osyncstream
  342. template <class _CharT, class _Traits, class _Allocator>
  343. class _LIBCPP_TEMPLATE_VIS basic_osyncstream : public basic_ostream<_CharT, _Traits> {
  344. public:
  345. using char_type = _CharT;
  346. using traits_type = _Traits;
  347. using int_type = typename traits_type::int_type;
  348. using pos_type = typename traits_type::pos_type;
  349. using off_type = typename traits_type::off_type;
  350. using allocator_type = _Allocator;
  351. using streambuf_type = basic_streambuf<char_type, traits_type>;
  352. using syncbuf_type = basic_syncbuf<char_type, traits_type, allocator_type>;
  353. // [syncstream.osyncstream.cons], construction and destruction
  354. _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc)
  355. : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {}
  356. _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf)
  357. : basic_osyncstream(__obuf, allocator_type()) {}
  358. _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc)
  359. : basic_osyncstream(__os.rdbuf(), __alloc) {}
  360. _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
  361. : basic_osyncstream(__os, allocator_type()) {}
  362. _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept
  363. : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) {
  364. this->set_rdbuf(std::addressof(__sb_));
  365. }
  366. // [syncstream.osyncstream.assign], assignment
  367. _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default;
  368. // [syncstream.osyncstream.members], member functions
  369. _LIBCPP_HIDE_FROM_ABI void emit() {
  370. // The basic_ostream::put places the sentry in a try
  371. // catch, this does not match the wording of the standard
  372. // [ostream.unformatted]
  373. // TODO validate other unformatted output functions.
  374. typename basic_ostream<char_type, traits_type>::sentry __s(*this);
  375. if (__s) {
  376. # ifndef _LIBCPP_HAS_NO_EXCEPTIONS
  377. try {
  378. # endif
  379. if (__sb_.emit() == false)
  380. this->setstate(ios::badbit);
  381. # ifndef _LIBCPP_HAS_NO_EXCEPTIONS
  382. } catch (...) {
  383. this->__set_badbit_and_consider_rethrow();
  384. }
  385. # endif
  386. }
  387. }
  388. _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
  389. _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
  390. return const_cast<syncbuf_type*>(std::addressof(__sb_));
  391. }
  392. private:
  393. syncbuf_type __sb_;
  394. };
  395. using std::osyncstream;
  396. # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
  397. using std::wosyncstream;
  398. # endif
  399. #endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
  400. _LIBCPP_END_NAMESPACE_STD
  401. _LIBCPP_POP_MACROS
  402. #endif // _LIBCPP_SYNCSTREAM