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