AUI Framework  master
Cross-platform module-based framework for developing C++20 desktop applications
ADynamicVector.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 <utility>
15#include <cmath>
16
17#include <glm/glm.hpp>
18#include <glm/gtc/integer.hpp>
19
20#include "AVector.h"
21#include "AException.h"
22
23
24#define AUI_ASSERT_MY_ITERATOR(it) AUI_ASSERTX((this->begin() <= it && it <= this->end()), "foreign iterator")
25
35template<typename StoredType>
37public:
38 using self = ADynamicVector;
39 using super = ADynamicVector;
40 using iterator = StoredType*;
41 using const_iterator = const StoredType*;
42 using reference = StoredType&;
43 using const_reference = const StoredType&;
44 using value = StoredType;
45
46 constexpr ADynamicVector() noexcept {}
47 constexpr ADynamicVector(const ADynamicVector& rhs): ADynamicVector() {
48 insert(mBegin, rhs.begin(), rhs.end());
49 }
50 constexpr ADynamicVector(ADynamicVector&& rhs) noexcept: ADynamicVector() {
51 operator=(std::move(rhs));
52 }
53 constexpr ~ADynamicVector() {
54 deallocate();
55 }
56
57 [[nodiscard]]
58 constexpr StoredType* data() noexcept {
59 return mBegin;
60 }
61 [[nodiscard]]
62 constexpr const StoredType* data() const noexcept {
63 return mBegin;
64 }
65
66 [[nodiscard]]
67 constexpr iterator begin() noexcept {
68 return mBegin;
69 }
70 [[nodiscard]]
71 constexpr const_iterator begin() const noexcept {
72 return mBegin;
73 }
74
75 [[nodiscard]]
76 constexpr iterator end() noexcept {
77 return mEnd;
78 }
79
80 [[nodiscard]]
81 constexpr const_iterator end() const noexcept {
82 return mEnd;
83 }
84
85 [[nodiscard]]
86 constexpr StoredType& front() noexcept {
87 return *begin();
88 }
89
90 [[nodiscard]]
91 constexpr StoredType& back() noexcept {
92 return *std::prev(end());
93 }
94
95 [[nodiscard]]
96 constexpr const StoredType& front() const noexcept {
97 return *begin();
98 }
99
100 [[nodiscard]]
101 constexpr const StoredType& back() const noexcept {
102 return *std::prev(end());
103 }
104
105 constexpr void push_back(StoredType value) noexcept {
106 insert(end(), std::move(value));
107 }
108
109 constexpr void push_front(StoredType value) noexcept {
110 insert(begin(), std::move(value));
111 }
112
113 constexpr void pop_back() noexcept {
114 AUI_ASSERTX(size() > 0, "ADynamicVector is empty");
115 erase(std::prev(end()));
116 }
117 constexpr void pop_front() noexcept {
118 AUI_ASSERTX(size() > 0, "ADynamicVector is empty");
119 erase(begin());
120 }
121
122 [[nodiscard]]
123 constexpr StoredType& operator[](std::size_t index) noexcept {
124 AUI_ASSERTX(index < size(), "out of bounds");
125 return *(data() + index);
126 }
127
128 [[nodiscard]]
129 constexpr StoredType& operator[](std::size_t index) const noexcept {
130 return const_cast<ADynamicVector*>(this)->operator[](index);
131 }
132
133 [[nodiscard]]
134 constexpr bool empty() const noexcept {
135 return begin() == end();
136 }
137
138 constexpr void clear() noexcept {
139 deallocate();
140 mBegin = mEnd = mBufferEnd = nullptr;
141 }
142
143 void deallocate() {
144 for (auto& v : *this) {
145 v.~StoredType();
146 }
147 operator delete[](mBegin);
148 }
149
150 [[nodiscard]]
151 constexpr std::size_t size() const noexcept {
152 return mEnd - mBegin;
153 }
154
155 [[nodiscard]]
156 constexpr std::size_t reserved() const noexcept {
157 return mBufferEnd - mBegin;
158 }
159
160 template<typename OtherIterator>
161 constexpr iterator insert(iterator at, OtherIterator begin, OtherIterator end) {
162 AUI_ASSERT_MY_ITERATOR(at);
163 auto distance = std::distance(begin, end);
164
165 if (size() + distance <= reserved()) {
166 return aui::container::vector_impl::insert_no_growth(mEnd, at, begin, end);
167 }
168 ADynamicVector temp;
169 temp.reserve(aui::container::vector_impl::ceilPower2(distance + size()));
170 aui::container::vector_impl::insert_no_growth(temp.mEnd, temp.mEnd,
171 std::make_move_iterator(mBegin), std::make_move_iterator(at));
172
173 auto result = aui::container::vector_impl::insert_no_growth(temp.mEnd, temp.mEnd,
174 begin, end);
175
176 aui::container::vector_impl::insert_no_growth(temp.mEnd, temp.mEnd,
177 std::make_move_iterator(at), std::make_move_iterator(mEnd));
178 operator=(std::move(temp));
179
180 return result;
181
182 }
183
184 constexpr iterator insert(iterator at, StoredType value) {
185 AUI_ASSERT_MY_ITERATOR(at);
186 return insert(at, std::make_move_iterator(&value), std::make_move_iterator(&value + 1));
187 }
188
189 constexpr iterator erase(iterator at) {
190 return erase(at, std::next(at));
191 }
192
193 constexpr iterator erase(iterator begin, iterator end) {
194 AUI_ASSERT_MY_ITERATOR(begin);
195 AUI_ASSERT_MY_ITERATOR(end);
196
197 return aui::container::vector_impl::erase(mBegin, mEnd, begin, end);
198 }
199
200 void reserve(std::size_t newSize) {
201 if (reserved() == newSize) {
202 return;
203 }
204
205 auto newBuffer = static_cast<StoredType*>(operator new[](newSize * sizeof(StoredType)));
206 auto newBufferEnd = newBuffer;
207 try {
208 auto elementsToMove = std::min(newSize, size());
209 auto moveFrom = begin();
210 for (std::size_t i = 0; i < elementsToMove; ++newBufferEnd, ++moveFrom) {
211 new (newBufferEnd) StoredType(std::move(*moveFrom));
212 }
213 deallocate();
214 mBegin = newBuffer;
215 mEnd = newBufferEnd;
216 mBufferEnd = newBuffer + newSize;
217 } catch (...) { // unlikely; but just in case
218 delete[] newBuffer;
219 throw;
220 }
221 }
222
223 ADynamicVector& operator=(ADynamicVector&& rhs) noexcept {
224 deallocate();
225 mBegin = rhs.mBegin;
226 mEnd = rhs.mEnd;
227 mBufferEnd = rhs.mBufferEnd;
228
229 rhs.mBegin = nullptr;
230 rhs.mEnd = nullptr;
231 rhs.mBufferEnd = nullptr;
232
233 return *this;
234 }
235
236 // AUI extensions - see AVector for reference
237
238
245 template<typename OtherContainer>
246 iterator insertAll(const OtherContainer& c) noexcept {
247 return insertAll(super::end(), c);
248 }
249
250
257 template<typename OtherContainer>
258 iterator insertAll(OtherContainer&& c) noexcept {
259 return insertAll(super::end(), std::forward<OtherContainer>(c));
260 }
261
262
270 template<typename OtherContainer>
271 iterator insertAll(iterator at, const OtherContainer& c) noexcept {
272 return super::insert(at, c.begin(), c.end());
273 }
274
275
283 template<typename OtherContainer>
284 iterator insertAll(iterator at, OtherContainer&& c) noexcept {
285 return super::insert(at, std::make_move_iterator(c.begin()), std::make_move_iterator(c.end()));
286 }
287
288
293 void removeAll(const StoredType& item) noexcept
294 {
295 aui::container::remove_all(*this, item);
296 }
297
302 void removeFirst(const StoredType& item) noexcept
303 {
304 aui::container::remove_first(*this, item);
305 }
306
307
311 template<typename OtherContainer>
312 bool isSubsetOf(const OtherContainer& c) const noexcept
313 {
314 return aui::container::is_subset(*this, c);
315 }
316
320 bool contains(const StoredType& value) const noexcept {
321 return aui::container::contains(*this, value);
322 }
323
324 [[nodiscard]]
325 std::size_t sizeInBytes() const noexcept {
326 return super::size() * sizeof(StoredType);
327 }
328
329 [[nodiscard]]
330 StoredType& at(std::size_t index) {
331 if (index >= super::size()) {
332 aui::impl::outOfBoundsException();
333 }
334 return super::operator[](index);
335 }
336
337 [[nodiscard]]
338 const StoredType& at(std::size_t index) const {
339 if (index >= super::size()) {
340 aui::impl::outOfBoundsException();
341 }
342 return super::operator[](index);
343 }
344
345
351 self& operator<<(const StoredType& rhs) noexcept
352 {
353 super::push_back(rhs);
354 return *this;
355 }
356
362 self& operator<<(StoredType&& rhs) noexcept
363 {
364 super::push_back(std::forward<StoredType>(rhs));
365 return *this;
366 }
367
373 template<typename OtherContainer, std::enable_if_t<!std::is_convertible_v<OtherContainer, StoredType>, bool> = true>
374 self& operator<<(const OtherContainer& c) noexcept
375 {
376 insertAll(c);
377 return *this;
378 }
379
385 template<typename OtherContainer, std::enable_if_t<!std::is_convertible_v<OtherContainer, StoredType>, bool> = true>
386 self& operator<<(OtherContainer&& c) noexcept
387 {
388 insertAll(std::forward<OtherContainer>(c));
389 return *this;
390 }
391
392
400 StoredType& first() noexcept
401 {
402 AUI_ASSERTX(!super::empty(), "empty container could not have the first element");
403 return super::front();
404 }
405
413 const StoredType& first() const noexcept
414 {
415 AUI_ASSERTX(!super::empty(), "empty container could not have the first element");
416 return super::front();
417 }
418
426 StoredType& last() noexcept
427 {
428 AUI_ASSERTX(!super::empty(), "empty container could not have the last element");
429 return super::back();
430 }
431
439 const StoredType& last() const noexcept
440 {
441 AUI_ASSERTX(!super::empty(), "empty container could not have the last element");
442 return super::back();
443 }
444
449 [[nodiscard]]
450 size_t indexOf(const StoredType& value) const noexcept
451 {
452 return aui::container::index_of(*this, value);
453 }
454
455
456 void sort() noexcept {
457 std::sort(super::begin(), super::end());
458 }
459
460 template<typename Comparator>
461 void sort(Comparator&& comparator) noexcept {
462 std::sort(super::begin(), super::end(), std::forward<Comparator>(comparator));
463 }
464
473 void removeAt(size_t index) noexcept
474 {
475 aui::container::remove_at(*this, index);
476 }
477
482 template<typename Predicate>
483 void removeIf(Predicate&& predicate) noexcept
484 {
485 super::erase(std::remove_if(super::begin(), super::end(), std::forward<Predicate>(predicate)), super::end());
486 }
487
488 ASet<StoredType> toSet() const noexcept {
489 return ASet<StoredType>(super::begin(), super::end());
490 }
491
498 template<aui::incrementable Iterator, aui::invocable<decltype(*std::declval<Iterator>())> UnaryOperation>
499 static auto fromRange(aui::range<Iterator> range, UnaryOperation&& transformer) -> AVector<decltype(transformer(range.first()))> {
500 AVector<decltype(transformer(range.first()))> result;
501 result.reserve(range.size());
502 std::transform(range.begin(), range.end(), std::back_inserter(result), std::forward<UnaryOperation>(transformer));
503 return result;
504 }
505
506 template<aui::invocable<const StoredType&> UnaryOperation>
507 auto map(UnaryOperation&& transformer) const -> AVector<decltype(transformer(std::declval<StoredType>()))> {
509 result.reserve(super::size());
510 std::transform(super::begin(), super::end(), std::back_inserter(result), std::forward<UnaryOperation>(transformer));
511 return result;
512 }
513
514 template<aui::invocable<const StoredType&> UnaryOperation>
515 [[nodiscard]]
516 auto toMap(UnaryOperation&& transformer) const -> AMap<decltype(transformer(std::declval<StoredType>()).first),
517 decltype(transformer(std::declval<StoredType>()).second)> {
518 return aui::container::to_map(super::begin(), super::end(), transformer);
519 }
520
521 template<aui::invocable<StoredType&> UnaryOperation>
522 [[nodiscard]]
523 auto toMap(UnaryOperation&& transformer) -> AMap<decltype(transformer(std::declval<StoredType>()).first),
524 decltype(transformer(std::declval<StoredType>()).second)> {
525 return aui::container::to_map(super::begin(), super::end(), transformer);
526 }
527
528 template<aui::predicate<const StoredType&> Predicate>
529 self filter(Predicate&& predicate) {
530 self result;
531 result.reserve(super::size());
532 for (const auto& element : *this) {
533 if (predicate(element)) {
534 result.push_back(element);
535 }
536 }
537 return result;
538 }
539
540
541 iterator mBegin = nullptr;
542 iterator mEnd = nullptr;
543 iterator mBufferEnd = nullptr;
544};
Vector implementation for ASmallVector.
Definition: ADynamicVector.h:36
bool isSubsetOf(const OtherContainer &c) const noexcept
Definition: ADynamicVector.h:312
StoredType & first() noexcept
Definition: ADynamicVector.h:400
const StoredType & last() const noexcept
Definition: ADynamicVector.h:439
self & operator<<(OtherContainer &&c) noexcept
Definition: ADynamicVector.h:386
void removeIf(Predicate &&predicate) noexcept
Definition: ADynamicVector.h:483
iterator insertAll(iterator at, const OtherContainer &c) noexcept
Definition: ADynamicVector.h:271
self & operator<<(StoredType &&rhs) noexcept
Definition: ADynamicVector.h:362
iterator insertAll(OtherContainer &&c) noexcept
Definition: ADynamicVector.h:258
size_t indexOf(const StoredType &value) const noexcept
Definition: ADynamicVector.h:450
const StoredType & first() const noexcept
Definition: ADynamicVector.h:413
iterator insertAll(iterator at, OtherContainer &&c) noexcept
Definition: ADynamicVector.h:284
void removeFirst(const StoredType &item) noexcept
Definition: ADynamicVector.h:302
self & operator<<(const OtherContainer &c) noexcept
Definition: ADynamicVector.h:374
void removeAll(const StoredType &item) noexcept
Definition: ADynamicVector.h:293
void removeAt(size_t index) noexcept
Definition: ADynamicVector.h:473
bool contains(const StoredType &value) const noexcept
Definition: ADynamicVector.h:320
StoredType & last() noexcept
Definition: ADynamicVector.h:426
iterator insertAll(const OtherContainer &c) noexcept
Definition: ADynamicVector.h:246
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: ADynamicVector.h:499
self & operator<<(const StoredType &rhs) noexcept
Definition: ADynamicVector.h:351
A std::map with AUI extensions.
Definition: AMap.h:218
A std::set with AUI extensions.
Definition: ASet.h:25
A std::vector with AUI extensions.
Definition: AVector.h:38
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_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