AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
iterators.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 <tuple>
   15#include <variant>
   16#include <cstdint>
   17#include <iterator>
   18#include <ostream>
   19#include "parameter_pack.h"
   20#include "macros.h"
   21
   22
   23namespace aui {
   24
   33    template <typename T>
   34    struct reverse_iterator_wrap {
   35    private:
   36        const T* mIterable;
   37
   38    public:
   39        explicit reverse_iterator_wrap(const T& mIterable) : mIterable(&mIterable) {}
   40
   41        auto begin() {
   42            return mIterable->rbegin();
   43        }
   44        auto end() {
   45            return mIterable->rend();
   46        }
   47    };
   48
   49    template<typename Iterator>
   50    struct range {
   51    private:
   52        Iterator mBegin;
   53        Iterator mEnd;
   54    public:
   55        constexpr range(Iterator mBegin, Iterator mEnd) : mBegin(mBegin), mEnd(mEnd) {}
   56
   57        constexpr ~range() {
   58            if constexpr (requires { std::distance(mBegin, mEnd); }) {
   59                AUI_NO_OPTIMIZE_OUT(range::size)
   60            }
   61        }
   62
   63        template<typename Container>
   64        constexpr range(Container& c): mBegin(c.begin()), mEnd(c.end()) {
   65
   66        }
   67
   68
   69        template<typename Container>
   70        constexpr range(const Container& c): mBegin(c.begin()), mEnd(c.end()) {
   71
   72        }
   73
   74        [[nodiscard]]
   75        constexpr bool empty() const noexcept {
   76            return mBegin == mEnd;
   77        }
   78
   79        [[nodiscard]]
   80        constexpr std::size_t size() const noexcept requires requires { std::distance(mBegin, mEnd); }  {
   81            return std::distance(mBegin, mEnd);
   82        }
   83
   84        [[nodiscard]]
   85        constexpr Iterator& begin() noexcept {
   86            return mBegin;
   87        }
   88
   89        [[nodiscard]]
   90        constexpr Iterator& end() noexcept {
   91            return mEnd;
   92        }
   93
   94        [[nodiscard]]
   95        constexpr Iterator begin() const noexcept {
   96            return mBegin;
   97        }
   98
   99        [[nodiscard]]
  100        constexpr Iterator end() const noexcept {
  101            return mEnd;
  102        }
  103
  104        [[nodiscard]]
  105        constexpr const auto& first() const {
  106            return *mBegin;
  107        }
  108
  109        [[nodiscard]]
  110        constexpr const auto& last() const {
  111            return *std::prev(mEnd);
  112        }
  113
  114        [[nodiscard]]
  115        constexpr bool operator==(const range& rhs) const noexcept;
  116
  117        [[nodiscard]]
  118        constexpr bool operator!=(const range& rhs) const noexcept {
  119            return !(*this == rhs);
  120        }
  121    };
  122
  123    template<typename Container>
  124    range(Container& c) -> range<decltype(c.begin())>;
  125
  126    template<typename Container>
  127    range(const Container& c) -> range<decltype(c.begin())>;
  128
  132    template<typename Container>
  133    using const_iterator_if_const = std::conditional_t<std::is_const_v<Container>,
  134                                                       typename Container::const_iterator,
  135                                                       typename Container::iterator>;
  136
  137
  155    template<typename... Containers>
  156    struct zip {
  157    private:
  158        using iterator_parallel = std::tuple<decltype(std::declval<Containers>().begin())...>;
  159
  160        iterator_parallel begins_;
  161        iterator_parallel ends_;
  162
  163    public:
  164        struct iterator {
  165            iterator_parallel iterators_;
  166
  167            iterator(iterator_parallel iterators) : iterators_(std::move(iterators)) {}
  168
  169            iterator& operator++() noexcept {
  170                std::apply([](auto&&... v) {
  171                    (++v, ...);
  172                }, iterators_);
  173                return *this;
  174            }
  175
  176            std::tuple<decltype(*std::declval<Containers>().begin())&...> operator*() noexcept {
  177                return std::apply([](auto&&... v) {
  178                    return std::tuple<decltype(*std::declval<Containers>().begin())&...>((*v)...);
  179                }, iterators_);
  180            }
  181
  182            bool operator==(const iterator& rhs) const noexcept {
  183                return iterators_ == rhs.iterators_;
  184            }
  185
  186            bool operator!=(const iterator& rhs) const noexcept {
  187                return iterators_ != rhs.iterators_;
  188            }
  189        };
  190
  191        zip(Containers&... c): begins_(c.begin()...), ends_(c.end()...) {
  192
  193        }
  194
  195        iterator begin() noexcept {
  196            return iterator(begins_);
  197        }
  198        iterator end() noexcept {
  199            return iterator(ends_);
  200        }
  201    };
  202
  203    namespace impl {
  204        template<typename Iterator, class = void>
  205        static constexpr bool is_forward_iterator = true;
  206
  207        template<typename Iterator>
  208        static constexpr bool is_forward_iterator<std::reverse_iterator<Iterator>> = false;
  209    }
  210
  222    template<typename Iterator>
  223    auto reverse_iterator_direction(Iterator iterator) noexcept ->
  224        decltype((iterator + 1).base()) requires (!impl::is_forward_iterator<Iterator>) {
  225        return (iterator + 1).base();
  226    }
  227
  228    template<typename Iterator>
  229    auto reverse_iterator_direction(Iterator iterator) noexcept ->
  230        decltype(std::make_reverse_iterator(std::declval<Iterator>())) requires (impl::is_forward_iterator<Iterator>) {
  231
  232        return std::make_reverse_iterator(iterator + 1);
  233    }
  234}
  235
  236template<typename Iterator>
  237inline constexpr bool aui::range<Iterator>::operator==(const range& rhs) const noexcept {
  238    if (size() != rhs.size()) {
  239        return false;
  240    }
  241    for (const auto&[l, r] : aui::zip(*this, rhs)) {
  242        if (l != r) {
  243            return false;
  244        }
  245    }
  246    return true;
  247}
  248
  249template<typename T>
  250inline std::ostream& operator<<(std::ostream& os, aui::range<T> range) {
  251    os << "[ ";
  252    bool isFirst = true;
  253    for (const auto& v : range) {
  254        if (isFirst) {
  255            isFirst = false;
  256        } else {
  257            os << ", ";
  258        }
  259        os << v;
  260    }
  261    return os << " ]";
  262}
#define AUI_NO_OPTIMIZE_OUT(object)
Forbids object from being optimized out by compiler.
Definition macros.h:40
Definition iterators.h:50
Iterates multiple containers in parallel.
Definition iterators.h:156