2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_DETAIL_OSTREAM_HPP
11 #define BOOST_BEAST_DETAIL_OSTREAM_HPP
13 #include <boost/beast/core/buffers_prefix.hpp>
14 #include <boost/beast/core/buffers_range.hpp>
15 #include <boost/throw_exception.hpp>
16 #include <boost/asio/buffer.hpp>
20 #include <type_traits>
27 struct basic_streambuf_movable_helper :
28 std::basic_streambuf<char, std::char_traits<char>>
30 basic_streambuf_movable_helper(
31 basic_streambuf_movable_helper&&) = default;
34 using basic_streambuf_movable =
35 std::is_move_constructible<basic_streambuf_movable_helper>;
37 template<class DynamicBuffer,
38 class CharT, class Traits, bool isMovable>
41 //------------------------------------------------------------------------------
43 template<class DynamicBuffer, class CharT, class Traits>
45 <DynamicBuffer, CharT, Traits, true> final
46 : public std::basic_streambuf<CharT, Traits>
48 using int_type = typename
49 std::basic_streambuf<CharT, Traits>::int_type;
51 using traits_type = typename
52 std::basic_streambuf<CharT, Traits>::traits_type;
57 ostream_buffer(ostream_buffer&&) = default;
58 ostream_buffer(ostream_buffer const&) = delete;
60 ~ostream_buffer() noexcept
66 ostream_buffer(DynamicBuffer& b)
73 overflow(int_type ch) override
75 BOOST_ASSERT(! Traits::eq_int_type(
79 static std::size_t constexpr max_size = 65536;
80 auto const max_prepare = std::min<std::size_t>(
81 std::max<std::size_t>(
82 512, b_.capacity() - b_.size()),
83 std::min<std::size_t>(
84 max_size, b_.max_size() - b_.size()));
87 auto const bs = b_.prepare(max_prepare);
88 auto const b = buffers_front(bs);
89 auto const p = static_cast<CharT*>(b.data());
90 this->setp(p, p + b.size() / sizeof(CharT));
92 BOOST_ASSERT(b_.capacity() > b_.size());
94 Traits::to_char_type(ch));
101 (this->pptr() - this->pbase()) *
103 this->setp(nullptr, nullptr);
108 //------------------------------------------------------------------------------
110 // This nonsense is all to work around a glitch in libstdc++
111 // where std::basic_streambuf copy constructor is private:
112 // https://github.com/gcc-mirror/gcc/blob/gcc-4_8-branch/libstdc%2B%2B-v3/include/std/streambuf#L799
114 template<class DynamicBuffer, class CharT, class Traits>
116 <DynamicBuffer, CharT, Traits, false>
117 : public std::basic_streambuf<CharT, Traits>
119 using int_type = typename
120 std::basic_streambuf<CharT, Traits>::int_type;
122 using traits_type = typename
123 std::basic_streambuf<CharT, Traits>::traits_type;
128 ostream_buffer(ostream_buffer&&) = delete;
129 ostream_buffer(ostream_buffer const&) = delete;
131 ~ostream_buffer() noexcept
137 ostream_buffer(DynamicBuffer& b)
143 overflow(int_type ch) override
145 BOOST_ASSERT(! Traits::eq_int_type(
149 static std::size_t constexpr max_size = 65536;
150 auto const max_prepare = std::min<std::size_t>(
151 std::max<std::size_t>(
152 512, b_.capacity() - b_.size()),
153 std::min<std::size_t>(
154 max_size, b_.max_size() - b_.size()));
156 return Traits::eof();
157 auto const bs = b_.prepare(max_prepare);
158 auto const b = buffers_front(bs);
159 auto const p = static_cast<CharT*>(b.data());
160 this->setp(p, p + b.size() / sizeof(CharT));
162 BOOST_ASSERT(b_.capacity() > b_.size());
164 Traits::to_char_type(ch));
171 (this->pptr() - this->pbase()) *
173 this->setp(nullptr, nullptr);
178 //------------------------------------------------------------------------------
180 template<class DynamicBuffer,
181 class CharT, class Traits, bool isMovable>
182 class ostream_helper;
184 template<class DynamicBuffer, class CharT, class Traits>
185 class ostream_helper<
186 DynamicBuffer, CharT, Traits, true>
187 : public std::basic_ostream<CharT, Traits>
190 DynamicBuffer, CharT, Traits, true> osb_;
194 ostream_helper(DynamicBuffer& b);
196 ostream_helper(ostream_helper&& other);
199 template<class DynamicBuffer, class CharT, class Traits>
200 ostream_helper<DynamicBuffer, CharT, Traits, true>::
201 ostream_helper(DynamicBuffer& b)
202 : std::basic_ostream<CharT, Traits>(&this->osb_)
207 template<class DynamicBuffer, class CharT, class Traits>
208 ostream_helper<DynamicBuffer, CharT, Traits, true>::
209 ostream_helper(ostream_helper&& other)
210 : std::basic_ostream<CharT, Traits>(&osb_)
211 , osb_(std::move(other.osb_))
215 // This work-around is for libstdc++ versions that
216 // don't have a movable std::basic_streambuf
219 class ostream_helper_base
222 std::unique_ptr<T> member;
225 ostream_helper_base&&) = default;
228 ostream_helper_base(T* t)
234 template<class DynamicBuffer, class CharT, class Traits>
235 class ostream_helper<
236 DynamicBuffer, CharT, Traits, false>
237 : private ostream_helper_base<ostream_buffer<
238 DynamicBuffer, CharT, Traits, false>>
239 , public std::basic_ostream<CharT, Traits>
243 ostream_helper(DynamicBuffer& b)
244 : ostream_helper_base<ostream_buffer<
245 DynamicBuffer, CharT, Traits, false>>(
246 new ostream_buffer<DynamicBuffer,
247 CharT, Traits, false>(b))
248 , std::basic_ostream<CharT, Traits>(
253 ostream_helper(ostream_helper&& other)
254 : ostream_helper_base<ostream_buffer<
255 DynamicBuffer, CharT, Traits, false>>(
257 , std::basic_ostream<CharT, Traits>(