diff --git a/base/base.pro b/base/base.pro index df72d751d2..e9dc2f3a1c 100644 --- a/base/base.pro +++ b/base/base.pro @@ -40,6 +40,7 @@ HEADERS += \ cancellable.hpp \ condition.hpp \ const_helper.hpp \ + enumerate.hpp \ exception.hpp \ internal/message.hpp \ limited_priority_queue.hpp \ diff --git a/base/base_tests/base_tests.pro b/base/base_tests/base_tests.pro index 07b397a618..257cca190f 100644 --- a/base/base_tests/base_tests.pro +++ b/base/base_tests/base_tests.pro @@ -19,6 +19,7 @@ SOURCES += \ condition_test.cpp \ const_helper.cpp \ containers_test.cpp \ + enumerate_test.cpp \ logging_test.cpp \ math_test.cpp \ matrix_test.cpp \ diff --git a/base/base_tests/enumerate_test.cpp b/base/base_tests/enumerate_test.cpp new file mode 100644 index 0000000000..77c608b6b5 --- /dev/null +++ b/base/base_tests/enumerate_test.cpp @@ -0,0 +1,39 @@ +#include "testing/testing.hpp" + +#include "base/enumerate.hpp" + +#include "std/map.hpp" +#include "std/vector.hpp" + +UNIT_TEST(enumerate) +{ + { + map result; + for (auto const p : my::enumerate(std::vector{1, 2, 3})) + result.insert(p); + TEST_EQUAL(result, (map{{0, 1}, {1, 2}, {2, 3}}), ()); + } + + { + map result; + for (auto const p : my::enumerate(std::vector{1, 2, 3}, 10)) + result.insert(p); + TEST_EQUAL(result, (map{{10, 1}, {11, 2}, {12, 3}}), ()); + } + + { + std::vector const vec{1, 2, 3}; + map result; + for (auto const p : my::enumerate(vec)) + result.insert(p); + TEST_EQUAL(result, (map{{0, 1}, {1, 2}, {2, 3}}), ()); + } + + { + std::vector vec{1, 2, 3, 4, 5, 6}; + for (auto const p : my::enumerate(vec, -6)) + p.item *= p.index; + + TEST_EQUAL(vec, (std::vector{-6, -10, -12, -12, -10, -6}), ()); + } +} diff --git a/base/enumerate.hpp b/base/enumerate.hpp new file mode 100644 index 0000000000..eaf3b61ad3 --- /dev/null +++ b/base/enumerate.hpp @@ -0,0 +1,102 @@ +#pragma once + +#include "std/iterator.hpp" +#include "std/utility.hpp" + +namespace my +{ +namespace details +{ +template +struct const_respective_iterator +{ + using hint = int; + using type = typename TCollection::iterator; +}; + +template +struct const_respective_iterator +{ + using hint = double; + using type = typename TCollection::const_iterator; +}; + +template +using const_respective_iterator_t = + typename const_respective_iterator::type>::type; +} // namespace details + +template +struct IndexedElement : std::pair +{ + using base = std::pair; + using base::base; + + TCounter const index{base::first}; + TElement & item{base::second}; +}; + +template +IndexedElement MakeIndexedElement(TElement && item, TCounter counter = {}) +{ + return IndexedElement(counter, item); +} + +template +struct EnumeratingIterator +{ + using original_iterator = TIterator; + using original_reference = typename std::iterator_traits::reference; + + using difference_type = typename std::iterator_traits::difference_type; + using value_type = IndexedElement; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::forward_iterator_tag; + + EnumeratingIterator(original_iterator const it, TCounter const counter) + : m_iterator(it), m_counter(counter) + { + } + + EnumeratingIterator & operator++() + { + ++m_iterator; + ++m_counter; + return *this; + } + + value_type operator*() { return MakeIndexedElement(*m_iterator, m_counter); } + bool operator==(EnumeratingIterator const & it) const { return m_iterator == it.m_iterator; } + bool operator!=(EnumeratingIterator const & it) const { return !(*this == it); } + original_iterator m_iterator; + TCounter m_counter; +}; + +template +struct EnumeratorWrapper +{ + using original_iterator = TIterator; + using iterator = EnumeratingIterator; + using value_type = typename std::iterator_traits::value_type; + + EnumeratorWrapper(original_iterator const begin, original_iterator const end, + TCounter const countFrom) + : m_begin(begin), m_end(end), m_countFrom(countFrom) + { + } + + iterator begin() { return {m_begin, m_countFrom}; } + iterator end() { return {m_end, {}}; } + original_iterator const m_begin; + original_iterator const m_end; + TCounter const m_countFrom; +}; + +template +auto enumerate(TCollection && collection, TCounter const counter = {}) + -> EnumeratorWrapper, TCounter> +{ + return {begin(collection), end(collection), counter}; +} +} // namespace my