ostream.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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>
  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. }
  57. int_type
  58. overflow(int_type ch) override
  59. {
  60. BOOST_ASSERT(! Traits::eq_int_type(
  61. ch, Traits::eof()));
  62. sync();
  63. static std::size_t constexpr max_size = 65536;
  64. auto const max_prepare = std::min<std::size_t>(
  65. std::max<std::size_t>(
  66. 512, b_.capacity() - b_.size()),
  67. std::min<std::size_t>(
  68. max_size, b_.max_size() - b_.size()));
  69. if(max_prepare == 0)
  70. return Traits::eof();
  71. auto const bs = b_.prepare(max_prepare);
  72. auto const b = buffers_front(bs);
  73. auto const p = static_cast<CharT*>(b.data());
  74. this->setp(p, p + b.size() / sizeof(CharT));
  75. BOOST_ASSERT(b_.capacity() > b_.size());
  76. return this->sputc(
  77. Traits::to_char_type(ch));
  78. }
  79. int
  80. sync() override
  81. {
  82. b_.commit(
  83. (this->pptr() - this->pbase()) *
  84. sizeof(CharT));
  85. return 0;
  86. }
  87. };
  88. //------------------------------------------------------------------------------
  89. // This nonsense is all to work around a glitch in libstdc++
  90. // where std::basic_streambuf copy constructor is private:
  91. // https://github.com/gcc-mirror/gcc/blob/gcc-4_8-branch/libstdc%2B%2B-v3/include/std/streambuf#L799
  92. template<class DynamicBuffer, class CharT, class Traits>
  93. class ostream_buffer
  94. <DynamicBuffer, CharT, Traits, false>
  95. : public std::basic_streambuf<CharT, Traits>
  96. {
  97. using int_type = typename
  98. std::basic_streambuf<CharT, Traits>::int_type;
  99. using traits_type = typename
  100. std::basic_streambuf<CharT, Traits>::traits_type;
  101. DynamicBuffer& b_;
  102. public:
  103. ostream_buffer(ostream_buffer&&) = delete;
  104. ostream_buffer(ostream_buffer const&) = delete;
  105. ~ostream_buffer() noexcept
  106. {
  107. sync();
  108. }
  109. explicit
  110. ostream_buffer(DynamicBuffer& b)
  111. : b_(b)
  112. {
  113. }
  114. int_type
  115. overflow(int_type ch) override
  116. {
  117. BOOST_ASSERT(! Traits::eq_int_type(
  118. ch, Traits::eof()));
  119. sync();
  120. static std::size_t constexpr max_size = 65536;
  121. auto const max_prepare = std::min<std::size_t>(
  122. std::max<std::size_t>(
  123. 512, b_.capacity() - b_.size()),
  124. std::min<std::size_t>(
  125. max_size, b_.max_size() - b_.size()));
  126. if(max_prepare == 0)
  127. return Traits::eof();
  128. auto const bs = b_.prepare(max_prepare);
  129. auto const b = buffers_front(bs);
  130. auto const p = static_cast<CharT*>(b.data());
  131. this->setp(p, p + b.size() / sizeof(CharT));
  132. BOOST_ASSERT(b_.capacity() > b_.size());
  133. return this->sputc(
  134. Traits::to_char_type(ch));
  135. }
  136. int
  137. sync() override
  138. {
  139. b_.commit(
  140. (this->pptr() - this->pbase()) *
  141. sizeof(CharT));
  142. return 0;
  143. }
  144. };
  145. //------------------------------------------------------------------------------
  146. template<class DynamicBuffer,
  147. class CharT, class Traits, bool isMovable>
  148. class ostream_helper;
  149. template<class DynamicBuffer, class CharT, class Traits>
  150. class ostream_helper<
  151. DynamicBuffer, CharT, Traits, true>
  152. : public std::basic_ostream<CharT, Traits>
  153. {
  154. ostream_buffer<
  155. DynamicBuffer, CharT, Traits, true> osb_;
  156. public:
  157. explicit
  158. ostream_helper(DynamicBuffer& b);
  159. ostream_helper(ostream_helper&& other);
  160. };
  161. template<class DynamicBuffer, class CharT, class Traits>
  162. ostream_helper<DynamicBuffer, CharT, Traits, true>::
  163. ostream_helper(DynamicBuffer& b)
  164. : std::basic_ostream<CharT, Traits>(&this->osb_)
  165. , osb_(b)
  166. {
  167. }
  168. template<class DynamicBuffer, class CharT, class Traits>
  169. ostream_helper<DynamicBuffer, CharT, Traits, true>::
  170. ostream_helper(ostream_helper&& other)
  171. : std::basic_ostream<CharT, Traits>(&osb_)
  172. , osb_(std::move(other.osb_))
  173. {
  174. }
  175. // This work-around is for libstdc++ versions that
  176. // don't have a movable std::basic_streambuf
  177. template<class T>
  178. class ostream_helper_base
  179. {
  180. protected:
  181. std::unique_ptr<T> member;
  182. ostream_helper_base(
  183. ostream_helper_base&&) = default;
  184. explicit
  185. ostream_helper_base(T* t)
  186. : member(t)
  187. {
  188. }
  189. };
  190. template<class DynamicBuffer, class CharT, class Traits>
  191. class ostream_helper<
  192. DynamicBuffer, CharT, Traits, false>
  193. : private ostream_helper_base<ostream_buffer<
  194. DynamicBuffer, CharT, Traits, false>>
  195. , public std::basic_ostream<CharT, Traits>
  196. {
  197. public:
  198. explicit
  199. ostream_helper(DynamicBuffer& b)
  200. : ostream_helper_base<ostream_buffer<
  201. DynamicBuffer, CharT, Traits, false>>(
  202. new ostream_buffer<DynamicBuffer,
  203. CharT, Traits, false>(b))
  204. , std::basic_ostream<CharT, Traits>(
  205. this->member.get())
  206. {
  207. }
  208. ostream_helper(ostream_helper&& other)
  209. : ostream_helper_base<ostream_buffer<
  210. DynamicBuffer, CharT, Traits, false>>(
  211. std::move(other))
  212. , std::basic_ostream<CharT, Traits>(
  213. this->member.get())
  214. {
  215. }
  216. };
  217. } // detail
  218. } // beast
  219. } // boost
  220. #endif