1#pragma once
2
3#include <ext/size.h>
4#include <type_traits>
5#include <utility>
6#include <iterator>
7
8
9/** \brief Provides a wrapper view around a container, allowing to iterate over it's elements and indices.
10 * Allow writing code like shown below:
11 *
12 * std::vector<T> v = getVector();
13 * for (const std::pair<const std::size_t, T &> index_and_value : ext::enumerate(v))
14 * std::cout << "element " << index_and_value.first << " is " << index_and_value.second << std::endl;
15 */
16namespace ext
17{
18 template <typename It> struct enumerate_iterator
19 {
20 using traits = typename std::iterator_traits<It>;
21 using iterator_category = typename traits::iterator_category;
22 using value_type = std::pair<const std::size_t, typename traits::value_type>;
23 using difference_type = typename traits::difference_type;
24 using reference = std::pair<const std::size_t, typename traits::reference>;
25
26 std::size_t idx;
27 It it;
28
29 enumerate_iterator(const std::size_t idx_, It it_) : idx{idx_}, it{it_} {}
30
31 auto operator*() const { return reference(idx, *it); }
32
33 bool operator!=(const enumerate_iterator & other) const { return it != other.it; }
34
35 enumerate_iterator & operator++() { return ++idx, ++it, *this; }
36 };
37
38 template <typename Collection> struct enumerate_wrapper
39 {
40 using underlying_iterator = decltype(std::begin(std::declval<Collection &>()));
41 using iterator = enumerate_iterator<underlying_iterator>;
42
43 Collection & collection;
44
45 enumerate_wrapper(Collection & collection_) : collection(collection_) {}
46
47 auto begin() { return iterator(0, std::begin(collection)); }
48 auto end() { return iterator(ext::size(collection), std::end(collection)); }
49 };
50
51 template <typename Collection> auto enumerate(Collection & collection)
52 {
53 return enumerate_wrapper<Collection>{collection};
54 }
55
56 template <typename Collection> auto enumerate(const Collection & collection)
57 {
58 return enumerate_wrapper<const Collection>{collection};
59 }
60}
61