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