Line | Branch | Exec | Source |
---|---|---|---|
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_WORKSPACE_HPP | ||
11 | #define BOOST_HTTP_PROTO_DETAIL_WORKSPACE_HPP | ||
12 | |||
13 | #include <boost/http_proto/detail/except.hpp> | ||
14 | #include <boost/assert.hpp> | ||
15 | #include <cstdlib> | ||
16 | #include <new> | ||
17 | #include <utility> | ||
18 | #include <stddef.h> // ::max_align_t | ||
19 | |||
20 | namespace boost { | ||
21 | namespace http_proto { | ||
22 | namespace detail { | ||
23 | |||
24 | class workspace | ||
25 | { | ||
26 | 76 | struct any | |
27 | { | ||
28 | any* next = nullptr; | ||
29 | |||
30 | BOOST_HTTP_PROTO_DECL | ||
31 | virtual ~any() = 0; | ||
32 | }; | ||
33 | |||
34 | template<class T> | ||
35 | struct alignas(alignof(::max_align_t)) | ||
36 | any_t : any | ||
37 | { | ||
38 | T t_; | ||
39 | |||
40 | any_t() = delete; | ||
41 | any_t(any_t&&) = default; | ||
42 | |||
43 | explicit | ||
44 | 28 | any_t( | |
45 | T&& t) | ||
46 | 28 | : t_(std::move(t)) | |
47 | { | ||
48 | 28 | } | |
49 | |||
50 | explicit | ||
51 | 6 | any_t( | |
52 | T const& t) | ||
53 | 6 | : t_(t) | |
54 | { | ||
55 | 6 | } | |
56 | }; | ||
57 | |||
58 | template<class T> | ||
59 | struct alignas(alignof(::max_align_t)) | ||
60 | any_n : any | ||
61 | { | ||
62 | std::size_t n_ = 0; | ||
63 | |||
64 | 21 | any_n() = default; | |
65 | |||
66 | 42 | ~any_n() | |
67 | { | ||
68 | 182 | for(std::size_t i = n_; | |
69 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 21 times.
|
182 | i-- > 0;) |
70 | 140 | data()[i].~T(); | |
71 | } | ||
72 | |||
73 | 21 | any_n( | |
74 | std::size_t n, | ||
75 | T const& t) | ||
76 | 21 | : any_n() | |
77 | { | ||
78 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 21 times.
|
91 | while(n_ < n) |
79 | { | ||
80 | 70 | new(&data()[n_]) T(t); | |
81 | 70 | ++n_; | |
82 | } | ||
83 | 21 | } | |
84 | |||
85 | T* | ||
86 | 161 | data() noexcept | |
87 | { | ||
88 | return | ||
89 | reinterpret_cast<T*>( | ||
90 | 161 | this + 1); | |
91 | } | ||
92 | }; | ||
93 | |||
94 | unsigned char* begin_ = nullptr; | ||
95 | unsigned char* end_ = nullptr; | ||
96 | unsigned char* head_ = nullptr; | ||
97 | |||
98 | public: | ||
99 | workspace() = default; | ||
100 | |||
101 | 15 | ~workspace() | |
102 | 15 | { | |
103 | 15 | clear(); | |
104 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | delete[] begin_; |
105 | 15 | } | |
106 | |||
107 | explicit | ||
108 | 15 | workspace( | |
109 | std::size_t n) | ||
110 | 15 | : begin_(new unsigned char[n]) | |
111 | 15 | , end_(begin_ + n) | |
112 | 15 | , head_(end_) | |
113 | { | ||
114 | 15 | } | |
115 | |||
116 | void* | ||
117 | 8 | data() noexcept | |
118 | { | ||
119 | 8 | return begin_; | |
120 | } | ||
121 | |||
122 | std::size_t | ||
123 | 35 | size() const noexcept | |
124 | { | ||
125 | 35 | return head_ - begin_; | |
126 | } | ||
127 | |||
128 | BOOST_HTTP_PROTO_DECL | ||
129 | void | ||
130 | clear() noexcept; | ||
131 | |||
132 | BOOST_HTTP_PROTO_DECL | ||
133 | void* | ||
134 | reserve(std::size_t n); | ||
135 | |||
136 | template<class T> | ||
137 | auto | ||
138 | 34 | push(T&& t) -> | |
139 | typename std::decay<T>::type& | ||
140 | { | ||
141 | |||
142 | using U = any_t<typename | ||
143 | std::decay<T>::type>; | ||
144 | 34 | auto p = ::new(bump_down( | |
145 | sizeof(U), alignof(U))) U( | ||
146 | 34 | std::forward<T>(t)); | |
147 | 34 | p->next = reinterpret_cast< | |
148 | 34 | any*>(head_); | |
149 | 34 | head_ = reinterpret_cast< | |
150 | unsigned char*>(p); | ||
151 | 34 | return p->t_; | |
152 | } | ||
153 | |||
154 | template<class T> | ||
155 | T* | ||
156 | 21 | push_array( | |
157 | std::size_t n, | ||
158 | T const& t) | ||
159 | { | ||
160 | using U = any_n<T>; | ||
161 | 21 | auto p = ::new(bump_down( | |
162 | 21 | sizeof(U) + n * sizeof(T), | |
163 | alignof(::max_align_t))) U(n, t); | ||
164 | 21 | p->next = reinterpret_cast< | |
165 | 21 | any*>(head_); | |
166 | 21 | head_ = reinterpret_cast< | |
167 | unsigned char*>(p); | ||
168 | 21 | return p->data(); | |
169 | } | ||
170 | |||
171 | private: | ||
172 | // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html | ||
173 | void* | ||
174 | 38 | bump_down( | |
175 | std::size_t size, | ||
176 | std::size_t align) | ||
177 | { | ||
178 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | BOOST_ASSERT(align > 0); |
179 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | BOOST_ASSERT( |
180 | (align & (align - 1)) == 0); | ||
181 | |||
182 | 38 | auto ip0 = reinterpret_cast< | |
183 | 38 | std::uintptr_t>(begin_); | |
184 | 38 | auto ip = reinterpret_cast< | |
185 | 38 | std::uintptr_t>(head_); | |
186 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | if(size > ip - ip0) |
187 | ✗ | detail::throw_bad_alloc(); | |
188 | 38 | ip -= size; | |
189 | 38 | ip &= ~(align - 1); | |
190 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | if(ip < ip0) |
191 | ✗ | detail::throw_bad_alloc(); | |
192 | 38 | return reinterpret_cast<void*>(ip); | |
193 | } | ||
194 | }; | ||
195 | |||
196 | } // detail | ||
197 | } // http_proto | ||
198 | } // boost | ||
199 | |||
200 | #endif | ||
201 |