]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // Copyright (c) 2013-2017 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 | ||
8 | #ifndef BEAST_STREAMBUF_HPP | |
9 | #define BEAST_STREAMBUF_HPP | |
10 | ||
11 | #include <beast/config.hpp> | |
12 | #include <beast/core/detail/empty_base_optimization.hpp> | |
13 | #include <boost/asio/buffer.hpp> | |
14 | #include <boost/intrusive/list.hpp> | |
15 | #include <iterator> | |
16 | #include <limits> | |
17 | #include <memory> | |
18 | #include <type_traits> | |
19 | ||
20 | namespace beast { | |
21 | ||
22 | /** A @b `DynamicBuffer` that uses multiple buffers internally. | |
23 | ||
24 | The implementation uses a sequence of one or more character arrays | |
25 | of varying sizes. Additional character array objects are appended to | |
26 | the sequence to accommodate changes in the size of the character | |
27 | sequence. | |
28 | ||
29 | @note Meets the requirements of @b DynamicBuffer. | |
30 | ||
31 | @tparam Allocator The allocator to use for managing memory. | |
32 | */ | |
33 | template<class Allocator> | |
34 | class basic_streambuf | |
35 | #if ! BEAST_DOXYGEN | |
36 | : private detail::empty_base_optimization< | |
37 | typename std::allocator_traits<Allocator>:: | |
38 | template rebind_alloc<char>> | |
39 | #endif | |
40 | { | |
41 | public: | |
42 | #if BEAST_DOXYGEN | |
43 | /// The type of allocator used. | |
44 | using allocator_type = Allocator; | |
45 | #else | |
46 | using allocator_type = typename | |
47 | std::allocator_traits<Allocator>:: | |
48 | template rebind_alloc<char>; | |
49 | #endif | |
50 | ||
51 | private: | |
52 | // Storage for the list of buffers representing the input | |
53 | // and output sequences. The allocation for each element | |
54 | // contains `element` followed by raw storage bytes. | |
55 | class element; | |
56 | ||
57 | using alloc_traits = std::allocator_traits<allocator_type>; | |
58 | using list_type = typename boost::intrusive::make_list<element, | |
59 | boost::intrusive::constant_time_size<true>>::type; | |
60 | using iterator = typename list_type::iterator; | |
61 | using const_iterator = typename list_type::const_iterator; | |
62 | ||
63 | using size_type = typename std::allocator_traits<Allocator>::size_type; | |
64 | using const_buffer = boost::asio::const_buffer; | |
65 | using mutable_buffer = boost::asio::mutable_buffer; | |
66 | ||
67 | static_assert(std::is_base_of<std::bidirectional_iterator_tag, | |
68 | typename std::iterator_traits<iterator>::iterator_category>::value, | |
69 | "BidirectionalIterator requirements not met"); | |
70 | ||
71 | static_assert(std::is_base_of<std::bidirectional_iterator_tag, | |
72 | typename std::iterator_traits<const_iterator>::iterator_category>::value, | |
73 | "BidirectionalIterator requirements not met"); | |
74 | ||
75 | list_type list_; // list of allocated buffers | |
76 | iterator out_; // element that contains out_pos_ | |
77 | size_type alloc_size_; // min amount to allocate | |
78 | size_type in_size_ = 0; // size of the input sequence | |
79 | size_type in_pos_ = 0; // input offset in list_.front() | |
80 | size_type out_pos_ = 0; // output offset in *out_ | |
81 | size_type out_end_ = 0; // output end offset in list_.back() | |
82 | ||
83 | public: | |
84 | #if BEAST_DOXYGEN | |
85 | /// The type used to represent the input sequence as a list of buffers. | |
86 | using const_buffers_type = implementation_defined; | |
87 | ||
88 | /// The type used to represent the output sequence as a list of buffers. | |
89 | using mutable_buffers_type = implementation_defined; | |
90 | ||
91 | #else | |
92 | class const_buffers_type; | |
93 | ||
94 | class mutable_buffers_type; | |
95 | ||
96 | #endif | |
97 | ||
98 | /// Destructor. | |
99 | ~basic_streambuf(); | |
100 | ||
101 | /** Move constructor. | |
102 | ||
103 | The new object will have the input sequence of | |
104 | the other stream buffer, and an empty output sequence. | |
105 | ||
106 | @note After the move, the moved-from object will have | |
107 | an empty input and output sequence, with no internal | |
108 | buffers allocated. | |
109 | */ | |
110 | basic_streambuf(basic_streambuf&&); | |
111 | ||
112 | /** Move constructor. | |
113 | ||
114 | The new object will have the input sequence of | |
115 | the other stream buffer, and an empty output sequence. | |
116 | ||
117 | @note After the move, the moved-from object will have | |
118 | an empty input and output sequence, with no internal | |
119 | buffers allocated. | |
120 | ||
121 | @param alloc The allocator to associate with the | |
122 | stream buffer. | |
123 | */ | |
124 | basic_streambuf(basic_streambuf&&, | |
125 | allocator_type const& alloc); | |
126 | ||
127 | /** Move assignment. | |
128 | ||
129 | This object will have the input sequence of | |
130 | the other stream buffer, and an empty output sequence. | |
131 | ||
132 | @note After the move, the moved-from object will have | |
133 | an empty input and output sequence, with no internal | |
134 | buffers allocated. | |
135 | */ | |
136 | basic_streambuf& | |
137 | operator=(basic_streambuf&&); | |
138 | ||
139 | /** Copy constructor. | |
140 | ||
141 | This object will have a copy of the other stream | |
142 | buffer's input sequence, and an empty output sequence. | |
143 | */ | |
144 | basic_streambuf(basic_streambuf const&); | |
145 | ||
146 | /** Copy constructor. | |
147 | ||
148 | This object will have a copy of the other stream | |
149 | buffer's input sequence, and an empty output sequence. | |
150 | ||
151 | @param alloc The allocator to associate with the | |
152 | stream buffer. | |
153 | */ | |
154 | basic_streambuf(basic_streambuf const&, | |
155 | allocator_type const& alloc); | |
156 | ||
157 | /** Copy assignment. | |
158 | ||
159 | This object will have a copy of the other stream | |
160 | buffer's input sequence, and an empty output sequence. | |
161 | */ | |
162 | basic_streambuf& operator=(basic_streambuf const&); | |
163 | ||
164 | /** Copy constructor. | |
165 | ||
166 | This object will have a copy of the other stream | |
167 | buffer's input sequence, and an empty output sequence. | |
168 | */ | |
169 | template<class OtherAlloc> | |
170 | basic_streambuf(basic_streambuf<OtherAlloc> const&); | |
171 | ||
172 | /** Copy constructor. | |
173 | ||
174 | This object will have a copy of the other stream | |
175 | buffer's input sequence, and an empty output sequence. | |
176 | ||
177 | @param alloc The allocator to associate with the | |
178 | stream buffer. | |
179 | */ | |
180 | template<class OtherAlloc> | |
181 | basic_streambuf(basic_streambuf<OtherAlloc> const&, | |
182 | allocator_type const& alloc); | |
183 | ||
184 | /** Copy assignment. | |
185 | ||
186 | This object will have a copy of the other stream | |
187 | buffer's input sequence, and an empty output sequence. | |
188 | */ | |
189 | template<class OtherAlloc> | |
190 | basic_streambuf& operator=(basic_streambuf<OtherAlloc> const&); | |
191 | ||
192 | /** Construct a stream buffer. | |
193 | ||
194 | @param alloc_size The size of buffer to allocate. This is a | |
195 | soft limit, calls to prepare for buffers exceeding this size | |
196 | will allocate the larger size. The default allocation size | |
197 | is 1KB (1024 bytes). | |
198 | ||
199 | @param alloc The allocator to use. If this parameter is | |
200 | unspecified, a default constructed allocator will be used. | |
201 | */ | |
202 | explicit | |
203 | basic_streambuf(std::size_t alloc_size = 1024, | |
204 | Allocator const& alloc = allocator_type{}); | |
205 | ||
206 | /// Returns a copy of the associated allocator. | |
207 | allocator_type | |
208 | get_allocator() const | |
209 | { | |
210 | return this->member(); | |
211 | } | |
212 | ||
213 | /** Returns the default allocation size. | |
214 | ||
215 | This is the smallest size that the stream buffer will allocate. | |
216 | The size of the allocation can influence capacity, which will | |
217 | affect algorithms that use capacity to efficiently read from | |
218 | streams. | |
219 | */ | |
220 | std::size_t | |
221 | alloc_size() const | |
222 | { | |
223 | return alloc_size_; | |
224 | } | |
225 | ||
226 | /** Set the default allocation size. | |
227 | ||
228 | This is the smallest size that the stream buffer will allocate. | |
229 | The size of the allocation can influence capacity, which will | |
230 | affect algorithms that use capacity to efficiently read from | |
231 | streams. | |
232 | ||
233 | @note This will not affect any already-existing allocations. | |
234 | ||
235 | @param n The number of bytes. | |
236 | */ | |
237 | void | |
238 | alloc_size(std::size_t n) | |
239 | { | |
240 | alloc_size_ = n; | |
241 | } | |
242 | ||
243 | /// Returns the size of the input sequence. | |
244 | size_type | |
245 | size() const | |
246 | { | |
247 | return in_size_; | |
248 | } | |
249 | ||
250 | /// Returns the permitted maximum sum of the sizes of the input and output sequence. | |
251 | size_type | |
252 | max_size() const | |
253 | { | |
254 | return (std::numeric_limits<std::size_t>::max)(); | |
255 | } | |
256 | ||
257 | /// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation. | |
258 | std::size_t | |
259 | capacity() const; | |
260 | ||
261 | /** Get a list of buffers that represents the input sequence. | |
262 | ||
263 | @note These buffers remain valid across subsequent calls to `prepare`. | |
264 | */ | |
265 | const_buffers_type | |
266 | data() const; | |
267 | ||
268 | /** Get a list of buffers that represents the output sequence, with the given size. | |
269 | ||
270 | @note Buffers representing the input sequence acquired prior to | |
271 | this call remain valid. | |
272 | */ | |
273 | mutable_buffers_type | |
274 | prepare(size_type n); | |
275 | ||
276 | /** Move bytes from the output sequence to the input sequence. | |
277 | ||
278 | @note Buffers representing the input sequence acquired prior to | |
279 | this call remain valid. | |
280 | */ | |
281 | void | |
282 | commit(size_type n); | |
283 | ||
284 | /// Remove bytes from the input sequence. | |
285 | void | |
286 | consume(size_type n); | |
287 | ||
288 | // Helper for boost::asio::read_until | |
289 | template<class OtherAllocator> | |
290 | friend | |
291 | std::size_t | |
292 | read_size_helper(basic_streambuf< | |
293 | OtherAllocator> const& streambuf, std::size_t max_size); | |
294 | ||
295 | private: | |
296 | void | |
297 | clear(); | |
298 | ||
299 | void | |
300 | move_assign(basic_streambuf& other, std::false_type); | |
301 | ||
302 | void | |
303 | move_assign(basic_streambuf& other, std::true_type); | |
304 | ||
305 | void | |
306 | copy_assign(basic_streambuf const& other, std::false_type); | |
307 | ||
308 | void | |
309 | copy_assign(basic_streambuf const& other, std::true_type); | |
310 | ||
311 | void | |
312 | delete_list(); | |
313 | ||
314 | void | |
315 | debug_check() const; | |
316 | }; | |
317 | ||
318 | /** A @b `DynamicBuffer` that uses multiple buffers internally. | |
319 | ||
320 | The implementation uses a sequence of one or more character arrays | |
321 | of varying sizes. Additional character array objects are appended to | |
322 | the sequence to accommodate changes in the size of the character | |
323 | sequence. | |
324 | ||
325 | @note Meets the requirements of @b `DynamicBuffer`. | |
326 | */ | |
327 | using streambuf = basic_streambuf<std::allocator<char>>; | |
328 | ||
329 | /** Format output to a @ref basic_streambuf. | |
330 | ||
331 | @param streambuf The @ref basic_streambuf to write to. | |
332 | ||
333 | @param t The object to write. | |
334 | ||
335 | @return A reference to the @ref basic_streambuf. | |
336 | */ | |
337 | template<class Allocator, class T> | |
338 | basic_streambuf<Allocator>& | |
339 | operator<<(basic_streambuf<Allocator>& streambuf, T const& t); | |
340 | ||
341 | } // beast | |
342 | ||
343 | #include <beast/core/impl/streambuf.ipp> | |
344 | ||
345 | #endif |