ostream.hpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_DETAIL_OSTREAM_HPP
  10. #define BOOST_BEAST_DETAIL_OSTREAM_HPP
  11. #include <boost/beast/core/buffers_prefix.hpp>
  12. #include <boost/beast/core/buffers_range.hpp>
  13. #include <boost/throw_exception.hpp>
  14. #include <boost/asio/buffer.hpp>
  15. #include <memory>
  16. #include <ostream>
  17. #include <streambuf>
  18. #include <type_traits>
  19. #include <utility>
  20. namespace boost {
  21. namespace beast {
  22. namespace detail {
  23. struct basic_streambuf_movable_helper :
  24. std::basic_streambuf<char, std::char_traits<char>>
  25. {
  26. basic_streambuf_movable_helper(
  27. basic_streambuf_movable_helper&&) = default;
  28. };
  29. using basic_streambuf_movable =
  30. std::is_move_constructible<basic_streambuf_movable_helper>;
  31. template<class DynamicBuffer,
  32. class CharT, class Traits, bool isMovable>
  33. class ostream_buffer;
  34. //------------------------------------------------------------------------------
  35. template<class DynamicBuffer, class CharT, class Traits>
  36. class ostream_buffer
  37. <DynamicBuffer, CharT, Traits, true> final
  38. : public std::basic_streambuf<CharT, Traits>
  39. {
  40. using int_type = typename
  41. std::basic_streambuf<CharT, Traits>::int_type;
  42. using traits_type = typename
  43. std::basic_streambuf<CharT, Traits>::traits_type;
  44. DynamicBuffer& b_;
  45. public:
  46. ostream_buffer(ostream_buffer&&) = default;
  47. ostream_buffer(ostream_buffer const&) = delete;
  48. ~ostream_buffer() noexcept
  49. {
  50. sync();
  51. }
  52. explicit
  53. ostream_buffer(DynamicBuffer& b)
  54. : b_(b)
  55. {
  56. b_.prepare(0);
  57. }
  58. int_type
  59. overflow(int_type ch) override
  60. {
  61. BOOST_ASSERT(! Traits::eq_int_type(
  62. ch, Traits::eof()));
  63. sync();
  64. static std::size_t constexpr max_size = 65536;
  65. auto const max_prepare = std::min<std::size_t>(
  66. std::max<std::size_t>(
  67. 512, b_.capacity() - b_.size()),
  68. std::min<std::size_t>(
  69. max_size, b_.max_size() - b_.size()));
  70. if(max_prepare == 0)
  71. return Traits::eof();
  72. auto const bs = b_.prepare(max_prepare);
  73. auto const b = buffers_front(bs);
  74. auto const p = static_cast<CharT*>(b.data());
  75. this->setp(p, p + b.size() / sizeof(CharT));
  76. BOOST_ASSERT(b_.capacity() > b_.size());
  77. return this->sputc(
  78. Traits::to_char_type(ch));
  79. }
  80. int
  81. sync() override
  82. {
  83. b_.commit(
  84. (this->pptr() - this->pbase()) *
  85. sizeof(CharT));
  86. this->setp(nullptr, nullptr);
  87. return 0;
  88. }
  89. };
  90. //------------------------------------------------------------------------------
  91. // This nonsense is all to work around a glitch in libstdc++
  92. // where std::basic_streambuf copy constructor is private:
  93. // https://github.com/gcc-mirror/gcc/blob/gcc-4_8-branch/libstdc%2B%2B-v3/include/std/streambuf#L799
  94. template<class DynamicBuffer, class CharT, class Traits>
  95. class ostream_buffer
  96. <DynamicBuffer, CharT, Traits, false>
  97. : public std::basic_streambuf<CharT, Traits>
  98. {
  99. using int_type = typename
  100. std::basic_streambuf<CharT, Traits>::int_type;
  101. using traits_type = typename
  102. std::basic_streambuf<CharT, Traits>::traits_type;
  103. DynamicBuffer& b_;
  104. public:
  105. ostream_buffer(ostream_buffer&&) = delete;
  106. ostream_buffer(ostream_buffer const&) = delete;
  107. ~ostream_buffer() noexcept
  108. {
  109. sync();
  110. }
  111. explicit
  112. ostream_buffer(DynamicBuffer& b)
  113. : b_(b)
  114. {
  115. }
  116. int_type
  117. overflow(int_type ch) override
  118. {
  119. BOOST_ASSERT(! Traits::eq_int_type(
  120. ch, Traits::eof()));
  121. sync();
  122. static std::size_t constexpr max_size = 65536;
  123. auto const max_prepare = std::min<std::size_t>(
  124. std::max<std::size_t>(
  125. 512, b_.capacity() - b_.size()),
  126. std::min<std::size_t>(
  127. max_size, b_.max_size() - b_.size()));
  128. if(max_prepare == 0)
  129. return Traits::eof();
  130. auto const bs = b_.prepare(max_prepare);
  131. auto const b = buffers_front(bs);
  132. auto const p = static_cast<CharT*>(b.data());
  133. this->setp(p, p + b.size() / sizeof(CharT));
  134. BOOST_ASSERT(b_.capacity() > b_.size());
  135. return this->sputc(
  136. Traits::to_char_type(ch));
  137. }
  138. int
  139. sync() override
  140. {
  141. b_.commit(
  142. (this->pptr() - this->pbase()) *
  143. sizeof(CharT));
  144. this->setp(nullptr, nullptr);
  145. return 0;
  146. }
  147. };
  148. //------------------------------------------------------------------------------
  149. template<class DynamicBuffer,
  150. class CharT, class Traits, bool isMovable>
  151. class ostream_helper;
  152. template<class DynamicBuffer, class CharT, class Traits>
  153. class ostream_helper<
  154. DynamicBuffer, CharT, Traits, true>
  155. : public std::basic_ostream<CharT, Traits>
  156. {
  157. ostream_buffer<
  158. DynamicBuffer, CharT, Traits, true> osb_;
  159. public:
  160. explicit
  161. ostream_helper(DynamicBuffer& b);
  162. ostream_helper(ostream_helper&& other);
  163. };
  164. template<class DynamicBuffer, class CharT, class Traits>
  165. ostream_helper<DynamicBuffer, CharT, Traits, true>::
  166. ostream_helper(DynamicBuffer& b)
  167. : std::basic_ostream<CharT, Traits>(&this->osb_)
  168. , osb_(b)
  169. {
  170. }
  171. template<class DynamicBuffer, class CharT, class Traits>
  172. ostream_helper<DynamicBuffer, CharT, Traits, true>::
  173. ostream_helper(ostream_helper&& other)
  174. : std::basic_ostream<CharT, Traits>(&osb_)
  175. , osb_(std::move(other.osb_))
  176. {
  177. }
  178. // This work-around is for libstdc++ versions that
  179. // don't have a movable std::basic_streambuf
  180. template<class T>
  181. class ostream_helper_base
  182. {
  183. protected:
  184. std::unique_ptr<T> member;
  185. ostream_helper_base(
  186. ostream_helper_base&&) = default;
  187. explicit
  188. ostream_helper_base(T* t)
  189. : member(t)
  190. {
  191. }
  192. };
  193. template<class DynamicBuffer, class CharT, class Traits>
  194. class ostream_helper<
  195. DynamicBuffer, CharT, Traits, false>
  196. : private ostream_helper_base<ostream_buffer<
  197. DynamicBuffer, CharT, Traits, false>>
  198. , public std::basic_ostream<CharT, Traits>
  199. {
  200. public:
  201. explicit
  202. ostream_helper(DynamicBuffer& b)
  203. : ostream_helper_base<ostream_buffer<
  204. DynamicBuffer, CharT, Traits, false>>(
  205. new ostream_buffer<DynamicBuffer,
  206. CharT, Traits, false>(b))
  207. , std::basic_ostream<CharT, Traits>(
  208. this->member.get())
  209. {
  210. }
  211. ostream_helper(ostream_helper&& other)
  212. : ostream_helper_base<ostream_buffer<
  213. DynamicBuffer, CharT, Traits, false>>(
  214. std::move(other))
  215. , std::basic_ostream<CharT, Traits>(
  216. this->member.get())
  217. {
  218. }
  219. };
  220. } // detail
  221. } // beast
  222. } // boost
  223. #endif