diff options
| author | Léo Lam <leo@leolam.fr> | 2022-06-22 18:27:45 +0200 |
|---|---|---|
| committer | Léo Lam <leo@leolam.fr> | 2022-06-22 20:23:08 +0200 |
| commit | 03410f3eb34b677575b0fd6241b4101af92435f2 (patch) | |
| tree | 780cf2746c8f245f1e9d54c145de8dcf37fe4279 | |
| parent | c423a56a63b345c9d272b1f256422eebffee09c4 (diff) | |
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
| -rw-r--r-- | src/KingSystem/Utils/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/KingSystem/Utils/IteratorUtil.h | 130 |
2 files changed, 131 insertions, 0 deletions
diff --git a/src/KingSystem/Utils/CMakeLists.txt b/src/KingSystem/Utils/CMakeLists.txt index 591c0361..e60e67e9 100644 --- a/src/KingSystem/Utils/CMakeLists.txt +++ b/src/KingSystem/Utils/CMakeLists.txt @@ -78,6 +78,7 @@ target_sources(uking PRIVATE HeapUtil.cpp HeapUtil.h InitTimeInfo.h + IteratorUtil.h ParamIO.cpp ParamIO.h SafeDelete.h diff --git a/src/KingSystem/Utils/IteratorUtil.h b/src/KingSystem/Utils/IteratorUtil.h new file mode 100644 index 00000000..3058201b --- /dev/null +++ b/src/KingSystem/Utils/IteratorUtil.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 |
