LCOV - code coverage report
Current view: top level - http_proto - buffer.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 111 129 86.0 %
Date: 2023-01-26 23:44:13 Functions: 42 43 97.7 %

          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

Generated by: LCOV version 1.15