LCOV - code coverage report
Current view: top level - http_proto - buffer.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 137 154 89.0 %
Date: 2023-01-15 07:18:31 Functions: 57 57 100.0 %

          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         711 :     mutable_buffer() = default;
     130             :     mutable_buffer(
     131             :         mutable_buffer const&) = default;
     132             :     mutable_buffer& operator=(
     133             :         mutable_buffer const&) = default;
     134             : 
     135       12727 :     mutable_buffer(
     136             :         void* data,
     137             :         std::size_t size) noexcept
     138       12727 :         : p_(data)
     139       12727 :         , n_(size)
     140             :     {
     141       12727 :     }
     142             : 
     143             :     template<
     144             :         class MutableBuffer
     145             : #ifndef BOOST_HTTP_PROTO_DOCS
     146             :         ,class = typename std::enable_if<
     147             :             is_mutable_buffer<MutableBuffer
     148             :                 >::value>::type
     149             : #endif
     150             :     >
     151           2 :     mutable_buffer(
     152             :         MutableBuffer const& b) noexcept
     153             :         : p_(b.data())
     154           2 :         , n_(b.size())
     155             :     {
     156           2 :     }
     157             : 
     158             :     void*
     159       12288 :     data() const noexcept
     160             :     {
     161       12288 :         return p_;
     162             :     }
     163             : 
     164             :     std::size_t
     165       28616 :     size() const noexcept
     166             :     {
     167       28616 :         return n_;
     168             :     }
     169             : 
     170             :     mutable_buffer&
     171           2 :     operator+=(std::size_t n) noexcept
     172             :     {
     173           2 :         if(n >= n_)
     174             :         {
     175           0 :             p_ = static_cast<
     176           0 :                 char*>(p_) + n_;
     177           0 :             n_ = 0;
     178           0 :             return *this;
     179             :         }
     180           2 :         p_ = static_cast<
     181           2 :             char*>(p_) + n;
     182           2 :         n_ -= n;
     183           2 :         return *this;
     184             :     }
     185             : 
     186             :     friend
     187             :     mutable_buffer
     188        4647 :     operator+(
     189             :         mutable_buffer const& b,
     190             :         std::size_t n) noexcept
     191             :     {
     192        4647 :         if(n < b.size())
     193             :             return {
     194             :                 static_cast<char*>(
     195        4647 :                     b.data()) + n,
     196        4647 :                 b.size() - n };
     197             :         return {
     198             :             static_cast<char*>(
     199           0 :                 b.data()) + b.size(),
     200           0 :             0 };
     201             :     }
     202             : 
     203             :     friend
     204             :     mutable_buffer
     205           1 :     operator+(
     206             :         std::size_t n,
     207             :         mutable_buffer const& b) noexcept
     208             :     {
     209           1 :         if(n < b.size())
     210             :             return {
     211             :                 static_cast<char*>(
     212           1 :                     b.data()) + n,
     213           1 :                 b.size() - n };
     214             :         return {
     215             :             static_cast<char*>(
     216           0 :                 b.data()) + b.size(),
     217           0 :             0 };
     218             :     }
     219             : };
     220             : 
     221             : //------------------------------------------------
     222             : 
     223             : class const_buffer
     224             : {
     225             :     void const* p_ = nullptr;
     226             :     std::size_t n_ = 0;
     227             : 
     228             : public:
     229          30 :     const_buffer() = default;
     230             :     const_buffer(
     231             :         const_buffer const&) = default;
     232             :     const_buffer& operator=(
     233             :         const_buffer const&) = default;
     234             : 
     235        9775 :     const_buffer(
     236             :         void const* data,
     237             :         std::size_t size) noexcept
     238        9775 :         : p_(data)
     239        9775 :         , n_(size)
     240             :     {
     241        9775 :     }
     242             : 
     243             :     template<
     244             :         class ConstBuffer
     245             : #ifndef BOOST_HTTP_PROTO_DOCS
     246             :         ,class = typename std::enable_if<
     247             :             is_const_buffer<ConstBuffer
     248             :                 >::value>::type
     249             : #endif
     250             :     >
     251          21 :     const_buffer(
     252             :         ConstBuffer const& b) noexcept
     253             :         : p_(b.data())
     254          21 :         , n_(b.size())
     255             :     {
     256          21 :     }
     257             : 
     258             :     void const*
     259        9306 :     data() const noexcept
     260             :     {
     261        9306 :         return p_;
     262             :     }
     263             : 
     264             :     std::size_t
     265       23956 :     size() const noexcept
     266             :     {
     267       23956 :         return n_;
     268             :     }
     269             : 
     270             :     const_buffer&
     271           2 :     operator+=(std::size_t n) noexcept
     272             :     {
     273           2 :         if(n >= n_)
     274             :         {
     275           0 :             p_ = static_cast<
     276           0 :                 char const*>(p_) + n_;
     277           0 :             n_ = 0;
     278           0 :             return *this;
     279             :         }
     280           2 :         p_ = static_cast<
     281           2 :             char const*>(p_) + n;
     282           2 :         n_ -= n;
     283           2 :         return *this;
     284             :     }
     285             : 
     286             :     friend
     287             :     const_buffer
     288        4647 :     operator+(
     289             :         const_buffer const& b,
     290             :         std::size_t n) noexcept
     291             :     {
     292        4647 :         if(n < b.size())
     293             :             return {
     294             :                 static_cast<char const*>(
     295        4647 :                     b.data()) + n,
     296        4647 :                 b.size() - n };
     297             :         return {
     298             :             static_cast<char const*>(
     299           0 :                 b.data()) + b.size(),
     300           0 :             0 };
     301             :     }
     302             : 
     303             :     friend
     304             :     const_buffer
     305           1 :     operator+(
     306             :         std::size_t n,
     307             :         const_buffer const& b) noexcept
     308             :     {
     309           1 :         if(n < b.size())
     310             :             return {
     311             :                 static_cast<char const*>(
     312           1 :                     b.data()) + n,
     313           1 :                 b.size() - n };
     314             :         return {
     315             :             static_cast<char const*>(
     316           0 :                 b.data()) + b.size(),
     317           0 :             0 };
     318             :     }
     319             : };
     320             : 
     321             : //------------------------------------------------
     322             : 
     323             : /** A MutableBuffer of length 1
     324             : */
     325             : class mutable_buffers_1
     326             : {
     327             :     mutable_buffer mb_;
     328             : 
     329             : public:
     330             :     using value_type =
     331             :         mutable_buffer;
     332             : 
     333             :     using const_iterator =
     334             :         mutable_buffer const*;
     335             : 
     336           2 :     mutable_buffers_1() = default;
     337             : 
     338             :     explicit
     339          15 :     mutable_buffers_1(
     340             :         mutable_buffer mb) noexcept
     341          15 :         : mb_(mb)
     342             :     {
     343          15 :     }
     344             : 
     345             :     mutable_buffers_1&
     346             :     operator=(
     347             :         mutable_buffers_1 const&) = default;
     348             : 
     349             :     const_iterator
     350          21 :     begin() const noexcept
     351             :     {
     352          21 :         return &mb_;
     353             :     }
     354             : 
     355             :     const_iterator
     356          21 :     end() const noexcept
     357             :     {
     358          21 :         return &mb_ + 1;
     359             :     }
     360             : };
     361             : 
     362             : /** A ConstBuffer of length 1
     363             : */
     364             : class const_buffers_1
     365             : {
     366             :     const_buffer cb_;
     367             : 
     368             : public:
     369             :     using value_type =
     370             :         const_buffer;
     371             : 
     372             :     using const_iterator =
     373             :         const_buffer const*;
     374             : 
     375           2 :     const_buffers_1() = default;
     376             : 
     377             :     explicit
     378          15 :     const_buffers_1(
     379             :         const_buffer cb) noexcept
     380          15 :         : cb_(cb)
     381             :     {
     382          15 :     }
     383             : 
     384             :     const_buffers_1&
     385             :     operator=(const_buffers_1 const&) = default;
     386             : 
     387             :     const_iterator
     388          21 :     begin() const noexcept
     389             :     {
     390          21 :         return &cb_;
     391             :     }
     392             : 
     393             :     const_iterator
     394          21 :     end() const noexcept
     395             :     {
     396          21 :         return &cb_ + 1;
     397             :     }
     398             : };
     399             : 
     400             : //------------------------------------------------
     401             : 
     402             : template<
     403             :     class ConstBuffer
     404             : #ifndef BOOST_HTTP_PROTO_DOCS
     405             :     ,class = typename std::enable_if<
     406             :         is_const_buffer<
     407             :             ConstBuffer>::value &&
     408             :         ! is_mutable_buffer<
     409             :             ConstBuffer>::value
     410             :                 >::type
     411             : #endif
     412             : >
     413             : auto
     414          15 : make_buffers(
     415             :     ConstBuffer const& b) ->
     416             :         const_buffers_1
     417             : {
     418             :     return const_buffers_1(
     419          15 :         const_buffer(b));
     420             : }
     421             : 
     422             : template<
     423             :     class MutableBuffer
     424             : #ifndef BOOST_HTTP_PROTO_DOCS
     425             :     ,class = typename std::enable_if<
     426             :         is_mutable_buffer<
     427             :             MutableBuffer>::value
     428             :                 >::type
     429             : #endif
     430             : >
     431             : auto
     432          15 : make_buffers(
     433             :     MutableBuffer const& b) ->
     434             :         mutable_buffers_1
     435             : {
     436             :     return mutable_buffers_1(
     437          15 :         mutable_buffer(b));
     438             : }
     439             : 
     440             : template<
     441             :     class Buffers
     442             : #ifndef BOOST_HTTP_PROTO_DOCS
     443             :     ,class = typename std::enable_if<
     444             :         ! is_const_buffer<
     445             :             Buffers>::value &&
     446             :         is_const_buffers<
     447             :             Buffers>::value
     448             :                 >::type
     449             : #endif
     450             : >
     451             : auto
     452        5118 : make_buffers(
     453             :     Buffers&& b) ->
     454             :         Buffers&&
     455             : {
     456             :     return std::forward<
     457        5118 :         Buffers>(b);
     458             : }
     459             : 
     460             : //------------------------------------------------
     461             : 
     462             : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
     463             : # pragma warning (push)
     464             : # pragma warning (disable: 4521) // multiple copy constructors specified
     465             : # pragma warning (disable: 4522) // multiple assignment operators specified
     466             : #endif
     467             : 
     468             : template<bool isConst>
     469             : class buffers_pair
     470             : {
     471             : public:
     472             :     // VFALCO: This type is public otherwise
     473             :     //         asio::buffers_iterator won't compile.
     474             :     using value_type = typename
     475             :         std::conditional<isConst,
     476             :             const_buffer,
     477             :             mutable_buffer>::type;
     478             : 
     479             :     using const_iterator = value_type const*;
     480             : 
     481             :     buffers_pair() = default;
     482             : 
     483             : #if defined(BOOST_HTTP_PROTO_DOCS) || ( \
     484             :         ! BOOST_WORKAROUND(BOOST_MSVC, < 1910))
     485             :     buffers_pair(
     486             :         buffers_pair const& other) = default;
     487             :     buffers_pair& operator=(
     488             :         buffers_pair const& other) = default;
     489             : 
     490             : #else
     491             :     buffers_pair(
     492             :         buffers_pair const& other)
     493             :         : buffers_pair(
     494             :             *other.begin(),
     495             :             *(other.begin() + 1))
     496             :     {
     497             :     }
     498             : 
     499             :     buffers_pair&
     500             :     operator=(buffers_pair const& other)
     501             :     {
     502             :         b_[0] = other.b_[0];
     503             :         b_[1] = other.b_[1];
     504             :         return *this;
     505             :     }
     506             : #endif
     507             : 
     508             :     // const pair construction
     509             :     // from mutable mutable pair
     510             :     template<
     511             :         bool isConst_ = isConst,
     512             :         class = typename std::enable_if<
     513             :             isConst_>::type>
     514             :     buffers_pair(
     515             :         buffers_pair<false> const& other)
     516             :         : buffers_pair(
     517             :             other.b_[0],
     518             :             other.b_[1])
     519             :     {
     520             :     }
     521             : 
     522             :     // const pair assignment
     523             :     // from mutable mutable pair
     524             :     template<
     525             :         bool isConst_ = isConst,
     526             :         class = typename std::enable_if<
     527             :             isConst_>::type>
     528             :     buffers_pair&
     529             :     operator=(
     530             :         buffers_pair<false> const& other)
     531             :     {
     532             :         b_[0] = other.b_[0];
     533             :         b_[1] = other.b_[1];
     534             :         return *this;
     535             :     }
     536             : 
     537        5086 :     buffers_pair(
     538             :         value_type b0,
     539             :         value_type b1) noexcept
     540        5086 :     {
     541        5086 :         if(b0.size() > 0)
     542             :         {
     543        4696 :             b_[0] = b0;
     544        4696 :             b_[1] = b1;
     545             :         }
     546             :         else
     547             :         {
     548         390 :             b_[0] = b1;
     549             :         }
     550        5086 :     }
     551             : 
     552             :     const_buffer
     553           8 :     operator[](
     554             :         std::size_t i) const noexcept
     555             :     {
     556           8 :         BOOST_ASSERT(i < 2);
     557           8 :         return b_[i];
     558             :     }
     559             : 
     560             :     const_iterator
     561        5089 :     begin() const noexcept
     562             :     {
     563        5089 :         return b_;
     564             :     }
     565             : 
     566             :     const_iterator
     567        5089 :     end() const noexcept
     568             :     {
     569        5089 :         if(b_[1].size() > 0)
     570        4681 :             return &b_[2];
     571         408 :         if(b_[0].size() > 0)
     572         408 :             return &b_[1];
     573           0 :         return b_;
     574             :     }
     575             : 
     576             : private:
     577             :     value_type b_[2];
     578             : };
     579             : 
     580             : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
     581             : # pragma warning (pop)
     582             : #endif
     583             : 
     584             : /** A mutable buffers pair
     585             : */
     586             : using mutable_buffers_pair =
     587             :     buffers_pair<false>;
     588             : 
     589             : /** A const buffers pair
     590             : */
     591             : using const_buffers_pair =
     592             :     buffers_pair<true>;
     593             : 
     594             : //------------------------------------------------
     595             : 
     596             : /** Return the total octets in a buffer sequence
     597             : */
     598             : template<
     599             :     class ConstBuffers
     600             : #ifndef BOOST_HTTP_PROTO_DOCS
     601             :     , class = typename std::enable_if<
     602             :         is_const_buffers<ConstBuffers>::value
     603             :     >::type
     604             : #endif
     605             : >
     606             : std::size_t
     607          20 : buffer_size(
     608             :     ConstBuffers const& buffers) noexcept
     609             : {
     610          20 :     std::size_t n = 0;
     611          50 :     for(const_buffer b
     612          20 :             : make_buffers(buffers))
     613          30 :         n += b.size();
     614          20 :     return n;
     615             : }
     616             : 
     617             : //------------------------------------------------
     618             : 
     619             : /** Copy buffer contents
     620             : */
     621             : template<
     622             :     class MutableBuffers,
     623             :     class ConstBuffers>
     624             : std::size_t
     625        2557 : buffer_copy(
     626             :     MutableBuffers const& to,
     627             :     ConstBuffers const& from,
     628             :     std::size_t at_most =
     629             :         std::size_t(-1)) noexcept
     630             : {
     631             :     // If you get a compile error here it
     632             :     // means that one or both of your types
     633             :     // do not meet the requirements.
     634             :     static_assert(
     635             :         is_mutable_buffers<MutableBuffers>::value &&
     636             :         is_const_buffers<ConstBuffers>::value,
     637             :         "Type requirements not met");
     638             : 
     639        2557 :     std::size_t total = 0;
     640        2557 :     std::size_t pos0 = 0;
     641        2557 :     std::size_t pos1 = 0;
     642        2557 :     auto const& bs0 = (make_buffers)(from);
     643        2557 :     auto const& bs1 = (make_buffers)(to);
     644        2557 :     auto const end0 = bs0.end();
     645        2557 :     auto const end1 = bs1.end();
     646        2557 :     auto it0 = bs0.begin();
     647        2557 :     auto it1 = bs1.begin();
     648        4646 :     while(
     649        4837 :         total < at_most &&
     650       11850 :         it0 != end0 &&
     651             :         it1 != end1)
     652             :     {
     653             :         const_buffer b0 =
     654        4646 :             const_buffer(*it0) + pos0;
     655             :         mutable_buffer b1 =
     656        4646 :             mutable_buffer(*it1) + pos1;
     657             :         std::size_t amount =
     658       26688 :         [&]
     659             :         {
     660        4646 :             std::size_t n = b0.size();
     661        4646 :             if( n > b1.size())
     662        1730 :                 n = b1.size();
     663        4646 :             if( n > at_most - total)
     664        1728 :                 n = at_most - total;
     665        4646 :             std::memcpy(
     666             :                 b1.data(),
     667             :                 b0.data(),
     668             :                 n);
     669        4646 :             return n;
     670        4646 :         }();
     671        4646 :         total += amount;
     672        4646 :         if(amount == b1.size())
     673             :         {
     674        1682 :             ++it1;
     675        1682 :             pos1 = 0;
     676             :         }
     677             :         else
     678             :         {
     679        2964 :             pos1 += amount;
     680             :         }
     681        4646 :         if(amount == b0.size())
     682             :         {
     683        1694 :             ++it0;
     684        1694 :             pos0 = 0;
     685             :         }
     686             :         else
     687             :         {
     688        2952 :             pos0 += amount;
     689             :         }
     690             :     }
     691        2557 :     return total;
     692             : }
     693             : 
     694             : //------------------------------------------------
     695             : 
     696             : // VFALCO GARBAGE
     697             : class mutable_buffers
     698             : {
     699             :     mutable_buffer const* p_ = nullptr;
     700             :     std::size_t n_ = 0;
     701             : 
     702             : public:
     703             :     using value_type = mutable_buffer;
     704             : 
     705             :     using iterator = value_type const*;
     706             : 
     707             :     mutable_buffers() = default;
     708             : 
     709             :     mutable_buffers(
     710             :         mutable_buffers const&) = default;
     711             : 
     712             :     mutable_buffers& operator=(
     713             :         mutable_buffers const&) = default;
     714             : 
     715        2969 :     mutable_buffers(
     716             :         value_type const* p,
     717             :         std::size_t n) noexcept
     718        2969 :         : p_(p)
     719        2969 :         , n_(n)
     720             :     {
     721        2969 :     }
     722             : 
     723             :     std::size_t
     724             :     size() const noexcept
     725             :     {
     726             :         return n_;
     727             :     }
     728             : 
     729             :     iterator
     730        2969 :     begin() const noexcept
     731             :     {
     732        2969 :         return p_;
     733             :     }
     734             : 
     735             :     iterator
     736             :     end() const noexcept
     737             :     {
     738             :         return p_ + n_;
     739             :     }
     740             : };
     741             : 
     742             : } // http_proto
     743             : } // boost
     744             : 
     745             : #endif

Generated by: LCOV version 1.15