On 02/11/20 08:10 -0800, Thomas Rodgers wrote:
From: Thomas Rodgers <trodg...@redhat.com>

IGNORE the previous patch.

Changes implementation to use a private __mutex type as discussed on
IRC.

libstdc++/ChangeLog:
        libstdc++-v3/doc/doxygen/user.cfg.in (INPUT): Add new header.
        libstdc++-v3/include/Makefile.am (std_headers): Add new header.
        libstdc++-v3/include/Makefile.in: Regenerate.
        libstdc++-v3/include/precompiled/stdc++.h: Include new header.
        (basic_streambuf): Befriend __detail::__streambuf_core_access.
        libstdc++-v3/include/std/syncstream: New header.
        libstdc++-v3/include/std/version: Add __cpp_lib_syncbuf:
        libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc: New test.
        libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc: Likewise.
        libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc:
        Likewise.
        libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc:
        Likewise.
        libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc:
        Likewise.
        libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc: Likewise.
        libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc: Likewise.
        libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc:
        Likewise.
        libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc:
        Likewise.
---
libstdc++-v3/doc/doxygen/user.cfg.in          |   1 +
libstdc++-v3/include/Makefile.am              |   1 +
libstdc++-v3/include/Makefile.in              |   1 +
libstdc++-v3/include/precompiled/stdc++.h     |   2 +-
libstdc++-v3/include/std/syncstream           | 333 ++++++++++++++++++
libstdc++-v3/include/std/version              |   4 +
.../testsuite/27_io/basic_syncbuf/1.cc        |  28 ++
.../testsuite/27_io/basic_syncbuf/2.cc        |  28 ++
.../27_io/basic_syncbuf/basic_ops/1.cc        | 137 +++++++
.../27_io/basic_syncbuf/requirements/types.cc |  42 +++
.../27_io/basic_syncbuf/sync_ops/1.cc         | 130 +++++++
.../testsuite/27_io/basic_syncstream/1.cc     |  28 ++
.../testsuite/27_io/basic_syncstream/2.cc     |  28 ++
.../27_io/basic_syncstream/basic_ops/1.cc     | 134 +++++++
.../basic_syncstream/requirements/types.cc    |  43 +++
15 files changed, 939 insertions(+), 1 deletion(-)
create mode 100644 libstdc++-v3/include/std/syncstream
create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc
create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc
create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc
create mode 100644 
libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc
create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc
create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc
create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc
create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc
create mode 100644 
libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc

diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in 
b/libstdc++-v3/doc/doxygen/user.cfg.in
index 9b49a15d31b..320f6dea688 100644
--- a/libstdc++-v3/doc/doxygen/user.cfg.in
+++ b/libstdc++-v3/doc/doxygen/user.cfg.in
@@ -897,6 +897,7 @@ INPUT                  = @srcdir@/doc/doxygen/doxygroups.cc 
\
                         include/streambuf \
                         include/string \
                         include/string_view \
+                         include/syncstream \
                         include/system_error \
                         include/thread \
                         include/tuple \
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c90ac555e15..8652b921274 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -73,6 +73,7 @@ std_headers = \
        ${std_srcdir}/shared_mutex \
        ${std_srcdir}/span \
        ${std_srcdir}/sstream \
+       ${std_srcdir}/syncstream \
        ${std_srcdir}/stack \
        ${std_srcdir}/stdexcept \
        ${std_srcdir}/stop_token \
diff --git a/libstdc++-v3/include/precompiled/stdc++.h 
b/libstdc++-v3/include/precompiled/stdc++.h
index 7518a98c25a..8899c323a28 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -141,6 +141,6 @@
#include <ranges>
#include <span>
#include <stop_token>
-// #include <syncstream>
+#include <syncstream>
#include <version>
#endif
diff --git a/libstdc++-v3/include/std/syncstream 
b/libstdc++-v3/include/std/syncstream
new file mode 100644
index 00000000000..ff96ca6cf59
--- /dev/null
+++ b/libstdc++-v3/include/std/syncstream
@@ -0,0 +1,333 @@
+// <syncstream> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/syncstream
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SYNCSTREAM
+#define _GLIBCXX_SYNCSTREAM 1
+
+#if __cplusplus > 201703L
+
+#include <bits/c++config.h>
+#if _GLIBCXX_USE_CXX11_ABI
+
+#define __cpp_lib_syncbuf 201803L
+
+#pragma GCC system_header
+
+#include <sstream>
+
+#include <bits/alloc_traits.h>
+#include <bits/allocator.h>
+#include <bits/functexcept.h>
+#include <bits/functional_hash.h>
+
+#if _GLIBCXX_HAS_GTHREADS
+# include <bits/std_mutex.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _CharT, typename _Traits = char_traits<_CharT>,
+           typename _Alloc = allocator<_CharT>>
+    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 = _Alloc;
+      using streambuf_type = basic_streambuf<_CharT, _Traits>;
+
+      basic_syncbuf()
+      : basic_syncbuf(nullptr, allocator_type{})
+      { }
+
+      explicit
+      basic_syncbuf(streambuf_type* __obuf)
+       : basic_syncbuf(__obuf, allocator_type{})
+      { }
+
+      basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)
+       : _M_wrapped(__obuf)
+       , _M_impl(__alloc)
+       , _M_mtx(__obuf)
+      { }
+
+      basic_syncbuf(basic_syncbuf&& __other)
+       : _M_wrapped(__other._M_wrapped)
+       , _M_impl(std::move(__other._M_impl))
+       , _M_mtx(std::move(__other._M_mtx))
+       , _M_emit_on_sync(__other._M_emit_on_sync)
+       , _M_needs_sync(__other._M_needs_sync)
+      {
+       __other._M_wrapped = nullptr;
+      }
+
+      ~basic_syncbuf()
+      {
+       __try
+         {
+           emit();
+         }
+       __catch (...)
+         { }
+      }
+
+      basic_syncbuf& operator=(basic_syncbuf&& __other)
+      {
+       if (std::__addressof(__other) != this)
+         {
+           emit();
+
+           _M_impl = std::move(__other._M_impl);
+           _M_wrapped = __other._M_wrapped; __other._M_wrapped = nullptr;
+           _M_mtx = std::move(__other._M_mtx);
+           _M_emit_on_sync = __other._M_emit_on_sync;
+           _M_needs_sync = __other._M_needs_sync;
+         }
+       return *this;
+      }
+
+      void
+      swap(basic_syncbuf& __other)
+      {
+       if (std::__addressof(__other) != this)
+         {
+           std::swap(_M_impl, __other._M_impl);
+           std::swap(_M_wrapped, __other._M_wrapped);
+           std::swap(_M_mtx, __other._M_mtx);
+           std::swap(_M_emit_on_sync, __other._M_emit_on_sync);
+           std::swap(_M_needs_sync, __other._M_needs_sync);
+         }
+      }
+
+      bool
+      emit()
+      {
+       if (!_M_wrapped)
+         return false;
+
+       auto __s = _M_impl.view();
+       if (__s.empty())
+         return true;
+
+       const lock_guard<__mutex> __l(_M_mtx);
+       if (_M_wrapped->sputn(__s.data(), __s.size()) != __s.size())
+         return false;
+
+       if (_M_needs_sync)
+         {
+           _M_needs_sync = false;
+           if (_M_wrapped->pubsync() != 0)
+             return false;
+         }
+
+       _M_impl.str("");
+       return true;
+      }
+
+      streambuf_type*
+      get_wrapped() const noexcept
+      { return _M_wrapped; }
+
+      allocator_type get_allocator() const noexcept
+      { return _M_impl.get_allocator(); }
+
+      void
+      set_emit_on_sync(bool __b) noexcept
+      { _M_emit_on_sync = __b; }
+
+    protected:
+      int
+      sync() override
+      {
+       auto __res = _M_impl.pubsync();
+       if (__res == 0)
+         {
+           _M_needs_sync = true;
+           if (_M_emit_on_sync)
+             return emit() ? 0 : -1;
+         }
+       return __res;
+      }
+
+      streamsize
+      xsputn(const char_type* __s, streamsize __n) override
+      { return _M_impl.sputn(__s, __n); }
+
+    private:
+      streambuf_type* _M_wrapped;
+
+      using __impl_type = basic_stringbuf<char_type, traits_type,
+                                         allocator_type>;
+      __impl_type _M_impl;
+
+      struct __mutex
+      {
+#if _GLIBCXX_HAS_GTHREADS
+       mutex* _M_mtx;
+
+       __mutex(void* __t)

Make this 'explicit' please.

+         : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)
+       { }
+
+       void
+       swap(__mutex& __other) noexcept
+       { std::swap(_M_mtx, __other._M_mtx); }
+
+       void
+       lock()
+       {
+         if (_M_mtx)
+           _M_mtx->lock();
+       }
+
+       void
+       unlock()
+       {
+         if (_M_mtx)
+           _M_mtx->unlock();
+       }
+
+       // FIXME: This should be put in the .so
+       static mutex&
+       _S_get_mutex(void* __t)
+       {
+         const unsigned char __mask = 0xf;
+         static mutex __m[__mask + 1];
+
+         auto __key = _Hash_impl::hash(__t) & __mask;
+         return __m[__key];
+       }
+#else
+       __mutex(void*)

And 'explicit' here too.

+       { }
+
+       void
+       swap(__mutex&&) noexcept

This needs to be an lvalue reference, or it won't compile.

+       { }
+
+       void
+       lock()
+       { }
+
+       void
+       unlock()
+       { }

All these completely empty functions can be put on one line:

      void unlock() { }

There's no need for these no-op members take up so many lines.

+#endif
+       __mutex(const __mutex&) = delete;
+       __mutex& operator=(const __mutex&) = delete;

These are redundant (the user-declared moves below cause the copies to
be deleted) but harmless.

+
+       __mutex(__mutex&&) = default;
+       __mutex& operator=(__mutex&&) = default;
+      };
+      __mutex _M_mtx;
+
+      bool _M_emit_on_sync = false;
+      bool _M_needs_sync = false;
+    };


OK for trunk, thanks.


Reply via email to