syncstream 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // <syncstream> -*- C++ -*-
  2. // Copyright (C) 2020-2021 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 = char_traits<_CharT>,
  40. typename _Alloc = allocator<_CharT>>
  41. class basic_syncbuf : public __syncbuf_base<_CharT, _Traits>
  42. {
  43. public:
  44. using char_type = _CharT;
  45. using int_type = typename _Traits::int_type;
  46. using pos_type = typename _Traits::pos_type;
  47. using off_type = typename _Traits::off_type;
  48. using traits_type = _Traits;
  49. using allocator_type = _Alloc;
  50. using streambuf_type = basic_streambuf<_CharT, _Traits>;
  51. basic_syncbuf()
  52. : basic_syncbuf(nullptr, allocator_type{})
  53. { }
  54. explicit
  55. basic_syncbuf(streambuf_type* __obuf)
  56. : basic_syncbuf(__obuf, allocator_type{})
  57. { }
  58. basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)
  59. : __syncbuf_base<_CharT, _Traits>(__obuf)
  60. , _M_impl(__alloc)
  61. , _M_mtx(__obuf)
  62. { }
  63. basic_syncbuf(basic_syncbuf&& __other)
  64. : __syncbuf_base<_CharT, _Traits>(__other._M_wrapped)
  65. , _M_impl(std::move(__other._M_impl))
  66. , _M_mtx(std::move(__other._M_mtx))
  67. {
  68. this->_M_emit_on_sync = __other._M_emit_on_sync;
  69. this->_M_needs_sync = __other._M_needs_sync;
  70. __other._M_wrapped = nullptr;
  71. }
  72. ~basic_syncbuf()
  73. {
  74. __try
  75. {
  76. emit();
  77. }
  78. __catch (...)
  79. { }
  80. }
  81. basic_syncbuf&
  82. operator=(basic_syncbuf&& __other)
  83. {
  84. emit();
  85. _M_impl = std::move(__other._M_impl);
  86. this->_M_emit_on_sync = __other._M_emit_on_sync;
  87. this->_M_needs_sync = __other._M_needs_sync;
  88. this->_M_wrapped = __other._M_wrapped;
  89. __other._M_wrapped = nullptr;
  90. _M_mtx = std::move(__other._M_mtx);
  91. return *this;
  92. }
  93. void
  94. swap(basic_syncbuf& __other) noexcept
  95. {
  96. using _ATr = allocator_traits<_Alloc>;
  97. if constexpr (!_ATr::propagate_on_container_swap::value)
  98. __glibcxx_assert(get_allocator() == __other.get_allocator());
  99. std::swap(_M_impl, __other._M_impl);
  100. std::swap(this->_M_emit_on_sync, __other._M_emit_on_sync);
  101. std::swap(this->_M_needs_sync, __other._M_needs_sync);
  102. std::swap(this->_M_wrapped, __other._M_wrapped);
  103. std::swap(_M_mtx, __other._M_mtx);
  104. }
  105. bool
  106. emit()
  107. {
  108. if (!this->_M_wrapped)
  109. return false;
  110. auto __s = std::move(_M_impl).str();
  111. const lock_guard<__mutex> __l(_M_mtx);
  112. if (auto __size = __s.size())
  113. {
  114. auto __n = this->_M_wrapped->sputn(__s.data(), __size);
  115. if (__n != __size)
  116. {
  117. __s.erase(0, __n);
  118. _M_impl.str(std::move(__s));
  119. return false;
  120. }
  121. }
  122. if (this->_M_needs_sync)
  123. {
  124. this->_M_needs_sync = false;
  125. if (this->_M_wrapped->pubsync() != 0)
  126. return false;
  127. }
  128. return true;
  129. }
  130. streambuf_type*
  131. get_wrapped() const noexcept
  132. { return this->_M_wrapped; }
  133. allocator_type
  134. get_allocator() const noexcept
  135. { return _M_impl.get_allocator(); }
  136. void
  137. set_emit_on_sync(bool __b) noexcept
  138. { this->_M_emit_on_sync = __b; }
  139. protected:
  140. int
  141. sync() override
  142. {
  143. this->_M_needs_sync = true;
  144. if (this->_M_emit_on_sync && !emit())
  145. return -1;
  146. return 0;
  147. }
  148. int_type
  149. overflow(int_type __c) override
  150. {
  151. int_type __eof = traits_type::eof();
  152. if (__builtin_expect(!traits_type::eq_int_type(__c, __eof), true))
  153. return _M_impl.sputc(__c);
  154. return __eof;
  155. }
  156. streamsize
  157. xsputn(const char_type* __s, streamsize __n) override
  158. { return _M_impl.sputn(__s, __n); }
  159. private:
  160. basic_stringbuf<char_type, traits_type, allocator_type> _M_impl;
  161. struct __mutex
  162. {
  163. #if _GLIBCXX_HAS_GTHREADS
  164. mutex* _M_mtx;
  165. __mutex(void* __t)
  166. : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)
  167. { }
  168. void
  169. swap(__mutex& __other) noexcept
  170. { std::swap(_M_mtx, __other._M_mtx); }
  171. void
  172. lock()
  173. {
  174. _M_mtx->lock();
  175. }
  176. void
  177. unlock()
  178. {
  179. _M_mtx->unlock();
  180. }
  181. // FIXME: This should be put in the .so
  182. static mutex&
  183. _S_get_mutex(void* __t)
  184. {
  185. const unsigned char __mask = 0xf;
  186. static mutex __m[__mask + 1];
  187. auto __key = _Hash_impl::hash(__t) & __mask;
  188. return __m[__key];
  189. }
  190. #else
  191. __mutex(void*) { }
  192. void swap(__mutex&&) noexcept { }
  193. void lock() { }
  194. void unlock() { }
  195. #endif
  196. __mutex(__mutex&&) = default;
  197. __mutex& operator=(__mutex&&) = default;
  198. };
  199. __mutex _M_mtx;
  200. };
  201. template <typename _CharT, typename _Traits = char_traits<_CharT>,
  202. typename _Alloc = allocator<_CharT>>
  203. class basic_osyncstream : public basic_ostream<_CharT, _Traits>
  204. {
  205. using __ostream_type = basic_ostream<_CharT, _Traits>;
  206. public:
  207. // Types:
  208. using char_type = _CharT;
  209. using traits_type = _Traits;
  210. using allocator_type = _Alloc;
  211. using int_type = typename traits_type::int_type;
  212. using pos_type = typename traits_type::pos_type;
  213. using off_type = typename traits_type::off_type;
  214. using syncbuf_type = basic_syncbuf<_CharT, _Traits, _Alloc>;
  215. using streambuf_type = typename syncbuf_type::streambuf_type;
  216. private:
  217. syncbuf_type _M_syncbuf;
  218. public:
  219. basic_osyncstream(streambuf_type* __buf, const allocator_type& __a)
  220. : _M_syncbuf(__buf, __a)
  221. { this->init(std::__addressof(_M_syncbuf)); }
  222. explicit basic_osyncstream(streambuf_type* __buf)
  223. : _M_syncbuf(__buf)
  224. { this->init(std::__addressof(_M_syncbuf)); }
  225. basic_osyncstream(basic_ostream<char_type, traits_type>& __os,
  226. const allocator_type& __a)
  227. : basic_osyncstream(__os.rdbuf(), __a)
  228. { this->init(std::__addressof(_M_syncbuf)); }
  229. explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
  230. : basic_osyncstream(__os.rdbuf())
  231. { this->init(std::__addressof(_M_syncbuf)); }
  232. basic_osyncstream(basic_osyncstream&& __rhs) noexcept
  233. : __ostream_type(std::move(__rhs)),
  234. _M_syncbuf(std::move(__rhs._M_syncbuf))
  235. { __ostream_type::set_rdbuf(std::__addressof(_M_syncbuf)); }
  236. ~basic_osyncstream() = default;
  237. basic_osyncstream& operator=(basic_osyncstream&&) noexcept = default;
  238. syncbuf_type* rdbuf() const noexcept
  239. { return const_cast<syncbuf_type*>(&_M_syncbuf); }
  240. streambuf_type* get_wrapped() const noexcept
  241. { return _M_syncbuf.get_wrapped(); }
  242. void emit()
  243. {
  244. if (!_M_syncbuf.emit())
  245. this->setstate(ios_base::failbit);
  246. }
  247. };
  248. template <class _CharT, class _Traits, class _Allocator>
  249. inline void
  250. swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __x,
  251. basic_syncbuf<_CharT, _Traits, _Allocator>& __y) noexcept
  252. { __x.swap(__y); }
  253. using syncbuf = basic_syncbuf<char>;
  254. using wsyncbuf = basic_syncbuf<wchar_t>;
  255. using osyncstream = basic_osyncstream<char>;
  256. using wosyncstream = basic_osyncstream<wchar_t>;
  257. _GLIBCXX_END_NAMESPACE_VERSION
  258. } // namespace std
  259. #endif // _GLIBCXX_USE_CXX11_ABI
  260. #endif // C++2a
  261. #endif /* _GLIBCXX_SYNCSTREAM */