Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
3
 * It is copyright by its individual contributors, as recorded in the
4
 * project's Git history.  See COPYING.txt at the top level for license
5
 * terms and a link to the Git history.
6
 */
7
#pragma once
8
 
9
#include <inttypes.h>
10
#include <iterator>
11
#include "dxxsconf.h"
12
#include "partial_range.h"
13
#include "ephemeral_range.h"
14
#include <tuple>
15
#include <type_traits>
16
 
17
/*
18
 * This could have been done using a std::pair, but using a custom type
19
 * allows for more descriptive member names.
20
 */
21
template <typename range_value_type, typename index_type>
22
struct enumerated_value
23
{
24
        range_value_type value;
25
        const index_type idx;
26
};
27
 
28
namespace d_enumerate {
29
 
30
namespace detail {
31
 
32
template <typename result_type, typename index_type>
33
struct adjust_iterator_dereference_type : std::false_type
34
{
35
        using value_type = enumerated_value<result_type, index_type>;
36
};
37
 
38
template <typename... T, typename index_type>
39
struct adjust_iterator_dereference_type<std::tuple<T...>, index_type> : std::true_type
40
{
41
        using value_type = std::tuple<index_type, T...>;
42
};
43
 
44
}
45
 
46
}
47
 
48
template <typename range_iterator_type, typename index_type, typename iterator_dereference_type>
49
class enumerated_iterator
50
{
51
        range_iterator_type m_iter;
52
        index_type m_idx;
53
        using adjust_iterator_dereference_type = d_enumerate::detail::adjust_iterator_dereference_type<typename std::remove_cv<iterator_dereference_type>::type, index_type>;
54
public:
55
        using iterator_category = std::forward_iterator_tag;
56
        using value_type = typename adjust_iterator_dereference_type::value_type;
57
        using difference_type = std::ptrdiff_t;
58
        using pointer = value_type *;
59
        using reference = value_type &;
60
        enumerated_iterator(const range_iterator_type &iter, const index_type idx) :
61
                m_iter(iter), m_idx(idx)
62
        {
63
        }
64
        value_type operator*() const
65
        {
66
                if constexpr (adjust_iterator_dereference_type::value)
67
                        return std::tuple_cat(std::tuple<index_type>(m_idx), *m_iter);
68
                else
69
                        return {*m_iter, m_idx};
70
        }
71
        enumerated_iterator &operator++()
72
        {
73
                ++ m_iter;
74
                ++ m_idx;
75
                return *this;
76
        }
77
        bool operator!=(const enumerated_iterator &i) const
78
        {
79
                return m_iter != i.m_iter;
80
        }
81
        bool operator==(const enumerated_iterator &i) const
82
        {
83
                return m_iter == i.m_iter;
84
        }
85
};
86
 
87
template <typename range_iterator_type, typename index_type>
88
class enumerate : partial_range_t<range_iterator_type>
89
{
90
        using base_type = partial_range_t<range_iterator_type>;
91
        using iterator_dereference_type = decltype(*std::declval<range_iterator_type>());
92
        using enumerated_iterator_type = enumerated_iterator<
93
                range_iterator_type,
94
                index_type,
95
                iterator_dereference_type>;
96
        const index_type m_idx;
97
public:
98
        using range_owns_iterated_storage = std::false_type;
99
        enumerate(const range_iterator_type b, const range_iterator_type e, const index_type i) :
100
                base_type(b, e), m_idx(i)
101
        {
102
        }
103
        template <typename range_type>
104
                enumerate(range_type &&t, const index_type i = 0) :
105
                        base_type(t), m_idx(i)
106
        {
107
                static_assert(!any_ephemeral_range<range_type &&>::value, "cannot enumerate storage of ephemeral ranges");
108
                static_assert(std::is_rvalue_reference<range_type &&>::value || std::is_lvalue_reference<iterator_dereference_type>::value, "lvalue range must produce lvalue reference enumerated_value");
109
        }
110
        enumerated_iterator_type begin() const
111
        {
112
                return enumerated_iterator_type(this->base_type::begin(), m_idx);
113
        }
114
        enumerated_iterator_type end() const
115
        {
116
                return enumerated_iterator_type(this->base_type::end(), 0 /* unused */);
117
        }
118
};
119
 
120
template <typename range_type, typename index_type = uint_fast32_t, typename range_iterator_type = decltype(std::begin(std::declval<range_type &>()))>
121
enumerate(range_type &&r, const index_type start = index_type(/* value ignored */)) -> enumerate<range_iterator_type, index_type>;