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 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 442 : explicit any_impl(Args&&... args)
44 442 : : u(std::forward<Args>(args)...)
45 : {
46 442 : }
47 : };
48 :
49 : struct workspace::undo
50 : {
51 : explicit
52 538 : undo(workspace& ws0) noexcept
53 538 : : ws_(ws0)
54 538 : , head_(ws0.head_)
55 : {
56 538 : }
57 :
58 538 : ~undo()
59 : {
60 538 : if(head_)
61 0 : ws_.head_ = head_;
62 538 : }
63 :
64 : void
65 538 : commit() noexcept
66 : {
67 538 : head_ = nullptr;
68 538 : }
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 442 : 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 442 : undo u(*this);
104 442 : auto prev_head = head_;
105 442 : head_ = bump_down(sizeof(U), alignof(U));
106 442 : auto p = ::new(head_) U(
107 442 : std::forward<Args>(args)...);
108 442 : u.commit();
109 442 : p->next = reinterpret_cast<
110 : any*>(prev_head);
111 442 : return p->u;
112 442 : }
113 :
114 : template<class T>
115 : T*
116 96 : 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 96 : U() = default;
127 96 : ~U()
128 : {
129 96 : for(std::size_t i = n_;
130 782 : i-- > 0;)
131 686 : data()[i].~T();
132 192 : }
133 :
134 96 : U( std::size_t n,
135 : T const& t)
136 96 : : U()
137 : {
138 782 : while(n_ < n)
139 : {
140 686 : new(&data()[n_]) T(t);
141 686 : ++n_;
142 : }
143 96 : }
144 :
145 1468 : T* data() noexcept
146 : {
147 : return reinterpret_cast<
148 1468 : T*>(this + 1);
149 : }
150 : };
151 :
152 96 : undo u(*this);
153 96 : auto prev_head = head_;
154 192 : head_ = bump_down(
155 96 : sizeof(U) + n * sizeof(T),
156 : alignof(::max_align_t));
157 96 : auto p = ::new(head_) U(n, t);
158 96 : u.commit();
159 96 : p->next = reinterpret_cast<
160 : any*>(prev_head);
161 192 : return p->data();
162 96 : }
163 :
164 : #if defined(BOOST_MSVC)
165 : #pragma warning(pop) /* C4324 */
166 : #endif
167 :
168 : } // detail
169 : } // http_proto
170 : } // boost
171 :
172 : #endif
|