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 : struct BOOST_HTTP_PROTO_DECL workspace::any
25 : {
26 : any* next = nullptr;
27 :
28 : virtual ~any() = 0;
29 : };
30 :
31 : template<class U>
32 : struct alignas(alignof(::max_align_t))
33 : workspace::any_impl : any
34 : {
35 : U u;
36 :
37 : any_impl() = default;
38 : any_impl(any_impl const&) = delete;
39 : any_impl(any_impl&&) = delete;
40 :
41 : template<class... Args>
42 314 : explicit any_impl(Args&&... args)
43 314 : : u(std::forward<Args>(args)...)
44 : {
45 314 : }
46 : };
47 :
48 : struct workspace::undo
49 : {
50 : explicit
51 347 : undo(workspace& ws0) noexcept
52 347 : : ws_(ws0)
53 347 : , head_(ws0.head_)
54 : {
55 347 : }
56 :
57 347 : ~undo()
58 : {
59 347 : if(head_)
60 0 : ws_.head_ = head_;
61 347 : }
62 :
63 : void
64 347 : commit() noexcept
65 : {
66 347 : head_ = nullptr;
67 347 : }
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, class... Args>
90 : auto
91 314 : workspace::
92 : emplace(Args&&... args) ->
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 314 : undo u(*this);
103 314 : auto p = ::new(bump_down(
104 : sizeof(U), alignof(U))) U(
105 314 : std::forward<Args>(args)...);
106 314 : u.commit();
107 314 : p->next = reinterpret_cast<
108 314 : any*>(head_);
109 314 : head_ = reinterpret_cast<
110 : unsigned char*>(p);
111 314 : return p->u;
112 314 : }
113 :
114 : template<class T>
115 : T*
116 33 : workspace::
117 : push_array(
118 : std::size_t n,
119 : T const& t)
120 : {
121 : struct alignas(alignof(::max_align_t))
122 : U : any
123 : {
124 : std::size_t n_ = 0;
125 :
126 33 : U() = default;
127 33 : ~U()
128 : {
129 33 : for(std::size_t i = n_;
130 106 : i-- > 0;)
131 73 : data()[i].~T();
132 66 : }
133 :
134 33 : U( std::size_t n,
135 : T const& t)
136 33 : : U()
137 : {
138 106 : while(n_ < n)
139 : {
140 73 : new(&data()[n_]) T(t);
141 73 : ++n_;
142 : }
143 33 : }
144 :
145 179 : T* data() noexcept
146 : {
147 : return reinterpret_cast<
148 179 : T*>(this + 1);
149 : }
150 : };
151 :
152 33 : undo u(*this);
153 33 : auto p = ::new(bump_down(
154 33 : sizeof(U) + n * sizeof(T),
155 : alignof(::max_align_t))) U(n, t);
156 33 : u.commit();
157 33 : p->next = reinterpret_cast<
158 33 : any*>(head_);
159 33 : head_ = reinterpret_cast<
160 : unsigned char*>(p);
161 66 : return p->data();
162 33 : }
163 :
164 : #if defined(BOOST_MSVC)
165 : #pragma warning(pop) /* C4324 */
166 : #endif
167 :
168 : } // detail
169 : } // http_proto
170 : } // boost
171 :
172 : #endif
|