Line data Source code
1 : //
2 : // Copyright (c) 2022 Vinnie Falco (vinnie dot falco at gmail dot 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/beast2
8 : //
9 :
10 : #ifndef BOOST_BEAST2_SERVER_FIXED_ARRAY_HPP
11 : #define BOOST_BEAST2_SERVER_FIXED_ARRAY_HPP
12 :
13 : #include <boost/beast2/detail/config.hpp>
14 : #include <boost/core/span.hpp>
15 : #include <boost/assert.hpp>
16 : #include <cstddef>
17 : #include <cstdlib>
18 : #include <memory>
19 : #include <new>
20 : #include <stdexcept>
21 : #include <utility>
22 :
23 : template<class T>
24 : class fixed_array;
25 :
26 : /** A type-erased fixed_array
27 : */
28 : class any_fixed_array
29 : {
30 : public:
31 : /** Destructor
32 :
33 : All elements are destroyed in reverse order.
34 : */
35 : ~any_fixed_array()
36 : {
37 : if(t_)
38 : destroy_(this);
39 : }
40 :
41 : /** Constructor
42 : */
43 : any_fixed_array() = default;
44 :
45 : /** Constructor
46 :
47 : Ownership of all elements in the moved-from object is transferred.
48 : */
49 : any_fixed_array(
50 : any_fixed_array&& other) noexcept
51 : : any_fixed_array()
52 : {
53 : swap(*this, other);
54 : }
55 :
56 : /** Constructor
57 :
58 : Ownership of all elements in the moved-from object is transferred.
59 :
60 : @par Postconditions
61 : @code
62 : other.size() == 0 && other.capacity() == 0
63 : @endcode
64 : */
65 : template<class T>
66 : any_fixed_array(
67 : fixed_array<T>&& other) noexcept
68 : : t_(other.t_)
69 : , n_(other.n_)
70 : , cap_(other.cap_)
71 : , destroy_(&destroy<T>)
72 : {
73 : other.t_ = nullptr;
74 : other.n_ = 0;
75 : other.cap_ = 0;
76 : }
77 :
78 : /** Constructor
79 :
80 : Ownership of all elements in the moved-from object is transferred.
81 :
82 : @par Postconditions
83 : @code
84 : other.size() == 0 && other.capacity() == 0
85 : @endcode
86 : */
87 : any_fixed_array&
88 : operator=(
89 : any_fixed_array&& other) noexcept
90 : {
91 : any_fixed_array temp;
92 : swap(*this, temp);
93 : swap(other, *this);
94 : return *this;
95 : }
96 :
97 : /** Return the number of elements
98 : */
99 : std::size_t size() const noexcept
100 : {
101 : return n_;
102 : }
103 :
104 : /** Return a typed span of elements
105 :
106 : This function returns the span of elements contained in the array.
107 : The specified type `T` must match the type of element used
108 : to construct the array, or else the behavior is undefined.
109 :
110 : @tparam T The type of element used to construct the array.
111 : */
112 : template<class T>
113 : boost::span<T>
114 : to_span() noexcept
115 : {
116 : return { reinterpret_cast<T*>(t_), n_ };
117 : }
118 :
119 : /** Swap objects
120 : */
121 : friend void swap(
122 : any_fixed_array& a0,
123 : any_fixed_array& a1) noexcept
124 : {
125 : std::swap(a0.t_, a1.t_);
126 : std::swap(a0.n_, a1.n_);
127 : std::swap(a0.cap_, a1.cap_);
128 : std::swap(a0.destroy_, a1.destroy_);
129 : }
130 :
131 : private:
132 : template<class T>
133 : friend class fixed_array;
134 :
135 : template<class T>
136 : static void destroy(any_fixed_array* p)
137 : {
138 : fixed_array<T> v(*p);
139 : }
140 :
141 : void* t_ = nullptr;
142 : std::size_t n_ = 0;
143 : std::size_t cap_ = 0;
144 : void(*destroy_)(any_fixed_array*) = 0;
145 : };
146 :
147 : //------------------------------------------------
148 :
149 : /** An append-only array with a fixed capacity
150 :
151 : This container is used to hold elements which
152 : are all constructed at once, where the elements
153 : do not require move constructability or assignability.
154 : */
155 : template<class T>
156 : class fixed_array
157 : {
158 : public:
159 : using value_type = T;
160 : using reference = T&;
161 : using pointer = T*;
162 : using iterator = T*;
163 : using const_reference = T const&;
164 : using const_pointer = T const*;
165 : using const_iterator = T const*;
166 : using difference_type = std::ptrdiff_t;
167 : using size_type = std::size_t;
168 :
169 0 : ~fixed_array()
170 : {
171 0 : if(! t_)
172 0 : return;
173 0 : while(n_--)
174 0 : t_[n_].~T();
175 0 : std::allocator<T>{}.deallocate(t_, cap_);
176 0 : }
177 :
178 : /** Constructor
179 :
180 : The moved-from object will have zero
181 : capacity and zero size.
182 : */
183 : fixed_array(fixed_array&& other) noexcept
184 : {
185 : t_ = other.t_;
186 : n_ = other.n_;
187 : cap_ = other.cap_;
188 : other.t_ = nullptr;
189 : other.n_ = 0;
190 : other.cap_ = 0;
191 : }
192 :
193 : /** Constructor
194 :
195 : The array will have the specified capacity.
196 :
197 : @par Postconditions
198 : ```
199 : size() == 0 && capacity() == cap
200 : ```
201 : */
202 : explicit
203 0 : fixed_array(std::size_t cap)
204 0 : : t_(std::allocator<T>{}.allocate(cap))
205 0 : , n_(0)
206 0 : , cap_(cap)
207 : {
208 0 : }
209 :
210 : std::size_t
211 : capacity() const noexcept
212 : {
213 : return cap_;
214 : }
215 :
216 : std::size_t
217 0 : size() const noexcept
218 : {
219 0 : return n_;
220 : }
221 :
222 : bool
223 0 : is_full() const noexcept
224 : {
225 0 : return n_ >= cap_;
226 : }
227 :
228 : /** Return a pointer to the beginning of the array
229 : */
230 0 : T* data() noexcept
231 : {
232 0 : return t_;
233 : }
234 :
235 : /** Return a pointer to the beginning of the array
236 : */
237 : T const* data() const noexcept
238 : {
239 : return t_;
240 : }
241 :
242 : reference operator[](std::size_t i)
243 : {
244 : BOOST_ASSERT(i < n_);
245 : return t_[i];
246 : }
247 :
248 : const_reference operator[](std::size_t i) const
249 : {
250 : BOOST_ASSERT(i < n_);
251 : return t_[i];
252 : }
253 :
254 : reference at(std::size_t i)
255 : {
256 : if(i < n_)
257 : return t_[i];
258 : // VFALCO use detail::throw_out_of_range when it is available
259 : throw std::out_of_range("i >= size()");
260 : }
261 :
262 : const_reference at(std::size_t i) const
263 : {
264 : if(i < n_)
265 : return t_[i];
266 : // VFALCO use detail::throw_out_of_range when it is available
267 : throw std::out_of_range("i >= size()");
268 : }
269 :
270 : template<class... Args>
271 0 : T& emplace_back(Args&&... args)
272 : {
273 0 : if(is_full())
274 : // VFALCO use detail::throw_out_of_range when it is available
275 0 : throw std::out_of_range("full");
276 0 : auto p = t_ + n_;
277 0 : ::new(p) T(std::forward<Args>(args)...);
278 0 : ++n_;
279 0 : return *p;
280 : }
281 :
282 : const_iterator
283 : begin() const noexcept
284 : {
285 : return t_;
286 : }
287 :
288 : const_iterator
289 : end() const noexcept
290 : {
291 : return t_ + n_;
292 : }
293 :
294 : iterator
295 0 : begin() noexcept
296 : {
297 0 : return t_;
298 : }
299 :
300 : iterator
301 0 : end() noexcept
302 : {
303 0 : return t_ + n_;
304 : }
305 :
306 : private:
307 : #if 0
308 : //#if __cplusplus < 201703L // gcc nonconforming
309 : static_assert(
310 : alignof(T) <=
311 : alignof(std::max_align_t),
312 : "T must not be overaligned");
313 : //#endif
314 : #endif
315 :
316 : friend class any_fixed_array;
317 :
318 : fixed_array(
319 : any_fixed_array& v) noexcept
320 : : t_(reinterpret_cast<T*>(v.t_))
321 : , n_(v.n_)
322 : , cap_(v.cap_)
323 : {
324 : }
325 :
326 : T* t_ = nullptr;
327 : std::size_t n_;
328 : std::size_t cap_;
329 : };
330 :
331 : #endif
|