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