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