libstdc++
syncstream
Go to the documentation of this file.
1 // <syncstream> -*- C++ -*-
2 
3 // Copyright (C) 2020-2026 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 #ifdef _GLIBCXX_SYSHDR
33 #pragma GCC system_header
34 #endif
35 
36 #include <bits/requires_hosted.h> // iostreams
37 
38 #include <bits/c++config.h>
39 
40 #define __glibcxx_want_syncbuf
41 #include <bits/version.h>
42 
43 #ifdef __cpp_lib_syncbuf // C++ >= 20 && HOSTED && CXX11ABI
44 #include <sstream>
45 
46 #include <bits/alloc_traits.h>
47 #include <bits/allocator.h>
48 #include <bits/std_mutex.h>
49 
50 namespace std _GLIBCXX_VISIBILITY(default)
51 {
52 _GLIBCXX_BEGIN_NAMESPACE_VERSION
53 
54  template<typename _CharT, typename _Traits, typename _Alloc>
55  class basic_syncbuf : public __syncbuf_base<_CharT, _Traits>
56  {
57  public:
58  using char_type = _CharT;
59  using int_type = typename _Traits::int_type;
60  using pos_type = typename _Traits::pos_type;
61  using off_type = typename _Traits::off_type;
62  using traits_type = _Traits;
63  using allocator_type = _Alloc;
64  using streambuf_type = basic_streambuf<_CharT, _Traits>;
65 
66  basic_syncbuf()
67  : basic_syncbuf(nullptr, allocator_type{})
68  { }
69 
70  explicit
71  basic_syncbuf(streambuf_type* __obuf)
72  : basic_syncbuf(__obuf, allocator_type{})
73  { }
74 
75  basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)
76  : __syncbuf_base<_CharT, _Traits>(__obuf)
77  , _M_impl(__alloc)
78  , _M_mtx(__obuf)
79  { }
80 
81  basic_syncbuf(basic_syncbuf&& __other)
82  : __syncbuf_base<_CharT, _Traits>(__other._M_wrapped)
83  , _M_impl(std::move(__other._M_impl))
84  , _M_mtx(std::move(__other._M_mtx))
85  {
86  this->_M_emit_on_sync = __other._M_emit_on_sync;
87  this->_M_needs_sync = __other._M_needs_sync;
88  __other._M_wrapped = nullptr;
89  }
90 
91  ~basic_syncbuf()
92  {
93  __try
94  {
95  emit();
96  }
97  __catch (...)
98  { }
99  }
100 
101  basic_syncbuf&
102  operator=(basic_syncbuf&& __other)
103  {
104  emit();
105 
106  _M_impl = std::move(__other._M_impl);
107  this->_M_emit_on_sync = __other._M_emit_on_sync;
108  this->_M_needs_sync = __other._M_needs_sync;
109  this->_M_wrapped = __other._M_wrapped;
110  __other._M_wrapped = nullptr;
111  _M_mtx = std::move(__other._M_mtx);
112 
113  return *this;
114  }
115 
116  void
117  swap(basic_syncbuf& __other)
118  {
119  using _ATr = allocator_traits<_Alloc>;
120  if constexpr (!_ATr::propagate_on_container_swap::value)
121  __glibcxx_assert(get_allocator() == __other.get_allocator());
122 
123  std::swap(_M_impl, __other._M_impl);
124  std::swap(this->_M_emit_on_sync, __other._M_emit_on_sync);
125  std::swap(this->_M_needs_sync, __other._M_needs_sync);
126  std::swap(this->_M_wrapped, __other._M_wrapped);
127  std::swap(_M_mtx, __other._M_mtx);
128  }
129 
130  bool
131  emit()
132  {
133  if (!this->_M_wrapped)
134  return false;
135 
136  auto __s = std::move(_M_impl).str();
137 
138  const lock_guard<__mutex> __l(_M_mtx);
139  if (auto __size = __s.size())
140  {
141  auto __n = this->_M_wrapped->sputn(__s.data(), __size);
142  if (__n != __size)
143  {
144  __s.erase(0, __n);
145  _M_impl.str(std::move(__s));
146  return false;
147  }
148  }
149 
150  if (this->_M_needs_sync)
151  {
152  this->_M_needs_sync = false;
153  if (this->_M_wrapped->pubsync() != 0)
154  return false;
155  }
156  return true;
157  }
158 
159  streambuf_type*
160  get_wrapped() const noexcept
161  { return this->_M_wrapped; }
162 
163  allocator_type
164  get_allocator() const noexcept
165  { return _M_impl.get_allocator(); }
166 
167  void
168  set_emit_on_sync(bool __b) noexcept
169  { this->_M_emit_on_sync = __b; }
170 
171  protected:
172  int
173  sync() override
174  {
175  this->_M_needs_sync = true;
176  if (this->_M_emit_on_sync && !emit())
177  return -1;
178  return 0;
179  }
180 
181  int_type
182  overflow(int_type __c) override
183  {
184  int_type __eof = traits_type::eof();
185  if (__builtin_expect(!traits_type::eq_int_type(__c, __eof), true))
186  return _M_impl.sputc(__c);
187  return __eof;
188  }
189 
190  streamsize
191  xsputn(const char_type* __s, streamsize __n) override
192  { return _M_impl.sputn(__s, __n); }
193 
194  private:
195  basic_stringbuf<char_type, traits_type, allocator_type> _M_impl;
196 
197  struct __mutex
198  {
199 #if _GLIBCXX_HAS_GTHREADS
200  mutex* _M_mtx = nullptr;
201 
202  __mutex(void* __t) // __t is the underlying sbuf, as hash seed.
203  {
204  extern mutex& __syncbuf_get_mutex(void*); // in src/c++20/syncbuf.cc
205  if (__t) _M_mtx = &__syncbuf_get_mutex(__t);
206  }
207 
208  void
209  swap(__mutex& __other) noexcept
210  { std::swap(_M_mtx, __other._M_mtx); }
211 
212  void
213  lock()
214  {
215  _M_mtx->lock();
216  }
217 
218  void
219  unlock()
220  {
221  _M_mtx->unlock();
222  }
223 #else
224  __mutex(void*) { }
225  void swap(__mutex&&) noexcept { }
226  void lock() { }
227  void unlock() { }
228 #endif
229  __mutex(__mutex&&) = default;
230  __mutex& operator=(__mutex&&) = default;
231  };
232  __mutex _M_mtx;
233  };
234 
235  template <typename _CharT, typename _Traits, typename _Alloc>
236  class basic_osyncstream : public basic_ostream<_CharT, _Traits>
237  {
238  using __ostream_type = basic_ostream<_CharT, _Traits>;
239 
240  public:
241  // Types:
242  using char_type = _CharT;
243  using traits_type = _Traits;
244  using allocator_type = _Alloc;
245  using int_type = typename traits_type::int_type;
246  using pos_type = typename traits_type::pos_type;
247  using off_type = typename traits_type::off_type;
248  using syncbuf_type = basic_syncbuf<_CharT, _Traits, _Alloc>;
249  using streambuf_type = typename syncbuf_type::streambuf_type;
250 
251  private:
252  syncbuf_type _M_syncbuf;
253 
254  public:
255  basic_osyncstream(streambuf_type* __buf, const allocator_type& __a)
256  : _M_syncbuf(__buf, __a)
257  { this->init(std::__addressof(_M_syncbuf)); }
258 
259  explicit basic_osyncstream(streambuf_type* __buf)
260  : _M_syncbuf(__buf)
261  { this->init(std::__addressof(_M_syncbuf)); }
262 
263  basic_osyncstream(basic_ostream<char_type, traits_type>& __os,
264  const allocator_type& __a)
265  : basic_osyncstream(__os.rdbuf(), __a)
266  { this->init(std::__addressof(_M_syncbuf)); }
267 
268  explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
269  : basic_osyncstream(__os.rdbuf())
270  { this->init(std::__addressof(_M_syncbuf)); }
271 
272  basic_osyncstream(basic_osyncstream&& __rhs) noexcept
273  : __ostream_type(std::move(__rhs)),
274  _M_syncbuf(std::move(__rhs._M_syncbuf))
275  { __ostream_type::set_rdbuf(std::__addressof(_M_syncbuf)); }
276 
277  ~basic_osyncstream() = default;
278 
279  basic_osyncstream& operator=(basic_osyncstream&&) = default;
280 
281  syncbuf_type* rdbuf() const noexcept
282  { return const_cast<syncbuf_type*>(&_M_syncbuf); }
283 
284  streambuf_type* get_wrapped() const noexcept
285  { return _M_syncbuf.get_wrapped(); }
286 
287  void emit()
288  {
289  if (!_M_syncbuf.emit())
290  this->setstate(ios_base::failbit);
291  }
292  };
293 
294  template <class _CharT, class _Traits, class _Allocator>
295  inline void
296  swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __x,
297  basic_syncbuf<_CharT, _Traits, _Allocator>& __y) noexcept
298  { __x.swap(__y); }
299 
300  using syncbuf = basic_syncbuf<char>;
301  using wsyncbuf = basic_syncbuf<wchar_t>;
302 
303  using osyncstream = basic_osyncstream<char>;
304  using wosyncstream = basic_osyncstream<wchar_t>;
305 _GLIBCXX_END_NAMESPACE_VERSION
306 } // namespace std
307 #endif // __cpp_lib_syncbuf
308 
309 #endif /* _GLIBCXX_SYNCSTREAM */
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:52
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:138
void lock(_L1 &__l1, _L2 &__l2, _L3 &... __l3)
Generic lock.
Definition: mutex:686
ISO C++ entities toplevel namespace is std.
ptrdiff_t streamsize
Integral type for I/O operation counts and buffer sizes.
Definition: postypes.h:73
static const iostate failbit
Indicates that an input operation failed to read the expected characters, or that an output operation...
Definition: ios_base.h:465