Add enumerate.

This commit is contained in:
Sergey Magidovich 2015-12-21 15:15:24 +03:00 committed by Sergey Yershov
parent 7b334ef200
commit db00bcfdee
4 changed files with 143 additions and 0 deletions

View file

@ -40,6 +40,7 @@ HEADERS += \
cancellable.hpp \
condition.hpp \
const_helper.hpp \
enumerate.hpp \
exception.hpp \
internal/message.hpp \
limited_priority_queue.hpp \

View file

@ -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 \

View file

@ -0,0 +1,39 @@
#include "testing/testing.hpp"
#include "base/enumerate.hpp"
#include "std/map.hpp"
#include "std/vector.hpp"
UNIT_TEST(enumerate)
{
{
map<size_t, int> result;
for (auto const p : my::enumerate(std::vector<int>{1, 2, 3}))
result.insert(p);
TEST_EQUAL(result, (map<size_t, int>{{0, 1}, {1, 2}, {2, 3}}), ());
}
{
map<size_t, int> result;
for (auto const p : my::enumerate(std::vector<int>{1, 2, 3}, 10))
result.insert(p);
TEST_EQUAL(result, (map<size_t, int>{{10, 1}, {11, 2}, {12, 3}}), ());
}
{
std::vector<int> const vec{1, 2, 3};
map<size_t, int> result;
for (auto const p : my::enumerate(vec))
result.insert(p);
TEST_EQUAL(result, (map<size_t, int>{{0, 1}, {1, 2}, {2, 3}}), ());
}
{
std::vector<int> vec{1, 2, 3, 4, 5, 6};
for (auto const p : my::enumerate(vec, -6))
p.item *= p.index;
TEST_EQUAL(vec, (std::vector<int>{-6, -10, -12, -12, -10, -6}), ());
}
}

102
base/enumerate.hpp Normal file
View file

@ -0,0 +1,102 @@
#pragma once
#include "std/iterator.hpp"
#include "std/utility.hpp"
namespace my
{
namespace details
{
template <typename TCollection>
struct const_respective_iterator
{
using hint = int;
using type = typename TCollection::iterator;
};
template <typename TCollection>
struct const_respective_iterator<TCollection const>
{
using hint = double;
using type = typename TCollection::const_iterator;
};
template <typename TCollection>
using const_respective_iterator_t =
typename const_respective_iterator<typename std::remove_reference<TCollection>::type>::type;
} // namespace details
template <typename TCounter, typename TElement>
struct IndexedElement : std::pair<TCounter, TElement>
{
using base = std::pair<TCounter, TElement>;
using base::base;
TCounter const index{base::first};
TElement & item{base::second};
};
template <typename TCounter, typename TElement>
IndexedElement<TCounter, TElement> MakeIndexedElement(TElement && item, TCounter counter = {})
{
return IndexedElement<TCounter, TElement>(counter, item);
}
template <typename TIterator, typename TCounter>
struct EnumeratingIterator
{
using original_iterator = TIterator;
using original_reference = typename std::iterator_traits<original_iterator>::reference;
using difference_type = typename std::iterator_traits<original_iterator>::difference_type;
using value_type = IndexedElement<TCounter, original_reference>;
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 <typename TIterator, typename TCounter>
struct EnumeratorWrapper
{
using original_iterator = TIterator;
using iterator = EnumeratingIterator<original_iterator, TCounter>;
using value_type = typename std::iterator_traits<iterator>::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 <typename TCollection, typename TCounter = size_t>
auto enumerate(TCollection && collection, TCounter const counter = {})
-> EnumeratorWrapper<details::const_respective_iterator_t<TCollection>, TCounter>
{
return {begin(collection), end(collection), counter};
}
} // namespace my