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