summaryrefslogtreecommitdiff
path: root/Ix/CPP/src/cpplinq/linq_iterators.hpp
blob: 3472281b7b1071471d309c49c301537f19c60317 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

#if !defined(CPPLINQ_LINQ_ITERATORS_HPP)
#define CPPLINQ_LINQ_ITERATORS_HPP
#pragma once

#include <cstddef>

namespace cpplinq {

    // if a member, provides the straightforward implementation of various redundant operators. For example,
    //   providing -> for any iterator providing *, and so forth.
    struct use_default_iterator_operators {};

    #define CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS \
    operator ::cpplinq::use_default_iterator_operators() const { return ::cpplinq::use_default_iterator_operators(); }

    template <class Iter>
    typename std::enable_if<
        std::is_convertible<Iter, use_default_iterator_operators>::value,
        Iter
        >::type
    operator+(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) {
        return it += n;
    }
    template <class Iter>
    typename std::enable_if<
        std::is_convertible<Iter, use_default_iterator_operators>::value,
        Iter
        >::type
    operator-(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) {
        return it -= n;
    }
    template <class Iter>
    typename std::enable_if<
        std::is_convertible<Iter, use_default_iterator_operators>::value,
        Iter
        >::type
    operator-=(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) {
        return it += (-n);
    }

    template <class Iter>
    typename std::enable_if<
        std::is_convertible<Iter, use_default_iterator_operators>::value,
        bool
        >::type
    operator!=(const Iter& it, const Iter& it2) {
        return !(it == it2);
    }
    template <class Iter>
    typename std::enable_if<
        std::is_convertible<Iter, use_default_iterator_operators>::value,
        bool
        >::type
    operator>(const Iter& it, const Iter& it2) {
        return it2 < it;
    }
    template <class Iter>
    typename std::enable_if<
        std::is_convertible<Iter, use_default_iterator_operators>::value,
        bool
        >::type
    operator<=(const Iter& it, const Iter& it2) {
        return !(it2 < it);
    }
    template <class Iter>
    typename std::enable_if<
        std::is_convertible<Iter, use_default_iterator_operators>::value,
        bool
        >::type
    operator>=(const Iter& it, const Iter& it2) {
        return !(it < it2);
    }   
    
    namespace util {
        template <class Iter, class T>
        typename std::iterator_traits<Iter>::pointer deref_iterator(const Iter& it) {
            return deref_iterator(it, util::identity<typename std::iterator_traits<Iter>::reference>());
        }

        template <class Iter, class T>
        T* deref_iterator(const Iter& it, util::identity<T&>) {
            return &*it;
        }

        template <class Iter, class T>
        util::value_ptr<T> deref_iterator(const Iter& it, util::identity<T>) {
            return util::value_ptr<T>(*it);
        }
    } 
    
    
    template <class Iter>
    class iter_range
    {
        Iter start, finish;
    public:

        CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS

        typedef Iter iterator;
        typedef typename iterator::value_type value_type;

        explicit iter_range(Iter start, Iter finish) : start(start), finish(finish) {}
        iterator begin() const { return start; }
        iterator end() const { return finish; }
    };
    template <class Iter>
    iter_range<Iter> make_range(Iter start, Iter finish) {
        return iter_range<Iter>(start, finish);
    }

    // decays into a onepass/forward iterator
    template <class Cursor>
    class cursor_iterator 
        : public std::iterator<std::forward_iterator_tag, 
                typename Cursor::element_type,
                std::ptrdiff_t,
                typename std::conditional<std::is_reference<typename Cursor::reference_type>::value,
                                          typename std::add_pointer<typename Cursor::element_type>::type,
                                          util::value_ptr<typename Cursor::element_type>>::type,
                typename Cursor::reference_type>
    {
    public:
        CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS;

        cursor_iterator(Cursor cur) : cur(cur) {
        }

        cursor_iterator() : cur() {
        }

        bool operator==(const cursor_iterator& other) const {
            return !cur && !other.cur;
        }

        typename Cursor::reference_type operator*() const {
            return cur->get();
        }

        typename cursor_iterator::pointer operator->() const {
            auto& v = **this;
            return &v;
        }
        
        cursor_iterator& operator++() {
            cur->inc();

            if (cur->empty()) { cur.reset(); }
            return *this;
        }

        cursor_iterator& operator+=(std::ptrdiff_t n) {
            cur->skip(n);

            if (cur->empty()) { cur.reset(); }
            return *this;
        }


        
    private:
        bool empty() const {
            !cur || cur->empty();
        }

        util::maybe<Cursor> cur;
    };

    template <class Container>
    class container_range
    {
        Container c;

    public:
        typedef cursor_iterator<typename Container::cursor> iterator;

        container_range(Container c) : c(c) 
        {
        }

        iterator begin() const
        {
            return iterator(c.get_cursor());
        }

        iterator end() const
        {
            return iterator();
        }
    };

}

#endif