mirror of https://github.com/zeldaret/botw.git
ksys/util: Add range() and indexIter() for convenience
- range() is similar to Python's range() - indexIter() can be used to simplify `for (int i = 0, n = c.size(); i < n; ++i)` index-based loops
This commit is contained in:
parent
c423a56a63
commit
03410f3eb3
|
@ -78,6 +78,7 @@ target_sources(uking PRIVATE
|
||||||
HeapUtil.cpp
|
HeapUtil.cpp
|
||||||
HeapUtil.h
|
HeapUtil.h
|
||||||
InitTimeInfo.h
|
InitTimeInfo.h
|
||||||
|
IteratorUtil.h
|
||||||
ParamIO.cpp
|
ParamIO.cpp
|
||||||
ParamIO.h
|
ParamIO.h
|
||||||
SafeDelete.h
|
SafeDelete.h
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace ksys::util {
|
||||||
|
|
||||||
|
template <typename IntType>
|
||||||
|
class IntRange {
|
||||||
|
public:
|
||||||
|
static_assert(std::is_integral_v<IntType>, "T is not a integer type");
|
||||||
|
|
||||||
|
class Iterator {
|
||||||
|
public:
|
||||||
|
constexpr explicit Iterator(IntType value) : mValue(value) {}
|
||||||
|
|
||||||
|
constexpr bool operator==(Iterator rhs) const { return mValue == rhs.mValue; }
|
||||||
|
constexpr bool operator!=(Iterator rhs) const { return !operator==(rhs); }
|
||||||
|
|
||||||
|
constexpr IntType operator*() const { return mValue; }
|
||||||
|
|
||||||
|
constexpr Iterator& operator++() {
|
||||||
|
++mValue;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Iterator operator++(int) const { return Iterator(mValue + 1); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
IntType mValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr IntRange(IntType begin, IntType end) : mBegin(begin), mEnd(end) {}
|
||||||
|
|
||||||
|
constexpr Iterator begin() const { return mBegin; }
|
||||||
|
constexpr Iterator end() const { return mEnd; }
|
||||||
|
constexpr Iterator cbegin() const { return mBegin; }
|
||||||
|
constexpr Iterator cend() const { return mEnd; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Iterator mBegin;
|
||||||
|
Iterator mEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Range [begin, end) with a step of 1.
|
||||||
|
template <typename IntType>
|
||||||
|
constexpr IntRange<IntType> range(IntType begin, IntType end) {
|
||||||
|
return {begin, end};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Range [0, end) with a step of 1.
|
||||||
|
template <typename IntType>
|
||||||
|
constexpr auto range(IntType end) {
|
||||||
|
return IntRange<IntType>{0, end};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use this as a replacement for `for (int i = 0, n = c.size(); i < n; ++i)` loops.
|
||||||
|
///
|
||||||
|
/// @warning The even better option is to use the container's own iterators,
|
||||||
|
/// as index-based loops can result in useless bounds checks at every iteration.
|
||||||
|
template <typename Container>
|
||||||
|
class IndexRange {
|
||||||
|
public:
|
||||||
|
class ElementProxy {
|
||||||
|
public:
|
||||||
|
constexpr ElementProxy(Container& container, int index)
|
||||||
|
: mIndex(index), mContainer(container) {}
|
||||||
|
|
||||||
|
int getIndex() const { return mIndex; }
|
||||||
|
constexpr auto& get() const { return mContainer[mIndex]; }
|
||||||
|
constexpr auto& operator*() const { return get(); }
|
||||||
|
constexpr auto* operator->() const { return &get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mIndex;
|
||||||
|
Container& mContainer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Iterator {
|
||||||
|
public:
|
||||||
|
constexpr Iterator(Container& container, int index)
|
||||||
|
: mIndex(index), mContainer(container) {}
|
||||||
|
|
||||||
|
constexpr bool operator==(Iterator rhs) const { return mIndex == rhs.mIndex; }
|
||||||
|
constexpr bool operator!=(Iterator rhs) const { return !operator==(rhs); }
|
||||||
|
|
||||||
|
int getIndex() const { return mIndex; }
|
||||||
|
constexpr ElementProxy operator*() const { return ElementProxy(mContainer, mIndex); }
|
||||||
|
|
||||||
|
constexpr Iterator& operator++() {
|
||||||
|
++mIndex;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Iterator operator++(int) const {
|
||||||
|
auto copy = *this;
|
||||||
|
++copy;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mIndex;
|
||||||
|
Container& mContainer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EndIterator {
|
||||||
|
public:
|
||||||
|
constexpr explicit EndIterator(int index) : mIndex(index) {}
|
||||||
|
constexpr bool notEnd(Iterator it) const { return it.getIndex() < mIndex; }
|
||||||
|
friend constexpr bool operator!=(EndIterator end, Iterator it) { return end.notEnd(it); }
|
||||||
|
friend constexpr bool operator!=(Iterator it, EndIterator end) { return end.notEnd(it); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr explicit IndexRange(Container& container) : mContainer(container) {}
|
||||||
|
|
||||||
|
constexpr Iterator begin() const { return Iterator(mContainer, 0); }
|
||||||
|
constexpr EndIterator end() const { return EndIterator(mContainer.size()); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Container& mContainer;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
constexpr auto indexIter(Container& container) {
|
||||||
|
return IndexRange<Container>{container};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ksys::util
|
Loading…
Reference in New Issue