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-2025 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>()))> {
  507        AVector<decltype(transformer(std::declval<StoredType>()))> result;
  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:33
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:205
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:172
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