TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 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/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_DETAIL_BUFFER_ARRAY_HPP
11 : #define BOOST_CAPY_DETAIL_BUFFER_ARRAY_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/detail/except.hpp>
15 : #include <boost/capy/buffers.hpp>
16 :
17 : #include <cstddef>
18 : #include <new>
19 : #include <span>
20 : #include <utility>
21 :
22 : namespace boost {
23 : namespace capy {
24 : namespace detail {
25 :
26 : /** A buffer sequence holding up to N buffers.
27 :
28 : This class template stores a fixed-capacity array of buffer
29 : descriptors, where the actual count can vary from 0 to N.
30 : It provides efficient storage for small buffer sequences
31 : without dynamic allocation.
32 :
33 : @par Example
34 : @code
35 : void process(ConstBufferSequence auto const& buffers)
36 : {
37 : detail::const_buffer_array<4> bufs(buffers);
38 : // use bufs.begin(), bufs.end(), bufs.to_span()
39 : }
40 : @endcode
41 :
42 : @tparam N Maximum number of buffers the array can hold.
43 : @tparam IsConst If true, holds const_buffer; otherwise mutable_buffer.
44 : */
45 : template<std::size_t N, bool IsConst>
46 : class buffer_array
47 : {
48 : public:
49 : /** The type of buffer stored in the array.
50 : */
51 : using value_type = std::conditional_t<IsConst, const_buffer, mutable_buffer>;
52 :
53 : private:
54 : std::size_t n_ = 0;
55 : std::size_t size_ = 0;
56 : union {
57 : int dummy_;
58 : value_type arr_[N];
59 : };
60 :
61 : public:
62 : /** Construct a default instance.
63 :
64 : Constructs an empty buffer array.
65 : */
66 HIT 6 : buffer_array() noexcept
67 6 : : dummy_(0)
68 : {
69 6 : }
70 :
71 : /** Construct a copy.
72 : */
73 292 : buffer_array(buffer_array const& other) noexcept
74 292 : : n_(other.n_)
75 292 : , size_(other.size_)
76 : {
77 811 : for(std::size_t i = 0; i < n_; ++i)
78 519 : ::new(&arr_[i]) value_type(other.arr_[i]);
79 292 : }
80 :
81 : /** Construct from a single buffer.
82 :
83 : @param b The buffer to store.
84 : */
85 130 : buffer_array(value_type const& b) noexcept
86 130 : : dummy_(0)
87 : {
88 130 : if(b.size() != 0)
89 : {
90 122 : ::new(&arr_[0]) value_type(b);
91 122 : n_ = 1;
92 122 : size_ = b.size();
93 : }
94 130 : }
95 :
96 : /** Construct from a buffer sequence.
97 :
98 : Copies up to N buffer descriptors from the source
99 : sequence into the internal array. If the sequence
100 : contains more than N non-empty buffers, excess
101 : buffers are silently ignored.
102 :
103 : @param bs The buffer sequence to copy from.
104 : */
105 : template<class BS>
106 : requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>)
107 : && (!std::same_as<std::remove_cvref_t<BS>, buffer_array>)
108 : && (!std::same_as<std::remove_cvref_t<BS>, value_type>)
109 185 : buffer_array(BS const& bs) noexcept
110 185 : : dummy_(0)
111 : {
112 185 : auto it = capy::begin(bs);
113 185 : auto const last = capy::end(bs);
114 618 : while(it != last && n_ < N)
115 : {
116 433 : value_type b(*it);
117 433 : if(b.size() != 0)
118 : {
119 427 : ::new(&arr_[n_++]) value_type(b);
120 427 : size_ += b.size();
121 : }
122 433 : ++it;
123 : }
124 185 : }
125 :
126 : /** Construct from a buffer sequence with overflow checking.
127 :
128 : Copies buffer descriptors from the source sequence
129 : into the internal array.
130 :
131 : @param bs The buffer sequence to copy from.
132 :
133 : @throws std::length_error if the sequence contains
134 : more than N non-empty buffers.
135 : */
136 : template<class BS>
137 : requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>)
138 4 : buffer_array(std::in_place_t, BS const& bs)
139 4 : : dummy_(0)
140 : {
141 4 : auto it = capy::begin(bs);
142 4 : auto const last = capy::end(bs);
143 14 : while(it != last)
144 : {
145 12 : value_type b(*it);
146 12 : if(b.size() != 0)
147 : {
148 12 : if(n_ >= N)
149 2 : detail::throw_length_error();
150 10 : ::new(&arr_[n_++]) value_type(b);
151 10 : size_ += b.size();
152 : }
153 10 : ++it;
154 : }
155 2 : }
156 :
157 : /** Construct from an iterator range.
158 :
159 : Copies up to N non-empty buffer descriptors from the
160 : range `[first, last)`. If the range contains more than
161 : N non-empty buffers, excess buffers are silently ignored.
162 :
163 : @param first Iterator to the first buffer descriptor.
164 : @param last Iterator past the last buffer descriptor.
165 : */
166 : template<class Iterator>
167 8 : buffer_array(Iterator first, Iterator last) noexcept
168 8 : : dummy_(0)
169 : {
170 26 : while(first != last && n_ < N)
171 : {
172 18 : value_type b(*first);
173 18 : if(b.size() != 0)
174 : {
175 14 : ::new(&arr_[n_++]) value_type(b);
176 14 : size_ += b.size();
177 : }
178 18 : ++first;
179 : }
180 8 : }
181 :
182 : /** Construct from an iterator range with overflow checking.
183 :
184 : Copies all non-empty buffer descriptors from the range
185 : `[first, last)` into the internal array.
186 :
187 : @param first Iterator to the first buffer descriptor.
188 : @param last Iterator past the last buffer descriptor.
189 :
190 : @throws std::length_error if the range contains more
191 : than N non-empty buffers.
192 : */
193 : template<class Iterator>
194 4 : buffer_array(std::in_place_t, Iterator first, Iterator last)
195 4 : : dummy_(0)
196 : {
197 14 : while(first != last)
198 : {
199 12 : value_type b(*first);
200 12 : if(b.size() != 0)
201 : {
202 12 : if(n_ >= N)
203 2 : detail::throw_length_error();
204 10 : ::new(&arr_[n_++]) value_type(b);
205 10 : size_ += b.size();
206 : }
207 10 : ++first;
208 : }
209 2 : }
210 :
211 : /** Destructor.
212 : */
213 625 : ~buffer_array()
214 : {
215 1725 : while(n_--)
216 1100 : arr_[n_].~value_type();
217 625 : }
218 :
219 : /** Assign by copying.
220 : */
221 : buffer_array&
222 4 : operator=(buffer_array const& other) noexcept
223 : {
224 4 : if(this != &other)
225 : {
226 4 : while(n_--)
227 MIS 0 : arr_[n_].~value_type();
228 HIT 4 : n_ = other.n_;
229 4 : size_ = other.size_;
230 10 : for(std::size_t i = 0; i < n_; ++i)
231 6 : ::new(&arr_[i]) value_type(other.arr_[i]);
232 : }
233 4 : return *this;
234 : }
235 :
236 : /** Return an iterator to the beginning.
237 : */
238 : value_type*
239 130 : begin() noexcept
240 : {
241 130 : return arr_;
242 : }
243 :
244 : /** Return an iterator to the beginning.
245 : */
246 : value_type const*
247 2441 : begin() const noexcept
248 : {
249 2441 : return arr_;
250 : }
251 :
252 : /** Return an iterator to the end.
253 : */
254 : value_type*
255 129 : end() noexcept
256 : {
257 129 : return arr_ + n_;
258 : }
259 :
260 : /** Return an iterator to the end.
261 : */
262 : value_type const*
263 2441 : end() const noexcept
264 : {
265 2441 : return arr_ + n_;
266 : }
267 :
268 : /** Return a span of the buffers.
269 : */
270 : std::span<value_type>
271 379 : to_span() noexcept
272 : {
273 379 : return { arr_, n_ };
274 : }
275 :
276 : /** Return a span of the buffers.
277 : */
278 : std::span<value_type const>
279 175 : to_span() const noexcept
280 : {
281 175 : return { arr_, n_ };
282 : }
283 :
284 : /** Conversion to mutable span.
285 : */
286 1 : operator std::span<value_type>() noexcept
287 : {
288 1 : return { arr_, n_ };
289 : }
290 :
291 : /** Conversion to const span.
292 : */
293 : operator std::span<value_type const>() const noexcept
294 : {
295 : return { arr_, n_ };
296 : }
297 :
298 : /** Return the total byte count in O(1).
299 : */
300 : std::size_t
301 : byte_size() const noexcept
302 : {
303 : return size_;
304 : }
305 : };
306 :
307 : /** Alias for buffer_array holding const_buffer.
308 :
309 : @tparam N Maximum number of buffers.
310 : */
311 : template<std::size_t N>
312 : using const_buffer_array = buffer_array<N, true>;
313 :
314 : /** Alias for buffer_array holding mutable_buffer.
315 :
316 : @tparam N Maximum number of buffers.
317 : */
318 : template<std::size_t N>
319 : using mutable_buffer_array = buffer_array<N, false>;
320 :
321 : } // namespace detail
322 : } // namespace capy
323 : } // namespace boost
324 :
325 : #endif
|