Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/CPPAlliance/http_proto
8 : //
9 :
10 : #ifndef BOOST_HTTP_PROTO_BUFFER_HPP
11 : #define BOOST_HTTP_PROTO_BUFFER_HPP
12 :
13 : #include <boost/http_proto/detail/config.hpp>
14 : #include <boost/assert.hpp>
15 : #include <boost/config/workaround.hpp>
16 : #include <boost/type_traits/make_void.hpp>
17 : #include <cstdlib>
18 : #include <cstring>
19 : #include <type_traits>
20 : #include <utility>
21 :
22 : namespace boost {
23 : namespace http_proto {
24 :
25 : //------------------------------------------------
26 :
27 : /** Determine if T is a possibly-const buffer.
28 : */
29 : #if BOOST_HTTP_PROTO_DOCS
30 : template<bool isConst, class T>
31 : struct is_buffer
32 : : std::integral_constant<bool, ...>{};
33 : #else
34 :
35 : template<
36 : bool isConst, class T,
37 : class = void>
38 : struct is_buffer : std::false_type {};
39 :
40 : template<
41 : bool isConst, class T>
42 : struct is_buffer<
43 : isConst, T, boost::void_t<decltype(
44 : std::declval<std::size_t&>() =
45 : std::declval<T const&>().size()
46 : ),
47 : typename std::enable_if<
48 : std::is_same<
49 : void*, decltype(
50 : std::declval<T const&>().data())
51 : >::value || (
52 : std::is_same<
53 : void const*, decltype(
54 : std::declval<T const&>().data())
55 : >::value && isConst)
56 : >::type
57 : >> : std::is_copy_constructible<T>
58 : {
59 : };
60 :
61 : #endif
62 :
63 : /** Determine if T is a const buffer.
64 : */
65 : template<class T>
66 : using is_const_buffer = is_buffer<true, T>;
67 :
68 : /** Determine if T is a mutable buffer.
69 : */
70 : template<class T>
71 : using is_mutable_buffer = is_buffer<false, T>;
72 :
73 : //------------------------------------------------
74 :
75 : /** Determine if T is a buffer sequence.
76 : */
77 : #if BOOST_HTTP_PROTO_DOCS
78 : template<bool isConst, class T>
79 : struct is_buffers
80 : : std::integral_constant<bool, ...>{};
81 : #else
82 :
83 : template<
84 : bool isConst, class T,
85 : class = void>
86 : struct is_buffers
87 : : is_buffer<isConst, T>
88 : {
89 : };
90 :
91 : template<
92 : bool isConst, class T>
93 : struct is_buffers<
94 : isConst, T, boost::void_t<
95 : typename std::enable_if<
96 : is_buffer<
97 : isConst, decltype(
98 : *std::declval<T const&>().begin())
99 : >::value &&
100 : is_buffer<
101 : isConst, decltype(
102 : *std::declval<T const&>().end())
103 : >::value
104 : >::type
105 : >> : std::is_move_constructible<T>
106 : {
107 : };
108 :
109 : #endif
110 :
111 : /** Determine if T is a const buffers.
112 : */
113 : template<class T>
114 : using is_const_buffers = is_buffers<true, T>;
115 :
116 : /** Determine if T is a mutable buffers.
117 : */
118 : template<class T>
119 : using is_mutable_buffers = is_buffers<false, T>;
120 :
121 : //------------------------------------------------
122 :
123 : class mutable_buffer
124 : {
125 : void* p_ = nullptr;
126 : std::size_t n_ = 0;
127 :
128 : public:
129 : using const_iterator =
130 : mutable_buffer const*;
131 :
132 3023 : mutable_buffer() = default;
133 : mutable_buffer(
134 : mutable_buffer const&) = default;
135 : mutable_buffer& operator=(
136 : mutable_buffer const&) = default;
137 :
138 12776 : mutable_buffer(
139 : void* data,
140 : std::size_t size) noexcept
141 12776 : : p_(data)
142 12776 : , n_(size)
143 : {
144 12776 : }
145 :
146 : template<
147 : class MutableBuffer
148 : #ifndef BOOST_HTTP_PROTO_DOCS
149 : ,class = typename std::enable_if<
150 : is_mutable_buffer<MutableBuffer
151 : >::value>::type
152 : #endif
153 : >
154 2 : mutable_buffer(
155 : MutableBuffer const& b) noexcept
156 : : p_(b.data())
157 2 : , n_(b.size())
158 : {
159 2 : }
160 :
161 : void*
162 12335 : data() const noexcept
163 : {
164 12335 : return p_;
165 : }
166 :
167 : std::size_t
168 31673 : size() const noexcept
169 : {
170 31673 : return n_;
171 : }
172 :
173 : const_iterator
174 21 : begin() const noexcept
175 : {
176 21 : return this;
177 : }
178 :
179 : const_iterator
180 21 : end() const noexcept
181 : {
182 21 : return this + 1;
183 : }
184 :
185 : mutable_buffer&
186 3 : operator+=(std::size_t n) noexcept
187 : {
188 3 : if(n >= n_)
189 : {
190 0 : p_ = static_cast<
191 0 : char*>(p_) + n_;
192 0 : n_ = 0;
193 0 : return *this;
194 : }
195 3 : p_ = static_cast<
196 3 : char*>(p_) + n;
197 3 : n_ -= n;
198 3 : return *this;
199 : }
200 :
201 : friend
202 : mutable_buffer
203 4647 : operator+(
204 : mutable_buffer const& b,
205 : std::size_t n) noexcept
206 : {
207 4647 : if(n < b.size())
208 : return {
209 : static_cast<char*>(
210 4647 : b.data()) + n,
211 4647 : b.size() - n };
212 : return {
213 : static_cast<char*>(
214 0 : b.data()) + b.size(),
215 0 : 0 };
216 : }
217 :
218 : friend
219 : mutable_buffer
220 1 : operator+(
221 : std::size_t n,
222 : mutable_buffer const& b) noexcept
223 : {
224 1 : if(n < b.size())
225 : return {
226 : static_cast<char*>(
227 1 : b.data()) + n,
228 1 : b.size() - n };
229 : return {
230 : static_cast<char*>(
231 0 : b.data()) + b.size(),
232 0 : 0 };
233 : }
234 : };
235 :
236 : //------------------------------------------------
237 :
238 : class const_buffer
239 : {
240 : void const* p_ = nullptr;
241 : std::size_t n_ = 0;
242 :
243 : public:
244 : using const_iterator =
245 : const_buffer const*;
246 :
247 29 : const_buffer() = default;
248 : const_buffer(
249 : const_buffer const&) = default;
250 : const_buffer& operator=(
251 : const_buffer const&) = default;
252 :
253 9769 : const_buffer(
254 : void const* data,
255 : std::size_t size) noexcept
256 9769 : : p_(data)
257 9769 : , n_(size)
258 : {
259 9769 : }
260 :
261 : template<
262 : class ConstBuffer
263 : #ifndef BOOST_HTTP_PROTO_DOCS
264 : ,class = typename std::enable_if<
265 : is_const_buffer<ConstBuffer
266 : >::value>::type
267 : #endif
268 : >
269 16 : const_buffer(
270 : ConstBuffer const& b) noexcept
271 : : p_(b.data())
272 16 : , n_(b.size())
273 : {
274 16 : }
275 :
276 : void const*
277 9306 : data() const noexcept
278 : {
279 9306 : return p_;
280 : }
281 :
282 : std::size_t
283 23972 : size() const noexcept
284 : {
285 23972 : return n_;
286 : }
287 :
288 : const_iterator
289 17 : begin() const noexcept
290 : {
291 17 : return this;
292 : }
293 :
294 : const_iterator
295 17 : end() const noexcept
296 : {
297 17 : return this + 1;
298 : }
299 :
300 : const_buffer&
301 2 : operator+=(std::size_t n) noexcept
302 : {
303 2 : if(n >= n_)
304 : {
305 0 : p_ = static_cast<
306 0 : char const*>(p_) + n_;
307 0 : n_ = 0;
308 0 : return *this;
309 : }
310 2 : p_ = static_cast<
311 2 : char const*>(p_) + n;
312 2 : n_ -= n;
313 2 : return *this;
314 : }
315 :
316 : friend
317 : const_buffer
318 4647 : operator+(
319 : const_buffer const& b,
320 : std::size_t n) noexcept
321 : {
322 4647 : if(n < b.size())
323 : return {
324 : static_cast<char const*>(
325 4647 : b.data()) + n,
326 4647 : b.size() - n };
327 : return {
328 : static_cast<char const*>(
329 0 : b.data()) + b.size(),
330 0 : 0 };
331 : }
332 :
333 : friend
334 : const_buffer
335 1 : operator+(
336 : std::size_t n,
337 : const_buffer const& b) noexcept
338 : {
339 1 : if(n < b.size())
340 : return {
341 : static_cast<char const*>(
342 1 : b.data()) + n,
343 1 : b.size() - n };
344 : return {
345 : static_cast<char const*>(
346 0 : b.data()) + b.size(),
347 0 : 0 };
348 : }
349 : };
350 :
351 : //------------------------------------------------
352 :
353 : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
354 : # pragma warning (push)
355 : # pragma warning (disable: 4521) // multiple copy constructors specified
356 : # pragma warning (disable: 4522) // multiple assignment operators specified
357 : #endif
358 :
359 : template<bool isConst>
360 : class buffers_pair
361 : {
362 : public:
363 : // VFALCO: This type is public otherwise
364 : // asio::buffers_iterator won't compile.
365 : using value_type = typename
366 : std::conditional<isConst,
367 : const_buffer,
368 : mutable_buffer>::type;
369 :
370 : using const_iterator = value_type const*;
371 :
372 0 : buffers_pair() = default;
373 :
374 : #if defined(BOOST_HTTP_PROTO_DOCS) || ( \
375 : ! BOOST_WORKAROUND(BOOST_MSVC, < 1910))
376 : buffers_pair(
377 : buffers_pair const& other) = default;
378 : buffers_pair& operator=(
379 : buffers_pair const& other) = default;
380 :
381 : #else
382 : buffers_pair(
383 : buffers_pair const& other)
384 : : buffers_pair(
385 : *other.begin(),
386 : *(other.begin() + 1))
387 : {
388 : }
389 :
390 : buffers_pair&
391 : operator=(buffers_pair const& other)
392 : {
393 : b_[0] = other.b_[0];
394 : b_[1] = other.b_[1];
395 : return *this;
396 : }
397 : #endif
398 :
399 : // const pair construction
400 : // from mutable mutable pair
401 : template<
402 : bool isConst_ = isConst,
403 : class = typename std::enable_if<
404 : isConst_>::type>
405 : buffers_pair(
406 : buffers_pair<false> const& other)
407 : : buffers_pair(
408 : other.b_[0],
409 : other.b_[1])
410 : {
411 : }
412 :
413 : // const pair assignment
414 : // from mutable mutable pair
415 : template<
416 : bool isConst_ = isConst,
417 : class = typename std::enable_if<
418 : isConst_>::type>
419 : buffers_pair&
420 : operator=(
421 : buffers_pair<false> const& other)
422 : {
423 : b_[0] = other.b_[0];
424 : b_[1] = other.b_[1];
425 : return *this;
426 : }
427 :
428 8103 : buffers_pair(
429 : value_type b0,
430 : value_type b1) noexcept
431 8103 : {
432 8103 : if(b0.size() > 0)
433 : {
434 7713 : b_[0] = b0;
435 7713 : b_[1] = b1;
436 : }
437 : else
438 : {
439 390 : b_[0] = b1;
440 : }
441 8103 : }
442 :
443 : const_buffer
444 : operator[](
445 : std::size_t i) const noexcept
446 : {
447 : BOOST_ASSERT(i < 2);
448 : return b_[i];
449 : }
450 :
451 : const_iterator
452 8106 : begin() const noexcept
453 : {
454 8106 : return b_;
455 : }
456 :
457 : const_iterator
458 5085 : end() const noexcept
459 : {
460 5085 : if(b_[1].size() > 0)
461 4681 : return &b_[2];
462 404 : if(b_[0].size() > 0)
463 404 : return &b_[1];
464 0 : return b_;
465 : }
466 :
467 : private:
468 : value_type b_[2];
469 : };
470 :
471 : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
472 : # pragma warning (pop)
473 : #endif
474 :
475 : /** A mutable buffers pair
476 : */
477 : using mutable_buffers_pair =
478 : buffers_pair<false>;
479 :
480 : /** A const buffers pair
481 : */
482 : using const_buffers_pair =
483 : buffers_pair<true>;
484 :
485 : //------------------------------------------------
486 :
487 : /** Return the total octets in a buffer sequence
488 : */
489 : template<
490 : class ConstBuffers
491 : #ifndef BOOST_HTTP_PROTO_DOCS
492 : , class = typename std::enable_if<
493 : is_const_buffers<ConstBuffers>::value
494 : >::type
495 : #endif
496 : >
497 : std::size_t
498 21 : buffer_size(
499 : ConstBuffers const& buffers) noexcept
500 : {
501 21 : std::size_t n = 0;
502 55 : for(const_buffer b : buffers)
503 34 : n += b.size();
504 21 : return n;
505 : }
506 :
507 : //------------------------------------------------
508 :
509 : /** Copy buffer contents
510 : */
511 : template<
512 : class MutableBuffers,
513 : class ConstBuffers>
514 : std::size_t
515 2557 : buffer_copy(
516 : MutableBuffers const& to,
517 : ConstBuffers const& from,
518 : std::size_t at_most =
519 : std::size_t(-1)) noexcept
520 : {
521 : // If you get a compile error here it
522 : // means that one or both of your types
523 : // do not meet the requirements.
524 : static_assert(
525 : is_mutable_buffers<MutableBuffers>::value &&
526 : is_const_buffers<ConstBuffers>::value,
527 : "Type requirements not met");
528 :
529 2557 : std::size_t total = 0;
530 2557 : std::size_t pos0 = 0;
531 2557 : std::size_t pos1 = 0;
532 2557 : auto const end0 = from.end();
533 2557 : auto const end1 = to.end();
534 2557 : auto it0 = from.begin();
535 2557 : auto it1 = to.begin();
536 4646 : while(
537 4837 : total < at_most &&
538 11854 : it0 != end0 &&
539 : it1 != end1)
540 : {
541 : const_buffer b0 =
542 4646 : const_buffer(*it0) + pos0;
543 : mutable_buffer b1 =
544 4646 : mutable_buffer(*it1) + pos1;
545 : std::size_t amount =
546 26688 : [&]
547 : {
548 4646 : std::size_t n = b0.size();
549 4646 : if( n > b1.size())
550 1730 : n = b1.size();
551 4646 : if( n > at_most - total)
552 1728 : n = at_most - total;
553 4646 : std::memcpy(
554 : b1.data(),
555 : b0.data(),
556 : n);
557 4646 : return n;
558 4646 : }();
559 4646 : total += amount;
560 4646 : if(amount == b1.size())
561 : {
562 1682 : ++it1;
563 1682 : pos1 = 0;
564 : }
565 : else
566 : {
567 2964 : pos1 += amount;
568 : }
569 4646 : if(amount == b0.size())
570 : {
571 1694 : ++it0;
572 1694 : pos0 = 0;
573 : }
574 : else
575 : {
576 2952 : pos0 += amount;
577 : }
578 : }
579 2557 : return total;
580 : }
581 :
582 : } // http_proto
583 : } // boost
584 :
585 : #endif
|