syncstream 8.1 KB

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