Home | History | Annotate | Line # | Download | only in std
      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