[libcxx-commits] [libcxx] [libc++] Implement p0753r2 Manipulators for C++ Synchronized Buffered Ostream (PR #97955)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jul 7 07:57:12 PDT 2024


https://github.com/huixie90 created https://github.com/llvm/llvm-project/pull/97955

None

>From e027c7fdd32cbfdd1d8a990490c1e6fe2c5c924b Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Sun, 7 Jul 2024 15:56:49 +0100
Subject: [PATCH] [libc++] Implement p0753r2 Manipulators for C++ Synchronized
 Buffered Ostream

---
 libcxx/include/CMakeLists.txt           |  1 +
 libcxx/include/__ostream/syncbuf_base.h | 92 +++++++++++++++++++++++++
 libcxx/include/module.modulemap         |  4 ++
 libcxx/include/ostream                  | 10 +++
 libcxx/include/syncstream               | 20 +++---
 5 files changed, 119 insertions(+), 8 deletions(-)
 create mode 100644 libcxx/include/__ostream/syncbuf_base.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 8d0ffd6ed725bd..9cc96730923b86 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -575,6 +575,7 @@ set(files
   __numeric/transform_reduce.h
   __ostream/basic_ostream.h
   __ostream/print.h
+  __ostream/syncbuf_base.h
   __pstl/backend.h
   __pstl/backend_fwd.h
   __pstl/backends/default.h
diff --git a/libcxx/include/__ostream/syncbuf_base.h b/libcxx/include/__ostream/syncbuf_base.h
new file mode 100644
index 00000000000000..fb49f94bc5704c
--- /dev/null
+++ b/libcxx/include/__ostream/syncbuf_base.h
@@ -0,0 +1,92 @@
+// -*- 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___OSTREAM_SYNCBUF_BASE_H
+#define _LIBCPP___OSTREAM_SYNCBUF_BASE_H
+
+#include <__config>
+#include <__ostream/basic_ostream.h>
+#include <streambuf>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
+
+template <class _CharT, class _Traits>
+class _LIBCPP_TEMPLATE_VIS __syncbuf_base : public basic_streambuf<_CharT, _Traits> {
+public:
+
+protected:
+  _LIBCPP_HIDE_FROM_ABI explicit __syncbuf_base(bool __b = false) : __emit_on_sync_(__b) {}
+
+private:
+  bool __emit_on_sync_{false};
+
+  virtual bool __emit() = 0;
+
+  template <class, class, class>
+  friend class basic_syncbuf;
+
+  friend struct __syncbuf_base_access;
+};
+
+struct __syncbuf_base_access {
+  template <class _CharT, class _Traits>
+  _LIBCPP_HIDE_FROM_ABI static void __set_emit_on_sync(__syncbuf_base<_CharT, _Traits>* __buf, bool __b) {
+    __buf->__emit_on_sync_ = __b;
+  }
+
+  template <class _CharT, class _Traits>
+  _LIBCPP_HIDE_FROM_ABI static bool __emit(__syncbuf_base<_CharT, _Traits>* __buf) {
+    return __buf->__emit();
+  }
+};
+
+template <class _CharT, class _Traits>
+_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& emit_on_flush(basic_ostream<_CharT, _Traits>& __os) {
+  if (auto* __buf = dynamic_cast<__syncbuf_base<_CharT, _Traits>*>(__os.rdbuf())) {
+    __syncbuf_base_access::__set_emit_on_sync(__buf, true);
+  }
+  return __os;
+}
+
+template <class _CharT, class _Traits>
+_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& noemit_on_flush(basic_ostream<_CharT, _Traits>& __os) {
+  if (auto* __buf = dynamic_cast<__syncbuf_base<_CharT, _Traits>*>(__os.rdbuf())) {
+    __syncbuf_base_access::__set_emit_on_sync(__buf, false);
+  }
+  return __os;
+}
+
+template <class _CharT, class _Traits>
+_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& flush_emit(basic_ostream<_CharT, _Traits>& __os) {
+  __os.flush();
+  if (auto* __buf = dynamic_cast<__syncbuf_base<_CharT, _Traits>*>(__os.rdbuf())) {
+    // The standard specifies that:
+    // After constructing a sentry object, calls buf->emit().
+    // If that call returns false, calls os.setstate(ios_base::badbit).
+    //
+    // syncstream::emit already constructs a sentry
+    bool __emit_result = __syncbuf_base_access::__emit(__buf);
+    if (!__emit_result) {
+      __os.setstate(ios_base::badbit);
+    }
+  }
+  return __os;
+}
+
+#endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___OSTREAM_SYNCBUF_BASE_H
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 9ffccf66ff0948..4b9921833c5117 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1631,6 +1631,10 @@ module std_private_ostream_print         [system] {
   export std_print
 }
 
+module std_private_ostream_syncbuf_base  [system] {
+  header "__ostream/syncbuf_base.h"
+}
+
 module std_private_random_bernoulli_distribution          [system] { header "__random/bernoulli_distribution.h" }
 module std_private_random_binomial_distribution           [system] { header "__random/binomial_distribution.h" }
 module std_private_random_cauchy_distribution             [system] { header "__random/cauchy_distribution.h" }
diff --git a/libcxx/include/ostream b/libcxx/include/ostream
index f75110e7d73f79..afb1a8b2f39c0b 100644
--- a/libcxx/include/ostream
+++ b/libcxx/include/ostream
@@ -126,6 +126,15 @@ template <class charT, class traits>
 template <class charT, class traits>
   basic_ostream<charT,traits>& flush(basic_ostream<charT,traits>& os);
 
+template<class charT, class traits>
+  basic_ostream<charT, traits>& emit_on_flush(basic_ostream<charT, traits>& os);                       // since C++20
+  
+template<class charT, class traits>
+  basic_ostream<charT, traits>& noemit_on_flush(basic_ostream<charT, traits>& os);                     // since C++20
+  
+template<class charT, class traits>
+  basic_ostream<charT, traits>& flush_emit(basic_ostream<charT, traits>& os);                          // since C++20
+
 // rvalue stream insertion
 template <class Stream, class T>
   Stream&& operator<<(Stream&& os, const T& x);
@@ -175,6 +184,7 @@ void vprint_nonunicode(ostream& os, string_view fmt, format_args args);
 #include <__config>
 #include <__ostream/basic_ostream.h>
 #include <__ostream/print.h>
+#include <__ostream/syncbuf_base.h>
 #include <version>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/syncstream b/libcxx/include/syncstream
index e6f35b6f428eda..243d6a56a5dc9c 100644
--- a/libcxx/include/syncstream
+++ b/libcxx/include/syncstream
@@ -116,6 +116,7 @@ namespace std {
 */
 
 #include <__config>
+#include <__ostream/syncbuf_base.h>
 #include <__utility/move.h>
 #include <ios>
 #include <iosfwd> // required for declaration of default arguments
@@ -240,7 +241,7 @@ private:
 // 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 _LIBCPP_TEMPLATE_VIS basic_syncbuf : public basic_streambuf<_CharT, _Traits> {
+class _LIBCPP_TEMPLATE_VIS basic_syncbuf : public __syncbuf_base<_CharT, _Traits> {
 public:
   using char_type      = _CharT;
   using traits_type    = _Traits;
@@ -262,7 +263,9 @@ public:
   }
 
   _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_) {
+      : __syncbuf_base<_CharT, _Traits>(__other.__emit_on_sync_),
+        __wrapped_(__other.get_wrapped()),
+        __str_(std::move(__other.__str_)) {
     __move_common(__other);
   }
 
@@ -286,9 +289,9 @@ public:
     emit();
     __dec_reference();
 
-    __wrapped_      = __other.get_wrapped();
-    __str_          = std::move(__other.__str_);
-    __emit_on_sync_ = __other.__emit_on_sync_;
+    __wrapped_            = __other.get_wrapped();
+    __str_                = std::move(__other.__str_);
+    this->__emit_on_sync_ = __other.__emit_on_sync_;
 
     __move_common(__other);
 
@@ -313,14 +316,14 @@ public:
 
   _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; }
+  _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { this->__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))
+    if (this->__emit_on_sync_ && !emit(true))
       return -1;
     return 0;
   }
@@ -361,7 +364,6 @@ private:
   // the now deprecated get_temporary_buffer
 
   basic_string<_CharT, _Traits, _Allocator> __str_;
-  bool __emit_on_sync_{false};
 
   _LIBCPP_HIDE_FROM_ABI bool emit(bool __flush) {
     if (!__wrapped_)
@@ -389,6 +391,8 @@ private:
     return __result;
   }
 
+  _LIBCPP_HIDE_FROM_ABI_VIRTUAL bool __emit() override { return emit(); }
+
   _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());



More information about the libcxx-commits mailing list