[rtsan] Remove mkfifoat interceptor (#116997)
[llvm-project.git] / libcxx / include / syncstream
blob970706976e1ff1bd2627c78f8a4bbaba84172bb6
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 <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         basic_syncbuf()
50           : basic_syncbuf(nullptr) {}
51         explicit basic_syncbuf(streambuf_type* obuf)
52           : basic_syncbuf(obuf, Allocator()) {}
53         basic_syncbuf(streambuf_type*, const Allocator&);
54         basic_syncbuf(basic_syncbuf&&);
55         ~basic_syncbuf();
57         // [syncstream.syncbuf.assign], assignment and swap
58         basic_syncbuf& operator=(basic_syncbuf&&);
59         void swap(basic_syncbuf&);
61         // [syncstream.syncbuf.members], member functions
62         bool emit();
63         streambuf_type* get_wrapped() const noexcept;
64         allocator_type get_allocator() const noexcept;
65         void set_emit_on_sync(bool) noexcept;
67     protected:
68         // [syncstream.syncbuf.virtuals], overridden virtual functions
69         int sync() override;
71     private:
72         streambuf_type* wrapped;    // exposition only
73         bool emit_on_sync{};        // exposition only
74     };
76     // [syncstream.syncbuf.special], specialized algorithms
77     template<class charT, class traits, class Allocator>
78     void swap(basic_syncbuf<charT, traits, Allocator>&,
79               basic_syncbuf<charT, traits, Allocator>&);
81     template<class charT, class traits, class Allocator>
82     class basic_osyncstream : public basic_ostream<charT, traits> {
83     public:
84         using char_type   = charT;
85         using int_type    = typename traits::int_type;
86         using pos_type    = typename traits::pos_type;
87         using off_type    = typename traits::off_type;
88         using traits_type = traits;
90         using allocator_type = Allocator;
91         using streambuf_type = basic_streambuf<charT, traits>;
92         using syncbuf_type   = basic_syncbuf<charT, traits, Allocator>;
94         // [syncstream.osyncstream.cons], construction and destruction
95         basic_osyncstream(streambuf_type*, const Allocator&);
96         explicit basic_osyncstream(streambuf_type* obuf)
97           : basic_osyncstream(obuf, Allocator()) {}
98         basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)
99           : basic_osyncstream(os.rdbuf(), allocator) {}
100         explicit basic_osyncstream(basic_ostream<charT, traits>& os)
101           : basic_osyncstream(os, Allocator()) {}
102         basic_osyncstream(basic_osyncstream&&) noexcept;
103         ~basic_osyncstream();
105         // [syncstream.osyncstream.assign], assignment
106         basic_osyncstream& operator=(basic_osyncstream&&);
108         // [syncstream.osyncstream.members], member functions
109         void emit();
110         streambuf_type* get_wrapped() const noexcept;
111         syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }
113     private:
114         syncbuf_type sb;    // exposition only
115     };
120 #include <__config>
122 #if _LIBCPP_HAS_LOCALIZATION
124 #  include <__utility/move.h>
125 #  include <ios>
126 #  include <iosfwd> // required for declaration of default arguments
127 #  include <streambuf>
128 #  include <string>
130 #  if _LIBCPP_HAS_THREADS
131 #    include <map>
132 #    include <mutex>
133 #    include <shared_mutex>
134 #  endif
136 // standard-mandated includes
138 // [syncstream.syn]
139 #  include <ostream>
141 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
142 #    pragma GCC system_header
143 #  endif
145 _LIBCPP_PUSH_MACROS
146 #  include <__undef_macros>
148 _LIBCPP_BEGIN_NAMESPACE_STD
150 #  if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
152 // [syncstream.syncbuf.overview]/1
153 //   Class template basic_syncbuf stores character data written to it,
154 //   known as the associated output, into internal buffers allocated
155 //   using the object's allocator. The associated output is transferred
156 //   to the wrapped stream buffer object *wrapped when emit() is called
157 //   or when the basic_syncbuf object is destroyed. Such transfers are
158 //   atomic with respect to transfers by other basic_syncbuf objects
159 //   with the same wrapped stream buffer object.
161 // This helper singleton is used to implement the required
162 // synchronisation guarantees.
163 #    if _LIBCPP_HAS_THREADS
164 class __wrapped_streambuf_mutex {
165   _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default;
167 public:
168   __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&)            = delete;
169   __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete;
171   _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) {
172     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
173     unique_lock __lock{__mutex_};
174     ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count;
175   }
177   // pre: __ptr is in __lut_
178   _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept {
179     unique_lock __lock{__mutex_};
181     auto __it = __get_it(__ptr);
182     if (__it->second.__count == 1)
183       __lut_.erase(__it);
184     else
185       --__it->second.__count;
186   }
188   // TODO
189   // This function causes emit() aquire two mutexes:
190   // - __mutex_ shared
191   // _ __get_it(__ptr)->second.__mutex exclusive
192   //
193   // Instead store a pointer to __get_it(__ptr)->second.__mutex when
194   // calling __inc_reference.
195   //
196   // pre: __ptr is in __lut_
197   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept {
198     shared_lock __lock{__mutex_};
199     return lock_guard{__get_it(__ptr)->second.__mutex};
200   }
202   // This function is used for testing.
203   //
204   // It is allowed to call this function with a non-registered pointer.
205   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept {
206     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
207     shared_lock __lock{__mutex_};
209     auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
210     return __it != __lut_.end() ? __it->second.__count : 0;
211   }
213   [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept {
214     static __wrapped_streambuf_mutex __result;
215     return __result;
216   }
218 private:
219   struct __value {
220     mutex __mutex;
221     size_t __count{0};
222   };
224   shared_mutex __mutex_;
225   map<uintptr_t, __value> __lut_;
227   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept {
228     _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
230     auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
231     _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered");
232     _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper");
233     return __it;
234   }
236 #    endif // _LIBCPP_HAS_THREADS
238 // basic_syncbuf
240 // The class uses a basic_string<_CharT, _Traits, _Allocator> as
241 // internal buffer. Per [syncstream.syncbuf.cons]/4
242 //   Remarks: A copy of allocator is used to allocate memory for
243 //   internal buffers holding the associated output.
245 // Therefore the allocator used in the constructor is passed to the
246 // basic_string. The class does not keep a copy of this allocator.
247 template <class _CharT, class _Traits, class _Allocator>
248 class _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> {
249 public:
250   using char_type      = _CharT;
251   using traits_type    = _Traits;
252   using int_type       = typename traits_type::int_type;
253   using pos_type       = typename traits_type::pos_type;
254   using off_type       = typename traits_type::off_type;
255   using allocator_type = _Allocator;
257   using streambuf_type = basic_streambuf<_CharT, _Traits>;
259   // [syncstream.syncbuf.cons], construction and destruction
261   _LIBCPP_HIDE_FROM_ABI basic_syncbuf() : basic_syncbuf(nullptr) {}
263   _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf) : basic_syncbuf(__obuf, _Allocator()) {}
265   _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc)
266       : __wrapped_(__obuf), __str_(__alloc) {
267     __inc_reference();
268   }
270   _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other)
271       : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) {
272     __move_common(__other);
273   }
275   _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() {
276 #    if _LIBCPP_HAS_EXCEPTIONS
277     try {
278 #    endif // _LIBCPP_HAS_EXCEPTIONS
279       emit();
280 #    if _LIBCPP_HAS_EXCEPTIONS
281     } catch (...) {
282     }
283 #    endif // _LIBCPP_HAS_EXCEPTIONS
284     __dec_reference();
285   }
287   // [syncstream.syncbuf.assign], assignment and swap
289   _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) {
290     // The function is specified to call emit. This call should
291     // propagate the exception thrown.
292     emit();
293     __dec_reference();
295     __wrapped_      = __other.get_wrapped();
296     __str_          = std::move(__other.__str_);
297     __emit_on_sync_ = __other.__emit_on_sync_;
299     __move_common(__other);
301     return *this;
302   }
304   _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) {
305     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
306         allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(),
307         "violates the mandated swap precondition");
309     basic_syncbuf __tmp(std::move(__other));
310     __other = std::move(*this);
311     *this   = std::move(__tmp);
312   }
314   // [syncstream.syncbuf.members], member functions
316   _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }
318   _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
320   _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
322   _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }
324 protected:
325   // [syncstream.syncbuf.virtuals], overridden virtual functions
327   _LIBCPP_HIDE_FROM_ABI_VIRTUAL
328   int sync() override {
329     if (__emit_on_sync_ && !emit(true))
330       return -1;
331     return 0;
332   }
334   _LIBCPP_HIDE_FROM_ABI_VIRTUAL
335   int_type overflow(int_type __c = traits_type::eof()) override {
336     if (traits_type::eq_int_type(__c, traits_type::eof()))
337       return traits_type::not_eof(__c);
339     if (this->pptr() == this->epptr()) {
340 #    if _LIBCPP_HAS_EXCEPTIONS
341       try {
342 #    endif
343         size_t __size = __str_.size();
344         __str_.resize(__str_.capacity() + 1);
345         _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown");
347         char_type* __p = static_cast<char_type*>(__str_.data());
348         this->setp(__p, __p + __str_.size());
349         this->pbump(__size);
351 #    if _LIBCPP_HAS_EXCEPTIONS
352       } catch (...) {
353         return traits_type::eof();
354       }
355 #    endif
356     }
358     return this->sputc(traits_type::to_char_type(__c));
359   }
361 private:
362   streambuf_type* __wrapped_;
364   // TODO Use a more generic buffer.
365   // That buffer should be light with almost no additional headers. Then
366   // it can be use here, the __retarget_buffer, and place that use
367   // the now removed get_temporary_buffer
369   basic_string<_CharT, _Traits, _Allocator> __str_;
370   bool __emit_on_sync_{false};
372   _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {
373     if (!__wrapped_)
374       return false;
376 #    if _LIBCPP_HAS_THREADS
377     lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_);
378 #    endif
380     bool __result = true;
381     if (this->pptr() != this->pbase()) {
382       _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid");
384       // The __str_ does not know how much of its buffer is used. This
385       // information is extracted from the information of the base class.
386       __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1);
387       // Clears the buffer, but keeps the contents (and) size of the
388       // internal buffer.
389       this->setp(this->pbase(), this->epptr());
390     }
392     if (__flush)
393       __result &= (__wrapped_->pubsync() != -1);
395     return __result;
396   }
398   _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) {
399     // Adjust the put area pointers to our buffer.
400     char_type* __p = static_cast<char_type*>(__str_.data());
401     this->setp(__p, __p + __str_.size());
402     this->pbump(__other.pptr() - __other.pbase());
404     // Clear __other_ so the destructor will act as a NOP.
405     __other.setp(nullptr, nullptr);
406     __other.__wrapped_ = nullptr;
407   }
409   _LIBCPP_HIDE_FROM_ABI void __inc_reference() {
410 #    if _LIBCPP_HAS_THREADS
411     if (__wrapped_)
412       __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_);
413 #    endif
414   }
416   _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept {
417 #    if _LIBCPP_HAS_THREADS
418     if (__wrapped_)
419       __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_);
420 #    endif
421   }
424 using std::syncbuf;
425 #    if _LIBCPP_HAS_WIDE_CHARACTERS
426 using std::wsyncbuf;
427 #    endif
429 // [syncstream.syncbuf.special], specialized algorithms
430 template <class _CharT, class _Traits, class _Allocator>
431 _LIBCPP_HIDE_FROM_ABI void
432 swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) {
433   __lhs.swap(__rhs);
436 // basic_osyncstream
438 template <class _CharT, class _Traits, class _Allocator>
439 class _LIBCPP_TEMPLATE_VIS basic_osyncstream : public basic_ostream<_CharT, _Traits> {
440 public:
441   using char_type   = _CharT;
442   using traits_type = _Traits;
443   using int_type    = typename traits_type::int_type;
444   using pos_type    = typename traits_type::pos_type;
445   using off_type    = typename traits_type::off_type;
447   using allocator_type = _Allocator;
448   using streambuf_type = basic_streambuf<char_type, traits_type>;
449   using syncbuf_type   = basic_syncbuf<char_type, traits_type, allocator_type>;
451   // [syncstream.osyncstream.cons], construction and destruction
453   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc)
454       : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {}
456   _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf)
457       : basic_osyncstream(__obuf, allocator_type()) {}
459   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc)
460       : basic_osyncstream(__os.rdbuf(), __alloc) {}
462   _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
463       : basic_osyncstream(__os, allocator_type()) {}
465   _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept
466       : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) {
467     this->set_rdbuf(std::addressof(__sb_));
468   }
470   // [syncstream.osyncstream.assign], assignment
472   _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default;
474   // [syncstream.osyncstream.members], member functions
476   _LIBCPP_HIDE_FROM_ABI void emit() {
477     // The basic_ostream::put places the sentry in a try
478     // catch, this does not match the wording of the standard
479     // [ostream.unformatted]
480     // TODO validate other unformatted output functions.
481     typename basic_ostream<char_type, traits_type>::sentry __s(*this);
482     if (__s) {
483 #    if _LIBCPP_HAS_EXCEPTIONS
484       try {
485 #    endif
487         if (__sb_.emit() == false)
488           this->setstate(ios::badbit);
489 #    if _LIBCPP_HAS_EXCEPTIONS
490       } catch (...) {
491         this->__set_badbit_and_consider_rethrow();
492       }
493 #    endif
494     }
495   }
497   _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
499   _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
500     return const_cast<syncbuf_type*>(std::addressof(__sb_));
501   }
503 private:
504   syncbuf_type __sb_;
507 using std::osyncstream;
508 #    if _LIBCPP_HAS_WIDE_CHARACTERS
509 using std::wosyncstream;
510 #    endif
512 #  endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
514 _LIBCPP_END_NAMESPACE_STD
516 _LIBCPP_POP_MACROS
518 #endif // _LIBCPP_HAS_LOCALIZATION
520 #endif // _LIBCPP_SYNCSTREAM