AUI Framework  master
Cross-platform module-based framework for developing C++20 desktop applications
ASmallVector.h
1/*
2 * AUI Framework - Declarative UI toolkit for modern C++20
3 * Copyright (C) 2020-2024 Alex2772 and Contributors
4 *
5 * SPDX-License-Identifier: MPL-2.0
6 *
7 * This Source Code Form is subject to the terms of the Mozilla Public
8 * License, v. 2.0. If a copy of the MPL was not distributed with this
9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 */
11
12#pragma once
13
14#include <cstddef>
15#include <functional>
16
17#include "ADynamicVector.h"
18#include "AStaticVector.h"
19#include "AUI/Traits/concepts.h"
20
33template<typename StoredType, std::size_t StaticVectorSize, typename Allocator = std::allocator<StoredType>>
35protected:
36 using self = ASmallVector;
37 using super = self;
40
41public:
42 using iterator = StoredType*;
43 using const_iterator = const StoredType*;
44 using reference = StoredType&;
45 using const_reference = const StoredType&;
46 using value = StoredType;
47
48 ASmallVector() noexcept {
49 new (&mBase.inplace) StaticVector();
50 }
51
52 ASmallVector(ASmallVector&& rhs) noexcept {
53 if (rhs.isInplaceAllocated()) {
54 new (&mBase.inplace) StaticVector(*rhs.inplace());
55 } else {
56 new (&mBase.dynamic) DynamicVector(*rhs.dynamic());
57 }
58
59 new (&rhs.mBase.inplace) StaticVector();
60 }
61
62 ~ASmallVector() noexcept {
63 deallocate();
64 }
65
66 [[nodiscard]]
67 constexpr StoredType* data() noexcept {
68 return reinterpret_cast<StoredType*>(mBase.common.begin);
69 }
70 [[nodiscard]]
71 constexpr const StoredType* data() const noexcept {
72 return reinterpret_cast<const StoredType*>(mBase.common.begin);
73 }
74
75 [[nodiscard]]
76 constexpr iterator begin() noexcept {
77 return mBase.common.begin;
78 }
79 [[nodiscard]]
80 constexpr const_iterator begin() const noexcept {
81 return mBase.common.begin;
82 }
83
84 [[nodiscard]]
85 constexpr iterator end() noexcept {
86 return mBase.common.end;
87 }
88
89 [[nodiscard]]
90 constexpr const_iterator end() const noexcept {
91 return mBase.common.end;
92 }
93
94 [[nodiscard]]
95 constexpr StoredType& front() noexcept {
96 return *begin();
97 }
98
99 [[nodiscard]]
100 constexpr StoredType& back() noexcept {
101 return *(begin() + (size() - 1));
102 }
103
104 [[nodiscard]]
105 constexpr const StoredType& front() const noexcept {
106 return *begin();
107 }
108
109 [[nodiscard]]
110 constexpr const StoredType& back() const noexcept {
111 return *(begin() + (size() - 1));
112 }
113
114 constexpr void push_back(StoredType value) noexcept {
115 insert(end(), std::move(value));
116 }
117
118 constexpr void push_front(StoredType value) noexcept {
119 insert(begin(), std::move(value));
120 }
121
122 constexpr void pop_back() noexcept {
123 AUI_ASSERTX(size() > 0, "ASmallVector is empty");
124 erase(std::prev(end()));
125 }
126 constexpr void pop_front() noexcept {
127 AUI_ASSERTX(size() > 0, "ASmallVector is empty");
128 erase(begin());
129 }
130
131 [[nodiscard]]
132 constexpr StoredType& operator[](std::size_t index) noexcept {
133 AUI_ASSERTX(index < size(), "out of bounds");
134 return *(data() + index);
135 }
136
137 [[nodiscard]]
138 constexpr StoredType& operator[](std::size_t index) const noexcept {
139 return const_cast<ASmallVector*>(this)->operator[](index);
140 }
141
142 [[nodiscard]]
143 constexpr bool empty() const noexcept {
144 return begin() == end();
145 }
146
147 constexpr void clear() noexcept {
148 deallocate();
149 new (&mBase.inplace) StaticVector();
150 }
151
155 [[nodiscard]]
156 std::size_t size() const noexcept {
157 return std::distance(begin(), end());
158 }
159
160
161 [[nodiscard]]
162 bool isInplaceAllocated() const noexcept {
163 return size() <= StaticVectorSize;
164 }
165
166
167 template<typename OtherIterator>
168 constexpr iterator insert(iterator at, OtherIterator begin, OtherIterator end) {
169 AUI_ASSERT_MY_ITERATOR(at);
170 auto distance = std::distance(begin, end);
171
172 if (distance + size() <= StaticVectorSize) {
173 return inplace()->insert(at, begin, end);
174 }
175 if (!isInplaceAllocated()) {
176 return dynamic()->insert(at, begin, end);
177 }
178
179 // switch from static to dynamic
180 DynamicVector temp;
181 temp.reserve(aui::container::vector_impl::ceilPower2(distance + size()));
182
183 aui::container::vector_impl::insert_no_growth(temp.mEnd, temp.mEnd,
184 std::make_move_iterator(this->begin()), std::make_move_iterator(at));
185
186 auto result = aui::container::vector_impl::insert_no_growth(temp.mEnd, temp.mEnd,
187 begin, end);
188
189 aui::container::vector_impl::insert_no_growth(temp.mEnd, temp.mEnd,
190 std::make_move_iterator(at), std::make_move_iterator(this->end()));
191
192 inplace()->~StaticVector();
193 new (&mBase.dynamic) DynamicVector(std::move(temp));
194
195 return result;
196 }
197
198 constexpr iterator erase(iterator begin, iterator end) noexcept {
199 AUI_ASSERT_MY_ITERATOR(begin);
200 AUI_ASSERT_MY_ITERATOR(end);
201
202 if (isInplaceAllocated()) {
203 return inplace()->erase(begin, end);
204 }
205
206 if (size() - std::distance(begin, end) > StaticVectorSize) {
207 return dynamic()->erase(begin, end);
208 }
209
210 auto index = std::distance(this->begin(), begin);
211
212 // switch from dynamic to static
213 auto temp = std::move(*dynamic());
214 temp.erase(begin, end);
215 new (inplace()) StaticVector();
216 inplace()->insert(inplace()->end(), std::make_move_iterator(temp.begin()), std::make_move_iterator(temp.end()));
217 return this->begin() + index;
218 }
219
220 constexpr iterator insert(iterator at, StoredType value) {
221 AUI_ASSERT_MY_ITERATOR(at);
222 return insert(at, std::make_move_iterator(&value), std::make_move_iterator(&value + 1));
223 }
224
225 constexpr iterator erase(iterator at) {
226 return erase(at, std::next(at));
227 }
228
229
230 // AUI extensions - see AVector for reference
231
232
239 template<typename OtherContainer>
240 iterator insertAll(const OtherContainer& c) noexcept {
241 return insertAll(super::end(), c);
242 }
243
244
251 template<typename OtherContainer>
252 iterator insertAll(OtherContainer&& c) noexcept {
253 return insertAll(super::end(), std::forward<OtherContainer>(c));
254 }
255
256
264 template<typename OtherContainer>
265 iterator insertAll(iterator at, const OtherContainer& c) noexcept {
266 return super::insert(at, c.begin(), c.end());
267 }
268
269
277 template<typename OtherContainer>
278 iterator insertAll(iterator at, OtherContainer&& c) noexcept {
279 return super::insert(at, std::make_move_iterator(c.begin()), std::make_move_iterator(c.end()));
280 }
281
282
287 void removeAll(const StoredType& item) noexcept
288 {
289 aui::container::remove_all(*this, item);
290 }
291
298 template<typename T, aui::mapper<const StoredType&, const T&> Projection>
299 void removeAll(const T& item, Projection projection) noexcept
300 {
301 aui::container::remove_all(*this, item, projection);
302 }
303
308 void removeFirst(const StoredType& item) noexcept
309 {
310 aui::container::remove_first(*this, item);
311 }
312
313
317 template<typename OtherContainer>
318 bool isSubsetOf(const OtherContainer& c) const noexcept
319 {
320 return aui::container::is_subset(*this, c);
321 }
322
326 bool contains(const StoredType& value) const noexcept {
327 return aui::container::contains(*this, value);
328 }
329
330 [[nodiscard]]
331 std::size_t sizeInBytes() const noexcept {
332 return super::size() * sizeof(StoredType);
333 }
334
335 [[nodiscard]]
336 StoredType& at(std::size_t index) {
337 if (index >= super::size()) {
338 aui::impl::outOfBoundsException();
339 }
340 return super::operator[](index);
341 }
342
343 [[nodiscard]]
344 const StoredType& at(std::size_t index) const {
345 if (index >= super::size()) {
346 aui::impl::outOfBoundsException();
347 }
348 return super::operator[](index);
349 }
350
351
357 self& operator<<(const StoredType& rhs) noexcept
358 {
359 super::push_back(rhs);
360 return *this;
361 }
362
368 self& operator<<(StoredType&& rhs) noexcept
369 {
370 super::push_back(std::forward<StoredType>(rhs));
371 return *this;
372 }
373
379 template<typename OtherContainer, std::enable_if_t<!std::is_convertible_v<OtherContainer, StoredType>, bool> = true>
380 self& operator<<(const OtherContainer& c) noexcept
381 {
382 insertAll(c);
383 return *this;
384 }
385
391 template<typename OtherContainer, std::enable_if_t<!std::is_convertible_v<OtherContainer, StoredType>, bool> = true>
392 self& operator<<(OtherContainer&& c) noexcept
393 {
394 insertAll(std::forward<OtherContainer>(c));
395 return *this;
396 }
397
398
406 StoredType& first() noexcept
407 {
408 AUI_ASSERTX(!super::empty(), "empty container could not have the first element");
409 return super::front();
410 }
411
419 const StoredType& first() const noexcept
420 {
421 AUI_ASSERTX(!super::empty(), "empty container could not have the first element");
422 return super::front();
423 }
424
432 StoredType& last() noexcept
433 {
434 AUI_ASSERTX(!super::empty(), "empty container could not have the last element");
435 return super::back();
436 }
437
445 const StoredType& last() const noexcept
446 {
447 AUI_ASSERTX(!super::empty(), "empty container could not have the last element");
448 return super::back();
449 }
450
455 [[nodiscard]]
456 size_t indexOf(const StoredType& value) const noexcept
457 {
458 return aui::container::index_of(*this, value);
459 }
460
461
462 void sort() noexcept {
463 std::sort(super::begin(), super::end());
464 }
465
466 template<typename Comparator>
467 void sort(Comparator&& comparator) noexcept {
468 std::sort(super::begin(), super::end(), std::forward<Comparator>(comparator));
469 }
470
476 template<aui::predicate<StoredType> Predicate>
477 StoredType* findIf(Predicate&& predicate) noexcept
478 {
479 if (auto i = std::find_if(super::begin(), super::end(), std::forward<Predicate>(predicate)); i != super::end()) {
480 return &*i;
481 }
482 return nullptr;
483 }
484
492 template<typename T, aui::mapper<const StoredType&, const T&> Projection>
493 StoredType* findIf(const T& value, Projection&& projection) noexcept
494 {
495 if (auto i = std::find_if(super::begin(),
496 super::end(),
497 [&](const StoredType& s) { return value == std::invoke(projection, s); }
498 ); i != super::end()) {
499 return &*i;
500 }
501 return nullptr;
502 }
503
512 void removeAt(size_t index) noexcept
513 {
514 aui::container::remove_at(*this, index);
515 }
516
521 template<typename Predicate>
522 void removeIf(Predicate&& predicate) noexcept
523 {
524 super::erase(std::remove_if(super::begin(), super::end(), std::forward<Predicate>(predicate)), super::end());
525 }
526
527 ASet<StoredType> toSet() const noexcept {
528 return ASet<StoredType>(super::begin(), super::end());
529 }
530
537 template<aui::incrementable Iterator, aui::invocable<decltype(*std::declval<Iterator>())> UnaryOperation>
538 static auto fromRange(aui::range<Iterator> range, UnaryOperation&& transformer) -> AVector<decltype(transformer(range.first()))> {
539 AVector<decltype(transformer(range.first()))> result;
540 result.reserve(range.size());
541 std::transform(range.begin(), range.end(), std::back_inserter(result), std::forward<UnaryOperation>(transformer));
542 return result;
543 }
544
545 template<aui::invocable<const StoredType&> UnaryOperation>
546 auto map(UnaryOperation&& transformer) const -> AVector<decltype(transformer(std::declval<StoredType>()))> {
548 result.reserve(super::size());
549 std::transform(super::begin(), super::end(), std::back_inserter(result), std::forward<UnaryOperation>(transformer));
550 return result;
551 }
552
553 template<aui::invocable<const StoredType&> UnaryOperation>
554 [[nodiscard]]
555 auto toMap(UnaryOperation&& transformer) const -> AMap<decltype(transformer(std::declval<StoredType>()).first),
556 decltype(transformer(std::declval<StoredType>()).second)> {
557 return aui::container::to_map(super::begin(), super::end(), transformer);
558 }
559
560 template<aui::invocable<StoredType&> UnaryOperation>
561 [[nodiscard]]
562 auto toMap(UnaryOperation&& transformer) -> AMap<decltype(transformer(std::declval<StoredType>()).first),
563 decltype(transformer(std::declval<StoredType>()).second)> {
564 return aui::container::to_map(super::begin(), super::end(), transformer);
565 }
566
567 template<aui::predicate<const StoredType&> Predicate>
568 self filter(Predicate&& predicate) {
569 self result;
570 for (const auto& element : *this) {
571 if (predicate(element)) {
572 result.push_back(element);
573 }
574 }
575 return result;
576 }
577
578
579private:
580 union {
581 struct {
582 StoredType* begin;
583 StoredType* end;
584 } common;
585
586 std::aligned_storage_t<sizeof(StaticVector), alignof(StaticVector)> inplace;
587 std::aligned_storage_t<sizeof(DynamicVector), alignof(DynamicVector)> dynamic;
588 } mBase;
589
590
591 StaticVector* inplace() {
592 AUI_ASSERT(isInplaceAllocated());
593 return reinterpret_cast<StaticVector*>(&mBase.inplace);
594 }
595
596 DynamicVector * dynamic() {
597 AUI_ASSERT(!isInplaceAllocated());
598 return reinterpret_cast<DynamicVector*>(&mBase.dynamic);
599 }
600
601 void deallocate() {
602 if (isInplaceAllocated()) {
603 inplace()->~StaticVector();
604 } else {
605 dynamic()->~DynamicVector();
606 }
607 }
608};
Vector implementation for ASmallVector.
Definition: ADynamicVector.h:36
A std::map with AUI extensions.
Definition: AMap.h:218
A std::set with AUI extensions.
Definition: ASet.h:25
Vector-like container consisting of few elements on stack and switches to dynamic allocation vector i...
Definition: ASmallVector.h:34
self & operator<<(const OtherContainer &c) noexcept
Definition: ASmallVector.h:380
size_t indexOf(const StoredType &value) const noexcept
Definition: ASmallVector.h:456
void removeAt(size_t index) noexcept
Definition: ASmallVector.h:512
StoredType * findIf(const T &value, Projection &&projection) noexcept
Finds element by value.
Definition: ASmallVector.h:493
StoredType & last() noexcept
Definition: ASmallVector.h:432
void removeFirst(const StoredType &item) noexcept
Definition: ASmallVector.h:308
bool contains(const StoredType &value) const noexcept
Definition: ASmallVector.h:326
std::size_t size() const noexcept
Definition: ASmallVector.h:156
iterator insertAll(iterator at, OtherContainer &&c) noexcept
Definition: ASmallVector.h:278
const StoredType & last() const noexcept
Definition: ASmallVector.h:445
void removeAll(const StoredType &item) noexcept
Definition: ASmallVector.h:287
self & operator<<(const StoredType &rhs) noexcept
Definition: ASmallVector.h:357
void removeIf(Predicate &&predicate) noexcept
Definition: ASmallVector.h:522
StoredType * findIf(Predicate &&predicate) noexcept
Finds element by predicate.
Definition: ASmallVector.h:477
self & operator<<(StoredType &&rhs) noexcept
Definition: ASmallVector.h:368
iterator insertAll(const OtherContainer &c) noexcept
Definition: ASmallVector.h:240
iterator insertAll(iterator at, const OtherContainer &c) noexcept
Definition: ASmallVector.h:265
static auto fromRange(aui::range< Iterator > range, UnaryOperation &&transformer) -> AVector< decltype(transformer(range.first()))>
Constructs a new vector of transformed items of the range.
Definition: ASmallVector.h:538
const StoredType & first() const noexcept
Definition: ASmallVector.h:419
iterator insertAll(OtherContainer &&c) noexcept
Definition: ASmallVector.h:252
bool isSubsetOf(const OtherContainer &c) const noexcept
Definition: ASmallVector.h:318
StoredType & first() noexcept
Definition: ASmallVector.h:406
self & operator<<(OtherContainer &&c) noexcept
Definition: ASmallVector.h:392
void removeAll(const T &item, Projection projection) noexcept
Definition: ASmallVector.h:299
Vector-like container up to maxSize elements inplace.
Definition: AStaticVector.h:33
A std::vector with AUI extensions.
Definition: AVector.h:38
Definition: DynamicVectorTest.cpp:16
Definition: StaticVectorTest.cpp:16
bool is_subset(LContainer &l, RContainer &r) noexcept
Definition: containers.h:233
bool contains(const Container &c, const typename Container::const_reference value) noexcept
Definition: containers.h:153
AOptional< std::size_t > remove_first(Container &container, typename Container::const_reference value) noexcept
Removes first occurrence of value.
Definition: containers.h:200
auto to_map(Iterator begin, Iterator end, UnaryOperation &&transformer)
Transforms sequence to map.
Definition: AMap.h:237
size_t index_of(const Container &c, const typename Container::const_reference value) noexcept
Finds the index of the first occurrence of the value.
Definition: containers.h:141
void remove_at(Container &c, size_t index) noexcept
Removes element at the specified index.
Definition: containers.h:128
void remove_all(Container &container, typename Container::const_reference value) noexcept
Removes all occurrences of value.
Definition: containers.h:172
#define AUI_ASSERT(condition)
Asserts that the passed condition evaluates to true.
Definition: Assert.h:55
#define AUI_ASSERTX(condition, what)
Asserts that the passed condition evaluates to true. Adds extra message string.
Definition: Assert.h:74
Definition: Empty.h:19
Definition: iterators.h:50