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