public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] libstdc++: Add c++2a <syncstream>
@ 2020-10-15 14:46 Thomas Rodgers
  2020-10-15 18:13 ` Jonathan Wakely
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Thomas Rodgers @ 2020-10-15 14:46 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers

From: Thomas Rodgers <trodgers@redhat.com>

* Note: depends on a sufficiently C++20ified basic_stringbuf<>.

libstdc++/Changelog:
	libstdc++-v3/include/Makefile.am (std_headers): Add new header.
	libstdc++-v3/include/Makefile.in: Regenerate.
	libstdc++-v3/include/std/streambuf
        (__detail::__streambuf_core_access): Define.
        (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/include/Makefile.am              |   1 +
 libstdc++-v3/include/Makefile.in              |   1 +
 libstdc++-v3/include/std/streambuf            |  81 +++++
 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        |  27 ++
 .../27_io/basic_syncbuf/basic_ops/1.cc        | 138 ++++++++
 .../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     |  27 ++
 .../27_io/basic_syncstream/basic_ops/1.cc     | 135 +++++++
 .../basic_syncstream/requirements/types.cc    |  43 +++
 14 files changed, 1018 insertions(+)
 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/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 28d273924ee..61aaff7a2f4 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/std/streambuf b/libstdc++-v3/include/std/streambuf
index cae35e75bda..d6053e4c1ed 100644
--- a/libstdc++-v3/include/std/streambuf
+++ b/libstdc++-v3/include/std/streambuf
@@ -48,6 +48,84 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #define _IsUnused __attribute__ ((__unused__))
 
+  template<typename _CharT, typename _Traits>
+    class basic_streambuf;
+
+#if __cplusplus > 201703L
+  namespace __detail
+  {
+    struct __streambuf_core_access
+    {
+      template<typename _CharT, typename _Traits>
+	static void
+	_S_imbue(basic_streambuf<_CharT, _Traits>& __b, const locale& __loc)
+	{ __b.imbue(__loc); }
+
+      template<typename _CharT, typename _Traits>
+	static basic_streambuf<_CharT, _Traits>*
+	_S_setbuf(basic_streambuf<_CharT, _Traits>& __b,
+		  _CharT* __c, streamsize __n)
+	{ return __b.setbuf(__c, __n); }
+
+      template<typename _CharT, typename _Traits>
+	static typename _Traits::pos_type
+	_S_seekoff(basic_streambuf<_CharT, _Traits>& __b,
+		   typename _Traits::off_type __off, ios_base::seekdir __dir,
+		   ios_base::openmode __mode)
+	  { return __b.seekoff(__off, __dir, __mode); }
+
+      template<typename _CharT, typename _Traits>
+	static typename _Traits::pos_type
+	_S_seekpos(basic_streambuf<_CharT, _Traits>& __b,
+		   typename _Traits::pos_type __pos, ios_base::openmode __mode)
+	{ return __b.seekpos(__pos, __mode); }
+
+      template<typename _CharT, typename _Traits>
+	static int
+	_S_sync(basic_streambuf<_CharT, _Traits>& __b)
+	{ return __b.sync(); }
+
+      template<typename _CharT, typename _Traits>
+	static streamsize
+	_S_showmanyc(basic_streambuf<_CharT, _Traits>& __b)
+	{ return __b.showmanyc(); }
+
+      template<typename _CharT, typename _Traits>
+	static streamsize
+	_S_xsgetn(basic_streambuf<_CharT, _Traits>& __b, _CharT* __s, streamsize __n)
+	{ return __b.xsgetn(__s, __n); }
+
+      template<typename _CharT, typename _Traits>
+	static typename _Traits::int_type
+	_S_underflow(basic_streambuf<_CharT, _Traits>& __b)
+	{ return __b.underflow(); }
+
+      template<typename _CharT, typename _Traits>
+	static typename _Traits::int_type
+	_S_uflow(basic_streambuf<_CharT, _Traits>& __b)
+	{ return __b.uflow(); }
+
+      template<typename _CharT, typename _Traits>
+	static typename _Traits::int_type
+	_S_pbackfail(basic_streambuf<_CharT, _Traits>& __b,
+		     typename _Traits::int_type __c)
+	{ return __b.pbackfail(__c); }
+
+      template<typename _CharT, typename _Traits>
+	static streamsize
+	_S_xsputn(basic_streambuf<_CharT, _Traits>& __b,
+	       const typename _Traits::char_type* __s, streamsize __n)
+	{ return __b.xsputn(__s, __n); }
+
+      template<typename _CharT, typename _Traits>
+	typename _Traits::int_type
+	_S_overflow(basic_streambuf<_CharT, _Traits>& __b,
+		    typename _Traits::int_type __c)
+	{ return __b.overflow(__c); } 
+    };
+  }
+#endif // C++20
+
   template<typename _CharT, typename _Traits>
     streamsize
     __copy_streambufs_eof(basic_streambuf<_CharT, _Traits>*,
@@ -456,6 +534,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return this->xsputn(__s, __n); }
 
     protected:
+#if __cplusplus > 201703L
+      friend __detail::__streambuf_core_access;
+#endif
       /**
        *  @brief  Base constructor.
        *
diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream
new file mode 100644
index 00000000000..0a034ed03f4
--- /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/ranges
+ *  This is a Standard C++ Library header.
+ */
+
+ #ifndef _GLIBCXX_SYNCSTREAM
+ #define _GLIBCXX_SYNCSTREAM 1
+
+#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+
+#define __cpp_lib_syncbuf 201803L
+
+#pragma GCC system_header
+
+#include <bits/alloc_traits.h>
+#include <bits/allocator.h>
+#include <bits/functional_hash.h>
+#include <bits/std_mutex.h>
+
+#include <ostream>
+#include <sstream>
+
+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)
+      { }
+
+      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 ? &_S_get_mutex(__obuf) : nullptr)
+      { }
+
+      basic_syncbuf(basic_syncbuf&& __other)
+	: _M_wrapped(__other._M_wrapped)
+	, _M_impl(std::move(__other._M_impl))
+	, _M_mtx(__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 (&__other != this)
+	  {
+	    emit();
+	    _M_wrapped = __other._M_wrapped; __other._M_wrapped = nullptr;
+	    _M_impl = std::move(__other._M_impl);
+	    _M_mtx = __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 (&__other != this)
+	  {
+	    std::swap(_M_wrapped, __other._M_wrapped);
+	    std::swap(_M_impl, __other._M_impl);
+	    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);
+	auto __xsz = _M_wrapped->sputn(__s.data(), __s.size());
+
+	if (__xsz != __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:
+      void
+      imbue(const locale& __loc) override
+      { __detail::__streambuf_core_access::_S_imbue(_M_impl, __loc); }
+
+      basic_streambuf<char_type,_Traits>*
+      setbuf(char_type* __c, streamsize __n) override
+      {
+	return __detail::__streambuf_core_access::_S_setbuf(_M_impl, __c, __n);
+      }
+
+      pos_type
+      seekoff(off_type __off, ios_base::seekdir __dir,
+	      ios_base::openmode __mode) override
+      {
+	return __detail::__streambuf_core_access::_S_seekoff(_M_impl, __off,
+							     __dir, __mode);
+      }
+
+      pos_type
+      seekpos(pos_type __pos, ios_base::openmode __mode) override
+      {
+	return __detail::__streambuf_core_access::_S_seekpos(_M_impl,
+							     __pos, __mode);
+      }
+
+      int
+      sync() override
+      {
+	auto __res = __detail::__streambuf_core_access::_S_sync(_M_impl);
+	if (__res == 0)
+	  {
+	    _M_needs_sync = true;
+	    if (_M_emit_on_sync)
+	      return emit() ? 0 : -1;
+	  }
+	return __res;
+      }
+
+      streamsize
+      showmanyc() override
+      { return __detail::__streambuf_core_access::_S_showmanyc(_M_impl); } 
+
+      streamsize
+      xsgetn(char_type* __s, streamsize __n) override
+      {
+	return __detail::__streambuf_core_access::_S_xsgetn(_M_impl, __s, __n);
+      } 
+
+      int_type
+      underflow() override
+      { return __detail::__streambuf_core_access::_S_underflow(_M_impl); }
+
+      int_type
+      uflow() override
+      { return __detail::__streambuf_core_access::_S_uflow(_M_impl); }
+
+      int_type
+      pbackfail(int_type __c) override
+      { return __detail::__streambuf_core_access::_S_pbackfail(_M_impl, __c); }
+
+      streamsize
+      xsputn(const char_type* __s, streamsize __n) override
+      {
+	return __detail::__streambuf_core_access::_S_xsputn(_M_impl, __s, __n);
+      }
+
+    private:
+      streambuf_type* _M_wrapped;
+
+      using __impl_type = basic_stringbuf<char_type, traits_type,
+					  allocator_type>;
+      __impl_type _M_impl;
+      mutex* _M_mtx;
+
+      bool _M_emit_on_sync = false;
+      bool _M_needs_sync = false;
+
+      static constexpr size_t _S_small_size = 128;
+
+      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];
+      }
+    };
+
+  template <typename _CharT, typename _Traits = char_traits<_CharT>,
+	    typename _Alloc = allocator<_CharT>>
+    class basic_osyncstream : public basic_ostream<_CharT, _Traits>
+    {
+    public:
+      // Types:
+      using char_type = _CharT;
+      using traits_type = _Traits;
+      using allocator_type = _Alloc;
+      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 syncbuf_type = basic_syncbuf<_CharT, _Traits, _Alloc>;
+      using streambuf_type = typename syncbuf_type::streambuf_type;
+
+      using __ostream_type = basic_ostream<_CharT, _Traits>;
+
+    private:
+      syncbuf_type _M_syncbuf;
+
+    public:
+      basic_osyncstream(streambuf_type* __buf, const allocator_type& __a)
+	: _M_syncbuf(__buf, __a)
+      { this->init(&_M_syncbuf); }
+
+      explicit basic_osyncstream(streambuf_type* __buf)
+	: _M_syncbuf(__buf)
+      { this->init(&_M_syncbuf); }
+
+      basic_osyncstream(basic_ostream<char_type, traits_type>& __os,
+		        const allocator_type& __a)
+	: basic_osyncstream(__os.rdbuf(), __a)
+      { this->init(&_M_syncbuf); }
+
+      explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
+	: basic_osyncstream(__os.rdbuf())
+      { this->init(&_M_syncbuf); }
+
+      basic_osyncstream(basic_osyncstream&& __rhs) noexcept
+	: __ostream_type(std::move(__rhs)),
+	_M_syncbuf(std::move(__rhs._M_syncbuf))
+      { __ostream_type::set_rdbuf(&_M_syncbuf); }
+
+      ~basic_osyncstream() = default;
+
+      basic_osyncstream& operator=(basic_osyncstream&& __rhs) noexcept
+      {
+	if (&__rhs != this)
+	  {
+	    __ostream_type::operator=(std::move(__rhs));
+	    _M_syncbuf = std::move(__rhs._M_syncbuf);
+	    __ostream_type::set_rdbuf(&_M_syncbuf);
+	  }
+	return *this;
+      }
+
+      syncbuf_type* rdbuf() const noexcept
+      { return const_cast<syncbuf_type*>(&_M_syncbuf); }
+
+      streambuf_type* get_wrapped() const noexcept
+      { return _M_syncbuf.get_wrapped(); }
+
+      void emit()
+      { _M_syncbuf.emit(); }
+    };
+
+  template <class _CharT, class _Traits, class _Allocator>
+    inline void
+    swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __x,
+	 basic_syncbuf<_CharT, _Traits, _Allocator>& __y)
+    { __x.swap(__y); }
+
+  using syncbuf = basic_syncbuf<char>;
+  using wsyncbuf = basic_syncbuf<wchar_t>;
+
+  using osyncstream = basic_osyncstream<char>;
+  using wosyncstream = basic_osyncstream<wchar_t>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++2a
+#endif	/* _GLIBCXX_SYNCSTREAM */
+
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d5d42ed0a72..8681d70fbfa 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -215,6 +215,10 @@
 #define __cpp_lib_interpolate 201902L
 #ifdef _GLIBCXX_HAS_GTHREADS
 # define __cpp_lib_jthread 201911L
+# ifdef _GLIBCXX_USE_CXX11_ABI
+// Only supported with cx11-abi
+#  define __cpp_lib_syncbuf 201803L
+# endif
 #endif
 #define __cpp_lib_list_remove_return_type 201806L
 #define __cpp_lib_math_constants 201907L
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc
new file mode 100644
index 00000000000..ebea9becdb3
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc
@@ -0,0 +1,28 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+
+#ifndef __cpp_lib_syncbuf
+# error "Feature-test macro for syncbuf missing in <syncstream>"
+#elif __cpp_lib_syncbuf!= 201803L
+# error "Feature-test macro for syncbuf has wrong value in <syncstream>"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc
new file mode 100644
index 00000000000..43538f89fb8
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc
@@ -0,0 +1,27 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_syncbuf
+# error "Feature-test macro for syncbuf missing in <version>"
+#elif __cpp_lib_syncbuf!= 201803L
+# error "Feature-test macro for syncbuf has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc
new file mode 100644
index 00000000000..98e00dea1f1
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc
@@ -0,0 +1,138 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-effective-target cxx11-abi }
+// { dg-require-gthreads "" }
+
+#include <sstream>
+#include <string_view>
+#include <syncstream>
+
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+
+void
+test01() // construction
+{
+  {
+    std::syncbuf s1;
+    VERIFY( s1.get_wrapped() == nullptr );
+
+    std::stringbuf b;
+    std::syncbuf s2(&b);
+    VERIFY( s2.get_wrapped() == &b );
+  }
+
+  {
+    using alloc_type = __gnu_test::uneq_allocator<char>;
+    using sbuf_t = std::basic_syncbuf<char, std::char_traits<char>,
+				      alloc_type>;
+
+    sbuf_t b;
+
+    alloc_type aa;
+    sbuf_t s1(&b, aa);
+    VERIFY( aa == s1.get_allocator() );
+
+    alloc_type aaa(42);
+    sbuf_t s2(&b, aaa);
+    VERIFY( aaa == s2.get_allocator() );
+
+    VERIFY( s1.get_allocator() != s2.get_allocator() );
+  }
+}
+
+void
+test02() // moving
+{
+  {
+    std::stringbuf b;
+    std::syncbuf s1(&b);
+
+    std::syncbuf s2(std::move(s1));
+
+    VERIFY( s1.get_wrapped() == nullptr );
+    VERIFY( s2.get_wrapped() == &b );
+  }
+
+  {
+    std::stringbuf b;
+    std::syncbuf s1(&b);
+
+    std::syncbuf s2;
+    s2 = std::move(s1);
+
+    VERIFY( s1.get_wrapped() == nullptr );
+    VERIFY( s2.get_wrapped() == &b );
+  }
+}
+
+void
+test03() // swaping
+{
+  std::stringbuf b;
+  std::syncbuf s1(&b);
+
+  std::syncbuf s2;
+  std::swap(s1, s2);
+
+  VERIFY( s1.get_wrapped() == nullptr );
+  VERIFY( s2.get_wrapped() == &b );
+}
+
+void
+test04() // emitting
+{
+  {
+    std::stringbuf b;
+    std::syncbuf s(&b);
+
+    const std::string_view txt("This is a test");
+    s.sputn(txt.data(), txt.size());
+
+    VERIFY( b.str() != txt );
+    VERIFY( s.pubsync() == 0 );
+    VERIFY( b.str() != txt );
+
+    VERIFY( s.emit() );
+    VERIFY( b.str() == txt );
+  }
+
+  {
+    std::stringbuf b;
+    std::syncbuf s(&b);
+    s.set_emit_on_sync(true);
+
+    const std::string_view txt("This is a test");
+    s.sputn(txt.data(), txt.size());
+
+    VERIFY( s.pubsync() == 0 );
+    VERIFY( b.str() == txt );
+  }
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc
new file mode 100644
index 00000000000..49266b4abf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc
@@ -0,0 +1,42 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+
+template<typename T>
+  struct type_reqs
+  {
+    using test_type = T;
+    using char_type = test_type::char_type;
+    using int_type = test_type::int_type;
+    using pos_type = test_type::pos_type;
+    using off_Type = test_type::off_type;
+    using traits_type = test_type::traits_type;
+    using allocator_type = test_type::allocator_type;
+    using streambuf_type = test_type::streambuf_type;
+  };
+
+void test01()
+{
+  // Check for required typedefs
+  using test_type = type_reqs<std::osyncstream>;
+  using wtest_type = type_reqs<std::wosyncstream>;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc
new file mode 100644
index 00000000000..097da110178
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc
@@ -0,0 +1,130 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread -Wl,--no-demangle" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-effective-target cxx11-abi }
+// { dg-require-gthreads "" }
+
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <syncstream>
+#include <thread>
+#include <vector>
+#include <unordered_map>
+#include <utility>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+  using namespace std::chrono_literals;
+
+  std::stringbuf b;
+  std::atomic<unsigned> running(0);
+
+  auto const cstr = "This is a test";
+
+  constexpr int ct = 1000;
+  auto const body = [&]{
+    ++running;
+    auto tid = std::this_thread::get_id();
+    std::syncbuf s(&b);
+    for (auto i = 0; i < ct; ++i)
+    {
+      std::stringstream stm;
+      stm << tid << ' ' << cstr << ' ' << i << std::endl;
+      auto sv = stm.view();
+      s.sputn(sv.data(), sv.size());
+      VERIFY( s.emit() );
+    }
+  };
+
+  const auto tct = 8;
+  std::vector<std::thread> ts;
+  ts.reserve(tct);
+
+  for (auto i = 0; i < tct; ++i)
+    ts.emplace_back(std::thread(body));
+
+  do
+  {
+    std::this_thread::sleep_for(100ms);
+  }
+  while (running.load() < tct);
+
+  std::unordered_map<std::string, int> tids;
+  for (auto&& t : ts)
+  {
+    std::stringstream stm;
+    stm << t.get_id();
+    tids.emplace(std::make_pair(stm.str(), 0));
+  };
+
+  for (auto&& t : ts)
+     t.join();
+
+  std::vector<std::string_view> lines;
+  const auto lct = ct * ts.size();
+  lines.reserve(lct);
+
+  std::size_t last = 0;
+  auto sv = b.view();
+  auto p = sv.find('\n');
+  while (p != std::string_view::npos)
+  {
+    lines.emplace_back(sv.substr(last, p - last));
+    last = p+1;
+    p = sv.find('\n', last);
+  }
+  VERIFY( lines.size() == lct );
+
+  auto sep = "";
+  auto i = 0;
+  sv = std::string_view(cstr);
+
+  for (auto&& l : lines)
+  {
+    auto p = l.find(' ');
+    VERIFY( p != std::string_view::npos );
+    std::string tid(l.substr(0, p));
+    ++p;
+
+    VERIFY( l.substr(p, sv.size()) == sv );
+    std::string s(l.substr(++p + sv.size()));
+    std::stringstream stm(s);
+    int n;
+    stm >> n;
+    VERIFY( stm.eof() );
+    VERIFY( n >= 0 && n < ct );
+    auto it = tids.find(tid);
+    VERIFY( it != std::end(tids) );
+    ++(it->second);
+  }
+
+  for (auto const& t : tids)
+  {
+    VERIFY( t.second == ct );
+  }
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc
new file mode 100644
index 00000000000..ebea9becdb3
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc
@@ -0,0 +1,28 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+
+#ifndef __cpp_lib_syncbuf
+# error "Feature-test macro for syncbuf missing in <syncstream>"
+#elif __cpp_lib_syncbuf!= 201803L
+# error "Feature-test macro for syncbuf has wrong value in <syncstream>"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc b/libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc
new file mode 100644
index 00000000000..43538f89fb8
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc
@@ -0,0 +1,27 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_syncbuf
+# error "Feature-test macro for syncbuf missing in <version>"
+#elif __cpp_lib_syncbuf!= 201803L
+# error "Feature-test macro for syncbuf has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc
new file mode 100644
index 00000000000..e2cb6404cbe
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc
@@ -0,0 +1,135 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-effective-target cxx11-abi }
+// { dg-require-gthreads "" }
+
+#include <sstream>
+#include <string_view>
+#include <syncstream>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+
+void
+test01() // construction
+{
+  {
+    std::stringbuf b;
+    std::osyncstream s(&b);
+    VERIFY( s.rdbuf() != nullptr );
+    VERIFY( s.get_wrapped() == &b );
+  }
+
+  {
+    std::ostringstream stm;
+    std::osyncstream s(stm);
+    VERIFY( s.get_wrapped() == stm.rdbuf() );
+  }
+
+  {
+    using alloc_type = __gnu_test::uneq_allocator<char>;
+    using sbuf_t = std::basic_syncbuf<char, std::char_traits<char>,
+				      alloc_type>;
+    using stream_t = std::basic_osyncstream<char, std::char_traits<char>,
+					    alloc_type>;
+    using str_t = std::basic_ostringstream<char, std::char_traits<char>,
+                                           alloc_type>;
+    sbuf_t b;
+
+    alloc_type aa;
+    stream_t s1(&b, aa);
+    VERIFY( aa == s1.rdbuf()->get_allocator() );
+
+    alloc_type aaa(42);
+    stream_t s2(&b, aaa);
+    VERIFY( aaa == s2.rdbuf()->get_allocator() );
+
+    VERIFY( s1.rdbuf()->get_allocator() != s2.rdbuf()->get_allocator() );
+
+    str_t stm;
+    stream_t s3(stm, aa);
+    VERIFY( s3.get_wrapped() == stm.rdbuf() );
+    VERIFY( aa == s1.rdbuf()->get_allocator() );
+  }
+}
+
+void
+test02() // moving
+{
+  {
+    std::stringbuf b;
+    std::osyncstream s1(&b);
+
+    std::osyncstream s2(std::move(s1));
+
+    VERIFY( s1.get_wrapped() == nullptr );
+    VERIFY( s2.get_wrapped() == &b );
+  }
+
+  {
+    std::stringbuf b1;
+    std::osyncstream s1(&b1);
+
+    std::stringbuf b2;
+    std::osyncstream s2(&b2);
+    s2 = std::move(s1);
+
+    VERIFY( s1.get_wrapped() == nullptr );
+    VERIFY( s2.get_wrapped() == &b1 );
+  }
+}
+
+void
+test03() // swaping
+{
+  std::stringbuf b1;
+  std::osyncstream s1(&b1);
+  
+  std::stringbuf b2;
+  std::osyncstream s2(&b2);
+
+  std::swap(s1, s2);
+
+  VERIFY( s1.get_wrapped() == &b2 );
+  VERIFY( s2.get_wrapped() == &b1 );
+}
+
+void
+test04() // emitting
+{
+  {
+    std::stringbuf b;
+    std::osyncstream s(&b);
+
+    const std::string_view txt("This is a test");
+    s << txt;
+
+    s.emit();
+    VERIFY( b.str() == txt );
+  }
+}
+int main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc b/libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc
new file mode 100644
index 00000000000..dfc0b72efcd
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc
@@ -0,0 +1,43 @@
+// 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+
+template<typename T>
+  struct type_reqs
+  {
+    using test_type = T;
+    using char_type = test_type::char_type;
+    using int_type = test_type::int_type;
+    using pos_type = test_type::pos_type;
+    using off_Type = test_type::off_type;
+    using traits_type = test_type::traits_type;
+    using allocator_type = test_type::allocator_type;
+    using streambuf_type = test_type::streambuf_type;
+    using syncbuf_type = test_type::syncbuf_type;
+  };
+
+void test01()
+{
+  // Check for required typedefs
+  using test_type = type_reqs<std::osyncstream>;
+  using wtest_type = type_reqs<std::wosyncstream>;
+}
-- 
2.26.2


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2020-11-03 22:00 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-15 14:46 [PATCH] libstdc++: Add c++2a <syncstream> Thomas Rodgers
2020-10-15 18:13 ` Jonathan Wakely
2020-10-15 18:18 ` Jonathan Wakely
2020-10-15 19:29 ` Jonathan Wakely
2020-10-16  0:24   ` Thomas Rodgers
2020-10-21 16:53   ` Thomas Rodgers
2020-10-21 17:34     ` Jonathan Wakely
2020-10-21 19:39       ` Thomas Rodgers
2020-10-29 16:18     ` Jonathan Wakely
2020-10-29 21:12       ` Thomas Rodgers
2020-11-02 15:58         ` Thomas Rodgers
2020-11-02 16:10         ` Thomas Rodgers
2020-11-02 17:38           ` Jonathan Wakely
2020-11-02 18:43             ` Thomas Rodgers
2020-11-03 21:22               ` Christophe Lyon
2020-11-03 22:00                 ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).