From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 675283840C19 for ; Mon, 2 Nov 2020 17:38:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 675283840C19 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-133-dxGJt118OZGNH7ps2Qyxwg-1; Mon, 02 Nov 2020 12:38:48 -0500 X-MC-Unique: dxGJt118OZGNH7ps2Qyxwg-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id A19808015C3; Mon, 2 Nov 2020 17:38:47 +0000 (UTC) Received: from localhost (unknown [10.33.36.7]) by smtp.corp.redhat.com (Postfix) with ESMTP id E2A895C5DE; Mon, 2 Nov 2020 17:38:46 +0000 (UTC) Date: Mon, 2 Nov 2020 17:38:45 +0000 From: Jonathan Wakely To: Thomas Rodgers Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org, trodgers@redhat.com Subject: Re: [PATCH] libstdc++: Add c++2a Message-ID: <20201102173845.GT503596@redhat.com> References: <20201029211212.1465538-1-rodgert@appliantology.com> <20201102161050.2120502-1-rodgert@appliantology.com> MIME-Version: 1.0 In-Reply-To: <20201102161050.2120502-1-rodgert@appliantology.com> X-Clacks-Overhead: GNU Terry Pratchett X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline X-Spam-Status: No, score=-14.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 02 Nov 2020 17:38:53 -0000 On 02/11/20 08:10 -0800, Thomas Rodgers wrote: >From: Thomas Rodgers > >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 > #include > #include >-// #include >+#include > #include > #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 @@ >+// -*- 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 >+// . >+ >+/** @file include/syncstream >+ * This is a Standard C++ Library header. >+ */ >+ >+#ifndef _GLIBCXX_SYNCSTREAM >+#define _GLIBCXX_SYNCSTREAM 1 >+ >+#if __cplusplus > 201703L >+ >+#include >+#if _GLIBCXX_USE_CXX11_ABI >+ >+#define __cpp_lib_syncbuf 201803L >+ >+#pragma GCC system_header >+ >+#include >+ >+#include >+#include >+#include >+#include >+ >+#if _GLIBCXX_HAS_GTHREADS >+# include >+#endif >+ >+namespace std _GLIBCXX_VISIBILITY(default) >+{ >+_GLIBCXX_BEGIN_NAMESPACE_VERSION >+ >+ template, >+ 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+ 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.