From b4c8bee9dd81919030b01ffa728d9bf2fa1f1246 Mon Sep 17 00:00:00 2001 From: namark <namark@disroot.org> Date: Wed, 26 Aug 2020 01:01:54 +0400 Subject: [PATCH] Small improvements for iterator range. --- source/simple/support/algorithm.hpp | 30 ++++++++++++++++-- source/simple/support/range.hpp | 47 +++++++++++++++++++++++------ unit_tests/algorithm.cpp | 19 ++++++++++-- unit_tests/range.cpp | 23 +++++++++++--- 4 files changed, 98 insertions(+), 21 deletions(-) diff --git a/source/simple/support/algorithm.hpp b/source/simple/support/algorithm.hpp index 2ad32ab..fc68859 100644 --- a/source/simple/support/algorithm.hpp +++ b/source/simple/support/algorithm.hpp @@ -187,6 +187,7 @@ namespace simple::support template <typename Container> + [[nodiscard]] constexpr auto make_range(Container& container) { using std::begin; @@ -198,6 +199,7 @@ namespace simple::support constexpr auto make_range(Container&& container) = delete; template <typename Container> + [[nodiscard]] constexpr auto reverse_range(Container& container) { using std::rbegin; @@ -210,12 +212,34 @@ namespace simple::support template<typename Index = std::size_t, typename Container> - constexpr + [[nodiscard]] constexpr auto get_iterator_range(Container&& container, const range<Index>& index_range) + { + return make_range(std::forward<Container>(container)).sub_range(index_range); + } + + template<typename It> + [[nodiscard]] constexpr + auto distance(const range<It>& rng, It origin) { using std::begin; using std::end; - return make_range(std::forward<Container>(container)).sub_range(index_range); + return range{ begin(rng) - origin, end(rng) - origin }; + } + + template <typename From, typename To, typename Origin> + [[nodiscard]] constexpr + auto map_range(const From& from, To&& to, Origin origin) + { + return get_iterator_range(to, distance(from, origin)); + } + + template <typename From, typename To> + [[nodiscard]] constexpr + auto map_range(const From& from, const To& to) + { + using std::begin; + return get_iterator_range(to, distance(from, begin(from))); } template <typename Itr, typename BinaryOp> @@ -317,7 +341,7 @@ namespace simple::support template <typename Integer, typename Unsigned = std::make_unsigned_t<Integer>> [[nodiscard]] constexpr - Integer midpoint(Integer a, Integer b) + Integer midpoint(Integer a, Integer b) noexcept // noexcept(noexcept(TODO)) { using std::numeric_limits; diff --git a/source/simple/support/range.hpp b/source/simple/support/range.hpp index 2b4b1ce..6bc1501 100644 --- a/source/simple/support/range.hpp +++ b/source/simple/support/range.hpp @@ -47,25 +47,41 @@ namespace simple::support return bounds == other.bounds; } - template <typename T = Type, std::enable_if_t<range_based_for_loopable<T>{}>...> - constexpr Type begin() const { return lower(); } - template <typename T = Type, std::enable_if_t<range_based_for_loopable<T>{}>...> - constexpr Type end() const { return upper(); } - - template<typename Range> - constexpr range sub_range(const Range& other) const + template <typename T = Type, + std::enable_if_t<range_based_for_loopable<T>{}>...> + [[nodiscard]] constexpr Type begin() const { return lower(); } + template <typename T = Type, + std::enable_if_t<range_based_for_loopable<T>{}>...> + [[nodiscard]] constexpr Type end() const { return upper(); } + + template <typename T = Type, + std::enable_if_t<range_based_for_loopable<T>{}>...> + [[nodiscard]] constexpr auto rbegin() const + { return std::make_reverse_iterator(upper()); } + template <typename T = Type, + std::enable_if_t<range_based_for_loopable<T>{}>...> + [[nodiscard]] constexpr auto rend() const + { return std::make_reverse_iterator(lower()); } + + template<typename OtherType> + [[nodiscard]] constexpr + range sub_range(range<OtherType> other) const { - range result + // TODO: use unsigned for other type when it makes sense, to avoid overflow + clamp_in_place(other, { + OtherType{}, + static_cast<OtherType>(upper() - lower()) + }); + return { lower() + other.lower(), lower() + other.upper() }; - clamp_in_place(result, {lower(), upper()}); - return result; } constexpr auto validity() const { return lower() <= upper(); } constexpr bool valid() const { return bool(validity()); } + constexpr range& fix() & { using std::min; @@ -89,6 +105,12 @@ namespace simple::support return range{*this}.fix(); } + [[nodiscard]] + constexpr auto reverse() const + { + return support::range{rbegin(), rend()}; + } + template <typename ValueType = Type, std::common_type_t<ValueType, Type>* = nullptr> constexpr bool contains(const ValueType& value) const { return lower() < value && value < upper(); } @@ -168,6 +190,11 @@ namespace simple::support constexpr range<Type> intersection(const range<Type>& one, range<Type> other) { return one.intersection(other); } + template <typename Type> + [[nodiscard]] + constexpr auto reverse(const range<Type>& one) + { return one.reverse(); } + template <typename Type> constexpr range<Type>& clamp_in_place(range<Type>& v, const range<Type>& hilo) diff --git a/unit_tests/algorithm.cpp b/unit_tests/algorithm.cpp index f9290f5..64ca939 100644 --- a/unit_tests/algorithm.cpp +++ b/unit_tests/algorithm.cpp @@ -116,6 +116,7 @@ void IteratorRange() array<int, 5> sub_array{3, 4, 5, 6, 7}; array<int, 5> sub_array_2{5, 6, 7, 8, 9}; array<int, 5> sub_array_3{0, 1, 2, 3, 4}; + array<int, 5> rsub_array_2{9, 8, 7, 6, 5}; int i = 0; for(auto&& element : get_iterator_range(arr, {3, 8})) @@ -125,6 +126,16 @@ void IteratorRange() for(auto&& element : get_iterator_range(arr, {5, 800})) assert(sub_array_2[i++] == element); + i = arr.size();; + for(auto&& element : reverse_range(arr)) + assert(arr[--i] == element); + + + i = 0; + for(auto&& element : reverse(get_iterator_range(arr, {5, 800}))) + assert(rsub_array_2[i++] == element); + + i = 0; for(auto&& element : get_iterator_range<int>(arr, {-105, 5})) assert(sub_array_3[i++] == element); @@ -164,9 +175,11 @@ void Average() constexpr bool Constexprness() { range<int> v{}; - get_iterator_range(v.bounds, v); - make_range(v.bounds); - reverse_range(v.bounds); + range<int*> vitr{}; + (void)get_iterator_range(v.bounds, v); + (void)make_range(v.bounds); + (void)reverse_range(v.bounds); + (void)reverse(vitr); auto itr = v.bounds.begin(); advance_vector(itr,itr,itr); advance_vector(itr,itr,itr,itr); diff --git a/unit_tests/range.cpp b/unit_tests/range.cpp index c5d3df3..3851611 100644 --- a/unit_tests/range.cpp +++ b/unit_tests/range.cpp @@ -127,10 +127,23 @@ void SubRange() range sub_rng_2{5, 9}; range sub_rng_3{0, 5}; - assert( sub_rng == rng.sub_range(make_range(3, 8)) ); - assert( sub_rng_2 == rng.sub_range(make_range(5, 800)) ); - assert( sub_rng_3 == rng.sub_range(make_range(-105, 5)) ); - assert( rng == rng.sub_range(make_range(-105, 105)) ); + assert( sub_rng == rng.sub_range(range{3, 8}) ); + assert( sub_rng_2 == rng.sub_range(range{5, 800}) ); + assert( sub_rng_3 == rng.sub_range(range{-105, 5}) ); + assert( rng == rng.sub_range(range{-105, 105}) ); + + auto limit = range<int>::limit(); + range inc{-1,1}; + + assert( inc == inc.sub_range(limit) ); + + range near_limit {limit.upper(), limit.upper()}; + near_limit -= 100; + near_limit.upper() += 50; + range overflow {25, 125}; + range sub_near_limit = near_limit; + sub_near_limit.lower() += 25; + assert( sub_near_limit == near_limit.sub_range(overflow) ); } template <typename Larger, typename Smaller> @@ -256,7 +269,7 @@ constexpr bool Constexprness() v.overlaps(v); v.intersects_lower(i); v.intersects_upper(i); - v.sub_range(v); + (void)v.sub_range(v); v += 1; v = v+1; v -= 1; -- GitLab