1// <syncstream> -*- C++ -*- 2 3// Copyright (C) 2020-2021 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 = char_traits<_CharT>, 54 typename _Alloc = allocator<_CharT>> 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) noexcept 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; 201 202 __mutex(void* __t) 203 : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr) 204 { } 205 206 void 207 swap(__mutex& __other) noexcept 208 { std::swap(_M_mtx, __other._M_mtx); } 209 210 void 211 lock() 212 { 213 _M_mtx->lock(); 214 } 215 216 void 217 unlock() 218 { 219 _M_mtx->unlock(); 220 } 221 222 // FIXME: This should be put in the .so 223 static mutex& 224 _S_get_mutex(void* __t) 225 { 226 const unsigned char __mask = 0xf; 227 static mutex __m[__mask + 1]; 228 229 auto __key = _Hash_impl::hash(__t) & __mask; 230 return __m[__key]; 231 } 232#else 233 __mutex(void*) { } 234 void swap(__mutex&&) noexcept { } 235 void lock() { } 236 void unlock() { } 237#endif 238 __mutex(__mutex&&) = default; 239 __mutex& operator=(__mutex&&) = default; 240 }; 241 __mutex _M_mtx; 242 }; 243 244 template <typename _CharT, typename _Traits = char_traits<_CharT>, 245 typename _Alloc = allocator<_CharT>> 246 class basic_osyncstream : public basic_ostream<_CharT, _Traits> 247 { 248 using __ostream_type = basic_ostream<_CharT, _Traits>; 249 250 public: 251 // Types: 252 using char_type = _CharT; 253 using traits_type = _Traits; 254 using allocator_type = _Alloc; 255 using int_type = typename traits_type::int_type; 256 using pos_type = typename traits_type::pos_type; 257 using off_type = typename traits_type::off_type; 258 using syncbuf_type = basic_syncbuf<_CharT, _Traits, _Alloc>; 259 using streambuf_type = typename syncbuf_type::streambuf_type; 260 261 private: 262 syncbuf_type _M_syncbuf; 263 264 public: 265 basic_osyncstream(streambuf_type* __buf, const allocator_type& __a) 266 : _M_syncbuf(__buf, __a) 267 { this->init(std::__addressof(_M_syncbuf)); } 268 269 explicit basic_osyncstream(streambuf_type* __buf) 270 : _M_syncbuf(__buf) 271 { this->init(std::__addressof(_M_syncbuf)); } 272 273 basic_osyncstream(basic_ostream<char_type, traits_type>& __os, 274 const allocator_type& __a) 275 : basic_osyncstream(__os.rdbuf(), __a) 276 { this->init(std::__addressof(_M_syncbuf)); } 277 278 explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os) 279 : basic_osyncstream(__os.rdbuf()) 280 { this->init(std::__addressof(_M_syncbuf)); } 281 282 basic_osyncstream(basic_osyncstream&& __rhs) noexcept 283 : __ostream_type(std::move(__rhs)), 284 _M_syncbuf(std::move(__rhs._M_syncbuf)) 285 { __ostream_type::set_rdbuf(std::__addressof(_M_syncbuf)); } 286 287 ~basic_osyncstream() = default; 288 289 basic_osyncstream& operator=(basic_osyncstream&&) noexcept = default; 290 291 syncbuf_type* rdbuf() const noexcept 292 { return const_cast<syncbuf_type*>(&_M_syncbuf); } 293 294 streambuf_type* get_wrapped() const noexcept 295 { return _M_syncbuf.get_wrapped(); } 296 297 void emit() 298 { 299 if (!_M_syncbuf.emit()) 300 this->setstate(ios_base::failbit); 301 } 302 }; 303 304 template <class _CharT, class _Traits, class _Allocator> 305 inline void 306 swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __x, 307 basic_syncbuf<_CharT, _Traits, _Allocator>& __y) noexcept 308 { __x.swap(__y); } 309 310 using syncbuf = basic_syncbuf<char>; 311 using wsyncbuf = basic_syncbuf<wchar_t>; 312 313 using osyncstream = basic_osyncstream<char>; 314 using wosyncstream = basic_osyncstream<wchar_t>; 315_GLIBCXX_END_NAMESPACE_VERSION 316} // namespace std 317#endif // _GLIBCXX_USE_CXX11_ABI 318#endif // C++2a 319#endif /* _GLIBCXX_SYNCSTREAM */ 320