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.