summaryrefslogtreecommitdiff
path: root/third_party/libcxx/include/c++/v1/syncstream
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-07-11 22:48:30 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-07-11 22:48:30 +0800
commit3ad39e9878310e5317ee73c9b353c1e2c1c5c4ee (patch)
tree4bd5a49ef60ad1e371c0984cd46838368c5ef83a /third_party/libcxx/include/c++/v1/syncstream
parent48ef95c24e9ac3d11200b61af617a01b10b507d1 (diff)
downloadlume-3ad39e9878310e5317ee73c9b353c1e2c1c5c4ee.tar.gz
lume-3ad39e9878310e5317ee73c9b353c1e2c1c5c4ee.tar.xz
lib: establish Zircon libc++ and KTL foundation
Diffstat (limited to 'third_party/libcxx/include/c++/v1/syncstream')
-rw-r--r--third_party/libcxx/include/c++/v1/syncstream523
1 files changed, 523 insertions, 0 deletions
diff --git a/third_party/libcxx/include/c++/v1/syncstream b/third_party/libcxx/include/c++/v1/syncstream
new file mode 100644
index 0000000..bd64453
--- /dev/null
+++ b/third_party/libcxx/include/c++/v1/syncstream
@@ -0,0 +1,523 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_SYNCSTREAM
+#define _LIBCPP_SYNCSTREAM
+
+/*
+ syncstream synopsis
+
+#include <ostream> // see [ostream.syn]
+
+namespace std {
+ template<class charT, class traits, class Allocator>
+ class basic_syncbuf;
+
+ // [syncstream.syncbuf.special], specialized algorithms
+ template<class charT, class traits, class Allocator>
+ void swap(basic_syncbuf<charT, traits, Allocator>&,
+ basic_syncbuf<charT, traits, Allocator>&);
+
+ using syncbuf = basic_syncbuf<char>;
+ using wsyncbuf = basic_syncbuf<wchar_t>;
+
+ template<class charT, class traits, class Allocator>
+ class basic_osyncstream;
+
+ using osyncstream = basic_osyncstream<char>;
+ using wosyncstream = basic_osyncstream<wchar_t>;
+
+ template<class charT, class traits, class Allocator>
+ class basic_syncbuf : public basic_streambuf<charT, traits> {
+ public:
+ using char_type = charT;
+ using int_type = typename traits::int_type;
+ using pos_type = typename traits::pos_type;
+ using off_type = typename traits::off_type;
+ using traits_type = traits;
+ using allocator_type = Allocator;
+
+ using streambuf_type = basic_streambuf<charT, traits>;
+
+ // [syncstream.syncbuf.cons], construction and destruction
+ basic_syncbuf()
+ : basic_syncbuf(nullptr) {}
+ explicit basic_syncbuf(streambuf_type* obuf)
+ : basic_syncbuf(obuf, Allocator()) {}
+ basic_syncbuf(streambuf_type*, const Allocator&);
+ basic_syncbuf(basic_syncbuf&&);
+ ~basic_syncbuf();
+
+ // [syncstream.syncbuf.assign], assignment and swap
+ basic_syncbuf& operator=(basic_syncbuf&&);
+ void swap(basic_syncbuf&);
+
+ // [syncstream.syncbuf.members], member functions
+ bool emit();
+ streambuf_type* get_wrapped() const noexcept;
+ allocator_type get_allocator() const noexcept;
+ void set_emit_on_sync(bool) noexcept;
+
+ protected:
+ // [syncstream.syncbuf.virtuals], overridden virtual functions
+ int sync() override;
+
+ private:
+ streambuf_type* wrapped; // exposition only
+ bool emit_on_sync{}; // exposition only
+ };
+
+ // [syncstream.syncbuf.special], specialized algorithms
+ template<class charT, class traits, class Allocator>
+ void swap(basic_syncbuf<charT, traits, Allocator>&,
+ basic_syncbuf<charT, traits, Allocator>&);
+
+ template<class charT, class traits, class Allocator>
+ class basic_osyncstream : public basic_ostream<charT, traits> {
+ public:
+ using char_type = charT;
+ using int_type = typename traits::int_type;
+ using pos_type = typename traits::pos_type;
+ using off_type = typename traits::off_type;
+ using traits_type = traits;
+
+ using allocator_type = Allocator;
+ using streambuf_type = basic_streambuf<charT, traits>;
+ using syncbuf_type = basic_syncbuf<charT, traits, Allocator>;
+
+ // [syncstream.osyncstream.cons], construction and destruction
+ basic_osyncstream(streambuf_type*, const Allocator&);
+ explicit basic_osyncstream(streambuf_type* obuf)
+ : basic_osyncstream(obuf, Allocator()) {}
+ basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)
+ : basic_osyncstream(os.rdbuf(), allocator) {}
+ explicit basic_osyncstream(basic_ostream<charT, traits>& os)
+ : basic_osyncstream(os, Allocator()) {}
+ basic_osyncstream(basic_osyncstream&&) noexcept;
+ ~basic_osyncstream();
+
+ // [syncstream.osyncstream.assign], assignment
+ basic_osyncstream& operator=(basic_osyncstream&&);
+
+ // [syncstream.osyncstream.members], member functions
+ void emit();
+ streambuf_type* get_wrapped() const noexcept;
+ syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }
+
+ private:
+ syncbuf_type sb; // exposition only
+ };
+}
+
+*/
+
+#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
+# include <__cxx03/__config>
+#else
+# include <__config>
+
+// standard-mandated includes
+
+// [syncstream.syn]
+# include <ostream>
+
+# if _LIBCPP_HAS_LOCALIZATION
+
+# include <__mutex/lock_guard.h>
+# include <__utility/move.h>
+# include <ios>
+# include <iosfwd> // required for declaration of default arguments
+# include <streambuf>
+# include <string>
+# if _LIBCPP_HAS_THREADS
+# include <map>
+# include <shared_mutex>
+# endif
+
+# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+# endif
+
+_LIBCPP_PUSH_MACROS
+# include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM
+
+// [syncstream.syncbuf.overview]/1
+// Class template basic_syncbuf stores character data written to it,
+// known as the associated output, into internal buffers allocated
+// using the object's allocator. The associated output is transferred
+// to the wrapped stream buffer object *wrapped when emit() is called
+// or when the basic_syncbuf object is destroyed. Such transfers are
+// atomic with respect to transfers by other basic_syncbuf objects
+// with the same wrapped stream buffer object.
+//
+// This helper singleton is used to implement the required
+// synchronisation guarantees.
+# if _LIBCPP_HAS_THREADS
+class __wrapped_streambuf_mutex {
+ _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex() = default;
+
+public:
+ __wrapped_streambuf_mutex(const __wrapped_streambuf_mutex&) = delete;
+ __wrapped_streambuf_mutex& operator=(const __wrapped_streambuf_mutex&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI void __inc_reference([[maybe_unused]] void* __ptr) {
+ _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
+ unique_lock __lock{__mutex_};
+ ++__lut_[reinterpret_cast<uintptr_t>(__ptr)].__count;
+ }
+
+ // pre: __ptr is in __lut_
+ _LIBCPP_HIDE_FROM_ABI void __dec_reference([[maybe_unused]] void* __ptr) noexcept {
+ unique_lock __lock{__mutex_};
+
+ auto __it = __get_it(__ptr);
+ if (__it->second.__count == 1)
+ __lut_.erase(__it);
+ else
+ --__it->second.__count;
+ }
+
+ // TODO
+ // This function causes emit() aquire two mutexes:
+ // - __mutex_ shared
+ // _ __get_it(__ptr)->second.__mutex exclusive
+ //
+ // Instead store a pointer to __get_it(__ptr)->second.__mutex when
+ // calling __inc_reference.
+ //
+ // pre: __ptr is in __lut_
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock([[maybe_unused]] void* __ptr) noexcept {
+ shared_lock __lock{__mutex_};
+ return lock_guard{__get_it(__ptr)->second.__mutex};
+ }
+
+ // This function is used for testing.
+ //
+ // It is allowed to call this function with a non-registered pointer.
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __get_count([[maybe_unused]] void* __ptr) noexcept {
+ _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
+ shared_lock __lock{__mutex_};
+
+ auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
+ return __it != __lut_.end() ? __it->second.__count : 0;
+ }
+
+ [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __wrapped_streambuf_mutex& __instance() noexcept {
+ static __wrapped_streambuf_mutex __result;
+ return __result;
+ }
+
+private:
+ struct __value {
+ mutex __mutex;
+ size_t __count{0};
+ };
+
+ shared_mutex __mutex_;
+ map<uintptr_t, __value> __lut_;
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(void* __ptr) noexcept {
+ _LIBCPP_ASSERT_INTERNAL(__ptr != nullptr, "non-wrapped streambufs are never written to");
+
+ auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
+ _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "using a wrapped streambuf that has not been registered");
+ _LIBCPP_ASSERT_INTERNAL(__it->second.__count >= 1, "found an inactive streambuf wrapper");
+ return __it;
+ }
+};
+# endif // _LIBCPP_HAS_THREADS
+
+// basic_syncbuf
+
+// The class uses a basic_string<_CharT, _Traits, _Allocator> as
+// internal buffer. Per [syncstream.syncbuf.cons]/4
+// Remarks: A copy of allocator is used to allocate memory for
+// internal buffers holding the associated output.
+//
+// Therefore the allocator used in the constructor is passed to the
+// basic_string. The class does not keep a copy of this allocator.
+template <class _CharT, class _Traits, class _Allocator>
+class basic_syncbuf : public basic_streambuf<_CharT, _Traits> {
+public:
+ using char_type = _CharT;
+ using traits_type = _Traits;
+ using int_type = typename traits_type::int_type;
+ using pos_type = typename traits_type::pos_type;
+ using off_type = typename traits_type::off_type;
+ using allocator_type = _Allocator;
+
+ using streambuf_type = basic_streambuf<_CharT, _Traits>;
+
+ // [syncstream.syncbuf.cons], construction and destruction
+
+ _LIBCPP_HIDE_FROM_ABI basic_syncbuf() : basic_syncbuf(nullptr) {}
+
+ _LIBCPP_HIDE_FROM_ABI explicit basic_syncbuf(streambuf_type* __obuf) : basic_syncbuf(__obuf, _Allocator()) {}
+
+ _LIBCPP_HIDE_FROM_ABI basic_syncbuf(streambuf_type* __obuf, _Allocator const& __alloc)
+ : __wrapped_(__obuf), __str_(__alloc) {
+ __inc_reference();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI basic_syncbuf(basic_syncbuf&& __other)
+ : __wrapped_(__other.get_wrapped()), __str_(std::move(__other.__str_)), __emit_on_sync_(__other.__emit_on_sync_) {
+ __move_common(__other);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI ~basic_syncbuf() {
+# if _LIBCPP_HAS_EXCEPTIONS
+ try {
+# endif // _LIBCPP_HAS_EXCEPTIONS
+ emit();
+# if _LIBCPP_HAS_EXCEPTIONS
+ } catch (...) {
+ }
+# endif // _LIBCPP_HAS_EXCEPTIONS
+ __dec_reference();
+ }
+
+ // [syncstream.syncbuf.assign], assignment and swap
+
+ _LIBCPP_HIDE_FROM_ABI basic_syncbuf& operator=(basic_syncbuf&& __other) {
+ // The function is specified to call emit. This call should
+ // propagate the exception thrown.
+ emit();
+ __dec_reference();
+
+ __wrapped_ = __other.get_wrapped();
+ __str_ = std::move(__other.__str_);
+ __emit_on_sync_ = __other.__emit_on_sync_;
+
+ __move_common(__other);
+
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void swap(basic_syncbuf& __other) {
+ _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
+ allocator_traits<_Allocator>::propagate_on_container_swap::value || get_allocator() == __other.get_allocator(),
+ "violates the mandated swap precondition");
+
+ basic_syncbuf __tmp(std::move(__other));
+ __other = std::move(*this);
+ *this = std::move(__tmp);
+ }
+
+ // [syncstream.syncbuf.members], member functions
+
+ _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
+
+ _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }
+
+protected:
+ // [syncstream.syncbuf.virtuals], overridden virtual functions
+
+ _LIBCPP_HIDE_FROM_ABI_VIRTUAL
+ int sync() override {
+ if (__emit_on_sync_ && !emit(true))
+ return -1;
+ return 0;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI_VIRTUAL
+ int_type overflow(int_type __c = traits_type::eof()) override {
+ if (traits_type::eq_int_type(__c, traits_type::eof()))
+ return traits_type::not_eof(__c);
+
+ if (this->pptr() == this->epptr()) {
+# if _LIBCPP_HAS_EXCEPTIONS
+ try {
+# endif
+ size_t __size = __str_.size();
+ __str_.resize(__str_.capacity() + 1);
+ _LIBCPP_ASSERT_INTERNAL(__str_.size() > __size, "the buffer hasn't grown");
+
+ char_type* __p = static_cast<char_type*>(__str_.data());
+ this->setp(__p, __p + __str_.size());
+ this->pbump(__size);
+
+# if _LIBCPP_HAS_EXCEPTIONS
+ } catch (...) {
+ return traits_type::eof();
+ }
+# endif
+ }
+
+ return this->sputc(traits_type::to_char_type(__c));
+ }
+
+private:
+ streambuf_type* __wrapped_;
+
+ // TODO Use a more generic buffer.
+ // That buffer should be light with almost no additional headers. Then
+ // it can be use here, the __retarget_buffer, and place that use
+ // the now removed get_temporary_buffer
+
+ basic_string<_CharT, _Traits, _Allocator> __str_;
+ bool __emit_on_sync_{false};
+
+ _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {
+ if (!__wrapped_)
+ return false;
+
+# if _LIBCPP_HAS_THREADS
+ lock_guard<mutex> __lock = __wrapped_streambuf_mutex::__instance().__get_lock(__wrapped_);
+# endif
+
+ bool __result = true;
+ if (this->pptr() != this->pbase()) {
+ _LIBCPP_ASSERT_INTERNAL(this->pbase() && this->pptr() && this->epptr(), "all put area pointers shold be valid");
+
+ // The __str_ does not know how much of its buffer is used. This
+ // information is extracted from the information of the base class.
+ __result &= (__wrapped_->sputn(this->pbase(), this->pptr() - this->pbase()) != -1);
+ // Clears the buffer, but keeps the contents (and) size of the
+ // internal buffer.
+ this->setp(this->pbase(), this->epptr());
+ }
+
+ if (__flush)
+ __result &= (__wrapped_->pubsync() != -1);
+
+ return __result;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void __move_common(basic_syncbuf& __other) {
+ // Adjust the put area pointers to our buffer.
+ char_type* __p = static_cast<char_type*>(__str_.data());
+ this->setp(__p, __p + __str_.size());
+ this->pbump(__other.pptr() - __other.pbase());
+
+ // Clear __other_ so the destructor will act as a NOP.
+ __other.setp(nullptr, nullptr);
+ __other.__wrapped_ = nullptr;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void __inc_reference() {
+# if _LIBCPP_HAS_THREADS
+ if (__wrapped_)
+ __wrapped_streambuf_mutex::__instance().__inc_reference(__wrapped_);
+# endif
+ }
+
+ _LIBCPP_HIDE_FROM_ABI void __dec_reference() noexcept {
+# if _LIBCPP_HAS_THREADS
+ if (__wrapped_)
+ __wrapped_streambuf_mutex::__instance().__dec_reference(__wrapped_);
+# endif
+ }
+};
+
+using std::syncbuf;
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+using std::wsyncbuf;
+# endif
+
+// [syncstream.syncbuf.special], specialized algorithms
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI void
+swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __lhs, basic_syncbuf<_CharT, _Traits, _Allocator>& __rhs) {
+ __lhs.swap(__rhs);
+}
+
+// basic_osyncstream
+
+template <class _CharT, class _Traits, class _Allocator>
+class basic_osyncstream : public basic_ostream<_CharT, _Traits> {
+public:
+ using char_type = _CharT;
+ using traits_type = _Traits;
+ using int_type = typename traits_type::int_type;
+ using pos_type = typename traits_type::pos_type;
+ using off_type = typename traits_type::off_type;
+
+ using allocator_type = _Allocator;
+ using streambuf_type = basic_streambuf<char_type, traits_type>;
+ using syncbuf_type = basic_syncbuf<char_type, traits_type, allocator_type>;
+
+ // [syncstream.osyncstream.cons], construction and destruction
+
+ _LIBCPP_HIDE_FROM_ABI basic_osyncstream(streambuf_type* __obuf, allocator_type const& __alloc)
+ : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(__obuf, __alloc) {}
+
+ _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(streambuf_type* __obuf)
+ : basic_osyncstream(__obuf, allocator_type()) {}
+
+ _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_ostream<char_type, traits_type>& __os, allocator_type const& __alloc)
+ : basic_osyncstream(__os.rdbuf(), __alloc) {}
+
+ _LIBCPP_HIDE_FROM_ABI explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
+ : basic_osyncstream(__os, allocator_type()) {}
+
+ _LIBCPP_HIDE_FROM_ABI basic_osyncstream(basic_osyncstream&& __other) noexcept
+ : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(std::move(__other.__sb_)) {
+ this->set_rdbuf(std::addressof(__sb_));
+ }
+
+ // [syncstream.osyncstream.assign], assignment
+
+ _LIBCPP_HIDE_FROM_ABI basic_osyncstream& operator=(basic_osyncstream&& __other) = default;
+
+ // [syncstream.osyncstream.members], member functions
+
+ _LIBCPP_HIDE_FROM_ABI void emit() {
+ // The basic_ostream::put places the sentry in a try
+ // catch, this does not match the wording of the standard
+ // [ostream.unformatted]
+ // TODO validate other unformatted output functions.
+ typename basic_ostream<char_type, traits_type>::sentry __s(*this);
+ if (__s) {
+# if _LIBCPP_HAS_EXCEPTIONS
+ try {
+# endif
+
+ if (__sb_.emit() == false)
+ this->setstate(ios::badbit);
+# if _LIBCPP_HAS_EXCEPTIONS
+ } catch (...) {
+ this->__set_badbit_and_consider_rethrow();
+ }
+# endif
+ }
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
+ return const_cast<syncbuf_type*>(std::addressof(__sb_));
+ }
+
+private:
+ syncbuf_type __sb_;
+};
+
+using std::osyncstream;
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+using std::wosyncstream;
+# endif
+
+# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+# endif // _LIBCPP_HAS_LOCALIZATION
+#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
+
+#endif // _LIBCPP_SYNCSTREAM