[rtsan] Remove mkfifoat interceptor (#116997)
[llvm-project.git] / libcxx / include / __cxx03 / syncstream
blob4e67b43f3ccb9e193100d3248f19a90e7aa84702
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 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP_SYNCSTREAM
11 #define _LIBCPP_SYNCSTREAM
14     syncstream synopsis
16 #include <__cxx03/ostream>  // see [ostream.syn]
18 namespace std {
19     template<class charT, class traits, class Allocator>
20     class basic_syncbuf;
22     // [syncstream.syncbuf.special], specialized algorithms
23     template<class charT, class traits, class Allocator>
24       void swap(basic_syncbuf<charT, traits, Allocator>&,
25                 basic_syncbuf<charT, traits, Allocator>&);
27     using syncbuf = basic_syncbuf<char>;
28     using wsyncbuf = basic_syncbuf<wchar_t>;
30     template<class charT, class traits, class Allocator>
31     class basic_osyncstream;
33     using osyncstream = basic_osyncstream<char>;
34     using wosyncstream = basic_osyncstream<wchar_t>;
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;
46         using streambuf_type = basic_streambuf<charT, traits>;
48         // [syncstream.syncbuf.cons], construction and destruction
49         explicit basic_syncbuf(streambuf_type* obuf = nullptr)
50           : basic_syncbuf(obuf, Allocator()) {}
51         basic_syncbuf(streambuf_type*, const Allocator&);
52         basic_syncbuf(basic_syncbuf&&);
53         ~basic_syncbuf();
55         // [syncstream.syncbuf.assign], assignment and swap
56         basic_syncbuf& operator=(basic_syncbuf&&);
57         void swap(basic_syncbuf&);
59         // [syncstream.syncbuf.members], member functions
60         bool emit();
61         streambuf_type* get_wrapped() const noexcept;
62         allocator_type get_allocator() const noexcept;
63         void set_emit_on_sync(bool) noexcept;
65     protected:
66         // [syncstream.syncbuf.virtuals], overridden virtual functions
67         int sync() override;
69     private:
70         streambuf_type* wrapped;    // exposition only
71         bool emit_on_sync{};        // exposition only
72     };
74     // [syncstream.syncbuf.special], specialized algorithms
75     template<class charT, class traits, class Allocator>
76     void swap(basic_syncbuf<charT, traits, Allocator>&,
77               basic_syncbuf<charT, traits, Allocator>&);
79     template<class charT, class traits, class Allocator>
80     class basic_osyncstream : public basic_ostream<charT, traits> {
81     public:
82         using char_type   = charT;
83         using int_type    = typename traits::int_type;
84         using pos_type    = typename traits::pos_type;
85         using off_type    = typename traits::off_type;
86         using traits_type = traits;
88         using allocator_type = Allocator;
89         using streambuf_type = basic_streambuf<charT, traits>;
90         using syncbuf_type   = basic_syncbuf<charT, traits, Allocator>;
92         // [syncstream.osyncstream.cons], construction and destruction
93         basic_osyncstream(streambuf_type*, const Allocator&);
94         explicit basic_osyncstream(streambuf_type* obuf)
95           : basic_osyncstream(obuf, Allocator()) {}
96         basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)
97           : basic_osyncstream(os.rdbuf(), allocator) {}
98         explicit basic_osyncstream(basic_ostream<charT, traits>& os)
99           : basic_osyncstream(os, Allocator()) {}
100         basic_osyncstream(basic_osyncstream&&) noexcept;
101         ~basic_osyncstream();
103         // [syncstream.osyncstream.assign], assignment
104         basic_osyncstream& operator=(basic_osyncstream&&);
106         // [syncstream.osyncstream.members], member functions
107         void emit();
108         streambuf_type* get_wrapped() const noexcept;
109         syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }
111     private:
112         syncbuf_type sb;    // exposition only
113     };
118 #include <__cxx03/__config>
119 #include <__cxx03/__utility/move.h>
120 #include <__cxx03/ios>
121 #include <__cxx03/iosfwd> // required for declaration of default arguments
122 #include <__cxx03/streambuf>
123 #include <__cxx03/string>
125 #ifndef _LIBCPP_HAS_NO_THREADS
126 #  include <__cxx03/map>
127 #  include <__cxx03/mutex>
128 #  include <__cxx03/shared_mutex>
129 #endif
131 // standard-mandated includes
133 // [syncstream.syn]
134 #include <__cxx03/ostream>
136 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
137 #  pragma GCC system_header
138 #endif
140 _LIBCPP_PUSH_MACROS
141 #include <__cxx03/__undef_macros>
143 _LIBCPP_BEGIN_NAMESPACE_STD
145 #if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
147 // [syncstream.syncbuf.overview]/1
148 //   Class template basic_syncbuf stores character data written to it,
149 //   known as the associated output, into internal buffers allocated
150 //   using the object's allocator. The associated output is transferred
151 //   to the wrapped stream buffer object *wrapped when emit() is called
152 //   or when the basic_syncbuf object is destroyed. Such transfers are
153 //   atomic with respect to transfers by other basic_syncbuf objects
154 //   with the same wrapped stream buffer object.
156 // This helper singleton is used to implement the required
157 // synchronisation guarantees.
158 #  ifndef _LIBCPP_HAS_NO_THREADS
159 class __wrapped_streambuf_mutex {
160   _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default;
162 public:
163   __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&)            = delete;
164   __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete;
166   _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) {
167     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
168     unique_lock __lock{__mutex_};
169     ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count;
170   }
172   // pre: __ptr is in __lut_
173   _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept {
174     unique_lock __lock{__mutex_};
176     auto __it = __get_it(__ptr);
177     if (__it->second.__count == 1)
178       __lut_.erase(__it);
179     else
180       --__it->second.__count;
181   }
183   // TODO
184   // This function causes emit() aquire two mutexes:
185   // - __mutex_ shared
186   // _ __get_it(__ptr)->second.__mutex exclusive
187   //
188   // Instead store a pointer to __get_it(__ptr)->second.__mutex when
189   // calling __inc_reference.
190   //
191   // pre: __ptr is in __lut_
192   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept {
193     shared_lock __lock{__mutex_};
194     return lock_guard{__get_it(__ptr)->second.__mutex};
195   }
197   // This function is used for testing.
198   //
199   // It is allowed to call this function with a non-registered pointer.
200   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept {
201     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
202     shared_lock __lock{__mutex_};
204     auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
205     return __it != __lut_.end() ? __it->second.__count : 0;
206   }
208   [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept {
209     static __wrapped_streambuf_mutex __result;
210     return __result;
211   }
213 private:
214   struct __value {
215     mutex __mutex;
216     size_t __count{0};
217   };
219   shared_mutex __mutex_;
220   map<uintptr_t, __value> __lut_;
222   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept {
223     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
225     auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
226     _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered");
227     _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper");
228     return __it;
229   }
231 #  endif // _LIBCPP_HAS_NO_THREADS
233 // basic_syncbuf
235 // The class uses a basic_string<_CharT, _Traits, _Allocator> as
236 // internal buffer. Per [syncstream.syncbuf.cons]/4
237 //   Remarks: A copy of allocator is used to allocate memory for
238 //   internal buffers holding the associated output.
240 // Therefore the allocator used in the constructor is passed to the
241 // basic_string. The class does not keep a copy of this allocator.
242 template <class _CharT, class _Traits, class _Allocator>
243 class _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> {
244 public:
245   using char_type      = _CharT;
246   using traits_type    = _Traits;
247   using int_type       = typename traits_type::int_type;
248   using pos_type       = typename traits_type::pos_type;
249   using off_type       = typename traits_type::off_type;
250   using allocator_type = _Allocator;
252   using streambuf_type = basic_streambuf<_CharT, _Traits>;
254   // [syncstream.syncbuf.cons], construction and destruction
256   _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf = nullptr)
257       : basic_syncbuf(__obuf, _Allocator()) {}
259   _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc)
260       : __wrapped_(__obuf), __str_(__alloc) {
261     __inc_reference();
262   }
264   _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other)
265       : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) {
266     __move_common(__other);
267   }
269   _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() {
270 #  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
271     try {
272 #  endif // _LIBCPP_HAS_NO_EXCEPTIONS
273       emit();
274 #  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
275     } catch (...) {
276     }
277 #  endif // _LIBCPP_HAS_NO_EXCEPTIONS
278     __dec_reference();
279   }
281   // [syncstream.syncbuf.assign], assignment and swap
283   _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) {
284     // The function is specified to call emit. This call should
285     // propagate the exception thrown.
286     emit();
287     __dec_reference();
289     __wrapped_      = __other.get_wrapped();
290     __str_          = std::move(__other.__str_);
291     __emit_on_sync_ = __other.__emit_on_sync_;
293     __move_common(__other);
295     return *this;
296   }
298   _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) {
299     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
300         allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(),
301         "violates the mandated swap precondition");
303     basic_syncbuf __tmp(std::move(__other));
304     __other = std::move(*this);
305     *this   = std::move(__tmp);
306   }
308   // [syncstream.syncbuf.members], member functions
310   _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }
312   _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
314   _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
316   _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }
318 protected:
319   // [syncstream.syncbuf.virtuals], overridden virtual functions
321   _LIBCPP_HIDE_FROM_ABI_VIRTUAL
322   int sync() override {
323     if (__emit_on_sync_ && !emit(true))
324       return -1;
325     return 0;
326   }
328   _LIBCPP_HIDE_FROM_ABI_VIRTUAL
329   int_type overflow(int_type __c = traits_type::eof()) override {
330     if (traits_type::eq_int_type(__c, traits_type::eof()))
331       return traits_type::not_eof(__c);
333     if (this->pptr() == this->epptr()) {
334 #  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
335       try {
336 #  endif
337         size_t __size = __str_.size();
338         __str_.resize(__str_.capacity() + 1);
339         _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown");
341         char_type* __p = static_cast<char_type*>(__str_.data());
342         this->setp(__p, __p + __str_.size());
343         this->pbump(__size);
345 #  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
346       } catch (...) {
347         return traits_type::eof();
348       }
349 #  endif
350     }
352     return this->sputc(traits_type::to_char_type(__c));
353   }
355 private:
356   streambuf_type* __wrapped_;
358   // TODO Use a more generic buffer.
359   // That buffer should be light with almost no additional headers. Then
360   // it can be use here, the __retarget_buffer, and place that use
361   // the now deprecated get_temporary_buffer
363   basic_string<_CharT, _Traits, _Allocator> __str_;
364   bool __emit_on_sync_{false};
366   _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {
367     if (!__wrapped_)
368       return false;
370 #  ifndef _LIBCPP_HAS_NO_THREADS
371     lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_);
372 #  endif
374     bool __result = true;
375     if (this->pptr() != this->pbase()) {
376       _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid");
378       // The __str_ does not know how much of its buffer is used. This
379       // information is extracted from the information of the base class.
380       __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1);
381       // Clears the buffer, but keeps the contents (and) size of the
382       // internal buffer.
383       this->setp(this->pbase(), this->epptr());
384     }
386     if (__flush)
387       __result &= (__wrapped_->pubsync() != -1);
389     return __result;
390   }
392   _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) {
393     // Adjust the put area pointers to our buffer.
394     char_type* __p = static_cast<char_type*>(__str_.data());
395     this->setp(__p, __p + __str_.size());
396     this->pbump(__other.pptr() - __other.pbase());
398     // Clear __other_ so the destructor will act as a NOP.
399     __other.setp(nullptr, nullptr);
400     __other.__wrapped_ = nullptr;
401   }
403   _LIBCPP_HIDE_FROM_ABI void __inc_reference() {
404 #  ifndef _LIBCPP_HAS_NO_THREADS
405     if (__wrapped_)
406       __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_);
407 #  endif
408   }
410   _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept {
411 #  ifndef _LIBCPP_HAS_NO_THREADS
412     if (__wrapped_)
413       __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_);
414 #  endif
415   }
418 using std::syncbuf;
419 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
420 using std::wsyncbuf;
421 #  endif
423 // [syncstream.syncbuf.special], specialized algorithms
424 template <class _CharT, class _Traits, class _Allocator>
425 _LIBCPP_HIDE_FROM_ABI void
426 swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) {
427   __lhs.swap(__rhs);
430 // basic_osyncstream
432 template <class _CharT, class _Traits, class _Allocator>
433 class _LIBCPP_TEMPLATE_VIS basic_osyncstream : public basic_ostream<_CharT, _Traits> {
434 public:
435   using char_type   = _CharT;
436   using traits_type = _Traits;
437   using int_type    = typename traits_type::int_type;
438   using pos_type    = typename traits_type::pos_type;
439   using off_type    = typename traits_type::off_type;
441   using allocator_type = _Allocator;
442   using streambuf_type = basic_streambuf<char_type, traits_type>;
443   using syncbuf_type   = basic_syncbuf<char_type, traits_type, allocator_type>;
445   // [syncstream.osyncstream.cons], construction and destruction
447   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc)
448       : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {}
450   _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf)
451       : basic_osyncstream(__obuf, allocator_type()) {}
453   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc)
454       : basic_osyncstream(__os.rdbuf(), __alloc) {}
456   _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
457       : basic_osyncstream(__os, allocator_type()) {}
459   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept
460       : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) {
461     this->set_rdbuf(std::addressof(__sb_));
462   }
464   // [syncstream.osyncstream.assign], assignment
466   _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default;
468   // [syncstream.osyncstream.members], member functions
470   _LIBCPP_HIDE_FROM_ABI void emit() {
471     // The basic_ostream::put places the sentry in a try
472     // catch, this does not match the wording of the standard
473     // [ostream.unformatted]
474     // TODO validate other unformatted output functions.
475     typename basic_ostream<char_type, traits_type>::sentry __s(*this);
476     if (__s) {
477 #  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
478       try {
479 #  endif
481         if (__sb_.emit() == false)
482           this->setstate(ios::badbit);
483 #  ifndef _LIBCPP_HAS_NO_EXCEPTIONS
484       } catch (...) {
485         this->__set_badbit_and_consider_rethrow();
486       }
487 #  endif
488     }
489   }
491   _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
493   _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
494     return const_cast<syncbuf_type*>(std::addressof(__sb_));
495   }
497 private:
498   syncbuf_type __sb_;
501 using std::osyncstream;
502 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
503 using std::wosyncstream;
504 #  endif
506 #endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
508 _LIBCPP_END_NAMESPACE_STD
510 _LIBCPP_POP_MACROS
512 #endif // _LIBCPP_SYNCSTREAM