]>
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_DETAIL_PREPARED_BUFFERS_HPP | |
9 | #define BEAST_DETAIL_PREPARED_BUFFERS_HPP | |
10 | ||
11 | #include <beast/core/prepare_buffer.hpp> | |
12 | #include <boost/asio/buffer.hpp> | |
13 | #include <algorithm> | |
14 | #include <cstdint> | |
15 | #include <iterator> | |
16 | #include <stdexcept> | |
17 | #include <type_traits> | |
18 | #include <utility> | |
19 | ||
20 | namespace beast { | |
21 | namespace detail { | |
22 | ||
23 | /** A buffer sequence adapter that shortens the sequence size. | |
24 | ||
25 | The class adapts a buffer sequence to efficiently represent | |
26 | a shorter subset of the original list of buffers starting | |
27 | with the first byte of the original sequence. | |
28 | ||
29 | @tparam BufferSequence The buffer sequence to adapt. | |
30 | */ | |
31 | template<class BufferSequence> | |
32 | class prepared_buffers | |
33 | { | |
34 | using iter_type = | |
35 | typename BufferSequence::const_iterator; | |
36 | ||
37 | BufferSequence bs_; | |
38 | iter_type back_; | |
39 | iter_type end_; | |
40 | std::size_t size_; | |
41 | ||
42 | template<class Deduced> | |
43 | prepared_buffers(Deduced&& other, | |
44 | std::size_t nback, std::size_t nend) | |
45 | : bs_(std::forward<Deduced>(other).bs_) | |
46 | , back_(std::next(bs_.begin(), nback)) | |
47 | , end_(std::next(bs_.begin(), nend)) | |
48 | , size_(other.size_) | |
49 | { | |
50 | } | |
51 | ||
52 | void | |
53 | setup(std::size_t n); | |
54 | ||
55 | public: | |
56 | /// The type for each element in the list of buffers. | |
57 | using value_type = typename std::conditional< | |
58 | std::is_convertible<typename | |
59 | std::iterator_traits<iter_type>::value_type, | |
60 | boost::asio::mutable_buffer>::value, | |
61 | boost::asio::mutable_buffer, | |
62 | boost::asio::const_buffer>::type; | |
63 | ||
64 | #if BEAST_DOXYGEN | |
65 | /// A bidirectional iterator type that may be used to read elements. | |
66 | using const_iterator = implementation_defined; | |
67 | ||
68 | #else | |
69 | class const_iterator; | |
70 | ||
71 | #endif | |
72 | ||
73 | /// Move constructor. | |
74 | prepared_buffers(prepared_buffers&&); | |
75 | ||
76 | /// Copy constructor. | |
77 | prepared_buffers(prepared_buffers const&); | |
78 | ||
79 | /// Move assignment. | |
80 | prepared_buffers& operator=(prepared_buffers&&); | |
81 | ||
82 | /// Copy assignment. | |
83 | prepared_buffers& operator=(prepared_buffers const&); | |
84 | ||
85 | /** Construct a shortened buffer sequence. | |
86 | ||
87 | @param n The maximum number of bytes in the wrapped | |
88 | sequence. If this is larger than the size of passed, | |
89 | buffers, the resulting sequence will represent the | |
90 | entire input sequence. | |
91 | ||
92 | @param buffers The buffer sequence to adapt. A copy of | |
93 | the sequence will be made, but ownership of the underlying | |
94 | memory is not transferred. | |
95 | */ | |
96 | prepared_buffers(std::size_t n, BufferSequence const& buffers); | |
97 | ||
98 | /// Get a bidirectional iterator to the first element. | |
99 | const_iterator | |
100 | begin() const; | |
101 | ||
102 | /// Get a bidirectional iterator to one past the last element. | |
103 | const_iterator | |
104 | end() const; | |
105 | }; | |
106 | ||
107 | template<class BufferSequence> | |
108 | class prepared_buffers<BufferSequence>::const_iterator | |
109 | { | |
110 | friend class prepared_buffers<BufferSequence>; | |
111 | ||
112 | using iter_type = | |
113 | typename BufferSequence::const_iterator; | |
114 | ||
115 | prepared_buffers const* b_ = nullptr; | |
116 | typename BufferSequence::const_iterator it_; | |
117 | ||
118 | public: | |
119 | using value_type = typename std::conditional< | |
120 | std::is_convertible<typename | |
121 | std::iterator_traits<iter_type>::value_type, | |
122 | boost::asio::mutable_buffer>::value, | |
123 | boost::asio::mutable_buffer, | |
124 | boost::asio::const_buffer>::type; | |
125 | using pointer = value_type const*; | |
126 | using reference = value_type; | |
127 | using difference_type = std::ptrdiff_t; | |
128 | using iterator_category = | |
129 | std::bidirectional_iterator_tag; | |
130 | ||
131 | const_iterator() = default; | |
132 | const_iterator(const_iterator&& other); | |
133 | const_iterator(const_iterator const& other); | |
134 | const_iterator& operator=(const_iterator&& other); | |
135 | const_iterator& operator=(const_iterator const& other); | |
136 | ||
137 | bool | |
138 | operator==(const_iterator const& other) const | |
139 | { | |
140 | return b_ == other.b_ && it_ == other.it_; | |
141 | } | |
142 | ||
143 | bool | |
144 | operator!=(const_iterator const& other) const | |
145 | { | |
146 | return !(*this == other); | |
147 | } | |
148 | ||
149 | reference | |
150 | operator*() const | |
151 | { | |
152 | if(it_ == b_->back_) | |
153 | return prepare_buffer(b_->size_, *it_); | |
154 | return *it_; | |
155 | } | |
156 | ||
157 | pointer | |
158 | operator->() const = delete; | |
159 | ||
160 | const_iterator& | |
161 | operator++() | |
162 | { | |
163 | ++it_; | |
164 | return *this; | |
165 | } | |
166 | ||
167 | const_iterator | |
168 | operator++(int) | |
169 | { | |
170 | auto temp = *this; | |
171 | ++(*this); | |
172 | return temp; | |
173 | } | |
174 | ||
175 | const_iterator& | |
176 | operator--() | |
177 | { | |
178 | --it_; | |
179 | return *this; | |
180 | } | |
181 | ||
182 | const_iterator | |
183 | operator--(int) | |
184 | { | |
185 | auto temp = *this; | |
186 | --(*this); | |
187 | return temp; | |
188 | } | |
189 | ||
190 | private: | |
191 | const_iterator(prepared_buffers const& b, | |
192 | bool at_end) | |
193 | : b_(&b) | |
194 | , it_(at_end ? b.end_ : b.bs_.begin()) | |
195 | { | |
196 | } | |
197 | }; | |
198 | ||
199 | template<class BufferSequence> | |
200 | void | |
201 | prepared_buffers<BufferSequence>:: | |
202 | setup(std::size_t n) | |
203 | { | |
204 | for(end_ = bs_.begin(); end_ != bs_.end(); ++end_) | |
205 | { | |
206 | auto const len = | |
207 | boost::asio::buffer_size(*end_); | |
208 | if(n <= len) | |
209 | { | |
210 | size_ = n; | |
211 | back_ = end_++; | |
212 | return; | |
213 | } | |
214 | n -= len; | |
215 | } | |
216 | size_ = 0; | |
217 | back_ = end_; | |
218 | } | |
219 | ||
220 | template<class BufferSequence> | |
221 | prepared_buffers<BufferSequence>::const_iterator:: | |
222 | const_iterator(const_iterator&& other) | |
223 | : b_(other.b_) | |
224 | , it_(std::move(other.it_)) | |
225 | { | |
226 | } | |
227 | ||
228 | template<class BufferSequence> | |
229 | prepared_buffers<BufferSequence>::const_iterator:: | |
230 | const_iterator(const_iterator const& other) | |
231 | : b_(other.b_) | |
232 | , it_(other.it_) | |
233 | { | |
234 | } | |
235 | ||
236 | template<class BufferSequence> | |
237 | auto | |
238 | prepared_buffers<BufferSequence>::const_iterator:: | |
239 | operator=(const_iterator&& other) -> | |
240 | const_iterator& | |
241 | { | |
242 | b_ = other.b_; | |
243 | it_ = std::move(other.it_); | |
244 | return *this; | |
245 | } | |
246 | ||
247 | template<class BufferSequence> | |
248 | auto | |
249 | prepared_buffers<BufferSequence>::const_iterator:: | |
250 | operator=(const_iterator const& other) -> | |
251 | const_iterator& | |
252 | { | |
253 | if(&other == this) | |
254 | return *this; | |
255 | b_ = other.b_; | |
256 | it_ = other.it_; | |
257 | return *this; | |
258 | } | |
259 | ||
260 | template<class BufferSequence> | |
261 | prepared_buffers<BufferSequence>:: | |
262 | prepared_buffers(prepared_buffers&& other) | |
263 | : prepared_buffers(std::move(other), | |
264 | std::distance<iter_type>(other.bs_.begin(), other.back_), | |
265 | std::distance<iter_type>(other.bs_.begin(), other.end_)) | |
266 | { | |
267 | } | |
268 | ||
269 | template<class BufferSequence> | |
270 | prepared_buffers<BufferSequence>:: | |
271 | prepared_buffers(prepared_buffers const& other) | |
272 | : prepared_buffers(other, | |
273 | std::distance<iter_type>(other.bs_.begin(), other.back_), | |
274 | std::distance<iter_type>(other.bs_.begin(), other.end_)) | |
275 | { | |
276 | } | |
277 | ||
278 | template<class BufferSequence> | |
279 | auto | |
280 | prepared_buffers<BufferSequence>:: | |
281 | operator=(prepared_buffers&& other) -> | |
282 | prepared_buffers& | |
283 | { | |
284 | auto const nback = std::distance<iter_type>( | |
285 | other.bs_.begin(), other.back_); | |
286 | auto const nend = std::distance<iter_type>( | |
287 | other.bs_.begin(), other.end_); | |
288 | bs_ = std::move(other.bs_); | |
289 | back_ = std::next(bs_.begin(), nback); | |
290 | end_ = std::next(bs_.begin(), nend); | |
291 | size_ = other.size_; | |
292 | return *this; | |
293 | } | |
294 | ||
295 | template<class BufferSequence> | |
296 | auto | |
297 | prepared_buffers<BufferSequence>:: | |
298 | operator=(prepared_buffers const& other) -> | |
299 | prepared_buffers& | |
300 | { | |
301 | auto const nback = std::distance<iter_type>( | |
302 | other.bs_.begin(), other.back_); | |
303 | auto const nend = std::distance<iter_type>( | |
304 | other.bs_.begin(), other.end_); | |
305 | bs_ = other.bs_; | |
306 | back_ = std::next(bs_.begin(), nback); | |
307 | end_ = std::next(bs_.begin(), nend); | |
308 | size_ = other.size_; | |
309 | return *this; | |
310 | } | |
311 | ||
312 | template<class BufferSequence> | |
313 | prepared_buffers<BufferSequence>:: | |
314 | prepared_buffers(std::size_t n, BufferSequence const& bs) | |
315 | : bs_(bs) | |
316 | { | |
317 | setup(n); | |
318 | } | |
319 | ||
320 | template<class BufferSequence> | |
321 | inline | |
322 | auto | |
323 | prepared_buffers<BufferSequence>::begin() const -> | |
324 | const_iterator | |
325 | { | |
326 | return const_iterator{*this, false}; | |
327 | } | |
328 | ||
329 | template<class BufferSequence> | |
330 | inline | |
331 | auto | |
332 | prepared_buffers<BufferSequence>::end() const -> | |
333 | const_iterator | |
334 | { | |
335 | return const_iterator{*this, true}; | |
336 | } | |
337 | ||
338 | } // detail | |
339 | } // beast | |
340 | ||
341 | #endif |