LCOV - code coverage report
Current view: top level - http_proto - buffer.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 132 140 94.3 %
Date: 2023-02-02 18:17:21 Functions: 51 52 98.1 %

          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 <iterator>
      20             : #include <type_traits>
      21             : #include <utility>
      22             : 
      23             : namespace boost {
      24             : namespace http_proto {
      25             : 
      26             : /** size tag for tag_invoke.
      27             : */
      28             : struct size_tag {};
      29             : 
      30             : /** prefix tag for tag_invoke.
      31             : */
      32             : struct prefix_tag {};
      33             : 
      34             : /** suffix tag for tag-invoke.
      35             : */
      36             : struct suffix_tag {};
      37             : 
      38             : //------------------------------------------------
      39             : 
      40             : /** Holds a buffer that can be modified.
      41             : */
      42             : class mutable_buffer
      43             : {
      44             :     unsigned char* p_ = nullptr;
      45             :     std::size_t n_ = 0;
      46             : 
      47             : public:
      48             :     using value_type = mutable_buffer;
      49             :     using const_iterator =
      50             :         value_type const*;
      51             : 
      52        3187 :     mutable_buffer() = default;
      53             :     mutable_buffer(
      54             :         mutable_buffer const&) = default;
      55             :     mutable_buffer& operator=(
      56             :         mutable_buffer const&) = default;
      57             : 
      58        8333 :     mutable_buffer(
      59             :         void* data,
      60             :         std::size_t size) noexcept
      61        8333 :         : p_(static_cast<
      62             :             unsigned char*>(data))
      63        8333 :         , n_(size)
      64             :     {
      65        8333 :     }
      66             : 
      67             : #ifndef BOOST_HTTP_PROTO_DOCS
      68             :     // conversion to boost::asio::mutable_buffer
      69             :     template<
      70             :         class T
      71             :         , class = typename std::enable_if<
      72             :             std::is_constructible<T,
      73             :                 void*, std::size_t>::value
      74             :             && ! std::is_same<T, mutable_buffer>::value
      75             :             //&& ! std::is_same<T, const_buffer>::value
      76             :         >::type
      77             :     >
      78             :     operator T() const noexcept
      79             :     {
      80             :         return T{ data(), size() };
      81             :     }
      82             : #endif
      83             : 
      84             :     void*
      85        7884 :     data() const noexcept
      86             :     {
      87        7884 :         return p_;
      88             :     }
      89             : 
      90             :     std::size_t
      91       23271 :     size() const noexcept
      92             :     {
      93       23271 :         return n_;
      94             :     }
      95             : 
      96             :     const_iterator
      97          56 :     begin() const noexcept
      98             :     {
      99          56 :         return this;
     100             :     }
     101             : 
     102             :     const_iterator
     103          56 :     end() const noexcept
     104             :     {
     105          56 :         return this + 1;
     106             :     }
     107             : 
     108             :     /** Remove a prefix from the buffer.
     109             :     */
     110             :     mutable_buffer&
     111        4848 :     operator+=(std::size_t n) noexcept
     112             :     {
     113        4848 :         if(n >= n_)
     114             :         {
     115          33 :             p_ = p_ + n_;
     116          33 :             n_ = 0;
     117          33 :             return *this;
     118             :         }
     119        4815 :         p_ = p_ + n;
     120        4815 :         n_ -= n;
     121        4815 :         return *this;
     122             :     }
     123             : 
     124             :     /** Return the buffer with a prefix removed.
     125             :     */
     126             :     friend
     127             :     mutable_buffer
     128        4844 :     operator+(
     129             :         mutable_buffer b,
     130             :         std::size_t n) noexcept
     131             :     {
     132        4844 :         return b += n;
     133             :     }
     134             : 
     135             :     /** Return the buffer with a prefix removed.
     136             :     */
     137             :     friend
     138             :     mutable_buffer
     139           1 :     operator+(
     140             :         std::size_t n,
     141             :         mutable_buffer b) noexcept
     142             :     {
     143           1 :         return b += n;
     144             :     }
     145             : 
     146             : #ifndef BOOST_HTTP_PROTO_DOCS
     147             :     friend
     148             :     mutable_buffer
     149           2 :     tag_invoke(
     150             :         prefix_tag const&,
     151             :         mutable_buffer const& b,
     152             :         std::size_t n) noexcept
     153             :     {
     154           2 :         if(n < b.size())
     155           2 :             return { b.p_, n };
     156           0 :         return b;
     157             :     }
     158             : 
     159             :     friend
     160             :     mutable_buffer
     161           2 :     tag_invoke(
     162             :         suffix_tag const&,
     163             :         mutable_buffer const& b,
     164             :         std::size_t n) noexcept
     165             :     {
     166           2 :         if(n < b.size())
     167           2 :             return { b.p_ + b.n_ - n, n };
     168           0 :         return b;
     169             :     }
     170             : #endif
     171             : };
     172             : 
     173             : //------------------------------------------------
     174             : 
     175             : /** Holds a buffer that cannot be modified.
     176             : */
     177             : class const_buffer
     178             : {
     179             :     unsigned char const* p_ = nullptr;
     180             :     std::size_t n_ = 0;
     181             : 
     182             : public:
     183             :     using value_type = const_buffer;
     184             :     using const_iterator =
     185             :         value_type const*;
     186             : 
     187          29 :     const_buffer() = default;
     188             :     const_buffer(
     189             :         const_buffer const&) = default;
     190             :     const_buffer& operator=(
     191             :         const_buffer const&) = default;
     192             : 
     193        5326 :     const_buffer(
     194             :         void const* data,
     195             :         std::size_t size) noexcept
     196        5326 :         : p_(static_cast<
     197             :             unsigned char const*>(data))
     198        5326 :         , n_(size)
     199             :     {
     200        5326 :     }
     201             : 
     202          14 :     const_buffer(
     203             :         mutable_buffer const& b) noexcept
     204          14 :         : p_(static_cast<
     205          14 :             unsigned char const*>(b.data()))
     206          14 :         , n_(b.size())
     207             :     {
     208          14 :     }
     209             : 
     210             : #ifndef BOOST_HTTP_PROTO_DOCS
     211             :     // conversion to boost::asio::const_buffer
     212             :     template<
     213             :         class T
     214             :         , class = typename std::enable_if<
     215             :             std::is_constructible<T,
     216             :                 void const*, std::size_t>::value &&
     217             :             ! std::is_same<T, mutable_buffer>::value &&
     218             :             ! std::is_same<T, const_buffer>::value
     219             :         >::type
     220             :     >
     221             :     operator T() const noexcept
     222             :     {
     223             :         return T{ data(), size() };
     224             :     }
     225             : #endif
     226             : 
     227             :     void const*
     228        4851 :     data() const noexcept
     229             :     {
     230        4851 :         return p_;
     231             :     }
     232             : 
     233             :     std::size_t
     234       15078 :     size() const noexcept
     235             :     {
     236       15078 :         return n_;
     237             :     }
     238             : 
     239             :     const_iterator
     240         216 :     begin() const noexcept
     241             :     {
     242         216 :         return this;
     243             :     }
     244             : 
     245             :     const_iterator
     246         216 :     end() const noexcept
     247             :     {
     248         216 :         return this + 1;
     249             :     }
     250             : 
     251             :     /** Remove a prefix from the buffer.
     252             :     */
     253             :     const_buffer&
     254        4847 :     operator+=(std::size_t n) noexcept
     255             :     {
     256        4847 :         if(n >= n_)
     257             :         {
     258          33 :             p_ = p_ + n_;
     259          33 :             n_ = 0;
     260          33 :             return *this;
     261             :         }
     262        4814 :         p_ = p_ + n;
     263        4814 :         n_ -= n;
     264        4814 :         return *this;
     265             :     }
     266             : 
     267             :     /** Return the buffer with a prefix removed.
     268             :     */
     269             :     friend
     270             :     const_buffer
     271        4844 :     operator+(
     272             :         const_buffer b,
     273             :         std::size_t n) noexcept
     274             :     {
     275        4844 :         return b += n;
     276             :     }
     277             : 
     278             :     /** Return the buffer with a prefix removed.
     279             :     */
     280             :     friend
     281             :     const_buffer
     282           1 :     operator+(
     283             :         std::size_t n,
     284             :         const_buffer b) noexcept
     285             :     {
     286           1 :         return b += n;
     287             :     }
     288             : 
     289             : #ifndef BOOST_HTTP_PROTO_DOCS
     290             :     friend
     291             :     const_buffer
     292           2 :     tag_invoke(
     293             :         prefix_tag const&,
     294             :         const_buffer const& b,
     295             :         std::size_t n) noexcept
     296             :     {
     297           2 :         if(n < b.size())
     298           2 :             return { b.p_, n };
     299           0 :         return b;
     300             :     }
     301             : 
     302             :     friend
     303             :     const_buffer
     304           2 :     tag_invoke(
     305             :         suffix_tag const&,
     306             :         const_buffer const& b,
     307             :         std::size_t n) noexcept
     308             :     {
     309           2 :         if(n < b.size())
     310           2 :             return { b.p_ + b.n_ - n, n };
     311           0 :         return b;
     312             :     }
     313             : #endif
     314             : };
     315             : 
     316             : //------------------------------------------------
     317             : 
     318             : #ifndef BOOST_HTTP_PROTO_DOCS
     319             : namespace detail {
     320             : 
     321             : // is bidirectional iterator
     322             : template<class T, class = void>
     323             : struct is_bidir_iter : std::false_type
     324             : {
     325             : };
     326             : 
     327             : template<class T>
     328             : struct is_bidir_iter<T, boost::void_t<decltype(
     329             :     // LegacyIterator
     330             :     *std::declval<T&>()
     331             :     ),
     332             :     // LegacyIterator
     333             :     typename std::iterator_traits<T>::value_type,
     334             :     typename std::iterator_traits<T>::difference_type,
     335             :     typename std::iterator_traits<T>::reference,
     336             :     typename std::iterator_traits<T>::pointer,
     337             :     typename std::iterator_traits<T>::iterator_category,
     338             :     typename std::enable_if<
     339             :     // LegacyIterator
     340             :     std::is_copy_constructible<T>::value &&
     341             :     std::is_copy_assignable<T>::value &&
     342             :     std::is_destructible<T>::value &&
     343             :     std::is_same<T&, decltype(
     344             :         ++std::declval<T&>())>::value &&
     345             :     // Swappable
     346             :     //  VFALCO TODO
     347             :     // EqualityComparable
     348             :     std::is_convertible<decltype(
     349             :         std::declval<T const&>() ==
     350             :             std::declval<T const&>()),
     351             :         bool>::value &&
     352             :     // LegacyInputIterator
     353             :     std::is_convertible<typename
     354             :         std::iterator_traits<T>::reference, typename
     355             :         std::iterator_traits<T>::value_type>::value &&
     356             :     std::is_same<typename
     357             :         std::iterator_traits<T>::reference,
     358             :         decltype(*std::declval<T const&>())>::value &&
     359             :     std::is_convertible<decltype(
     360             :         std::declval<T const&>() !=
     361             :             std::declval<T const&>()),
     362             :         bool>::value &&
     363             :     std::is_same<T&, decltype(
     364             :         ++std::declval<T&>())>::value &&
     365             :     // VFALCO (void)r++   (void)++r
     366             :     std::is_convertible<decltype(
     367             :         *std::declval<T&>()++), typename
     368             :         std::iterator_traits<T>::value_type>::value &&
     369             :     // LegacyForwardIterator
     370             :     std::is_default_constructible<T>::value &&
     371             :     std::is_same<T, decltype(
     372             :         std::declval<T&>()++)>::value &&
     373             :     std::is_same<typename
     374             :         std::iterator_traits<T>::reference,
     375             :             decltype(*std::declval<T&>()++)
     376             :                 >::value &&
     377             :     // LegacyBidirectionalIterator
     378             :     std::is_same<T&, decltype(
     379             :         --std::declval<T&>())>::value &&
     380             :     std::is_convertible<decltype(
     381             :         std::declval<T&>()--),
     382             :             T const&>::value &&
     383             :     std::is_same<typename
     384             :         std::iterator_traits<T>::reference,
     385             :         decltype(*std::declval<T&>()--)>::value
     386             :     >::type >>
     387             :     : std::true_type
     388             : {
     389             : };
     390             : 
     391             : } // detail
     392             : #endif
     393             : 
     394             : //------------------------------------------------
     395             : 
     396             : // https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ConstBufferSequence.html
     397             : 
     398             : /** Determine if T is a ConstBuffers.
     399             : */
     400             : #if BOOST_HTTP_PROTO_DOCS
     401             : template<class T>
     402             : struct is_const_buffers
     403             :     : std::integral_constant<bool, ...>{};
     404             : #else
     405             : 
     406             : template<class T, class = void>
     407             : struct is_const_buffers : std::false_type
     408             : {
     409             : };
     410             : 
     411             : template<class T>
     412             : struct is_const_buffers<T const>
     413             :     : is_const_buffers<typename
     414             :         std::decay<T>::type>
     415             : {
     416             : };
     417             : 
     418             : template<class T>
     419             : struct is_const_buffers<T const&>
     420             :     : is_const_buffers<typename
     421             :         std::decay<T>::type>
     422             : {
     423             : };
     424             : 
     425             : template<class T>
     426             : struct is_const_buffers<T&>
     427             :     : is_const_buffers<typename
     428             :         std::decay<T>::type>
     429             : {
     430             : };
     431             : 
     432             : template<class T>
     433             : struct is_const_buffers<T, boost::void_t<
     434             :     typename std::enable_if<
     435             :         (std::is_same<const_buffer, typename 
     436             :             T::value_type>::value
     437             :         || std::is_same<mutable_buffer, typename
     438             :             T::value_type>::value
     439             :             ) &&
     440             :         detail::is_bidir_iter<typename
     441             :             T::const_iterator>::value &&
     442             :         std::is_same<typename
     443             :             T::const_iterator, decltype(
     444             :             std::declval<T const&>().begin())
     445             :                 >::value &&
     446             :         std::is_same<typename
     447             :             T::const_iterator, decltype(
     448             :             std::declval<T const&>().end())
     449             :                 >::value && (
     450             :         std::is_same<const_buffer, typename
     451             :             std::remove_const<typename
     452             :                 std::iterator_traits<
     453             :                     typename T::const_iterator
     454             :                         >::value_type>::type
     455             :                 >::value ||
     456             :         std::is_same<mutable_buffer, typename
     457             :             std::remove_const<typename
     458             :                 std::iterator_traits<
     459             :                     typename T::const_iterator
     460             :                         >::value_type>::type
     461             :                 >::value)
     462             :         >::type
     463             :     > > : std::is_move_constructible<T>
     464             : {
     465             : };
     466             : 
     467             : #endif
     468             : 
     469             : /** Determine if T is a MutableBuffers.
     470             : */
     471             : #if BOOST_HTTP_PROTO_DOCS
     472             : template<class T>
     473             : struct is_mutable_buffers
     474             :     : std::integral_constant<bool, ...>{};
     475             : #else
     476             : 
     477             : template<class T, class = void>
     478             : struct is_mutable_buffers : std::false_type
     479             : {
     480             : };
     481             : 
     482             : template<class T>
     483             : struct is_mutable_buffers<T const>
     484             :     : is_mutable_buffers<typename
     485             :         std::decay<T>::type>
     486             : {
     487             : };
     488             : 
     489             : template<class T>
     490             : struct is_mutable_buffers<T const&>
     491             :     : is_mutable_buffers<typename
     492             :         std::decay<T>::type>
     493             : {
     494             : };
     495             : 
     496             : template<class T>
     497             : struct is_mutable_buffers<T&>
     498             :     : is_mutable_buffers<typename
     499             :         std::decay<T>::type>
     500             : {
     501             : };
     502             : 
     503             : template<class T>
     504             : struct is_mutable_buffers<T, boost::void_t<
     505             :     typename std::enable_if<
     506             :         detail::is_bidir_iter<typename
     507             :             T::const_iterator>::value &&
     508             :         std::is_same<typename
     509             :             T::const_iterator, decltype(
     510             :             std::declval<T const&>().begin())
     511             :                 >::value &&
     512             :         std::is_same<typename
     513             :             T::const_iterator, decltype(
     514             :             std::declval<T const&>().end())
     515             :                 >::value &&
     516             :         std::is_same<mutable_buffer, typename
     517             :             std::remove_const<typename
     518             :                 std::iterator_traits<
     519             :                     typename T::const_iterator
     520             :                         >::value_type>::type
     521             :                 >::value
     522             :         >::type
     523             :     >> : std::is_move_constructible<T>
     524             : {
     525             : };
     526             : 
     527             : #endif
     528             : 
     529             : //------------------------------------------------
     530             : 
     531             : /** Determine if T is a DynamicBuffer
     532             : */
     533             : #if BOOST_HTTP_PROTO_DOCS
     534             : template<class T>
     535             : struct is_dynamic_buffer
     536             :     : std::integral_constant<bool, ...>{};
     537             : #else
     538             : 
     539             : template<
     540             :     class T,
     541             :     class = void>
     542             : struct is_dynamic_buffer : std::false_type {};
     543             : 
     544             : template<class T>
     545             : struct is_dynamic_buffer<
     546             :     T, boost::void_t<decltype(
     547             :         std::declval<std::size_t&>() =
     548             :             std::declval<T const&>().size()
     549             :         ,std::declval<std::size_t&>() =
     550             :             std::declval<T const&>().max_size()
     551             :         ,std::declval<std::size_t&>() =
     552             :             std::declval<T const&>().capacity()
     553             :         ,std::declval<T&>().commit(
     554             :             std::declval<std::size_t>())
     555             :         ,std::declval<T&>().consume(
     556             :             std::declval<std::size_t>())
     557             :     )
     558             :     ,typename std::enable_if<
     559             :         is_const_buffers<typename
     560             :             T::const_buffers_type>::value
     561             :         && is_mutable_buffers<typename
     562             :             T::mutable_buffers_type>::value
     563             :         >::type
     564             :     ,typename std::enable_if<
     565             :         std::is_same<decltype(
     566             :             std::declval<T const&>().data()),
     567             :             typename T::const_buffers_type>::value
     568             :         && std::is_same<decltype(
     569             :             std::declval<T&>().prepare(
     570             :                 std::declval<std::size_t>())),
     571             :             typename T::mutable_buffers_type>::value
     572             :         >::type
     573             :     > > : std::true_type
     574             : {
     575             : };
     576             : 
     577             : #endif
     578             : 
     579             : //------------------------------------------------
     580             : 
     581             : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
     582             : # pragma warning (push)
     583             : # pragma warning (disable: 4521) // multiple copy constructors specified
     584             : # pragma warning (disable: 4522) // multiple assignment operators specified
     585             : #endif
     586             : 
     587             : template<bool isConst>
     588             : class buffers_pair
     589             : {
     590             : public:
     591             :     // VFALCO: This type is public otherwise
     592             :     //         asio::buffers_iterator won't compile.
     593             :     using value_type = typename
     594             :         std::conditional<isConst,
     595             :             const_buffer,
     596             :             mutable_buffer>::type;
     597             : 
     598             :     using const_iterator = value_type const*;
     599             : 
     600           0 :     buffers_pair() = default;
     601             : 
     602             : #if defined(BOOST_HTTP_PROTO_DOCS) || ( \
     603             :         ! BOOST_WORKAROUND(BOOST_MSVC, < 1910))
     604             :     buffers_pair(
     605             :         buffers_pair const& other) = default;
     606             :     buffers_pair& operator=(
     607             :         buffers_pair const& other) = default;
     608             : 
     609             : #else
     610             :     buffers_pair(
     611             :         buffers_pair const& other) noexcept
     612             :         : buffers_pair(
     613             :             *other.begin(),
     614             :             *(other.begin() + 1))
     615             :     {
     616             :     }
     617             : 
     618             :     buffers_pair&
     619             :     operator=(buffers_pair const& other)
     620             :     {
     621             :         b_[0] = other.b_[0];
     622             :         b_[1] = other.b_[1];
     623             :         return *this;
     624             :     }
     625             : #endif
     626             : 
     627             :     // const pair construction
     628             :     // from mutable mutable pair
     629             :     template<
     630             :         bool isConst_ = isConst,
     631             :         class = typename std::enable_if<
     632             :             isConst_>::type>
     633             :     buffers_pair(
     634             :         buffers_pair<false> const& other)
     635             :         : buffers_pair(
     636             :             other.b_[0],
     637             :             other.b_[1])
     638             :     {
     639             :     }
     640             : 
     641             :     // const pair assignment
     642             :     // from mutable mutable pair
     643             :     template<
     644             :         bool isConst_ = isConst,
     645             :         class = typename std::enable_if<
     646             :             isConst_>::type>
     647             :     buffers_pair&
     648             :     operator=(
     649             :         buffers_pair<false> const& other)
     650             :     {
     651             :         b_[0] = other.b_[0];
     652             :         b_[1] = other.b_[1];
     653             :         return *this;
     654             :     }
     655             : 
     656        8267 :     buffers_pair(
     657             :         value_type b0,
     658             :         value_type b1) noexcept
     659        8267 :     {
     660        8267 :         if(b0.size() > 0)
     661             :         {
     662        7877 :             b_[0] = b0;
     663        7877 :             b_[1] = b1;
     664             :         }
     665             :         else
     666             :         {
     667         390 :             b_[0] = b1;
     668             :         }
     669        8267 :     }
     670             : 
     671             :     const_buffer
     672             :     operator[](
     673             :         std::size_t i) const noexcept
     674             :     {
     675             :         BOOST_ASSERT(i < 2);
     676             :         return b_[i];
     677             :     }
     678             : 
     679             :     const_iterator
     680        8270 :     begin() const noexcept
     681             :     {
     682        8270 :         return b_;
     683             :     }
     684             : 
     685             :     const_iterator
     686        5249 :     end() const noexcept
     687             :     {
     688        5249 :         if(b_[1].size() > 0)
     689        4681 :             return &b_[2];
     690         568 :         if(b_[0].size() > 0)
     691         568 :             return &b_[1];
     692           0 :         return b_;
     693             :     }
     694             : 
     695             : private:
     696             :     value_type b_[2];
     697             : };
     698             : 
     699             : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
     700             : # pragma warning (pop)
     701             : #endif
     702             : 
     703             : /** A mutable buffers pair
     704             : */
     705             : using mutable_buffers_pair =
     706             :     buffers_pair<false>;
     707             : 
     708             : /** A const buffers pair
     709             : */
     710             : using const_buffers_pair =
     711             :     buffers_pair<true>;
     712             : 
     713             : //------------------------------------------------
     714             : 
     715             : /** Return the total octets in a buffer sequence
     716             : */
     717             : template<
     718             :     class ConstBuffers
     719             : #ifndef BOOST_HTTP_PROTO_DOCS
     720             :     , class = typename std::enable_if<
     721             :         is_const_buffers<ConstBuffers>::value
     722             :     >::type
     723             : #endif
     724             : >
     725             : std::size_t
     726          25 : buffer_size(
     727             :     ConstBuffers const& buffers) noexcept
     728             : {
     729          25 :     std::size_t n = 0;
     730          63 :     for(const_buffer b : buffers)
     731          38 :         n += b.size();
     732          25 :     return n;
     733             : }
     734             : 
     735             : //------------------------------------------------
     736             : 
     737             : /** Copy buffer contents
     738             : */
     739             : template<
     740             :     class MutableBuffers,
     741             :     class ConstBuffers>
     742             : std::size_t
     743        2754 : buffer_copy(
     744             :     MutableBuffers const& to,
     745             :     ConstBuffers const& from,
     746             :     std::size_t at_most =
     747             :         std::size_t(-1)) noexcept
     748             : {
     749             :     // If you get a compile error here it
     750             :     // means that one or both of your types
     751             :     // do not meet the requirements.
     752             :     static_assert(
     753             :         is_mutable_buffers<MutableBuffers>::value,
     754             :         "Type requirements not met");
     755             :     static_assert(
     756             :         is_const_buffers<ConstBuffers>::value,
     757             :         "Type requirements not met");
     758             : 
     759        2754 :     std::size_t total = 0;
     760        2754 :     std::size_t pos0 = 0;
     761        2754 :     std::size_t pos1 = 0;
     762        2754 :     auto const end0 = from.end();
     763        2754 :     auto const end1 = to.end();
     764        2754 :     auto it0 = from.begin();
     765        2754 :     auto it1 = to.begin();
     766        4843 :     while(
     767        5231 :         total < at_most &&
     768       12445 :         it0 != end0 &&
     769             :         it1 != end1)
     770             :     {
     771             :         const_buffer b0 =
     772        4843 :             const_buffer(*it0) + pos0;
     773             :         mutable_buffer b1 =
     774        4843 :             mutable_buffer(*it1) + pos1;
     775             :         std::size_t amount =
     776       27673 :         [&]
     777             :         {
     778        4843 :             std::size_t n = b0.size();
     779        4843 :             if( n > b1.size())
     780        1730 :                 n = b1.size();
     781        4843 :             if( n > at_most - total)
     782        1728 :                 n = at_most - total;
     783        4843 :             std::memcpy(
     784             :                 b1.data(),
     785             :                 b0.data(),
     786             :                 n);
     787        4843 :             return n;
     788        4843 :         }();
     789        4843 :         total += amount;
     790        4843 :         if(amount == b1.size())
     791             :         {
     792        1715 :             ++it1;
     793        1715 :             pos1 = 0;
     794             :         }
     795             :         else
     796             :         {
     797        3128 :             pos1 += amount;
     798             :         }
     799        4843 :         if(amount == b0.size())
     800             :         {
     801        1891 :             ++it0;
     802        1891 :             pos0 = 0;
     803             :         }
     804             :         else
     805             :         {
     806        2952 :             pos0 += amount;
     807             :         }
     808             :     }
     809        2754 :     return total;
     810             : }
     811             : 
     812             : //------------------------------------------------
     813             : 
     814             : //
     815             : // size
     816             : //
     817             : 
     818             : //
     819             : // prefix
     820             : //
     821             : 
     822             : #ifndef BOOST_HTTP_PROTO_DOCS
     823             : template<class Buffers>
     824             : void
     825             : tag_invoke(
     826             :     prefix_tag const&,
     827             :     Buffers const&,
     828             :     std::size_t) = delete;
     829             : #endif
     830             : 
     831             : /** Returns the type of a prefix of Buffers
     832             : */
     833             : #ifdef BOOST_HTTP_PROTO_DOCS
     834             : template<class Buffers>
     835             : using prefix_type = __see_below__;
     836             : #else
     837             : template<class Buffers>
     838             : using prefix_type = decltype(
     839             :     tag_invoke(
     840             :         prefix_tag{},
     841             :         std::declval<Buffers const&>(),
     842             :         std::size_t{}));
     843             : #endif
     844             : 
     845             : /** Return a prefix of the buffers.
     846             : */
     847             : template<class Buffers>
     848             : auto
     849           4 : prefix(
     850             :     Buffers const& b,
     851             :     std::size_t n) ->
     852             :         prefix_type<Buffers>
     853             : {
     854             :     static_assert(
     855             :         is_const_buffers<Buffers>::value,
     856             :         "Type requirements not met");
     857             : 
     858           8 :     return tag_invoke(
     859           4 :         prefix_tag{}, b, n);
     860             : }
     861             : 
     862             : /** Return a prefix of the buffers.
     863             : */
     864             : template<class Buffers>
     865             : auto
     866           2 : sans_suffix(
     867             :     Buffers const& b,
     868             :     std::size_t n) ->
     869             :         prefix_type<Buffers>
     870             : {
     871           2 :     auto const n0 = buffer_size(b);
     872           2 :     if( n > n0)
     873           0 :         n = n0;
     874           2 :     return prefix(b, n0 - n);
     875             : }
     876             : 
     877             : //
     878             : // suffix
     879             : //
     880             : 
     881             : #ifndef BOOST_HTTP_PROTO_DOCS
     882             : template<class Buffers>
     883             : void
     884             : tag_invoke(
     885             :     suffix_tag const&,
     886             :     Buffers const&,
     887             :     std::size_t) = delete;
     888             : #endif
     889             : 
     890             : /** Returns the type of a suffix of Buffers.
     891             : */
     892             : #ifdef BOOST_HTTP_PROTO_DOCS
     893             : template<class Buffers>
     894             : using suffix_type = __see_below__;
     895             : #else
     896             : template<class Buffers>
     897             : using suffix_type = decltype(
     898             :     tag_invoke(
     899             :         suffix_tag{},
     900             :         std::declval<Buffers const&>(),
     901             :         std::size_t{}));
     902             : #endif
     903             : 
     904             : /** Return a suffix of the buffers.
     905             : */
     906             : template<class Buffers>
     907             : auto
     908           4 : suffix(
     909             :     Buffers const& b,
     910             :     std::size_t n) ->
     911             :         suffix_type<Buffers>   
     912             : {
     913             :     static_assert(
     914             :         is_const_buffers<Buffers>::value,
     915             :         "Type requirements not met");
     916             : 
     917           8 :     return tag_invoke(
     918           4 :         suffix_tag{}, b, n);
     919             : }
     920             : 
     921             : /** Return a suffix of the buffers.
     922             : */
     923             : template<class Buffers>
     924             : auto
     925           2 : sans_prefix(
     926             :     Buffers const& b,
     927             :     std::size_t n) ->
     928             :         suffix_type<Buffers>
     929             : {
     930             :     static_assert(
     931             :         is_const_buffers<Buffers>::value,
     932             :         "Type requirements not met");
     933             : 
     934           2 :     auto const n0 = buffer_size(b);
     935           2 :     if( n > n0)
     936           0 :         n = n0;
     937           2 :     return suffix(b, n0 - n);
     938             : }
     939             : 
     940             : } // http_proto
     941             : } // boost
     942             : 
     943             : #endif

Generated by: LCOV version 1.15