AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
AStaticVector.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 "AVector.h"
   15#include "AException.h"
   16#include <utility>
   17#include <span>
   18
   19
   20#define AUI_ASSERT_MY_ITERATOR(it) AUI_ASSERTX((this->begin() <= it && it <= this->end()), "foreign iterator")
   21
   32template<typename StoredType, std::size_t MaxSize>
   33class AStaticVector {
   34public:
   35    using self = AStaticVector;
   36    using super = AStaticVector;
   37    using iterator = StoredType*;
   38    using const_iterator = const StoredType*;
   39    using reference = StoredType&;
   40    using const_reference = const StoredType&;
   41    using value = StoredType;
   42
   43    constexpr AStaticVector() noexcept: mBegin(reinterpret_cast<StoredType*>(&mStorage)), mEnd(mBegin) {}
   44    constexpr AStaticVector(const AStaticVector& rhs): AStaticVector() {
   45        insert(mBegin, rhs.begin(), rhs.end());
   46    }
   47    constexpr AStaticVector(AStaticVector&& rhs) noexcept: AStaticVector() {
   48        insert(mBegin, std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
   49        rhs.clear();
   50    }
   51    constexpr AStaticVector(std::initializer_list<StoredType> rhs) noexcept: AStaticVector() {
   52        insert(mBegin, std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
   53    }
   54    template<typename Iterator>
   55    constexpr AStaticVector(Iterator begin, Iterator end) noexcept: AStaticVector() {
   56        for (auto it = begin; it != end; ++it) { // range-v3 fix: basic range traversal instead of insert
   57            push_back(*it);
   58        }
   59    }
   60    constexpr ~AStaticVector() {
   61        for (auto& v : *this) {
   62            v.~StoredType();
   63        }
   64    }
   65
   66    [[nodiscard]]
   67    static constexpr size_t capacity() noexcept {
   68        return MaxSize;
   69    }
   70
   71    AStaticVector& operator=(const AStaticVector& rhs) {
   72        if (this == &rhs) {
   73            return *this;
   74        }
   75        clear();
   76        insert(mBegin, rhs.begin(), rhs.end());
   77        return *this;
   78    }
   79
   80    AStaticVector& operator=(AStaticVector&& rhs) noexcept {
   81        if (this == &rhs) {
   82            return *this;
   83        }
   84        clear();
   85        insert(mBegin, std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
   86        rhs.clear();
   87        return *this;
   88    }
   89
   90    [[nodiscard]]
   91    constexpr bool full() const noexcept {
   92        return size() >= MaxSize;
   93    }
   94
   95    [[nodiscard]]
   96    constexpr StoredType* data() noexcept {
   97        return mBegin;
   98    }
   99    [[nodiscard]]
  100    constexpr const StoredType* data() const noexcept {
  101        return mBegin;
  102    }
  103
  104    [[nodiscard]]
  105    constexpr iterator begin() noexcept {
  106        return mBegin;
  107    }
  108    [[nodiscard]]
  109    constexpr const_iterator begin() const noexcept {
  110        return mBegin;
  111    }
  112
  113    [[nodiscard]]
  114    constexpr iterator end() noexcept {
  115        return mEnd;
  116    }
  117
  118    [[nodiscard]]
  119    constexpr const_iterator end() const noexcept {
  120        return mEnd;
  121    }
  122
  123    [[nodiscard]]
  124    constexpr StoredType& front() noexcept {
  125        return *begin();
  126    }
  127
  128    [[nodiscard]]
  129    constexpr StoredType& back() noexcept {
  130        return *std::prev(end());
  131    }
  132
  133    [[nodiscard]]
  134    constexpr const StoredType& front() const noexcept {
  135        return *begin();
  136    }
  137
  138    [[nodiscard]]
  139    constexpr const StoredType& back() const noexcept {
  140        return *std::prev(end());
  141    }
  142
  143    template<typename... Args>
  144    constexpr void emplace_back(Args&&... args) noexcept {
  145        AUI_ASSERTX(!full(), "insufficient size in AStaticVector");
  146        new (mEnd++) StoredType(std::forward<Args>(args)...);
  147    }
  148
  149
  150    constexpr void push_back(StoredType value) noexcept {
  151        AUI_ASSERTX(!full(), "insufficient size in AStaticVector");
  152        new (mEnd++) StoredType(std::move(value));
  153    }
  154
  155    constexpr void push_front(StoredType value) noexcept {
  156        AUI_ASSERTX(!full(), "insufficient size in AStaticVector");
  157        insert(begin(), std::move(value));
  158    }
  159
  160    constexpr void pop_back() noexcept {
  161        AUI_ASSERTX(size() > 0, "AStaticVector is empty");
  162        erase(std::prev(end()));
  163    }
  164    constexpr void pop_front() noexcept {
  165        AUI_ASSERTX(size() > 0, "AStaticVector is empty");
  166        erase(begin());
  167    }
  168
  169    [[nodiscard]]
  170    constexpr StoredType& operator[](std::size_t index) noexcept {
  171        AUI_ASSERTX(index < size(), "out of bounds");
  172        return *(data() + index);
  173    }
  174
  175    [[nodiscard]]
  176    constexpr StoredType& operator[](std::size_t index) const noexcept {
  177        return const_cast<AStaticVector*>(this)->operator[](index);
  178    }
  179
  180    [[nodiscard]]
  181    constexpr bool empty() const noexcept {
  182        return begin() == end();
  183    }
  184
  185    constexpr void clear() noexcept {
  186        for (auto& v : *this) {
  187            v.~StoredType();
  188        }
  189        mEnd = mBegin;
  190    }
  191
  192    [[nodiscard]]
  193    constexpr std::size_t size() const noexcept {
  194        return mEnd - mBegin;
  195    }
  196
  197    template<typename OtherIterator>
  198    constexpr iterator insert(iterator at, OtherIterator begin, OtherIterator end) {
  199        AUI_ASSERT_MY_ITERATOR(at);
  200        auto distance = std::distance(begin, end);
  201        AUI_ASSERTX(size() + distance <= MaxSize, "out of bounds");
  202
  203        return aui::container::vector_impl::insert_no_growth(mEnd, at, begin, end);
  204    }
  205
  206    constexpr iterator insert(iterator at, StoredType value) {
  207        AUI_ASSERT_MY_ITERATOR(at);
  208        return insert(at, std::make_move_iterator(&value), std::make_move_iterator(&value + 1));
  209    }
  210
  211    constexpr iterator erase(iterator at) {
  212        return erase(at, std::next(at));
  213    }
  214
  215    constexpr iterator erase(iterator begin, iterator end) {
  216        AUI_ASSERT_MY_ITERATOR(begin);
  217        AUI_ASSERT_MY_ITERATOR(end);
  218
  219        return aui::container::vector_impl::erase(mBegin, mEnd, begin, end);
  220    }
  221
  222    void reserve(std::size_t) {
  223        // does nothing - just for std::vector compatibility
  224    }
  225
  226    // AUI extensions - see AVector for reference
  227
  228
  235    template<typename OtherContainer>
  236    iterator insertAll(const OtherContainer& c) noexcept {
  237        return insertAll(super::end(), c);
  238    }
  239
  240
  247    template<typename OtherContainer>
  248    iterator insertAll(OtherContainer&& c) noexcept {
  249        return insertAll(super::end(), std::forward<OtherContainer>(c));
  250    }
  251
  252
  260    template<typename OtherContainer>
  261    iterator insertAll(iterator at, const OtherContainer& c) noexcept {
  262        return super::insert(at, c.begin(), c.end());
  263    }
  264
  265
  273    template<typename OtherContainer>
  274    iterator insertAll(iterator at, OtherContainer&& c) noexcept {
  275        return super::insert(at, std::make_move_iterator(c.begin()), std::make_move_iterator(c.end()));
  276    }
  277
  278
  283    void removeAll(const StoredType& item) noexcept
  284    {
  285        aui::container::remove_all(*this, item);
  286    }
  287
  292    void removeFirst(const StoredType& item) noexcept
  293    {
  294        aui::container::remove_first(*this, item);
  295    }
  296
  297
  301    template<typename OtherContainer>
  302    bool isSubsetOf(const OtherContainer& c) const noexcept
  303    {
  304        return aui::container::is_subset(*this, c);
  305    }
  306
  310    bool contains(const StoredType& value) const noexcept {
  311        return aui::container::contains(*this, value);
  312    }
  313
  314    [[nodiscard]]
  315    std::size_t sizeInBytes() const noexcept {
  316        return super::size() * sizeof(StoredType);
  317    }
  318
  319    [[nodiscard]]
  320    StoredType& at(std::size_t index) {
  321        if (index >= super::size()) {
  322            aui::impl::outOfBoundsException();
  323        }
  324        return super::operator[](index);
  325    }
  326
  327    [[nodiscard]]
  328    const StoredType& at(std::size_t index) const {
  329        if (index >= super::size()) {
  330            aui::impl::outOfBoundsException();
  331        }
  332        return super::operator[](index);
  333    }
  334
  335
  341    self& operator<<(const StoredType& rhs) noexcept
  342    {
  343        super::push_back(rhs);
  344        return *this;
  345    }
  346
  352    self& operator<<(StoredType&& rhs) noexcept
  353    {
  354        super::push_back(std::forward<StoredType>(rhs));
  355        return *this;
  356    }
  357
  363    template<typename OtherContainer, std::enable_if_t<!std::is_convertible_v<OtherContainer, StoredType>, bool> = true>
  364    self& operator<<(const OtherContainer& c) noexcept
  365    {
  366        insertAll(c);
  367        return *this;
  368    }
  369
  375    template<typename OtherContainer, std::enable_if_t<!std::is_convertible_v<OtherContainer, StoredType>, bool> = true>
  376    self& operator<<(OtherContainer&& c) noexcept
  377    {
  378        insertAll(std::forward<OtherContainer>(c));
  379        return *this;
  380    }
  381
  382
  390    StoredType& first() noexcept
  391    {
  392        AUI_ASSERTX(!super::empty(), "empty container could not have the first element");
  393        return super::front();
  394    }
  395
  403    const StoredType& first() const noexcept
  404    {
  405        AUI_ASSERTX(!super::empty(), "empty container could not have the first element");
  406        return super::front();
  407    }
  408
  416    StoredType& last() noexcept
  417    {
  418        AUI_ASSERTX(!super::empty(), "empty container could not have the last element");
  419        return super::back();
  420    }
  421
  429    const StoredType& last() const noexcept
  430    {
  431        AUI_ASSERTX(!super::empty(), "empty container could not have the last element");
  432        return super::back();
  433    }
  434
  439    [[nodiscard]]
  440    AOptional<size_t> indexOf(const StoredType& value) const noexcept
  441    {
  442        return aui::container::index_of(*this, value);
  443    }
  444
  445
  446    void sort() noexcept {
  447        std::sort(super::begin(), super::end());
  448    }
  449
  450    template<typename Comparator>
  451    void sort(Comparator&& comparator) noexcept {
  452        std::sort(super::begin(), super::end(), std::forward<Comparator>(comparator));
  453    }
  454
  463    void removeAt(size_t index) noexcept
  464    {
  465        aui::container::remove_at(*this, index);
  466    }
  467
  472    template<typename Predicate>
  473    void removeIf(Predicate&& predicate) noexcept
  474    {
  475        super::erase(std::remove_if(super::begin(), super::end(), std::forward<Predicate>(predicate)), super::end());
  476    }
  477
  478    ASet<StoredType> toSet() const noexcept {
  479        return ASet<StoredType>(super::begin(), super::end());
  480    }
  481
  488    template<aui::incrementable Iterator, aui::invocable<decltype(*std::declval<Iterator>())> UnaryOperation>
  489    static auto fromRange(aui::range<Iterator> range, UnaryOperation&& transformer) -> AVector<decltype(transformer(range.first()))> {
  490        AVector<decltype(transformer(range.first()))> result;
  491        result.reserve(range.size());
  492        std::transform(range.begin(), range.end(), std::back_inserter(result), std::forward<UnaryOperation>(transformer));
  493        return result;
  494    }
  495
  496    template<aui::invocable<const StoredType&> UnaryOperation>
  497    auto map(UnaryOperation&& transformer) const -> AVector<decltype(transformer(std::declval<StoredType>()))> {
  498        AVector<decltype(transformer(std::declval<StoredType>()))> result;
  499        result.reserve(super::size());
  500        std::transform(super::begin(), super::end(), std::back_inserter(result), std::forward<UnaryOperation>(transformer));
  501        return result;
  502    }
  503
  504    template<aui::invocable<const StoredType&> UnaryOperation>
  505    [[nodiscard]]
  506    auto toMap(UnaryOperation&& transformer) const -> AMap<decltype(transformer(std::declval<StoredType>()).first),
  507            decltype(transformer(std::declval<StoredType>()).second)> {
  508        return aui::container::to_map(super::begin(), super::end(), transformer);
  509    }
  510
  511    template<aui::invocable<StoredType&> UnaryOperation>
  512    [[nodiscard]]
  513    auto toMap(UnaryOperation&& transformer) -> AMap<decltype(transformer(std::declval<StoredType>()).first),
  514            decltype(transformer(std::declval<StoredType>()).second)> {
  515        return aui::container::to_map(super::begin(), super::end(), transformer);
  516    }
  517
  518    template<aui::predicate<const StoredType&> Predicate>
  519    self filter(Predicate&& predicate) {
  520        self result;
  521        result.reserve(super::size());
  522        for (const auto& element : *this) {
  523            if (predicate(element)) {
  524                result.push_back(element);
  525            }
  526        }
  527        return result;
  528    }
  529
  530    [[nodiscard]]
  531    operator std::span<StoredType>() {
  532        return std::span(data(), size());
  533    }
  534
  535    [[nodiscard]]
  536    operator std::span<const StoredType>() const {
  537        return std::span(data(), size());
  538    }
  539
  540private:
  541    iterator mBegin;
  542    iterator mEnd;
  543    std::aligned_storage_t<sizeof(StoredType) * MaxSize, alignof(StoredType)> mStorage;
  544};
Utility wrapper implementing the stack-allocated (fast) optional idiom.
Definition AOptional.h:33
A std::set with AUI extensions.
Definition ASet.h:25
StoredType & first() noexcept
Definition AStaticVector.h:390
iterator insertAll(iterator at, const OtherContainer &c) noexcept
Definition AStaticVector.h:261
void removeAt(size_t index) noexcept
Definition AStaticVector.h:463
self & operator<<(const StoredType &rhs) noexcept
Definition AStaticVector.h:341
void removeFirst(const StoredType &item) noexcept
Definition AStaticVector.h:292
void removeAll(const StoredType &item) noexcept
Definition AStaticVector.h:283
self & operator<<(StoredType &&rhs) noexcept
Definition AStaticVector.h:352
AOptional< size_t > indexOf(const StoredType &value) const noexcept
Definition AStaticVector.h:440
const StoredType & first() const noexcept
Definition AStaticVector.h:403
bool contains(const StoredType &value) const noexcept
Definition AStaticVector.h:310
iterator insertAll(OtherContainer &&c) noexcept
Definition AStaticVector.h:248
iterator insertAll(const OtherContainer &c) noexcept
Definition AStaticVector.h:236
void removeIf(Predicate &&predicate) noexcept
Definition AStaticVector.h:473
self & operator<<(OtherContainer &&c) noexcept
Definition AStaticVector.h:376
const StoredType & last() const noexcept
Definition AStaticVector.h:429
self & operator<<(const OtherContainer &c) noexcept
Definition AStaticVector.h:364
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 AStaticVector.h:489
StoredType & last() noexcept
Definition AStaticVector.h:416
bool isSubsetOf(const OtherContainer &c) const noexcept
Definition AStaticVector.h:302
iterator insertAll(iterator at, OtherContainer &&c) noexcept
Definition AStaticVector.h:274
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