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