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 | */ |
16 | namespace 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 | |