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
10#ifndef BOOST_BEAST_DETAIL_OSTREAM_HPP
11#define BOOST_BEAST_DETAIL_OSTREAM_HPP
12
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>
17#include <memory>
18#include <ostream>
19#include <streambuf>
20#include <type_traits>
21#include <utility>
22
23namespace boost {
24namespace beast {
25namespace detail {
26
27struct basic_streambuf_movable_helper :
28 std::basic_streambuf<char, std::char_traits<char>>
29{
30 basic_streambuf_movable_helper(
31 basic_streambuf_movable_helper&&) = default;
32};
33
34using basic_streambuf_movable =
35 std::is_move_constructible<basic_streambuf_movable_helper>;
36
37template<class DynamicBuffer,
38 class CharT, class Traits, bool isMovable>
39class ostream_buffer;
40
41//------------------------------------------------------------------------------
42
43template<class DynamicBuffer, class CharT, class Traits>
44class ostream_buffer
45 <DynamicBuffer, CharT, Traits, true> final
46 : public std::basic_streambuf<CharT, Traits>
47{
48 using int_type = typename
49 std::basic_streambuf<CharT, Traits>::int_type;
50
51 using traits_type = typename
52 std::basic_streambuf<CharT, Traits>::traits_type;
53
54 DynamicBuffer& b_;
55
56public:
57 ostream_buffer(ostream_buffer&&) = default;
58 ostream_buffer(ostream_buffer const&) = delete;
59
60 ~ostream_buffer() noexcept
61 {
62 sync();
63 }
64
65 explicit
66 ostream_buffer(DynamicBuffer& b)
67 : b_(b)
68 {
69 b_.prepare(0);
70 }
71
72 int_type
73 overflow(int_type ch) override
74 {
75 BOOST_ASSERT(! Traits::eq_int_type(
76 ch, Traits::eof()));
77 sync();
78
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()));
85 if(max_prepare == 0)
86 return Traits::eof();
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));
91
92 BOOST_ASSERT(b_.capacity() > b_.size());
93 return this->sputc(
94 Traits::to_char_type(ch));
95 }
96
97 int
98 sync() override
99 {
100 b_.commit(
101 (this->pptr() - this->pbase()) *
102 sizeof(CharT));
103 this->setp(nullptr, nullptr);
104 return 0;
105 }
106};
107
108//------------------------------------------------------------------------------
109
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
113
114template<class DynamicBuffer, class CharT, class Traits>
115class ostream_buffer
116 <DynamicBuffer, CharT, Traits, false>
117 : public std::basic_streambuf<CharT, Traits>
118{
119 using int_type = typename
120 std::basic_streambuf<CharT, Traits>::int_type;
121
122 using traits_type = typename
123 std::basic_streambuf<CharT, Traits>::traits_type;
124
125 DynamicBuffer& b_;
126
127public:
128 ostream_buffer(ostream_buffer&&) = delete;
129 ostream_buffer(ostream_buffer const&) = delete;
130
131 ~ostream_buffer() noexcept
132 {
133 sync();
134 }
135
136 explicit
137 ostream_buffer(DynamicBuffer& b)
138 : b_(b)
139 {
140 }
141
142 int_type
143 overflow(int_type ch) override
144 {
145 BOOST_ASSERT(! Traits::eq_int_type(
146 ch, Traits::eof()));
147 sync();
148
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()));
155 if(max_prepare == 0)
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));
161
162 BOOST_ASSERT(b_.capacity() > b_.size());
163 return this->sputc(
164 Traits::to_char_type(ch));
165 }
166
167 int
168 sync() override
169 {
170 b_.commit(
171 (this->pptr() - this->pbase()) *
172 sizeof(CharT));
173 this->setp(nullptr, nullptr);
174 return 0;
175 }
176};
177
178//------------------------------------------------------------------------------
179
180template<class DynamicBuffer,
181 class CharT, class Traits, bool isMovable>
182class ostream_helper;
183
184template<class DynamicBuffer, class CharT, class Traits>
185class ostream_helper<
186 DynamicBuffer, CharT, Traits, true>
187 : public std::basic_ostream<CharT, Traits>
188{
189 ostream_buffer<
190 DynamicBuffer, CharT, Traits, true> osb_;
191
192public:
193 explicit
194 ostream_helper(DynamicBuffer& b);
195
196 ostream_helper(ostream_helper&& other);
197};
198
199template<class DynamicBuffer, class CharT, class Traits>
200ostream_helper<DynamicBuffer, CharT, Traits, true>::
201ostream_helper(DynamicBuffer& b)
202 : std::basic_ostream<CharT, Traits>(&this->osb_)
203 , osb_(b)
204{
205}
206
207template<class DynamicBuffer, class CharT, class Traits>
208ostream_helper<DynamicBuffer, CharT, Traits, true>::
209ostream_helper(ostream_helper&& other)
210 : std::basic_ostream<CharT, Traits>(&osb_)
211 , osb_(std::move(other.osb_))
212{
213}
214
215// This work-around is for libstdc++ versions that
216// don't have a movable std::basic_streambuf
217
218template<class T>
219class ostream_helper_base
220{
221protected:
222 std::unique_ptr<T> member;
223
224 ostream_helper_base(
225 ostream_helper_base&&) = default;
226
227 explicit
228 ostream_helper_base(T* t)
229 : member(t)
230 {
231 }
232};
233
234template<class DynamicBuffer, class CharT, class Traits>
235class 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>
240{
241public:
242 explicit
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>(
249 this->member.get())
250 {
251 }
252
253 ostream_helper(ostream_helper&& other)
254 : ostream_helper_base<ostream_buffer<
255 DynamicBuffer, CharT, Traits, false>>(
256 std::move(other))
257 , std::basic_ostream<CharT, Traits>(
258 this->member.get())
259 {
260 }
261};
262
263} // detail
264} // beast
265} // boost
266
267#endif
268

source code of boost/libs/beast/include/boost/beast/core/detail/ostream.hpp