From 03410f3eb34b677575b0fd6241b4101af92435f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 22 Jun 2022 18:27:45 +0200 Subject: [PATCH] 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 --- src/KingSystem/Utils/CMakeLists.txt | 1 + src/KingSystem/Utils/IteratorUtil.h | 130 ++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/KingSystem/Utils/IteratorUtil.h 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 + +namespace ksys::util { + +template +class IntRange { +public: + static_assert(std::is_integral_v, "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 +constexpr IntRange range(IntType begin, IntType end) { + return {begin, end}; +} + +/// Range [0, end) with a step of 1. +template +constexpr auto range(IntType end) { + return IntRange{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 +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 +constexpr auto indexIter(Container& container) { + return IndexRange{container}; +} + +} // namespace ksys::util