// SPDX-License-Identifier: MIT #ifndef RGBDS_ITERTOOLS_HPP #define RGBDS_ITERTOOLS_HPP #include #include #include #include #include #include #include #include template class InsertionOrderedMap { std::deque list; std::unordered_map map; // Indexes into `list` public: size_t size() const { return list.size(); } bool empty() const { return list.empty(); } bool contains(std::string const &name) const { return map.find(name) != map.end(); } T &operator[](size_t i) { return list[i]; } typename decltype(list)::iterator begin() { return list.begin(); } typename decltype(list)::iterator end() { return list.end(); } typename decltype(list)::const_iterator begin() const { return list.begin(); } typename decltype(list)::const_iterator end() const { return list.end(); } T &add(std::string const &name) { map[name] = list.size(); return list.emplace_back(); } T &add(std::string const &name, T &&value) { map[name] = list.size(); list.emplace_back(std::move(value)); return list.back(); } T &addAnonymous() { // Add the new item to the list, but do not update the map return list.emplace_back(); } std::optional findIndex(std::string const &name) const { if (auto search = map.find(name); search != map.end()) { return search->second; } return std::nullopt; } }; template class EnumSeq { T _start; T _stop; class Iterator { T _value; public: explicit Iterator(T value) : _value(value) {} Iterator &operator++() { _value = static_cast(_value + 1); return *this; } T operator*() const { return _value; } bool operator==(Iterator const &rhs) const { return _value == rhs._value; } }; public: explicit EnumSeq(T stop) : _start(static_cast(0)), _stop(stop) {} explicit EnumSeq(T start, T stop) : _start(start), _stop(stop) {} Iterator begin() { return Iterator(_start); } Iterator end() { return Iterator(_stop); } }; // This is not a fully generic implementation; its current use cases only require for-loop behavior. // We also assume that all iterators have the same length. template class ZipIterator { std::tuple _iters; public: explicit ZipIterator(std::tuple &&iters) : _iters(iters) {} ZipIterator &operator++() { std::apply([](auto &&...it) { (++it, ...); }, _iters); return *this; } auto operator*() const { return std::apply( [](auto &&...it) { return std::tuple(*it...); }, _iters ); } bool operator==(ZipIterator const &rhs) const { return std::get<0>(_iters) == std::get<0>(rhs._iters); } }; template class ZipContainer { std::tuple _containers; public: explicit ZipContainer(Ts &&...containers) : _containers(std::forward(containers)...) {} auto begin() { return ZipIterator(std::apply( [](auto &&...containers) { using std::begin; return std::make_tuple(begin(containers)...); }, _containers )); } auto end() { return ZipIterator(std::apply( [](auto &&...containers) { using std::end; return std::make_tuple(end(containers)...); }, _containers )); } }; // Take ownership of objects and rvalue refs passed to us, but not lvalue refs template using Holder = std:: conditional_t, T, std::remove_cv_t>>; // Does the same number of iterations as the first container's iterator! template static constexpr auto zip(Ts &&...cs) { return ZipContainer...>(std::forward(cs)...); } #endif // RGBDS_ITERTOOLS_HPP