1 // <syncstream> -*- C++ -*- 2 3 // Copyright (C) 2020-2024 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 #pragma GCC system_header 33 34 #include <bits/requires_hosted.h> // iostreams 35 36 #include <bits/c++config.h> 37 38 #define __glibcxx_want_syncbuf 39 #include <bits/version.h> 40 41 #ifdef __cpp_lib_syncbuf // C++ >= 20 && HOSTED && CXX11ABI 42 #include <sstream> 43 44 #include <bits/alloc_traits.h> 45 #include <bits/allocator.h> 46 #include <bits/functexcept.h> 47 #include <bits/functional_hash.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; 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, typename _Alloc> 245 class basic_osyncstream : public basic_ostream<_CharT, _Traits> 246 { 247 using __ostream_type = basic_ostream<_CharT, _Traits>; 248 249 public: 250 // Types: 251 using char_type = _CharT; 252 using traits_type = _Traits; 253 using allocator_type = _Alloc; 254 using int_type = typename traits_type::int_type; 255 using pos_type = typename traits_type::pos_type; 256 using off_type = typename traits_type::off_type; 257 using syncbuf_type = basic_syncbuf<_CharT, _Traits, _Alloc>; 258 using streambuf_type = typename syncbuf_type::streambuf_type; 259 260 private: 261 syncbuf_type _M_syncbuf; 262 263 public: 264 basic_osyncstream(streambuf_type* __buf, const allocator_type& __a) 265 : _M_syncbuf(__buf, __a) 266 { this->init(std::__addressof(_M_syncbuf)); } 267 268 explicit basic_osyncstream(streambuf_type* __buf) 269 : _M_syncbuf(__buf) 270 { this->init(std::__addressof(_M_syncbuf)); } 271 272 basic_osyncstream(basic_ostream<char_type, traits_type>& __os, 273 const allocator_type& __a) 274 : basic_osyncstream(__os.rdbuf(), __a) 275 { this->init(std::__addressof(_M_syncbuf)); } 276 277 explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os) 278 : basic_osyncstream(__os.rdbuf()) 279 { this->init(std::__addressof(_M_syncbuf)); } 280 281 basic_osyncstream(basic_osyncstream&& __rhs) noexcept 282 : __ostream_type(std::move(__rhs)), 283 _M_syncbuf(std::move(__rhs._M_syncbuf)) 284 { __ostream_type::set_rdbuf(std::__addressof(_M_syncbuf)); } 285 286 ~basic_osyncstream() = default; 287 288 basic_osyncstream& operator=(basic_osyncstream&&) = default; 289 290 syncbuf_type* rdbuf() const noexcept 291 { return const_cast<syncbuf_type*>(&_M_syncbuf); } 292 293 streambuf_type* get_wrapped() const noexcept 294 { return _M_syncbuf.get_wrapped(); } 295 296 void emit() 297 { 298 if (!_M_syncbuf.emit()) 299 this->setstate(ios_base::failbit); 300 } 301 }; 302 303 template <class _CharT, class _Traits, class _Allocator> 304 inline void 305 swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __x, 306 basic_syncbuf<_CharT, _Traits, _Allocator>& __y) noexcept 307 { __x.swap(__y); } 308 309 using syncbuf = basic_syncbuf<char>; 310 using wsyncbuf = basic_syncbuf<wchar_t>; 311 312 using osyncstream = basic_osyncstream<char>; 313 using wosyncstream = basic_osyncstream<wchar_t>; 314 _GLIBCXX_END_NAMESPACE_VERSION 315 } // namespace std 316 #endif // __cpp_lib_syncbuf 317 318 #endif /* _GLIBCXX_SYNCSTREAM */ 319