xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/std/syncstream (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1// <syncstream> -*- C++ -*-
2
3// Copyright (C) 2020-2022 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file include/syncstream
26 *  This is a Standard C++ Library header.
27 */
28
29#ifndef _GLIBCXX_SYNCSTREAM
30#define _GLIBCXX_SYNCSTREAM 1
31
32#if __cplusplus > 201703L
33
34#include <bits/c++config.h>
35#if _GLIBCXX_USE_CXX11_ABI
36
37#define __cpp_lib_syncbuf 201803L
38
39#pragma GCC system_header
40
41#include <sstream>
42
43#include <bits/alloc_traits.h>
44#include <bits/allocator.h>
45#include <bits/functexcept.h>
46#include <bits/functional_hash.h>
47#include <bits/std_mutex.h>
48
49namespace std _GLIBCXX_VISIBILITY(default)
50{
51_GLIBCXX_BEGIN_NAMESPACE_VERSION
52
53  template<typename _CharT, typename _Traits, typename _Alloc>
54    class basic_syncbuf : public __syncbuf_base<_CharT, _Traits>
55    {
56    public:
57      using char_type = _CharT;
58      using int_type = typename _Traits::int_type;
59      using pos_type = typename _Traits::pos_type;
60      using off_type = typename _Traits::off_type;
61      using traits_type = _Traits;
62      using allocator_type = _Alloc;
63      using streambuf_type = basic_streambuf<_CharT, _Traits>;
64
65      basic_syncbuf()
66      : basic_syncbuf(nullptr, allocator_type{})
67      { }
68
69      explicit
70      basic_syncbuf(streambuf_type* __obuf)
71      : basic_syncbuf(__obuf, allocator_type{})
72      { }
73
74      basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)
75      : __syncbuf_base<_CharT, _Traits>(__obuf)
76      , _M_impl(__alloc)
77      , _M_mtx(__obuf)
78      { }
79
80      basic_syncbuf(basic_syncbuf&& __other)
81      : __syncbuf_base<_CharT, _Traits>(__other._M_wrapped)
82      , _M_impl(std::move(__other._M_impl))
83      , _M_mtx(std::move(__other._M_mtx))
84      {
85	this->_M_emit_on_sync = __other._M_emit_on_sync;
86	this->_M_needs_sync = __other._M_needs_sync;
87	__other._M_wrapped = nullptr;
88      }
89
90      ~basic_syncbuf()
91      {
92	__try
93	  {
94	    emit();
95	  }
96	__catch (...)
97	  { }
98      }
99
100      basic_syncbuf&
101      operator=(basic_syncbuf&& __other)
102      {
103	emit();
104
105	_M_impl = std::move(__other._M_impl);
106	this->_M_emit_on_sync = __other._M_emit_on_sync;
107	this->_M_needs_sync = __other._M_needs_sync;
108	this->_M_wrapped = __other._M_wrapped;
109	__other._M_wrapped = nullptr;
110	_M_mtx = std::move(__other._M_mtx);
111
112	return *this;
113      }
114
115      void
116      swap(basic_syncbuf& __other)
117      {
118	using _ATr = allocator_traits<_Alloc>;
119	if constexpr (!_ATr::propagate_on_container_swap::value)
120	  __glibcxx_assert(get_allocator() == __other.get_allocator());
121
122	std::swap(_M_impl, __other._M_impl);
123	std::swap(this->_M_emit_on_sync, __other._M_emit_on_sync);
124	std::swap(this->_M_needs_sync, __other._M_needs_sync);
125	std::swap(this->_M_wrapped, __other._M_wrapped);
126	std::swap(_M_mtx, __other._M_mtx);
127      }
128
129      bool
130      emit()
131      {
132	if (!this->_M_wrapped)
133	  return false;
134
135	auto __s = std::move(_M_impl).str();
136
137	const lock_guard<__mutex> __l(_M_mtx);
138	if (auto __size = __s.size())
139	  {
140	    auto __n = this->_M_wrapped->sputn(__s.data(), __size);
141	    if (__n != __size)
142	      {
143		__s.erase(0, __n);
144		_M_impl.str(std::move(__s));
145		return false;
146	      }
147	  }
148
149	if (this->_M_needs_sync)
150	  {
151	    this->_M_needs_sync = false;
152	    if (this->_M_wrapped->pubsync() != 0)
153	      return false;
154	  }
155	return true;
156      }
157
158      streambuf_type*
159      get_wrapped() const noexcept
160      { return this->_M_wrapped; }
161
162      allocator_type
163      get_allocator() const noexcept
164      { return _M_impl.get_allocator(); }
165
166      void
167      set_emit_on_sync(bool __b) noexcept
168      { this->_M_emit_on_sync = __b; }
169
170    protected:
171      int
172      sync() override
173      {
174	this->_M_needs_sync = true;
175	if (this->_M_emit_on_sync && !emit())
176	  return -1;
177	return 0;
178      }
179
180      int_type
181      overflow(int_type __c) override
182      {
183	int_type __eof = traits_type::eof();
184	if (__builtin_expect(!traits_type::eq_int_type(__c, __eof), true))
185	  return _M_impl.sputc(__c);
186	return __eof;
187      }
188
189      streamsize
190      xsputn(const char_type* __s, streamsize __n) override
191      { return _M_impl.sputn(__s, __n); }
192
193    private:
194      basic_stringbuf<char_type, traits_type, allocator_type> _M_impl;
195
196      struct __mutex
197      {
198#if _GLIBCXX_HAS_GTHREADS
199	mutex* _M_mtx;
200
201	__mutex(void* __t)
202	  : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)
203	{ }
204
205	void
206	swap(__mutex& __other) noexcept
207	{ std::swap(_M_mtx, __other._M_mtx); }
208
209	void
210	lock()
211	{
212	  _M_mtx->lock();
213	}
214
215	void
216	unlock()
217	{
218	  _M_mtx->unlock();
219	}
220
221	// FIXME: This should be put in the .so
222	static mutex&
223	_S_get_mutex(void* __t)
224	{
225	  const unsigned char __mask = 0xf;
226	  static mutex __m[__mask + 1];
227
228	  auto __key = _Hash_impl::hash(__t) & __mask;
229	  return __m[__key];
230	}
231#else
232	__mutex(void*) { }
233	void swap(__mutex&&) noexcept { }
234	void lock() { }
235	void unlock() { }
236#endif
237	__mutex(__mutex&&) = default;
238	__mutex& operator=(__mutex&&) = default;
239      };
240      __mutex _M_mtx;
241    };
242
243  template <typename _CharT, typename _Traits, typename _Alloc>
244    class basic_osyncstream : public basic_ostream<_CharT, _Traits>
245    {
246      using __ostream_type = basic_ostream<_CharT, _Traits>;
247
248    public:
249      // Types:
250      using char_type = _CharT;
251      using traits_type = _Traits;
252      using allocator_type = _Alloc;
253      using int_type = typename traits_type::int_type;
254      using pos_type = typename traits_type::pos_type;
255      using off_type = typename traits_type::off_type;
256      using syncbuf_type = basic_syncbuf<_CharT, _Traits, _Alloc>;
257      using streambuf_type = typename syncbuf_type::streambuf_type;
258
259    private:
260      syncbuf_type _M_syncbuf;
261
262    public:
263      basic_osyncstream(streambuf_type* __buf, const allocator_type& __a)
264	: _M_syncbuf(__buf, __a)
265      { this->init(std::__addressof(_M_syncbuf)); }
266
267      explicit basic_osyncstream(streambuf_type* __buf)
268	: _M_syncbuf(__buf)
269      { this->init(std::__addressof(_M_syncbuf)); }
270
271      basic_osyncstream(basic_ostream<char_type, traits_type>& __os,
272		        const allocator_type& __a)
273	: basic_osyncstream(__os.rdbuf(), __a)
274      { this->init(std::__addressof(_M_syncbuf)); }
275
276      explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
277	: basic_osyncstream(__os.rdbuf())
278      { this->init(std::__addressof(_M_syncbuf)); }
279
280      basic_osyncstream(basic_osyncstream&& __rhs) noexcept
281	: __ostream_type(std::move(__rhs)),
282	_M_syncbuf(std::move(__rhs._M_syncbuf))
283      { __ostream_type::set_rdbuf(std::__addressof(_M_syncbuf)); }
284
285      ~basic_osyncstream() = default;
286
287      basic_osyncstream& operator=(basic_osyncstream&&) = default;
288
289      syncbuf_type* rdbuf() const noexcept
290      { return const_cast<syncbuf_type*>(&_M_syncbuf); }
291
292      streambuf_type* get_wrapped() const noexcept
293      { return _M_syncbuf.get_wrapped(); }
294
295      void emit()
296      {
297	if (!_M_syncbuf.emit())
298	  this->setstate(ios_base::failbit);
299      }
300    };
301
302  template <class _CharT, class _Traits, class _Allocator>
303    inline void
304    swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __x,
305	 basic_syncbuf<_CharT, _Traits, _Allocator>& __y) noexcept
306    { __x.swap(__y); }
307
308  using syncbuf = basic_syncbuf<char>;
309  using wsyncbuf = basic_syncbuf<wchar_t>;
310
311  using osyncstream = basic_osyncstream<char>;
312  using wosyncstream = basic_osyncstream<wchar_t>;
313_GLIBCXX_END_NAMESPACE_VERSION
314} // namespace std
315#endif // _GLIBCXX_USE_CXX11_ABI
316#endif // C++2a
317#endif	/* _GLIBCXX_SYNCSTREAM */
318