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_IMPL_WORKSPACE_HPP 11 : #define BOOST_HTTP_PROTO_DETAIL_IMPL_WORKSPACE_HPP 12 : 13 : #include <boost/config.hpp> 14 : 15 : namespace boost { 16 : namespace http_proto { 17 : namespace detail { 18 : 19 : #if defined(BOOST_MSVC) 20 : #pragma warning(push) 21 : #pragma warning(disable : 4324) /* structure was padded due to __declspec(align()) */ 22 : #endif 23 : 24 346 : struct workspace::any 25 : { 26 : any* next = nullptr; 27 : 28 : BOOST_HTTP_PROTO_DECL 29 : virtual ~any() = 0; 30 : }; 31 : 32 : template<class U> 33 : struct alignas(alignof(::max_align_t)) 34 : workspace::any_impl : any 35 : { 36 : U u; 37 : 38 : any_impl() = delete; 39 : any_impl(any_impl const&) = delete; 40 : any_impl(any_impl&&) = delete; 41 : 42 : template<class... Args> 43 314 : explicit any_impl(Args&&... args) 44 314 : : u(std::forward<Args>(args)...) 45 : { 46 314 : } 47 : }; 48 : 49 : struct workspace::undo 50 : { 51 : explicit 52 346 : undo(workspace& ws0) noexcept 53 346 : : ws_(ws0) 54 346 : , head_(ws0.head_) 55 : { 56 346 : } 57 : 58 346 : ~undo() 59 346 : { 60 346 : if(head_) 61 0 : ws_.head_ = head_; 62 346 : } 63 : 64 : void 65 346 : commit() noexcept 66 : { 67 346 : head_ = nullptr; 68 346 : } 69 : 70 : private: 71 : workspace& ws_; 72 : unsigned char* head_; 73 : }; 74 : 75 : template<class T> 76 : constexpr 77 : std::size_t 78 : workspace:: 79 : space_needed() 80 : { 81 : using U = typename std::decay<T>::type; 82 : 83 : static_assert( 84 : alignof(U) <= alignof(::max_align_t), 85 : "Overaligned types not supported"); 86 : 87 : return sizeof(any_impl<U>); 88 : } 89 : 90 : template<class T, class... Args> 91 : auto 92 314 : workspace:: 93 : emplace(Args&&... args) -> 94 : typename std::decay<T>::type& 95 : { 96 : static_assert( 97 : alignof(T) <= alignof(::max_align_t), 98 : "Overaligned types not supported"); 99 : 100 : using U = any_impl<typename 101 : std::decay<T>::type>; 102 : 103 314 : undo u(*this); 104 314 : auto p = ::new(bump_down( 105 : sizeof(U), alignof(U))) U( 106 314 : std::forward<Args>(args)...); 107 314 : u.commit(); 108 314 : p->next = reinterpret_cast< 109 314 : any*>(head_); 110 314 : head_ = reinterpret_cast< 111 : unsigned char*>(p); 112 628 : return p->u; 113 : } 114 : 115 : template<class T> 116 : T* 117 32 : workspace:: 118 : push_array( 119 : std::size_t n, 120 : T const& t) 121 : { 122 : struct alignas(alignof(::max_align_t)) 123 32 : U : any 124 : { 125 : std::size_t n_ = 0; 126 : 127 : U() = default; 128 32 : ~U() 129 : { 130 102 : for(std::size_t i = n_; 131 102 : i-- > 0;) 132 70 : data()[i].~T(); 133 64 : } 134 : 135 32 : U( std::size_t n, 136 : T const& t) 137 32 : : U() 138 : { 139 102 : while(n_ < n) 140 : { 141 70 : new(&data()[n_]) T(t); 142 70 : ++n_; 143 : } 144 32 : } 145 : 146 172 : T* data() noexcept 147 : { 148 : return reinterpret_cast< 149 172 : T*>(this + 1); 150 : } 151 : }; 152 : 153 64 : undo u(*this); 154 32 : auto p = ::new(bump_down( 155 32 : sizeof(U) + n * sizeof(T), 156 : alignof(::max_align_t))) U(n, t); 157 32 : u.commit(); 158 32 : p->next = reinterpret_cast< 159 32 : any*>(head_); 160 32 : head_ = reinterpret_cast< 161 : unsigned char*>(p); 162 64 : return p->data(); 163 : } 164 : 165 : #if defined(BOOST_MSVC) 166 : #pragma warning(pop) /* C4324 */ 167 : #endif 168 : 169 : } // detail 170 : } // http_proto 171 : } // boost 172 : 173 : #endif