@@ -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 \
@@ -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 \
@@ -141,6 +141,6 @@
#include <ranges>
#include <span>
#include <stop_token>
-// #include <syncstream>
+#include <syncstream>
#include <version>
#endif
new file mode 100644
@@ -0,0 +1,328 @@
+// <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_locker(__obuf)
+ { }
+
+ basic_syncbuf(basic_syncbuf&& __other)
+ : _M_wrapped(__other._M_wrapped)
+ , _M_impl(std::move(__other._M_impl))
+ , _M_locker(std::move(__other._M_locker))
+ , _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_locker = std::move(__other._M_locker);
+ _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_locker, __other._M_locker);
+ 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;
+
+ auto res = _M_locker([&, this]
+ {
+ 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 __with_lock
+ {
+#if _GLIBCXX_HAS_GTHREADS
+ mutex* _M_mtx;
+
+ __with_lock(void* __t)
+ : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)
+ { }
+
+ void
+ swap(__with_lock& __other) noexcept
+ { std::swap(_M_mtx, __other._M_mtx); }
+
+ template<typename _Func>
+ bool
+ operator()(_Func __f)
+ {
+ const lock_guard<mutex> __l(*_M_mtx);
+ return __f();
+ }
+
+ // 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
+ __with_lock(void*)
+ { }
+
+ void
+ swap(__with_lock&) noexcept
+ { }
+
+ template<typename _Func>
+ bool
+ operator()(_Func && __f)
+ {
+ return __f();
+ }
+#endif
+ __with_lock(const __with_lock&) = delete;
+ __with_lock& operator=(const __with_lock&) = delete;
+
+ __with_lock(__with_lock&&) = default;
+ __with_lock& operator=(__with_lock&&) = default;
+ };
+ __with_lock _M_locker;
+
+ bool _M_emit_on_sync = false;
+ bool _M_needs_sync = false;
+ };
+
+ template <typename _CharT, typename _Traits = char_traits<_CharT>,
+ typename _Alloc = allocator<_CharT>>
+ class basic_osyncstream : public basic_ostream<_CharT, _Traits>
+ {
+ using __ostream_type = 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;
+
+ private:
+ syncbuf_type _M_syncbuf;
+
+ public:
+ basic_osyncstream(streambuf_type* __buf, const allocator_type& __a)
+ : _M_syncbuf(__buf, __a)
+ { this->init(std::__addressof(_M_syncbuf)); }
+
+ explicit basic_osyncstream(streambuf_type* __buf)
+ : _M_syncbuf(__buf)
+ { this->init(std::__addressof(_M_syncbuf)); }
+
+ basic_osyncstream(basic_ostream<char_type, traits_type>& __os,
+ const allocator_type& __a)
+ : basic_osyncstream(__os.rdbuf(), __a)
+ { this->init(std::__addressof(_M_syncbuf)); }
+
+ explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
+ : basic_osyncstream(__os.rdbuf())
+ { this->init(std::__addressof(_M_syncbuf)); }
+
+ basic_osyncstream(basic_osyncstream&& __rhs) noexcept
+ : __ostream_type(std::move(__rhs)),
+ _M_syncbuf(std::move(__rhs._M_syncbuf))
+ { __ostream_type::set_rdbuf(std::__addressof(_M_syncbuf)); }
+
+ ~basic_osyncstream() = default;
+
+ basic_osyncstream& operator=(basic_osyncstream&&) noexcept = default;
+
+ 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()
+ {
+ if (!_M_syncbuf.emit())
+ this->setstate(ios_base::failbit);
+ }
+ };
+
+ template <class _CharT, class _Traits, class _Allocator>
+ inline void
+ swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __x,
+ basic_syncbuf<_CharT, _Traits, _Allocator>& __y) noexcept
+ { __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 // _GLIBCXX_USE_CXX11_ABI
+#endif // C++2a
+#endif /* _GLIBCXX_SYNCSTREAM */
@@ -229,6 +229,10 @@
#define __cpp_lib_span 202002L
#define __cpp_lib_ssize 201902L
#define __cpp_lib_starts_ends_with 201711L
+# if _GLIBCXX_USE_CXX11_ABI
+// Only supported with cx11-abi
+# define __cpp_lib_syncbuf 201803L
+# endif
#define __cpp_lib_to_address 201711L
#define __cpp_lib_to_array 201907L
#endif
new file mode 100644
@@ -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
new file mode 100644
@@ -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 <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
new file mode 100644
@@ -0,0 +1,137 @@
+// 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-additional-options "-pthread" { target pthread } }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#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;
+}
new file mode 100644
@@ -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>;
+}
new file mode 100644
@@ -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" }
+// { 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;
+}
new file mode 100644
@@ -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
new file mode 100644
@@ -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 <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
new file mode 100644
@@ -0,0 +1,134 @@
+// 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-additional-options "-pthread" { target pthread } }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#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;
+}
new file mode 100644
@@ -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>;
+}
From: Thomas Rodgers <trodgers@redhat.com> Addresses latest patch feedback. Changes <syncstream> to also work on single threaded configurations. 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 | 328 ++++++++++++++++++ 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, 934 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