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 336 : 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&&) = default; 40 : 41 : template<class U_> 42 312 : explicit any_impl(U_&& u_) 43 312 : : u(std::move(u_)) 44 : { 45 312 : } 46 : }; 47 : 48 : struct workspace::undo 49 : { 50 : explicit 51 336 : undo(workspace& ws0) noexcept 52 336 : : ws_(ws0) 53 336 : , head_(ws0.head_) 54 : { 55 336 : } 56 : 57 336 : ~undo() 58 336 : { 59 336 : if(head_) 60 0 : ws_.head_ = head_; 61 336 : } 62 : 63 : void 64 336 : commit() noexcept 65 : { 66 336 : head_ = nullptr; 67 336 : } 68 : 69 : private: 70 : workspace& ws_; 71 : unsigned char* head_; 72 : }; 73 : 74 : template<class T> 75 : constexpr 76 : std::size_t 77 : workspace:: 78 : space_needed() 79 : { 80 : using U = typename std::decay<T>::type; 81 : 82 : static_assert( 83 : alignof(U) <= alignof(::max_align_t), 84 : "Overaligned types not supported"); 85 : 86 : return sizeof(any_impl<U>); 87 : } 88 : 89 : template<class T> 90 : auto 91 312 : workspace:: 92 : push(T&& t) -> 93 : typename std::decay<T>::type& 94 : { 95 : static_assert( 96 : alignof(T) <= alignof(::max_align_t), 97 : "Overaligned types not supported"); 98 : 99 : using U = any_impl<typename 100 : std::decay<T>::type>; 101 : 102 312 : undo u(*this); 103 312 : auto p = ::new(bump_down( 104 : sizeof(U), alignof(U))) U( 105 312 : std::forward<T>(t)); 106 312 : u.commit(); 107 312 : p->next = reinterpret_cast< 108 312 : any*>(head_); 109 312 : head_ = reinterpret_cast< 110 : unsigned char*>(p); 111 624 : return p->u; 112 : } 113 : 114 : template<class T> 115 : T* 116 24 : workspace:: 117 : push_array( 118 : std::size_t n, 119 : T const& t) 120 : { 121 : struct alignas(alignof(::max_align_t)) 122 24 : U : any 123 : { 124 : std::size_t n_ = 0; 125 : 126 : U() = default; 127 24 : ~U() 128 : { 129 70 : for(std::size_t i = n_; 130 70 : i-- > 0;) 131 46 : data()[i].~T(); 132 48 : } 133 : 134 24 : U( std::size_t n, 135 : T const& t) 136 24 : : U() 137 : { 138 70 : while(n_ < n) 139 : { 140 46 : new(&data()[n_]) T(t); 141 46 : ++n_; 142 : } 143 24 : } 144 : 145 116 : T* data() noexcept 146 : { 147 : return reinterpret_cast< 148 116 : T*>(this + 1); 149 : } 150 : }; 151 : 152 48 : undo u(*this); 153 24 : auto p = ::new(bump_down( 154 24 : sizeof(U) + n * sizeof(T), 155 : alignof(::max_align_t))) U(n, t); 156 24 : u.commit(); 157 24 : p->next = reinterpret_cast< 158 24 : any*>(head_); 159 24 : head_ = reinterpret_cast< 160 : unsigned char*>(p); 161 48 : return p->data(); 162 : } 163 : 164 : #if defined(BOOST_MSVC) 165 : #pragma warning(pop) /* C4324 */ 166 : #endif 167 : 168 : } // detail 169 : } // http_proto 170 : } // boost 171 : 172 : #endif