LibSWOC++ 1.5.14
Solid Wall of C++
Loading...
Searching...
No Matches
Vectray.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Apache Software Foundation 2019
8
9#pragma once
10
11#include <array>
12#include <vector>
13#include <variant>
14#include <new>
15#include <cstddef>
16
17#include <swoc/MemSpan.h>
18#include <swoc/swoc_meta.h>
19
20namespace swoc { inline namespace SWOC_VERSION_NS {
21
36template <typename T, size_t N, class A = std::allocator<T>> class Vectray {
37 using self_type = Vectray;
38 using vector_type = std::vector<T, A>;
39
40public: // STL compliance types.
41 using value_type = T;
42 using reference = std::remove_reference<T> &;
43 using const_reference = std::remove_reference<T> const &;
44 using pointer = std::remove_reference<T> *;
45 using const_pointer = std::remove_reference<T> const *;
46 using allocator_type = A;
47 using size_type = typename vector_type::size_type;
48 using difference_type = typename vector_type::difference_type;
51 // Need to add reverse iterators - @c reverse_iterator and @c const_reverse_iterator
52
54 struct FixedStore {
55 std::array<std::byte, sizeof(T) * N> _raw;
56 size_t _count = 0;
58
59 FixedStore() = default;
60
65 explicit FixedStore(allocator_type const &a) : _a(a) {}
66
68
71
73 T *data();
74
76 T const *data() const;
77 };
78
79 using DynamicStore = vector_type;
80
85
86public:
88 Vectray();
91 ~Vectray() = default;
92
94 constexpr explicit Vectray(allocator_type const &a) : _store(std::in_place_type_t<FixedStore>{}, a) {}
95
101 explicit Vectray(size_type n, allocator_type const &alloc = allocator_type{});
102
104 template <size_t M> Vectray(Vectray<T, M, A> &&that);
105
107 Vectray(self_type &&that, allocator_type const &a);
108
110 size_type size() const;
111
113 T *data();
114
116 T const *data() const;
117
119 bool empty() const;
120
122 operator span() { return this->items(); }
124 operator const_span() const { return this->items(); }
125
131 T &operator[](size_type idx);
132
138 T const &operator[](size_type idx) const;
139
141 T const &
142 front() const {
143 return (*this)[0];
144 }
145
147 T &
149 return (*this)[0];
150 }
151
153 T const &
154 back() const {
155 return (*this)[this->size() - 1];
156 }
157
159 T &
161 return (*this)[this->size() - 1];
162 }
163
168 self_type &push_back(T const &t);
169
175 self_type &push_back(T &&t);
176
183 template <typename... Args> self_type &emplace_back(Args &&...args);
184
189 self_type &pop_back();
190
192 const_iterator begin() const;
193
195 const_iterator end() const;
196
198 iterator begin();
199
201 iterator end();
202
204 void reserve(size_type n);
205
206protected:
209 std::variant<FixedStore, DynamicStore> _store;
210
211 static constexpr auto FIXED = 0;
212 static constexpr auto DYNAMIC = 1;
213
215 span items();
217 const_span items() const;
218
220 static constexpr size_type BASE_DYNAMIC_SIZE = (7 * N) / 5;
221
229};
230
231// --- Implementation ---
232
233template <typename T, size_t N, typename A> Vectray<T, N, A>::Vectray() {}
234
235template <typename T, size_t N, class A> Vectray<T, N, A>::Vectray(Vectray::size_type n, allocator_type const &) : Vectray() {
236 this->reserve(n);
237 while (n-- > 0) {
238 this->emplace_back();
239 }
240}
241
242template <typename T, size_t N, class A> template <size_t M> Vectray<T, N, A>::Vectray(Vectray<T, M, A> &&that) {
243 // If @a that is already a vector, always move that here.
244 if (DYNAMIC == that._store.index()) {
245 _store = std::move(std::get<DYNAMIC>(that._store));
246 } else {
247 auto span = std::get<FIXED>(that._store).span();
248 if (span.size() > N) {
249 } else {
250 for (auto &&item : span) {
251 this->template emplace_back<T, N, A>(std::move(item));
252 }
253 }
254 }
255}
256
257template <typename T, size_t N, class A> Vectray<T, N, A>::FixedStore::~FixedStore() {
258 for (auto &item : this->span()) {
259 std::destroy_at(std::addressof(item));
260 }
261}
262
263template <typename T, size_t N, class A>
266 return MemSpan<std::byte>(_raw).template rebind<T>();
267}
268
269template <typename T, size_t N, class A>
270T *
272 return reinterpret_cast<T *>(_raw.data());
273}
274
275template <typename T, size_t N, class A>
276T const *
278 return reinterpret_cast<T *>(_raw.data());
279}
280
281template <typename T, size_t N, typename A>
282T &
284 return this->items()[idx];
285}
286
287template <typename T, size_t N, typename A>
288T const &
290 return this->items()[idx];
291}
292
293template <typename T, size_t N, typename A>
294auto
295Vectray<T, N, A>::push_back(const T &t) -> self_type & {
296 std::visit(swoc::meta::vary{[&](FixedStore &fs) -> void {
297 if (fs._count < N) {
298 new (reinterpret_cast<T *>(fs._raw.data()) + fs._count++) T(t); // A::traits ?
299 } else {
300 this->transfer();
301 std::get<DYNAMIC>(_store).push_back(t);
302 }
303 },
304 [&](DynamicStore &ds) -> void { ds.push_back(t); }},
305 _store);
306 return *this;
307}
308
309template <typename T, size_t N, typename A>
310auto
311Vectray<T, N, A>::push_back(T &&t) -> self_type & {
312 std::visit(swoc::meta::vary{[&](FixedStore &fs) -> void {
313 if (fs._count < N) {
314 new (reinterpret_cast<T *>(fs._raw.data()) + fs._count++) T(std::move(t)); // A::traits ?
315 } else {
316 this->transfer();
317 std::get<DYNAMIC>(_store).push_back(std::move(t));
318 }
319 },
320 [&](DynamicStore &ds) -> void { ds.push_back(std::move(t)); }},
321 _store);
322 return *this;
323}
324
325template <typename T, size_t N, class A>
326template <typename... Args>
327typename Vectray<T, N, A>::self_type &
329 if (_store.index() == FIXED) {
330 auto &fs{std::get<FIXED>(_store)};
331 if (fs._count < N) {
332 new (reinterpret_cast<T *>(fs._raw.data()) + fs._count++) T(std::forward<Args>(args)...); // A::traits ?
333 return *this;
334 }
335 this->transfer(); // transfer to dynamic and fall through to add item.
336 }
337 std::get<DYNAMIC>(_store).emplace_back(std::forward<Args>(args)...);
338 return *this;
339}
340
341template <typename T, size_t N, class A>
342auto
344 std::visit(swoc::meta::vary{[&](FixedStore &fs) -> void { std::destroy_at(fs.span()[--fs._count]); },
345 [&](DynamicStore &ds) -> void { ds.pop_back(); }},
346 _store);
347 return *this;
348}
349
350template <typename T, size_t N, typename A>
351auto
353 return std::visit(
354 swoc::meta::vary{[](FixedStore const &fs) { return fs._count; }, [](DynamicStore const &ds) { return ds.size(); }}, _store);
355}
356
357template <typename T, size_t N, typename A>
358bool
360 return std::visit(
361 swoc::meta::vary{[](FixedStore const &fs) { return fs._count == 0; }, [](DynamicStore const &ds) { return ds.empty(); }},
362 _store);
363}
364
365// --- iterators
366template <typename T, size_t N, typename A>
367auto
369 return this->items().begin();
370}
371
372template <typename T, size_t N, typename A>
373auto
375 return this->items().end();
376}
377
378template <typename T, size_t N, typename A>
379auto
381 return this->items().begin();
382}
383
384template <typename T, size_t N, typename A>
385auto
387 return this->items().end();
388}
389// --- iterators
390
391template <typename T, size_t N, class A>
392void
394 DynamicStore tmp{std::get<FIXED>(_store)._a};
395 tmp.reserve(rN);
396
397 for (auto &&item : this->items()) {
398 tmp.emplace_back(std::move(item)); // move if supported, copy if not.
399 }
400 // Fixed elements destroyed here, by variant.
401 _store = std::move(tmp);
402}
403
404template <typename T, size_t N, class A>
405auto
407 return std::visit(swoc::meta::vary{[](FixedStore const &fs) { fs.span(); },
408 [](DynamicStore const &ds) { return const_span(ds.data(), ds.size()); }},
409 _store);
410}
411
412template <typename T, size_t N, class A>
413T *
415 return std::visit(swoc::meta::vary{[](FixedStore const &fs) { fs.data(); }, [](DynamicStore const &ds) { return ds.data(); }},
416 _store);
417}
418
419template <typename T, size_t N, class A>
420T const *
422 return std::visit(swoc::meta::vary{[](FixedStore const &fs) { fs.data(); }, [](DynamicStore const &ds) { return ds.data(); }},
423 _store);
424}
425
426template <typename T, size_t N, class A>
427auto
429 return std::visit(
430 swoc::meta::vary{[](FixedStore &fs) { return fs.span(); }, [](DynamicStore &ds) { return span(ds.data(), ds.size()); }},
431 _store);
432}
433
434template <typename T, size_t N, class A>
435void
437 if (DYNAMIC == _store.index()) {
438 std::get<DYNAMIC>(_store).reserve(n);
439 } else if (n > N) {
440 this->transfer(n);
441 }
442}
443
444}} // namespace swoc::SWOC_VERSION_NS
T * iterator
Iterator.
Definition MemSpan.h:59
constexpr T * begin() const
Pointer to the first element in the span.
Definition MemSpan.h:1148
constexpr T * end() const
Pointer to first element not in the span.
Definition MemSpan.h:1166
span items()
Get the span of the valid items.
Definition Vectray.h:428
static constexpr auto DYNAMIC
Variant index for dynamic storage.
Definition Vectray.h:212
typename swoc::MemSpan< const T >::iterator const_iterator
Constant element iteration.
Definition Vectray.h:50
void reserve(size_type n)
Force at internal storage to hold at least n items.
Definition Vectray.h:436
std::remove_reference< T > const * const_pointer
Pointer to constant element.
Definition Vectray.h:45
std::remove_reference< T > & reference
Reference to element.
Definition Vectray.h:42
Vectray(self_type &&that, allocator_type const &a)
Move constructor.
typename swoc::MemSpan< T >::iterator iterator
Element iteration.
Definition Vectray.h:49
constexpr Vectray(allocator_type const &a)
Construct empty instance with allocator.
Definition Vectray.h:94
std::remove_reference< T > * pointer
Pointer to element.
Definition Vectray.h:44
const_iterator end() const
Iterator past last element.
Definition Vectray.h:374
static constexpr auto FIXED
Variant index for fixed storage.
Definition Vectray.h:211
Vectray()
Default constructor, construct an empty container.
Definition Vectray.h:233
T const & back() const
Definition Vectray.h:154
T & front()
Definition Vectray.h:148
bool empty() const
Definition Vectray.h:359
self_type & emplace_back(Args &&...args)
Definition Vectray.h:328
std::variant< FixedStore, DynamicStore > _store
Definition Vectray.h:209
void transfer(size_type rN=BASE_DYNAMIC_SIZE)
Definition Vectray.h:393
A allocator_type
Dynamic storage allocator.
Definition Vectray.h:46
~Vectray()=default
self_type & push_back(T const &t)
Definition Vectray.h:295
self_type & pop_back()
Definition Vectray.h:343
typename vector_type::size_type size_type
Type for element count.
Definition Vectray.h:47
static constexpr size_type BASE_DYNAMIC_SIZE
Default size to reserve in the vector when switching to dynamic.
Definition Vectray.h:220
swoc::MemSpan< T > span
Element access.
Definition Vectray.h:82
T & operator[](size_type idx)
Definition Vectray.h:283
const_iterator begin() const
Iterator for first element.
Definition Vectray.h:368
T value_type
Element type for container.
Definition Vectray.h:41
size_type size() const
Definition Vectray.h:352
T const & front() const
Definition Vectray.h:142
vector_type DynamicStore
Dynamic (heap) storage.
Definition Vectray.h:79
std::remove_reference< T > const & const_reference
Reference to constant element.
Definition Vectray.h:43
typename vector_type::difference_type difference_type
Iterator difference.
Definition Vectray.h:48
swoc::MemSpan< T const > const_span
Constant element access.
Definition Vectray.h:84
STL namespace.
For template deduction guides.
Definition ArenaWriter.cc:9
MemSpan(std::array< T, N > &) -> MemSpan< T >
Deduction guides.
Internal (fixed) storage.
Definition Vectray.h:54
size_t _count
Number of valid elements.
Definition Vectray.h:56
allocator_type _a
Allocator instance - used for construction.
Definition Vectray.h:57
MemSpan< T > span()
Definition Vectray.h:265
FixedStore(allocator_type const &a)
Definition Vectray.h:65
FixedStore()=default
Default construct - empty.
std::array< std::byte, sizeof(T) *N > _raw
Raw memory for element storage.
Definition Vectray.h:55