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 37 : struct any 27 : { 28 : any* next = nullptr; 29 : 30 : BOOST_HTTP_PROTO_DECL 31 : virtual ~any() = 0; 32 : }; 33 : 34 : unsigned char* begin_ = nullptr; 35 : unsigned char* end_; 36 : unsigned char* head_; 37 : 38 : public: 39 : ~workspace(); 40 : 41 745 : workspace() = default; 42 : workspace(workspace&&) noexcept; 43 : workspace& operator=( 44 : workspace&&) noexcept; 45 : 46 : explicit 47 : workspace( 48 : std::size_t n); 49 : 50 : void* 51 7952 : data() noexcept 52 : { 53 7952 : return begin_; 54 : } 55 : 56 : std::size_t 57 14 : size() const noexcept 58 : { 59 14 : return head_ - begin_; 60 : } 61 : 62 : BOOST_HTTP_PROTO_DECL 63 : void 64 : clear() noexcept; 65 : 66 : BOOST_HTTP_PROTO_DECL 67 : void* 68 : reserve(std::size_t n); 69 : 70 : template<class T> 71 : auto 72 : push(T&& t) -> 73 : typename std::decay<T>::type&; 74 : 75 : template<class T> 76 : T* 77 : push_array( 78 : std::size_t n, 79 : T const& t); 80 : 81 : private: 82 : BOOST_HTTP_PROTO_DECL 83 : void* 84 : bump_down( 85 : std::size_t size, 86 : std::size_t align); 87 : }; 88 : 89 : template<class T> 90 : auto 91 13 : workspace:: 92 : push(T&& t) -> 93 : typename std::decay<T>::type& 94 : { 95 : struct alignas(alignof(::max_align_t)) 96 : U : any 97 : { 98 : typename std::decay<T>::type v_; 99 : 100 : U() = delete; 101 : U(U&&) = default; 102 : 103 13 : explicit U(T&& t) 104 13 : : v_(std::move(t)) 105 : { 106 13 : } 107 : }; 108 : 109 13 : auto p = ::new(bump_down( 110 : sizeof(U), alignof(U))) U( 111 13 : std::forward<T>(t)); 112 13 : p->next = reinterpret_cast< 113 13 : any*>(head_); 114 13 : head_ = reinterpret_cast< 115 : unsigned char*>(p); 116 13 : return p->v_; 117 : } 118 : 119 : template<class T> 120 : T* 121 24 : workspace:: 122 : push_array( 123 : std::size_t n, 124 : T const& t) 125 : { 126 : struct alignas(alignof(::max_align_t)) 127 24 : U : any 128 : { 129 : std::size_t n_ = 0; 130 : 131 : U() = default; 132 24 : ~U() 133 : { 134 70 : for(std::size_t i = n_; 135 70 : i-- > 0;) 136 46 : data()[i].~T(); 137 48 : } 138 : 139 24 : U( std::size_t n, 140 : T const& t) 141 24 : : U() 142 : { 143 70 : while(n_ < n) 144 : { 145 46 : new(&data()[n_]) T(t); 146 46 : ++n_; 147 : } 148 24 : } 149 : 150 116 : T* data() noexcept 151 : { 152 : return reinterpret_cast< 153 116 : T*>(this + 1); 154 : } 155 : }; 156 : 157 24 : auto p = ::new(bump_down( 158 24 : sizeof(U) + n * sizeof(T), 159 : alignof(::max_align_t))) U(n, t); 160 24 : p->next = reinterpret_cast< 161 24 : any*>(head_); 162 24 : head_ = reinterpret_cast< 163 : unsigned char*>(p); 164 24 : return p->data(); 165 : } 166 : 167 : } // detail 168 : } // http_proto 169 : } // boost 170 : 171 : #endif