LCOV - code coverage report
Current view: top level - http_proto/detail - workspace.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 61 63 96.8 %
Date: 2023-01-15 07:18:31 Functions: 25 27 92.6 %

          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_DETAIL_WORKSPACE_HPP
      11             : #define BOOST_HTTP_PROTO_DETAIL_WORKSPACE_HPP
      12             : 
      13             : #include <boost/http_proto/detail/except.hpp>
      14             : #include <boost/assert.hpp>
      15             : #include <cstdlib>
      16             : #include <new>
      17             : #include <utility>
      18             : #include <stddef.h> // ::max_align_t
      19             : 
      20             : namespace boost {
      21             : namespace http_proto {
      22             : namespace detail {
      23             : 
      24             : class workspace
      25             : {
      26          38 :     struct any
      27             :     {
      28             :         any* next = nullptr;
      29             : 
      30             :         BOOST_HTTP_PROTO_DECL
      31             :         virtual ~any() = 0;
      32             :     };
      33             : 
      34             :     template<class T>
      35             :     struct alignas(alignof(::max_align_t))
      36             :         any_t : any
      37             :     {
      38             :         T t_;
      39             : 
      40             :         any_t() = delete;
      41             :         any_t(any_t&&) = default;
      42             : 
      43             :         explicit
      44          14 :         any_t(
      45             :             T&& t)
      46          14 :             : t_(std::move(t))
      47             :         {
      48          14 :         }
      49             : 
      50             :         explicit
      51           3 :         any_t(
      52             :             T const& t)
      53           3 :             : t_(t)
      54             :         {
      55           3 :         }
      56             :     };
      57             : 
      58             :     template<class T>
      59             :     struct alignas(alignof(::max_align_t))
      60             :         any_n : any
      61             :     {
      62             :         std::size_t n_ = 0;
      63             : 
      64          21 :         any_n() = default;
      65             : 
      66          21 :         ~any_n()
      67             :         {
      68          91 :             for(std::size_t i = n_;
      69          91 :                     i-- > 0;)
      70          70 :                 data()[i].~T();
      71          42 :         }
      72             : 
      73          21 :         any_n(
      74             :             std::size_t n,
      75             :             T const& t)
      76          21 :             : any_n()
      77             :         {
      78          91 :             while(n_ < n)
      79             :             {
      80          70 :                 new(&data()[n_]) T(t);
      81          70 :                 ++n_;
      82             :             }
      83          21 :         }
      84             : 
      85             :         T*
      86         161 :         data() noexcept
      87             :         {
      88             :             return
      89             :                 reinterpret_cast<T*>(
      90         161 :                     this + 1);
      91             :         }
      92             :     };
      93             : 
      94             :     unsigned char* begin_ = nullptr;
      95             :     unsigned char* end_ = nullptr;
      96             :     unsigned char* head_ = nullptr;
      97             : 
      98             : public:
      99             :     workspace() = default;
     100             : 
     101          15 :     ~workspace()
     102          15 :     {
     103          15 :         clear();
     104          15 :         delete[] begin_;
     105          15 :     }
     106             : 
     107             :     explicit
     108          15 :     workspace(
     109             :         std::size_t n)
     110          15 :         : begin_(new unsigned char[n])
     111          15 :         , end_(begin_ + n)
     112          15 :         , head_(end_)
     113             :     {
     114          15 :     }
     115             : 
     116             :     void*
     117           8 :     data() noexcept
     118             :     {
     119           8 :         return begin_;
     120             :     }
     121             : 
     122             :     std::size_t
     123          35 :     size() const noexcept
     124             :     {
     125          35 :         return head_ - begin_;
     126             :     }
     127             : 
     128             :     BOOST_HTTP_PROTO_DECL
     129             :     void
     130             :     clear() noexcept;
     131             : 
     132             :     BOOST_HTTP_PROTO_DECL
     133             :     void*
     134             :     reserve(std::size_t n);
     135             : 
     136             :     template<class T>
     137             :     auto
     138          17 :     push(T&& t) ->
     139             :         typename std::decay<T>::type&
     140             :     {
     141             : 
     142             :         using U = any_t<typename
     143             :             std::decay<T>::type>;
     144          17 :         auto p = ::new(bump_down(
     145             :             sizeof(U), alignof(U))) U(
     146          17 :                 std::forward<T>(t));
     147          17 :         p->next = reinterpret_cast<
     148          17 :             any*>(head_);
     149          17 :         head_ = reinterpret_cast<
     150             :             unsigned char*>(p);
     151          17 :         return p->t_;
     152             :     }
     153             : 
     154             :     template<class T>
     155             :     T*
     156          21 :     push_array(
     157             :         std::size_t n,
     158             :         T const& t)
     159             :     {
     160             :         using U = any_n<T>;
     161          21 :         auto p = ::new(bump_down(
     162          21 :             sizeof(U) + n * sizeof(T),
     163             :                 alignof(::max_align_t))) U(n, t);
     164          21 :         p->next = reinterpret_cast<
     165          21 :             any*>(head_);
     166          21 :         head_ = reinterpret_cast<
     167             :             unsigned char*>(p);
     168          21 :         return p->data();
     169             :     }
     170             : 
     171             : private:
     172             :     // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html
     173             :     void*
     174          38 :     bump_down(
     175             :         std::size_t size,
     176             :         std::size_t align)
     177             :     {
     178          38 :         BOOST_ASSERT(align > 0);
     179          38 :         BOOST_ASSERT(
     180             :             (align & (align - 1)) == 0);
     181             : 
     182          38 :         auto ip0 = reinterpret_cast<
     183          38 :             std::uintptr_t>(begin_);
     184          38 :         auto ip = reinterpret_cast<
     185          38 :             std::uintptr_t>(head_);
     186          38 :         if(size > ip - ip0)
     187           0 :             detail::throw_bad_alloc();
     188          38 :         ip -= size;
     189          38 :         ip &= ~(align - 1);
     190          38 :         if(ip < ip0)
     191           0 :             detail::throw_bad_alloc();
     192          38 :         return reinterpret_cast<void*>(ip);
     193             :     }
     194             : };
     195             : 
     196             : } // detail
     197             : } // http_proto
     198             : } // boost
     199             : 
     200             : #endif

Generated by: LCOV version 1.15