mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
- Since we have style rules to include foo.hpp at the top of its corresponding foo.cpp, this takes any headers included by foo.hpp as being also guaranteed for foo.cpp. - Use C-style <foo.h> instead of <cfoo>, since the latter only guarantees putting symbols in the `std` namespace, which we are not using for C functions (e.g. `printf` not `std::printf`). - Remove now-unused `__PRETTY_FUNCTION__` reporting
117 lines
2.8 KiB
C++
117 lines
2.8 KiB
C++
/* SPDX-License-Identifier: MIT */
|
|
|
|
#ifndef RGBDS_ITERTOOLS_HPP
|
|
#define RGBDS_ITERTOOLS_HPP
|
|
|
|
#include <tuple>
|
|
#include <utility>
|
|
|
|
template<typename T>
|
|
class EnumSeqIterator {
|
|
T _value;
|
|
|
|
public:
|
|
explicit EnumSeqIterator(T value) : _value(value) {}
|
|
|
|
EnumSeqIterator &operator++() {
|
|
_value = (T)(_value + 1);
|
|
return *this;
|
|
}
|
|
|
|
auto operator*() const { return _value; }
|
|
|
|
friend auto operator==(EnumSeqIterator const &lhs, EnumSeqIterator const &rhs) {
|
|
return lhs._value == rhs._value;
|
|
}
|
|
|
|
friend auto operator!=(EnumSeqIterator const &lhs, EnumSeqIterator const &rhs) {
|
|
return lhs._value != rhs._value;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
class EnumSeq {
|
|
T _start;
|
|
T _stop;
|
|
|
|
public:
|
|
explicit EnumSeq(T stop) : _start((T)0), _stop(stop) {}
|
|
explicit EnumSeq(T start, T stop) : _start(start), _stop(stop) {}
|
|
|
|
EnumSeqIterator<T> begin() { return EnumSeqIterator(_start); }
|
|
EnumSeqIterator<T> end() { return EnumSeqIterator(_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<typename... Iters>
|
|
class Zip {
|
|
std::tuple<Iters...> _iters;
|
|
|
|
public:
|
|
explicit Zip(std::tuple<Iters...> &&iters) : _iters(iters) {}
|
|
|
|
Zip &operator++() {
|
|
std::apply([](auto &&...it) { (++it, ...); }, _iters);
|
|
return *this;
|
|
}
|
|
|
|
auto operator*() const {
|
|
return std::apply(
|
|
[](auto &&...it) { return std::tuple<decltype(*it)...>(*it...); }, _iters
|
|
);
|
|
}
|
|
|
|
friend auto operator==(Zip const &lhs, Zip const &rhs) {
|
|
return std::get<0>(lhs._iters) == std::get<0>(rhs._iters);
|
|
}
|
|
|
|
friend auto operator!=(Zip const &lhs, Zip const &rhs) {
|
|
return std::get<0>(lhs._iters) != std::get<0>(rhs._iters);
|
|
}
|
|
};
|
|
|
|
namespace detail {
|
|
template<typename... Containers>
|
|
class ZipContainer {
|
|
std::tuple<Containers...> _containers;
|
|
|
|
public:
|
|
explicit ZipContainer(Containers &&...containers)
|
|
: _containers(std::forward<Containers>(containers)...) {}
|
|
|
|
auto begin() {
|
|
return Zip(std::apply(
|
|
[](auto &&...containers) {
|
|
using std::begin;
|
|
return std::make_tuple(begin(containers)...);
|
|
},
|
|
_containers
|
|
));
|
|
}
|
|
|
|
auto end() {
|
|
return Zip(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<typename T>
|
|
using Holder = std::
|
|
conditional_t<std::is_lvalue_reference_v<T>, T, std::remove_cv_t<std::remove_reference_t<T>>>;
|
|
} // namespace detail
|
|
|
|
// Does the same number of iterations as the first container's iterator!
|
|
template<typename... Containers>
|
|
static constexpr auto zip(Containers &&...cs) {
|
|
return detail::ZipContainer<detail::Holder<Containers>...>(std::forward<Containers>(cs)...);
|
|
}
|
|
|
|
#endif // RGBDS_ITERTOOLS_HPP
|