1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2 
3 #if !defined(CPPLINQ_LINQ_ITERATORS_HPP)
4 #define CPPLINQ_LINQ_ITERATORS_HPP
5 #pragma once
6 
7 #include <cstddef>
8 
9 namespace cpplinq {
10 
11     // if a member, provides the straightforward implementation of various redundant operators. For example,
12     //   providing -> for any iterator providing *, and so forth.
13     struct use_default_iterator_operators {};
14 
15     #define CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS \
16     operator ::cpplinq::use_default_iterator_operators() const { return ::cpplinq::use_default_iterator_operators(); }
17 
18     template <class Iter>
19     typename std::enable_if<
20         std::is_convertible<Iter, use_default_iterator_operators>::value,
21         Iter
22         >::type
operator +(const Iter & it,typename std::iterator_traits<Iter>::distance_type n)23     operator+(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) {
24         return it += n;
25     }
26     template <class Iter>
27     typename std::enable_if<
28         std::is_convertible<Iter, use_default_iterator_operators>::value,
29         Iter
30         >::type
operator -(const Iter & it,typename std::iterator_traits<Iter>::distance_type n)31     operator-(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) {
32         return it -= n;
33     }
34     template <class Iter>
35     typename std::enable_if<
36         std::is_convertible<Iter, use_default_iterator_operators>::value,
37         Iter
38         >::type
operator -=(const Iter & it,typename std::iterator_traits<Iter>::distance_type n)39     operator-=(const Iter& it, typename std::iterator_traits<Iter>::distance_type n) {
40         return it += (-n);
41     }
42 
43     template <class Iter>
44     typename std::enable_if<
45         std::is_convertible<Iter, use_default_iterator_operators>::value,
46         bool
47         >::type
operator !=(const Iter & it,const Iter & it2)48     operator!=(const Iter& it, const Iter& it2) {
49         return !(it == it2);
50     }
51     template <class Iter>
52     typename std::enable_if<
53         std::is_convertible<Iter, use_default_iterator_operators>::value,
54         bool
55         >::type
operator >(const Iter & it,const Iter & it2)56     operator>(const Iter& it, const Iter& it2) {
57         return it2 < it;
58     }
59     template <class Iter>
60     typename std::enable_if<
61         std::is_convertible<Iter, use_default_iterator_operators>::value,
62         bool
63         >::type
operator <=(const Iter & it,const Iter & it2)64     operator<=(const Iter& it, const Iter& it2) {
65         return !(it2 < it);
66     }
67     template <class Iter>
68     typename std::enable_if<
69         std::is_convertible<Iter, use_default_iterator_operators>::value,
70         bool
71         >::type
operator >=(const Iter & it,const Iter & it2)72     operator>=(const Iter& it, const Iter& it2) {
73         return !(it < it2);
74     }
75 
76     namespace util {
77         template <class Iter, class T>
deref_iterator(const Iter & it)78         typename std::iterator_traits<Iter>::pointer deref_iterator(const Iter& it) {
79             return deref_iterator(it, util::identity<typename std::iterator_traits<Iter>::reference>());
80         }
81 
82         template <class Iter, class T>
deref_iterator(const Iter & it,util::identity<T &>)83         T* deref_iterator(const Iter& it, util::identity<T&>) {
84             return &*it;
85         }
86 
87         template <class Iter, class T>
deref_iterator(const Iter & it,util::identity<T>)88         util::value_ptr<T> deref_iterator(const Iter& it, util::identity<T>) {
89             return util::value_ptr<T>(*it);
90         }
91     }
92 
93 
94     template <class Iter>
95     class iter_range
96     {
97         Iter start, finish;
98     public:
99 
100         CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS
101 
102         typedef Iter iterator;
103         typedef typename iterator::value_type value_type;
104 
iter_range(Iter start,Iter finish)105         explicit iter_range(Iter start, Iter finish) : start(start), finish(finish) {}
begin() const106         iterator begin() const { return start; }
end() const107         iterator end() const { return finish; }
108     };
109     template <class Iter>
make_range(Iter start,Iter finish)110     iter_range<Iter> make_range(Iter start, Iter finish) {
111         return iter_range<Iter>(start, finish);
112     }
113 
114     // decays into a onepass/forward iterator
115     template <class Cursor>
116     class cursor_iterator
117         : public std::iterator<std::forward_iterator_tag,
118                 typename Cursor::element_type,
119                 std::ptrdiff_t,
120                 typename std::conditional<std::is_reference<typename Cursor::reference_type>::value,
121                                           typename std::add_pointer<typename Cursor::element_type>::type,
122                                           util::value_ptr<typename Cursor::element_type>>::type,
123                 typename Cursor::reference_type>
124     {
125     public:
126         CPPLINQ_USE_DEFAULT_ITERATOR_OPERATORS;
127 
cursor_iterator(Cursor cur)128         cursor_iterator(Cursor cur) : cur(cur) {
129         }
130 
cursor_iterator()131         cursor_iterator() : cur() {
132         }
133 
operator ==(const cursor_iterator & other) const134         bool operator==(const cursor_iterator& other) const {
135             return !cur && !other.cur;
136         }
137 
operator *() const138         typename Cursor::reference_type operator*() const {
139             return cur->get();
140         }
141 
operator ->() const142         typename cursor_iterator::pointer operator->() const {
143             auto& v = **this;
144             return &v;
145         }
146 
operator ++()147         cursor_iterator& operator++() {
148             cur->inc();
149 
150             if (cur->empty()) { cur.reset(); }
151             return *this;
152         }
153 
operator +=(std::ptrdiff_t n)154         cursor_iterator& operator+=(std::ptrdiff_t n) {
155             cur->skip(n);
156 
157             if (cur->empty()) { cur.reset(); }
158             return *this;
159         }
160 
161 
162 
163     private:
empty() const164         bool empty() const {
165             !cur || cur->empty();
166         }
167 
168         util::maybe<Cursor> cur;
169     };
170 
171     template <class Container>
172     class container_range
173     {
174         Container c;
175 
176     public:
177         typedef cursor_iterator<typename Container::cursor> iterator;
178 
container_range(Container c)179         container_range(Container c) : c(c)
180         {
181         }
182 
begin() const183         iterator begin() const
184         {
185             return iterator(c.get_cursor());
186         }
187 
end() const188         iterator end() const
189         {
190             return iterator();
191         }
192     };
193 
194 }
195 
196 #endif
197