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 : /** A contiguous buffer of storage used by algorithms. 25 : 26 : Objects of this type retain ownership of a 27 : contiguous buffer of storage allocated upon 28 : construction. This storage is divided into 29 : three regions: 30 : 31 : @li The reserved area, which starts at the 32 : beginning of the buffer and can grow 33 : upwards towards the end of the buffer. 34 : 35 : @li The acquired area, which starts at the 36 : end of the buffer and can grow downwards 37 : towards the beginning of the buffer. 38 : 39 : @li The unused area, which starts from the 40 : end of the reserved area and stretches 41 : until the beginning of the acquired area. 42 : */ 43 : class workspace 44 : { 45 37 : struct any 46 : { 47 : any* next = nullptr; 48 : 49 : BOOST_HTTP_PROTO_DECL 50 : virtual ~any() = 0; 51 : }; 52 : 53 : unsigned char* base_ = nullptr; 54 : unsigned char* begin_ = nullptr; 55 : unsigned char* head_ = nullptr; 56 : unsigned char* end_ = nullptr; 57 : 58 : public: 59 : /** Destructor. 60 : */ 61 : ~workspace(); 62 : 63 : /** Constructor. 64 : 65 : @param n The number of bytes of storage 66 : to allocate for the internal buffer. 67 : */ 68 : explicit 69 : workspace( 70 : std::size_t n); 71 : 72 : /** Constructor. 73 : */ 74 745 : workspace() = default; 75 : 76 : /** Constructor. 77 : */ 78 : workspace(workspace&&) noexcept; 79 : 80 : /** Allocate internal storage. 81 : 82 : @throws std::logic_error this->size() > 0 83 : 84 : @throws std::invalid_argument n == 0 85 : */ 86 : void 87 : allocate( 88 : std::size_t n); 89 : 90 : /** Return a pointer to the unused area. 91 : */ 92 : void* 93 7958 : data() noexcept 94 : { 95 7958 : return begin_; 96 : } 97 : 98 : /** Return the size of the unused area. 99 : */ 100 : std::size_t 101 20 : size() const noexcept 102 : { 103 20 : return head_ - begin_; 104 : } 105 : 106 : /** Clear the contents while preserving capacity. 107 : */ 108 : BOOST_HTTP_PROTO_DECL 109 : void 110 : clear() noexcept; 111 : 112 : /** Convert unused storage to reserved storage. 113 : 114 : @throws std::invalid_argument n >= this->size() 115 : */ 116 : BOOST_HTTP_PROTO_DECL 117 : void 118 : reserve(std::size_t n); 119 : 120 : template<class T> 121 : auto 122 : push(T&& t) -> 123 : typename std::decay<T>::type&; 124 : 125 : template<class T> 126 : T* 127 : push_array( 128 : std::size_t n, 129 : T const& t); 130 : 131 : private: 132 : BOOST_HTTP_PROTO_DECL 133 : void* 134 : bump_down( 135 : std::size_t size, 136 : std::size_t align); 137 : }; 138 : 139 : template<class T> 140 : auto 141 13 : workspace:: 142 : push(T&& t) -> 143 : typename std::decay<T>::type& 144 : { 145 : struct alignas(alignof(::max_align_t)) 146 : U : any 147 : { 148 : typename std::decay<T>::type v_; 149 : 150 : U() = delete; 151 : U(U&&) = default; 152 : 153 13 : explicit U(T&& t) 154 13 : : v_(std::move(t)) 155 : { 156 13 : } 157 : }; 158 : 159 13 : auto p = ::new(bump_down( 160 : sizeof(U), alignof(U))) U( 161 13 : std::forward<T>(t)); 162 13 : p->next = reinterpret_cast< 163 13 : any*>(head_); 164 13 : head_ = reinterpret_cast< 165 : unsigned char*>(p); 166 13 : return p->v_; 167 : } 168 : 169 : template<class T> 170 : T* 171 24 : workspace:: 172 : push_array( 173 : std::size_t n, 174 : T const& t) 175 : { 176 : struct alignas(alignof(::max_align_t)) 177 24 : U : any 178 : { 179 : std::size_t n_ = 0; 180 : 181 : U() = default; 182 24 : ~U() 183 : { 184 70 : for(std::size_t i = n_; 185 70 : i-- > 0;) 186 46 : data()[i].~T(); 187 48 : } 188 : 189 24 : U( std::size_t n, 190 : T const& t) 191 24 : : U() 192 : { 193 70 : while(n_ < n) 194 : { 195 46 : new(&data()[n_]) T(t); 196 46 : ++n_; 197 : } 198 24 : } 199 : 200 116 : T* data() noexcept 201 : { 202 : return reinterpret_cast< 203 116 : T*>(this + 1); 204 : } 205 : }; 206 : 207 24 : auto p = ::new(bump_down( 208 24 : sizeof(U) + n * sizeof(T), 209 : alignof(::max_align_t))) U(n, t); 210 24 : p->next = reinterpret_cast< 211 24 : any*>(head_); 212 24 : head_ = reinterpret_cast< 213 : unsigned char*>(p); 214 24 : return p->data(); 215 : } 216 : 217 : } // detail 218 : } // http_proto 219 : } // boost 220 : 221 : #endif