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

Generated by: LCOV version 1.15