├── license-mit.txt ├── reduce.h ├── function_sequence.h ├── invertible_function_sequence.h ├── integer_interval.h ├── map.h ├── slice.h ├── filter.h ├── zip.h ├── readme.md ├── distinct_pairs.h └── product.h /license-mit.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Chris Welshman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /reduce.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Chris Welshman 2014 3 | */ 4 | #ifndef INCLUDED_REDUCE 5 | #define INCLUDED_REDUCE 6 | #include 7 | #include 8 | 9 | template 10 | inline auto reduce( Range&& c, F&& f ) { 11 | auto it = begin(c); 12 | auto e = end(c); 13 | std::decay_t x{}; 14 | if( it != e ) { 15 | x = *it; 16 | for(++it;it!=e;++it) { 17 | x = f(x,*it); 18 | } 19 | } 20 | return x; 21 | } 22 | 23 | template 24 | inline auto creduce( const Range& c, F&& f ) { 25 | auto it = cbegin(c); 26 | auto e = cend(c); 27 | std::decay_t x{}; 28 | if( it != e ) { 29 | x = *it; 30 | for(++it;it!=e;++it) { 31 | x = f(x,*it); 32 | } 33 | } 34 | return x; 35 | } 36 | 37 | template 38 | inline auto reduce( Range&& c, T x, F&& f ) { 39 | auto it = begin(c); 40 | auto e = end(c); 41 | if( it != e ) { 42 | x = *it; 43 | for(++it;it!=e;++it) { 44 | x = f(x,*it); 45 | } 46 | } 47 | return x; 48 | } 49 | 50 | template 51 | inline auto creduce( const Range& c, T x, F&& f ) { 52 | auto it = cbegin(c); 53 | auto e = cend(c); 54 | if( it != e ) { 55 | x = *it; 56 | for(++it;it!=e;++it) { 57 | x = f(x,*it); 58 | } 59 | } 60 | return x; 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /function_sequence.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_FUNCTION_SEQUENCE 2 | #define INCLUDED_FUNCTION_SEQUENCE 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct function_sequence_iterator { 9 | 10 | typedef typename std::result_of::type value_type; 11 | typedef const value_type& reference; 12 | typedef const value_type* pointer; 13 | 14 | typedef ptrdiff_t difference_type; 15 | typedef std::forward_iterator_tag iterator_category; 16 | typedef function_sequence_iterator iterator; 17 | 18 | explicit function_sequence_iterator( const F& f ) : f(f), infinity(true) {} 19 | 20 | function_sequence_iterator( const F& f, const State& state ) : f(f), state(state), infinity(false) { 21 | this->operator++(); 22 | } 23 | 24 | reference operator*() const { 25 | return value; 26 | } 27 | 28 | pointer operator->() const { 29 | return &value; 30 | } 31 | 32 | iterator& operator++() { 33 | value = f(state); 34 | return *this; 35 | } 36 | 37 | iterator operator++(int) { 38 | iterator temp = *this; 39 | ++(*this); 40 | return temp; 41 | } 42 | 43 | iterator& operator--() { 44 | value = inverse(state); 45 | return *this; 46 | } 47 | 48 | iterator operator--(int) { 49 | iterator temp = *this; 50 | --(*this); 51 | return temp; 52 | } 53 | 54 | iterator& operator+=( difference_type offset ) { 55 | for(difference_type i=0;ioffset;--i) 58 | --(*this); 59 | return *this; 60 | } 61 | 62 | iterator operator+( difference_type offset ) const { 63 | iterator temp = *this; 64 | return temp += offset; 65 | } 66 | 67 | iterator& operator-=( difference_type offset ) { 68 | return *this += -offset; 69 | } 70 | 71 | iterator operator-( difference_type offset ) const { 72 | iterator temp = *this; 73 | return temp -= offset; 74 | } 75 | 76 | reference operator[]( difference_type offset ) const { 77 | return *(*this + offset); 78 | } 79 | 80 | bool operator==( const iterator& rhs ) const { 81 | return infinity == rhs.infinity && ( infinity || state == rhs.state ); 82 | } 83 | 84 | bool operator!=( const iterator& rhs ) const { 85 | return !(*this == rhs); 86 | } 87 | 88 | protected: 89 | 90 | F f; 91 | State state; 92 | value_type value; 93 | bool infinity; 94 | }; 95 | 96 | template 97 | struct function_sequence_range { 98 | 99 | typedef typename std::result_of::type value_type; 100 | typedef const value_type& reference; 101 | typedef const value_type* pointer; 102 | 103 | typedef ptrdiff_t difference_type; 104 | typedef std::forward_iterator_tag iterator_category; 105 | typedef function_sequence_iterator iterator; 106 | typedef std::reverse_iterator reverse_iterator; 107 | 108 | function_sequence_range( F&& f, const State& initial ) : f(f), initial(initial) {} 109 | 110 | iterator begin() const { 111 | return iterator( f, initial ); 112 | } 113 | 114 | iterator end() const { 115 | return iterator(f); 116 | } 117 | 118 | protected: 119 | F f; 120 | State initial; 121 | }; 122 | 123 | template 124 | function_sequence_range function_sequence( State&& initial, F&& f ) { 125 | return function_sequence_range( std::forward(f), std::forward(initial) ); 126 | } 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /invertible_function_sequence.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_INVERTIBLE_FUNCTION_SEQUENCE 2 | #define INCLUDED_INVERTIBLE_FUNCTION_SEQUENCE 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct invertible_function_sequence_iterator { 9 | 10 | typedef typename std::result_of::type value_type; 11 | typedef const value_type& reference; 12 | typedef const value_type* pointer; 13 | 14 | typedef ptrdiff_t difference_type; 15 | typedef std::bidirectional_iterator_tag iterator_category; 16 | typedef invertible_function_sequence_iterator iterator; 17 | 18 | invertible_function_sequence_iterator( const F& f, const Finverse& inverse ) : f(f), inverse(inverse), infinity(true) {} 19 | 20 | invertible_function_sequence_iterator( const F& f, const Finverse& inverse, const State& state ) : f(f), inverse(inverse), state(state), infinity(false) { 21 | this->operator++(); 22 | } 23 | 24 | reference operator*() const { 25 | return value; 26 | } 27 | 28 | pointer operator->() const { 29 | return &value; 30 | } 31 | 32 | iterator& operator++() { 33 | value = f(state); 34 | return *this; 35 | } 36 | 37 | iterator operator++(int) { 38 | iterator temp = *this; 39 | ++(*this); 40 | return temp; 41 | } 42 | 43 | iterator& operator--() { 44 | value = inverse(state); 45 | return *this; 46 | } 47 | 48 | iterator operator--(int) { 49 | iterator temp = *this; 50 | --(*this); 51 | return temp; 52 | } 53 | 54 | iterator& operator+=( difference_type offset ) { 55 | for(difference_type i=0;ioffset;--i) 58 | ++(*this); 59 | return *this; 60 | } 61 | 62 | iterator operator+( difference_type offset ) const { 63 | iterator temp = *this; 64 | return temp += offset; 65 | } 66 | 67 | iterator& operator-=( difference_type offset ) { 68 | return *this += -offset; 69 | } 70 | 71 | iterator operator-( difference_type offset ) const { 72 | iterator temp = *this; 73 | return temp -= offset; 74 | } 75 | 76 | reference operator[]( difference_type offset ) const { 77 | return *(*this + offset); 78 | } 79 | 80 | bool operator==( const iterator& rhs ) const { 81 | return infinity == rhs.infinity && ( infinity || state == rhs.state ); 82 | } 83 | 84 | bool operator!=( const iterator& rhs ) const { 85 | return !(*this == rhs); 86 | } 87 | 88 | protected: 89 | 90 | F f; 91 | Finverse inverse; 92 | State state; 93 | value_type value; 94 | bool infinity; 95 | }; 96 | 97 | template 98 | struct invertible_function_sequence_range { 99 | 100 | typedef typename std::result_of::type value_type; 101 | typedef const value_type& reference; 102 | typedef const value_type* pointer; 103 | 104 | typedef ptrdiff_t difference_type; 105 | typedef std::bidirectional_iterator_tag iterator_category; 106 | typedef invertible_function_sequence_iterator iterator; 107 | typedef std::reverse_iterator reverse_iterator; 108 | 109 | invertible_function_sequence_range( const F& f, const Finverse& inverse, const State& initial ) : f(f), inverse(inverse), initial(initial) {} 110 | 111 | iterator begin() const { 112 | return iterator( f, inverse, initial ); 113 | } 114 | 115 | iterator end() const { 116 | return iterator( f, inverse ); 117 | } 118 | 119 | protected: 120 | F f; 121 | Finverse inverse; 122 | State initial; 123 | }; 124 | 125 | template 126 | invertible_function_sequence_range invertible_function_sequence( State&& initial, F&& f, Finverse&& inverse ) { 127 | return invertible_function_sequence_range( 128 | std::forward(f), 129 | std::forward(inverse), 130 | std::forward(initial) 131 | ); 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /integer_interval.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Chris Welshman 2014 3 | */ 4 | #ifndef INCLUDED_INTEGER_INTERVAL 5 | #define INCLUDED_INTEGER_INTERVAL 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | struct integer_iterator { 12 | typedef T value_type; 13 | typedef typename std::make_signed_t difference_type; 14 | typedef value_type reference; 15 | typedef typename std::add_pointer_t pointer; 16 | typedef typename std::iterator_traits::iterator_category iterator_category; 17 | 18 | integer_iterator() = default; 19 | 20 | explicit integer_iterator( T value ) : value(value) {} 21 | 22 | value_type operator*() const { 23 | return value; 24 | } 25 | 26 | integer_iterator& operator++() { 27 | ++value; 28 | return *this; 29 | } 30 | 31 | integer_iterator operator++(int) { 32 | integer_iterator temp = *this; 33 | ++(*this); 34 | return temp; 35 | } 36 | 37 | integer_iterator& operator--() { 38 | --value; 39 | return *this; 40 | } 41 | 42 | integer_iterator operator--(int) { 43 | integer_iterator temp = *this; 44 | --(*this); 45 | return temp; 46 | } 47 | 48 | integer_iterator& operator+=( difference_type offset ) { 49 | value += offset; 50 | return *this; 51 | } 52 | 53 | integer_iterator operator+( difference_type offset ) const { 54 | integer_iterator temp = *this; 55 | return temp += offset; 56 | } 57 | 58 | integer_iterator& operator-=( difference_type offset ) { 59 | return *this += -offset; 60 | } 61 | 62 | integer_iterator operator-( difference_type offset ) const { 63 | integer_iterator temp = *this; 64 | return temp -= offset; 65 | } 66 | 67 | difference_type operator-( const integer_iterator& rhs ) const { 68 | return difference_type(value) - difference_type(rhs.value); 69 | } 70 | 71 | value_type operator[]( difference_type offset ) const { 72 | return *(*this + offset); 73 | } 74 | 75 | bool operator==( const integer_iterator& rhs ) const { 76 | return value == rhs.value; 77 | } 78 | 79 | bool operator!=( const integer_iterator& rhs ) const { 80 | return !(*this == rhs); 81 | } 82 | 83 | bool operator<( const integer_iterator& rhs ) const { 84 | return rhs - *this > 0; 85 | } 86 | 87 | bool operator>( const integer_iterator& rhs ) const { 88 | return rhs < *this; 89 | } 90 | 91 | bool operator<=( const integer_iterator& rhs ) const { 92 | return !( *this > rhs ); 93 | } 94 | 95 | bool operator>=( const integer_iterator& rhs ) const { 96 | return !( *this < rhs ); 97 | } 98 | 99 | protected: 100 | T value; 101 | }; 102 | 103 | template 104 | struct integer_interval_range { 105 | typedef T value_type; 106 | typedef typename std::make_signed_t difference_type; 107 | typedef integer_iterator iterator; 108 | typedef std::reverse_iterator reverse_iterator; 109 | typedef std::pair range_type; 110 | 111 | explicit integer_interval_range( range_type range ) : range(range) {} 112 | 113 | integer_interval_range( T lower, T upper ) : range(lower,upper) {} 114 | 115 | difference_type size() const { 116 | return difference_type(T(1) + range.second) - difference_type(range.first); 117 | } 118 | 119 | iterator begin() const { 120 | return iterator( range.first ); 121 | } 122 | 123 | iterator end() const { 124 | return iterator( range.second + T(1) ); 125 | } 126 | 127 | value_type lower() const { 128 | return range.first; 129 | } 130 | 131 | value_type upper() const { 132 | return range.second; 133 | } 134 | 135 | protected: 136 | range_type range; 137 | }; 138 | 139 | template 140 | inline auto integer_interval( T a, T b ) { 141 | return integer_interval_range( a, b ); 142 | } 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Chris Welshman 2014 3 | */ 4 | #ifndef INCLUDED_MAP 5 | #define INCLUDED_MAP 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | struct map_iterator { 12 | typedef typename std::iterator_traits::value_type original_value_type; 13 | typedef typename std::iterator_traits::difference_type difference_type; 14 | typedef typename std::iterator_traits::iterator_category iterator_category; 15 | typedef typename std::result_of::type value_type; 16 | typedef std::pair range_type; 17 | typedef const value_type* pointer; 18 | typedef value_type reference; 19 | 20 | map_iterator() = default; 21 | 22 | map_iterator( const F& f, const range_type& range ) : f(f), range(range), it(range.first) {} 23 | 24 | map_iterator( const F& f, const range_type& range, const Iterator& it ) : f(f), range(range), it(it) {} 25 | 26 | map_iterator( const F& f, const Iterator& first, const Iterator& last ) : map_iterator(f,range_type(first,last)) {} 27 | 28 | map_iterator( const F& f, const Iterator& first, const Iterator& last, const Iterator& it ) : map_iterator(f,range_type(first,last),it) {} 29 | 30 | value_type operator*() const { 31 | return f(*it); 32 | } 33 | 34 | map_iterator& operator++() { 35 | ++it; 36 | return *this; 37 | } 38 | 39 | map_iterator operator++(int) { 40 | map_iterator temp = *this; 41 | ++(*this); 42 | return temp; 43 | } 44 | 45 | map_iterator& operator--() { 46 | --it; 47 | return *this; 48 | } 49 | 50 | map_iterator operator--(int) { 51 | map_iterator temp = *this; 52 | --(*this); 53 | return temp; 54 | } 55 | 56 | map_iterator& operator+=( difference_type offset ) { 57 | it += offset; 58 | return *this; 59 | } 60 | 61 | map_iterator operator+( difference_type offset ) const { 62 | map_iterator temp = *this; 63 | return temp += offset; 64 | } 65 | 66 | map_iterator& operator-=( difference_type offset ) { 67 | return *this += -offset; 68 | } 69 | 70 | map_iterator operator-( difference_type offset ) const { 71 | map_iterator temp = *this; 72 | return temp -= offset; 73 | } 74 | 75 | difference_type operator-( const map_iterator& rhs ) const { 76 | return std::distance( rhs.it, it ); 77 | } 78 | 79 | value_type operator[]( difference_type offset ) const { 80 | return *(*this + offset); 81 | } 82 | 83 | difference_type index() const { 84 | return N = std::distance( range.first, it ); 85 | } 86 | 87 | bool operator==( const map_iterator& rhs ) const { 88 | return it == rhs.it; 89 | } 90 | 91 | bool operator!=( const map_iterator& rhs ) const { 92 | return !(*this == rhs); 93 | } 94 | 95 | bool operator<( const map_iterator& rhs ) const { 96 | return rhs - *this > 0; 97 | } 98 | 99 | bool operator>( const map_iterator& rhs ) const { 100 | return rhs < *this; 101 | } 102 | 103 | bool operator<=( const map_iterator& rhs ) const { 104 | return !( *this > rhs ); 105 | } 106 | 107 | bool operator>=( const map_iterator& rhs ) const { 108 | return !( *this < rhs ); 109 | } 110 | 111 | protected: 112 | range_type range; 113 | Iterator it; 114 | F f; 115 | }; 116 | 117 | template 118 | struct map_range { 119 | typedef typename std::iterator_traits::value_type original_value_type; 120 | typedef typename std::result_of::type value_type; 121 | typedef typename std::iterator_traits::difference_type difference_type; 122 | typedef Iterator original_iterator; 123 | typedef map_iterator iterator; 124 | typedef std::reverse_iterator reverse_iterator; 125 | typedef std::pair range_type; 126 | 127 | map_range( const F& f, const range_type& range ) : f(f), range(range) {} 128 | 129 | map_range( const F& f, const Iterator& first, const Iterator& last ) : map_range(f,range_type(first,last)) {} 130 | 131 | difference_type size() const { 132 | return std::distance( range.first, range.second ); 133 | } 134 | 135 | iterator begin() const { 136 | return iterator( f, range ); 137 | } 138 | 139 | iterator end() const { 140 | return iterator( f, range, range.second ); 141 | } 142 | 143 | protected: 144 | range_type range; 145 | F f; 146 | }; 147 | 148 | template 149 | inline map_range map( Iterator&& first, Iterator&& last, F&& f ) { 150 | return map_range( std::forward(f), 151 | std::make_pair( 152 | std::forward(first), 153 | std::forward(last) 154 | ) 155 | ); 156 | } 157 | 158 | template 159 | inline auto map( Range&& r, F&& f ) { 160 | return map( 161 | begin( std::forward(r) ), 162 | end( std::forward(r) ), 163 | std::forward(f) 164 | ); 165 | } 166 | 167 | template 168 | inline auto cmap( const Range& r, F&& f ) { 169 | return map( 170 | cbegin( r ), 171 | cend( r ), 172 | std::forward(f) 173 | ); 174 | } 175 | 176 | #endif 177 | -------------------------------------------------------------------------------- /slice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Chris Welshman 2014 3 | */ 4 | #ifndef INCLUDED_SLICE 5 | #define INCLUDED_SLICE 6 | #include 7 | #include 8 | 9 | template 10 | struct step_iterator { 11 | typedef typename std::iterator_traits::value_type original_value_type; 12 | typedef typename std::iterator_traits::reference original_reference; 13 | typedef typename std::iterator_traits::difference_type difference_type; 14 | typedef typename std::iterator_traits::iterator_category iterator_category; 15 | typedef original_value_type value_type; 16 | typedef original_reference reference; 17 | typedef Iterator pointer; 18 | typedef std::pair range_type; 19 | 20 | step_iterator() = default; 21 | 22 | explicit step_iterator( const Iterator& it ) : it(it), step(1) {} 23 | 24 | step_iterator( const Iterator& it, difference_type step ) : it(it), step(step) {} 25 | 26 | reference operator*() const { 27 | return *it; 28 | } 29 | 30 | pointer operator->() const { 31 | return it; 32 | } 33 | 34 | step_iterator& operator++() { 35 | for(difference_type i=0;i operator++(int) { 41 | step_iterator temp = *this; 42 | ++(*this); 43 | return temp; 44 | } 45 | 46 | step_iterator& operator--() { 47 | for(difference_type i=0;i operator--(int) { 53 | step_iterator temp = *this; 54 | --(*this); 55 | return temp; 56 | } 57 | 58 | step_iterator& operator+=( difference_type offset ) { 59 | it += offset * step; 60 | return *this; 61 | } 62 | 63 | step_iterator operator+( difference_type offset ) const { 64 | step_iterator temp = *this; 65 | return temp += offset; 66 | } 67 | 68 | step_iterator& operator-=( difference_type offset ) { 69 | return *this += -offset; 70 | } 71 | 72 | step_iterator operator-( difference_type offset ) const { 73 | step_iterator temp = *this; 74 | return temp -= offset; 75 | } 76 | 77 | difference_type operator-( const step_iterator& rhs ) const { 78 | return std::distance( rhs.it, it ) / step; 79 | } 80 | 81 | reference operator[]( difference_type offset ) const { 82 | return *(*this + offset); 83 | } 84 | 85 | bool operator==( const step_iterator& rhs ) const { 86 | return it == rhs.it; 87 | } 88 | 89 | bool operator!=( const step_iterator& rhs ) const { 90 | return !(*this == rhs); 91 | } 92 | 93 | bool operator<( const step_iterator& rhs ) const { 94 | return rhs - *this > 0; 95 | } 96 | 97 | bool operator>( const step_iterator& rhs ) const { 98 | return rhs < *this; 99 | } 100 | 101 | bool operator<=( const step_iterator& rhs ) const { 102 | return !( *this > rhs ); 103 | } 104 | 105 | bool operator>=( const step_iterator& rhs ) const { 106 | return !( *this < rhs ); 107 | } 108 | 109 | protected: 110 | difference_type step; 111 | Iterator it; 112 | }; 113 | 114 | template 115 | struct slice_range { 116 | typedef typename std::iterator_traits::value_type value_type; 117 | typedef typename std::iterator_traits::difference_type difference_type; 118 | typedef Iterator original_iterator; 119 | typedef step_iterator iterator; 120 | typedef std::reverse_iterator reverse_iterator; 121 | typedef std::pair range_type; 122 | 123 | slice_range( const range_type& range, difference_type skip, difference_type count, difference_type step ) : range(range), skip(skip), count(count), step(step) { 124 | difference_type N = std::distance( range.first, range.second ); 125 | count = std::min( N - skip, count ); 126 | } 127 | 128 | slice_range( const range_type& range, difference_type skip, difference_type count ) : slice_range(range,skip,count,1) {} 129 | 130 | slice_range( const range_type& range, difference_type count ) : slice_range(range,0,count,1) {} 131 | 132 | iterator begin() const { 133 | return iterator( range.first + skip, step ); 134 | } 135 | 136 | iterator end() const { 137 | return iterator( range.first + (skip + count), step ); 138 | } 139 | 140 | protected: 141 | range_type range; 142 | difference_type skip, count, step; 143 | }; 144 | 145 | template 146 | inline slice_range slice( Iterator&& first, Iterator&& last, uint32_t skip, uint32_t count, uint32_t step ) { 147 | return slice_range( 148 | std::make_pair( 149 | std::forward(first), 150 | std::forward(last) 151 | ), skip, count, step 152 | ); 153 | } 154 | 155 | template 156 | inline auto slice( Range&& r, uint32_t skip, uint32_t count, uint32_t step ) { 157 | return slice( 158 | begin( std::forward(r) ), 159 | end( std::forward(r) ), 160 | skip, count, step 161 | ); 162 | } 163 | 164 | template 165 | inline auto cslice( const Range& r, uint32_t skip, uint32_t count, uint32_t step ) { 166 | return slice( cbegin(r), cend(r), skip, count, step ); 167 | } 168 | 169 | template 170 | inline auto slice( Range&& r, uint32_t skip, uint32_t count ) { 171 | return slice( 172 | begin( std::forward(r) ), 173 | end( std::forward(r) ), 174 | skip, count, 1 175 | ); 176 | } 177 | 178 | template 179 | inline auto cslice( const Range& r, uint32_t skip, uint32_t count ) { 180 | return slice( cbegin(r), cend(r), skip, count, 1 ); 181 | } 182 | 183 | template 184 | inline auto slice( Range&& r, uint32_t count ) { 185 | return slice( 186 | begin( std::forward(r) ), 187 | end( std::forward(r) ), 188 | 0, count, 1 189 | ); 190 | } 191 | 192 | template 193 | inline auto cslice( const Range& r, uint32_t count ) { 194 | return slice( cbegin(r), cend(r), 0, count, 1 ); 195 | } 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /filter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Chris Welshman 2014 3 | */ 4 | #ifndef INCLUDED_FILTER 5 | #define INCLUDED_FILTER 6 | #include 7 | #include 8 | 9 | template 10 | struct filter_range; 11 | 12 | template 13 | struct filter_iterator { 14 | typedef typename std::iterator_traits::value_type original_value_type; 15 | typedef typename std::iterator_traits::reference original_reference; 16 | typedef typename std::iterator_traits::difference_type difference_type; 17 | typedef typename std::iterator_traits::iterator_category iterator_category; 18 | typedef original_value_type value_type; 19 | typedef original_reference reference; 20 | typedef Iterator pointer; 21 | typedef std::pair range_type; 22 | 23 | filter_iterator() = default; 24 | 25 | filter_iterator( const F& f, const range_type& r ) : f(f), range(r) { 26 | if( range.first != range.second ) { 27 | while( !f(*range.first) ) { 28 | ++range.first; 29 | if( range.first == range.second ) break; 30 | } 31 | } 32 | if( range.first != range.second ) { 33 | do { 34 | --range.second; 35 | if( f(*range.second) ) { 36 | ++range.second; 37 | break; 38 | } 39 | } while( range.first != range.second ); 40 | } 41 | it = range.first; 42 | } 43 | 44 | filter_iterator( const F& f, const range_type& range, const Iterator& i ) : filter_iterator(f,range) { 45 | it = i; 46 | } 47 | 48 | filter_iterator( const F& f, const Iterator& first, const Iterator& last ) : filter_iterator(f,range_type(first,last)) {} 49 | 50 | filter_iterator( const F& f, const Iterator& first, const Iterator& last, const Iterator& it ) : filter_iterator(f,range_type(first,last),it) {} 51 | 52 | reference operator*() const { 53 | return *it; 54 | } 55 | 56 | pointer operator->() const { 57 | return it; 58 | } 59 | 60 | filter_iterator& operator++() { 61 | do { 62 | ++it; 63 | if( it == range.second ) break; 64 | } while( !f(*it) ); 65 | return *this; 66 | } 67 | 68 | filter_iterator operator++(int) { 69 | filter_iterator temp = *this; 70 | ++(*this); 71 | return temp; 72 | } 73 | 74 | filter_iterator& operator--() { 75 | do { 76 | --it; 77 | } while( !f(*it) ); 78 | return *this; 79 | } 80 | 81 | filter_iterator operator--(int) { 82 | filter_iterator temp = *this; 83 | --(*this); 84 | return temp; 85 | } 86 | 87 | filter_iterator& operator+=( difference_type offset ) { 88 | for(;offset>0;--offset) { 89 | ++*this; 90 | } 91 | for(;offset<0;++offset) { 92 | --*this; 93 | } 94 | return *this; 95 | } 96 | 97 | filter_iterator operator+( difference_type offset ) const { 98 | filter_iterator temp = *this; 99 | return temp += offset; 100 | } 101 | 102 | filter_iterator& operator-=( difference_type offset ) { 103 | return *this += -offset; 104 | } 105 | 106 | filter_iterator operator-( difference_type offset ) const { 107 | filter_iterator temp = *this; 108 | return temp -= offset; 109 | } 110 | 111 | difference_type operator-( const filter_iterator& rhs ) const { 112 | difference_type N = std::distance( rhs.it, it ); 113 | difference_type r = 0; 114 | Iterator temp = it; 115 | for(difference_type i=0;iN;--i) { 121 | if( f(*temp) ) 122 | ++r; 123 | --temp; 124 | } 125 | return r; 126 | } 127 | 128 | reference operator[]( difference_type offset ) const { 129 | return *(*this + offset); 130 | } 131 | 132 | bool operator==( const filter_iterator& rhs ) const { 133 | return it == rhs.it; 134 | } 135 | 136 | bool operator!=( const filter_iterator& rhs ) const { 137 | return !(*this == rhs); 138 | } 139 | 140 | bool operator<( const filter_iterator& rhs ) const { 141 | return rhs - *this > 0; 142 | } 143 | 144 | bool operator>( const filter_iterator& rhs ) const { 145 | return rhs < *this; 146 | } 147 | 148 | bool operator<=( const filter_iterator& rhs ) const { 149 | return !( *this > rhs ); 150 | } 151 | 152 | bool operator>=( const filter_iterator& rhs ) const { 153 | return !( *this < rhs ); 154 | } 155 | 156 | friend filter_range; 157 | 158 | protected: 159 | range_type range; 160 | Iterator it; 161 | F f; 162 | }; 163 | 164 | template 165 | struct filter_range { 166 | typedef typename std::iterator_traits::value_type value_type; 167 | typedef typename std::iterator_traits::difference_type difference_type; 168 | typedef Iterator original_iterator; 169 | typedef filter_iterator iterator; 170 | typedef std::reverse_iterator reverse_iterator; 171 | typedef std::pair range_type; 172 | 173 | filter_range( const F& f, const range_type& range ) : f(f), range(range) {} 174 | 175 | filter_range( const F& f, const Iterator& first, const Iterator& last ) : map_range(f,range_type(first,last)) {} 176 | 177 | iterator begin() const { 178 | return iterator( f, range ); 179 | } 180 | 181 | iterator end() const { 182 | iterator r( f, range ); 183 | r.it = r.range.second; 184 | return r; 185 | } 186 | 187 | protected: 188 | range_type range; 189 | F f; 190 | }; 191 | 192 | template 193 | inline filter_range filter( Iterator&& first, Iterator&& last, F&& f ) { 194 | return filter_range( std::forward(f), 195 | std::make_pair( 196 | std::forward(first), 197 | std::forward(last) 198 | ) 199 | ); 200 | } 201 | 202 | template 203 | inline auto filter( Range&& r, F&& f ) { 204 | return filter( 205 | begin( std::forward(r) ), 206 | end( std::forward(r) ), 207 | std::forward(f) 208 | ); 209 | } 210 | 211 | template 212 | inline auto cfilter( const Range& r, F&& f ) { 213 | return filter( 214 | cbegin( r ), 215 | cend( r ), 216 | std::forward(f) 217 | ); 218 | } 219 | 220 | #endif 221 | -------------------------------------------------------------------------------- /zip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Chris Welshman 2014 3 | */ 4 | #ifndef INCLUDED_ZIP 5 | #define INCLUDED_ZIP 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | struct zip_iterator { 12 | typedef typename std::iterator_traits::value_type value_type_1; 13 | typedef typename std::iterator_traits::reference reference_1; 14 | typedef typename std::iterator_traits::difference_type difference_type_1; 15 | typedef typename std::iterator_traits::iterator_category iterator_category_1; 16 | 17 | typedef typename std::iterator_traits::value_type value_type_2; 18 | typedef typename std::iterator_traits::reference reference_2; 19 | typedef typename std::iterator_traits::difference_type difference_type_2; 20 | typedef typename std::iterator_traits::iterator_category iterator_category_2; 21 | 22 | typedef std::pair value_type; 23 | typedef std::pair reference; 24 | typedef std::pair pair_type; 25 | typedef const pair_type* pointer; 26 | 27 | typedef difference_type_1 difference_type; 28 | typedef iterator_category_1 iterator_category; 29 | 30 | zip_iterator() = default; 31 | 32 | explicit zip_iterator( const pair_type& pair ) : pair(pair) {} 33 | 34 | zip_iterator( const It1& it1, const It2& it2 ) : zip_iterator(pair_type(it1,it2)) {} 35 | 36 | reference operator*() const { 37 | return reference( *pair.first, *pair.second ); 38 | } 39 | 40 | pointer operator->() const { 41 | return &pair; 42 | } 43 | 44 | reference_1 first() const { 45 | return reference_1( *pair.first ); 46 | } 47 | 48 | reference_2 second() const { 49 | return reference_2( *pair.second ); 50 | } 51 | 52 | zip_iterator& operator++() { 53 | ++pair.first; 54 | ++pair.second; 55 | return *this; 56 | } 57 | 58 | zip_iterator operator++(int) { 59 | zip_iterator temp = *this; 60 | ++(*this); 61 | return temp; 62 | } 63 | 64 | zip_iterator& operator--() { 65 | --pair.first; 66 | --pair.second; 67 | return *this; 68 | } 69 | 70 | zip_iterator operator--(int) { 71 | zip_iterator temp = *this; 72 | --(*this); 73 | return temp; 74 | } 75 | 76 | zip_iterator& operator+=( difference_type offset ) { 77 | pair.first += offset; 78 | pair.second += offset; 79 | return *this; 80 | } 81 | 82 | zip_iterator operator+( difference_type offset ) const { 83 | zip_iterator temp = *this; 84 | return temp += offset; 85 | } 86 | 87 | zip_iterator& operator-=( difference_type offset ) { 88 | return *this += -offset; 89 | } 90 | 91 | zip_iterator operator-( difference_type offset ) const { 92 | zip_iterator temp = *this; 93 | return temp -= offset; 94 | } 95 | 96 | difference_type operator-( const zip_iterator& rhs ) const { 97 | return std::distance( rhs.pair.first, pair.first ); 98 | } 99 | 100 | reference operator[]( difference_type offset ) const { 101 | return *(*this + offset); 102 | } 103 | 104 | bool operator==( const zip_iterator& rhs ) const { 105 | return pair == rhs.pair; 106 | } 107 | 108 | bool operator!=( const zip_iterator& rhs ) const { 109 | return !(*this == rhs); 110 | } 111 | 112 | bool operator<( const zip_iterator& rhs ) const { 113 | return rhs - *this > 0; 114 | } 115 | 116 | bool operator>( const zip_iterator& rhs ) const { 117 | return rhs < *this; 118 | } 119 | 120 | bool operator<=( const zip_iterator& rhs ) const { 121 | return !( *this > rhs ); 122 | } 123 | 124 | bool operator>=( const zip_iterator& rhs ) const { 125 | return !( *this < rhs ); 126 | } 127 | 128 | protected: 129 | pair_type pair; 130 | }; 131 | 132 | template 133 | struct zip_range { 134 | typedef typename std::iterator_traits::value_type value_type_1; 135 | typedef typename std::iterator_traits::value_type value_type_2; 136 | typedef typename std::iterator_traits::difference_type difference_type_1; 137 | typedef typename std::iterator_traits::difference_type difference_type_2; 138 | typedef typename std::common_type::type difference_type; 139 | typedef It1 iterator_1; 140 | typedef It2 iterator_2; 141 | typedef zip_iterator iterator; 142 | typedef std::reverse_iterator reverse_iterator; 143 | typedef std::pair pair_type_1; 144 | typedef std::pair pair_type_2; 145 | typedef std::pair range_type; 146 | typedef std::pair value_type; 147 | 148 | explicit zip_range( const range_type& range ) : range(range) {} 149 | 150 | zip_range( const pair_type_1& range_1, const pair_type_2& range_2 ) : range(range_type(range_1,range_2)) {} 151 | 152 | difference_type size() const { 153 | difference_type N1 = std::distance( range.first.first, range.first.second ); 154 | difference_type N2 = std::distance( range.second.first, range.second.second ); 155 | return std::min( N1, N2 ); 156 | } 157 | 158 | iterator begin() const { 159 | return iterator( range.first.first, range.second.first ); 160 | } 161 | 162 | iterator end() const { 163 | difference_type N = size(); 164 | return iterator( range.first.first + N, range.second.first + N ); 165 | } 166 | 167 | protected: 168 | range_type range; 169 | }; 170 | 171 | template 172 | inline zip_range zip( It1&& first_1, It1&& last_1, It2&& first_2, It2&& last_2 ) { 173 | return zip_range( 174 | std::make_pair( 175 | std::forward(first_1), 176 | std::forward(last_1) 177 | ), 178 | std::make_pair( 179 | std::forward(first_2), 180 | std::forward(last_2) 181 | ) 182 | ); 183 | } 184 | 185 | template 186 | inline auto zip( R1&& r1, R2&& r2 ) { 187 | return zip( 188 | begin( std::forward(r1) ), 189 | end( std::forward(r1) ), 190 | begin( std::forward(r2) ), 191 | end( std::forward(r2) ) 192 | ); 193 | } 194 | 195 | template 196 | inline auto czip( const R1& r1, const R2& r2 ) { 197 | return zip( 198 | cbegin( r1 ), 199 | cend( r1 ), 200 | cbegin( r2 ), 201 | cend( r2 ) 202 | ); 203 | } 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Lazy Iterators 2 | ============== 3 | 4 | C++ iterators for iterating over various sets where the elements are computed on demand, without the need to precompute or store the set. Features sets of pairs (Cartesian product, distinct pairs, zip), subsets (filter, slice), and function applications (map, reduce, function_sequence). 5 | 6 | A longer introduction can be read here: 7 | 8 | https://cwzx.wordpress.com/2014/04/15/iterating-over-distinct-pairs-in-cpp/ 9 | 10 | ### Product 11 | 12 | product(X,Y) is the Cartesian product of X and Y, which is the set of all pairs (x,y). There are N*M pairs, where N is the size of X and M is the size of Y. 13 | 14 | pairs(X) = product(X,X). There are N^2 pairs. 15 | 16 | ### Distinct Pairs 17 | 18 | distinct_pairs(X) is the set of all pairs (x,y) such that x and y are different instances and the order doesn't matter, so (x,y) is the same distinct pair as (y,x). These are known in combinatorics as '2-combinations'. There are 'N choose 2' distinct pairs, which is N(N-1)/2. 19 | 20 | ### Zip 21 | 22 | zip(X,Y) is the set of element-wise pairings, e.g. 23 | 24 | zip( (1,2,3), (4,5,6) ) = { (1,4), (2,5), (3,6) } 25 | 26 | The number of pairs is min(M,N), i.e. if one of the lists is longer than the other, its extra elements will be ignored. 27 | 28 | ### Filter 29 | 30 | filter(X,f) is the subset of elements satisfying the predicate f. 31 | 32 | filter( {1,2,3}, f ) = { 1, 3 }, where f(x) = ( x % 2 != 0 ). 33 | 34 | ### Slice 35 | 36 | slice(X,skip,count,step) is a subset of X. The first skip elements are skipped, the following count elements are iterated through with a step size. Defaults: skip=0, step=1. 37 | 38 | ### Map 39 | 40 | map(X,f) is the set of element-wise evaluations of the function f. 41 | 42 | map( {1,2,3}, f ) = { f(1), f(2), f(3) } 43 | 44 | ### Reduce 45 | 46 | reduce(X,f) is the single value obtained by repeated application of the binary function f. 47 | 48 | reduce( {1,2,3}, f ) = f( f(1,2), 3 ). 49 | 50 | ### Integer Interval 51 | 52 | integer_interval(a,b) is a closed interval of integers, [a..b]. The integer type is templated, so you can use any data type that behaves like an integer. 53 | 54 | ### Function Sequence 55 | 56 | function_sequence(initial,f) is a sequence produced by repeated application of a function f to an initial state. Each application mutates the state and returns a value. The sequence can only be iterated forward. 57 | 58 | ### Invertible Function Sequence 59 | 60 | invertible_function_sequence(initial,f,finv) is a sequence produced by repeated application of an invertible function f with inverse finv to an initial state. Each application mutates the state and returns a value. The sequence supports bidirectional iteration. 61 | 62 | 63 | Usage Notes 64 | ----------- 65 | 66 | The pairs iterators' dereference operations return a pair of references, not a reference. Therefore you should receive this by-value, not by-reference (e.g. in the range-based for loop). 67 | 68 | Examples 69 | -------- 70 | 71 | ### Fibonacci 72 | 73 | ```cpp 74 | auto fibonacci = function_sequence( make_pair(1,0), 75 | []( auto& p ) { 76 | auto temp = p.first + p.second; 77 | p.first = p.second; 78 | return p.second = temp; 79 | } 80 | ); 81 | 82 | for( auto f : fibonacci ) { 83 | if( f > 1000 ) break; 84 | cout << f << endl; 85 | } 86 | 87 | /* Output: 88 | 1 89 | 1 90 | 2 91 | 3 92 | 5 93 | 8 94 | 13 95 | 21 96 | 34 97 | 55 98 | 89 99 | 144 100 | 233 101 | 377 102 | 610 103 | 987 104 | */ 105 | ``` 106 | 107 | ### Primes 108 | 109 | ```cpp 110 | auto primes( int lower, int upper ) { 111 | upper = max(upper,2); lower = min(max(lower,2),upper); 112 | return filter( integer_interval( lower, upper ), 113 | []( auto i ) { 114 | auto tests = integer_interval( 2, max((int)sqrt(i),2) ); 115 | auto results = map( tests, [i]( auto j ) { return (i % j) != 0; } ); 116 | return reduce( results, []( bool x, bool y ) { return x && y; } ); 117 | } 118 | ); 119 | } 120 | 121 | for( auto p : primes(100,150) ) { 122 | cout << p << endl; 123 | } 124 | 125 | /* Output: 126 | 101 127 | 103 128 | 107 129 | 109 130 | 113 131 | 127 132 | 131 133 | 137 134 | 139 135 | 149 136 | */ 137 | ``` 138 | 139 | ### Pythagorean Triples 140 | 141 | ```cpp 142 | auto range = integer_interval( 1, 100 ); 143 | 144 | auto triples = product( range, distinct_pairs(range) ); // (z,(x,y)) 145 | 146 | auto pythagorean_triples = filter( triples, 147 | []( auto t ) { 148 | return t.second.first*t.second.first + t.second.second*t.second.second == t.first*t.first; 149 | } 150 | ); 151 | 152 | for( auto t : pythagorean_triples ) { 153 | cout << "( " << t.second.first << ", " << t.second.second << ", " << t.first << " )" << endl; 154 | } 155 | 156 | /* Output: 157 | ( 3, 4, 5 ) 158 | ( 6, 8, 10 ) 159 | ( 5, 12, 13 ) 160 | ( 9, 12, 15 ) 161 | ( 8, 15, 17 ) 162 | ( 12, 16, 20 ) 163 | ( 7, 24, 25 ) 164 | ( 15, 20, 25 ) 165 | ( 10, 24, 26 ) 166 | ( 20, 21, 29 ) 167 | ( 18, 24, 30 ) 168 | ( 16, 30, 34 ) 169 | ( 21, 28, 35 ) 170 | ( 12, 35, 37 ) 171 | ( 15, 36, 39 ) 172 | ( 24, 32, 40 ) 173 | ( 9, 40, 41 ) 174 | ( 27, 36, 45 ) 175 | ( 14, 48, 50 ) 176 | ( 30, 40, 50 ) 177 | ( 24, 45, 51 ) 178 | ( 20, 48, 52 ) 179 | ( 28, 45, 53 ) 180 | ( 33, 44, 55 ) 181 | ( 40, 42, 58 ) 182 | ( 36, 48, 60 ) 183 | ( 11, 60, 61 ) 184 | ( 16, 63, 65 ) 185 | ( 25, 60, 65 ) 186 | ( 33, 56, 65 ) 187 | ( 39, 52, 65 ) 188 | ( 32, 60, 68 ) 189 | ( 42, 56, 70 ) 190 | ( 48, 55, 73 ) 191 | ( 24, 70, 74 ) 192 | ( 21, 72, 75 ) 193 | ( 45, 60, 75 ) 194 | ( 30, 72, 78 ) 195 | ( 48, 64, 80 ) 196 | ( 18, 80, 82 ) 197 | ( 13, 84, 85 ) 198 | ( 36, 77, 85 ) 199 | ( 40, 75, 85 ) 200 | ( 51, 68, 85 ) 201 | ( 60, 63, 87 ) 202 | ( 39, 80, 89 ) 203 | ( 54, 72, 90 ) 204 | ( 35, 84, 91 ) 205 | ( 57, 76, 95 ) 206 | ( 65, 72, 97 ) 207 | ( 28, 96, 100 ) 208 | ( 60, 80, 100 ) 209 | */ 210 | ``` 211 | 212 | ### Distinct pairs of distinct pairs 213 | 214 | ```cpp 215 | auto v = integer_interval( 1, 4 ); 216 | 217 | for( auto p : distinct_pairs(distinct_pairs(v)) ) { 218 | cout << "( ( " << p.first.first << ", " << p.first.second << " ), ( " << p.second.first << ", " << p.second.second << " ) )" << endl; 219 | } 220 | 221 | /* Output: 222 | ( ( 1, 2 ), ( 1, 3 ) ) 223 | ( ( 1, 2 ), ( 1, 4 ) ) 224 | ( ( 1, 2 ), ( 2, 3 ) ) 225 | ( ( 1, 2 ), ( 2, 4 ) ) 226 | ( ( 1, 2 ), ( 3, 4 ) ) 227 | ( ( 1, 3 ), ( 1, 4 ) ) 228 | ( ( 1, 3 ), ( 2, 3 ) ) 229 | ( ( 1, 3 ), ( 2, 4 ) ) 230 | ( ( 1, 3 ), ( 3, 4 ) ) 231 | ( ( 1, 4 ), ( 2, 3 ) ) 232 | ( ( 1, 4 ), ( 2, 4 ) ) 233 | ( ( 1, 4 ), ( 3, 4 ) ) 234 | ( ( 2, 3 ), ( 2, 4 ) ) 235 | ( ( 2, 3 ), ( 3, 4 ) ) 236 | ( ( 2, 4 ), ( 3, 4 ) ) 237 | */ 238 | ``` 239 | 240 | -------------------------------------------------------------------------------- /distinct_pairs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Chris Welshman 2014 3 | */ 4 | #ifndef INCLUDED_DISTINCT_PAIRS 5 | #define INCLUDED_DISTINCT_PAIRS 6 | #include 7 | #include 8 | 9 | template 10 | struct distinct_pairs_iterator { 11 | typedef typename std::iterator_traits::value_type original_value_type; 12 | typedef typename std::iterator_traits::reference original_reference; 13 | typedef typename std::iterator_traits::difference_type difference_type; 14 | typedef typename std::iterator_traits::iterator_category iterator_category; 15 | 16 | typedef std::pair value_type; 17 | typedef std::pair reference; 18 | typedef std::pair pair_type; 19 | typedef const pair_type* pointer; 20 | 21 | distinct_pairs_iterator() = default; 22 | 23 | explicit distinct_pairs_iterator( const pair_type& range ) : range(range) { 24 | pair.first = range.first; 25 | pair.second = range.first; 26 | if( range.first != range.second ) 27 | ++pair.second; 28 | } 29 | 30 | distinct_pairs_iterator( const Iterator& first, const Iterator& last ) : distinct_pairs_iterator(pair_type(first,last)) {} 31 | 32 | distinct_pairs_iterator( const pair_type& range, const pair_type& pair ) : range(range), pair(pair) {} 33 | 34 | reference operator*() const { 35 | return reference( *pair.first, *pair.second ); 36 | } 37 | 38 | pointer operator->() const { 39 | return &pair; 40 | } 41 | 42 | original_reference first() const { 43 | return *pair.first; 44 | } 45 | 46 | original_reference second() const { 47 | return *pair.second; 48 | } 49 | 50 | distinct_pairs_iterator& operator++() { 51 | ++pair.second; 52 | if( pair.second == range.second ) { 53 | ++pair.first; 54 | pair.second = pair.first; 55 | ++pair.second; 56 | } 57 | return *this; 58 | } 59 | 60 | distinct_pairs_iterator operator++(int) { 61 | distinct_pairs_iterator temp = *this; 62 | ++(*this); 63 | return temp; 64 | } 65 | 66 | distinct_pairs_iterator& operator--() { 67 | --pair.second; 68 | if( pair.second == pair.first ) { 69 | --pair.first; 70 | pair.second = range.second; 71 | --pair.second; 72 | } 73 | return *this; 74 | } 75 | 76 | distinct_pairs_iterator operator--(int) { 77 | distinct_pairs_iterator temp = *this; 78 | --(*this); 79 | return temp; 80 | } 81 | 82 | distinct_pairs_iterator& operator+=( difference_type offset ) { 83 | difference_type N = std::distance( range.first, range.second ); 84 | difference_type k = index(N) + offset; 85 | difference_type i = index_i( k, N ); 86 | difference_type j = index_j( k, i, N ); 87 | pair.first = range.first + i; 88 | pair.second = range.first + j; 89 | return *this; 90 | } 91 | 92 | distinct_pairs_iterator operator+( difference_type offset ) const { 93 | distinct_pairs_iterator temp = *this; 94 | return temp += offset; 95 | } 96 | 97 | distinct_pairs_iterator& operator-=( difference_type offset ) const { 98 | return *this += -offset; 99 | } 100 | 101 | distinct_pairs_iterator operator-( difference_type offset ) const { 102 | distinct_pairs_iterator temp = *this; 103 | return temp -= offset; 104 | } 105 | 106 | difference_type operator-( const distinct_pairs_iterator& rhs ) const { 107 | difference_type dfirst = std::distance( rhs.pair.first, pair.first ); 108 | difference_type dsecond = std::distance( rhs.pair.second, pair.second ); 109 | difference_type N = std::distance( range.first, range.second ); 110 | difference_type sumfirst = std::distance( range.first, pair.first ) + std::distance( range.first, rhs.pair.first ); 111 | 112 | return ( ( 2*(N-1) - 1 - sumfirst ) * dfirst ) / 2 + dsecond; 113 | } 114 | 115 | reference operator[]( difference_type offset ) const { 116 | return *(*this + offset); 117 | } 118 | 119 | difference_type index() const { 120 | difference_type N = std::distance( range.first, range.second ); 121 | return index(N); 122 | } 123 | 124 | bool operator==( const distinct_pairs_iterator& rhs ) const { 125 | if( pair == rhs.pair ) 126 | return true; 127 | if( pair.first == rhs.pair.second && pair.second == rhs.pair.first ) 128 | return true; 129 | return false; 130 | } 131 | 132 | bool operator!=( const distinct_pairs_iterator& rhs ) const { 133 | return !(*this == rhs); 134 | } 135 | 136 | bool operator<( const distinct_pairs_iterator& rhs ) const { 137 | return rhs - *this > 0; 138 | } 139 | 140 | bool operator>( const distinct_pairs_iterator& rhs ) const { 141 | return rhs < *this; 142 | } 143 | 144 | bool operator<=( const distinct_pairs_iterator& rhs ) const { 145 | return !( *this > rhs ); 146 | } 147 | 148 | bool operator>=( const distinct_pairs_iterator& rhs ) const { 149 | return !( *this < rhs ); 150 | } 151 | 152 | protected: 153 | pair_type range, pair; 154 | 155 | difference_type index( difference_type N ) const { 156 | return index( 157 | std::distance( range.first, pair.first ), 158 | std::distance( range.first, pair.second ), 159 | N 160 | ); 161 | } 162 | 163 | difference_type index( difference_type i, difference_type j, difference_type N ) const { 164 | return j - i + ( i * ( 2*N - ( i + 1 ) ) ) / 2 - 1; 165 | } 166 | 167 | difference_type index_i( difference_type k, difference_type N ) const { 168 | difference_type d = N, total = 0; 169 | for(difference_type a=0;a k ) return a; 172 | } 173 | return N-1; 174 | } 175 | 176 | difference_type index_j( difference_type k, difference_type i, difference_type N ) const { 177 | return (k + i + 1) - ( i * ( 2*N - ( i + 1 ) ) ) / 2; 178 | } 179 | 180 | }; 181 | 182 | template 183 | struct distinct_pairs_range { 184 | typedef typename std::iterator_traits::value_type value_type; 185 | typedef typename std::iterator_traits::difference_type difference_type; 186 | typedef Iterator original_iterator; 187 | typedef distinct_pairs_iterator iterator; 188 | typedef std::reverse_iterator reverse_iterator; 189 | typedef std::pair pair_type; 190 | 191 | explicit distinct_pairs_range( const pair_type& range ) : range(range) {} 192 | 193 | distinct_pairs_range( const Iterator& first, const Iterator& last ) : range(pair_type(first,last)) {} 194 | 195 | difference_type size() const { 196 | difference_type N = std::distance( range.first, range.second ); 197 | return ( N * ( N - 1 ) ) / 2; 198 | } 199 | 200 | iterator begin() const { 201 | return iterator( range ); 202 | } 203 | 204 | iterator end() const { 205 | pair_type temp = range; 206 | temp.first = range.second; 207 | if( range.first != range.second ) 208 | --temp.first; 209 | return iterator( range, temp ); 210 | } 211 | 212 | protected: 213 | pair_type range; 214 | }; 215 | 216 | template 217 | inline distinct_pairs_range distinct_pairs( Iterator&& first, Iterator&& last ) { 218 | return distinct_pairs_range( 219 | std::make_pair( 220 | std::forward(first), 221 | std::forward(last) 222 | ) 223 | ); 224 | } 225 | 226 | template 227 | inline auto distinct_pairs( Range&& r ) { 228 | return distinct_pairs( 229 | begin( std::forward(r) ), 230 | end( std::forward(r) ) 231 | ); 232 | } 233 | 234 | template 235 | inline auto cdistinct_pairs( const Range& r ) { 236 | return distinct_pairs( 237 | cbegin( r ), 238 | cend( r ) 239 | ); 240 | } 241 | 242 | #endif 243 | -------------------------------------------------------------------------------- /product.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Chris Welshman 2014 3 | */ 4 | #ifndef INCLUDED_PRODUCT 5 | #define INCLUDED_PRODUCT 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | struct product_iterator { 12 | typedef typename std::iterator_traits::value_type value_type_1; 13 | typedef typename std::iterator_traits::reference reference_1; 14 | typedef typename std::iterator_traits::difference_type difference_type_1; 15 | typedef typename std::iterator_traits::iterator_category iterator_category_1; 16 | typedef std::pair pair_type_1; 17 | 18 | typedef typename std::iterator_traits::value_type value_type_2; 19 | typedef typename std::iterator_traits::reference reference_2; 20 | typedef typename std::iterator_traits::difference_type difference_type_2; 21 | typedef typename std::iterator_traits::iterator_category iterator_category_2; 22 | typedef std::pair pair_type_2; 23 | 24 | typedef std::pair value_type; 25 | typedef std::pair reference; 26 | typedef std::pair pair_type; 27 | typedef const pair_type* pointer; 28 | typedef std::pair range_type; 29 | 30 | //typedef typename std::common_type::type difference_type; // fatal error C1001: An internal error has occurred in the compiler. 31 | typedef difference_type_2 difference_type; 32 | typedef iterator_category_2 iterator_category; 33 | 34 | product_iterator() = default; 35 | 36 | explicit product_iterator( const range_type& range ) : range(range) { 37 | pair.first = range.first.first; 38 | pair.second = range.second.first; 39 | } 40 | 41 | product_iterator( const pair_type_1& range_1, const pair_type_2& range_2 ) : product_iterator(range_type(range_1,range_2)) {} 42 | 43 | product_iterator( const range_type& range, const pair_type& pair ) : range(range), pair(pair) {} 44 | 45 | reference operator*() const { 46 | return reference( *pair.first, *pair.second ); 47 | } 48 | 49 | pointer operator->() const { 50 | return &pair; 51 | } 52 | 53 | reference_1 first() const { 54 | return reference_1( *pair.first ); 55 | } 56 | 57 | reference_2 second() const { 58 | return reference_2( *pair.second ); 59 | } 60 | 61 | product_iterator& operator++() { 62 | ++pair.second; 63 | if( pair.second == range.second.second ) { 64 | ++pair.first; 65 | pair.second = range.second.first; 66 | } 67 | return *this; 68 | } 69 | 70 | product_iterator operator++(int) { 71 | product_iterator temp = *this; 72 | ++(*this); 73 | return temp; 74 | } 75 | 76 | product_iterator& operator--() { 77 | if( pair.second == range.second.first ) { 78 | pair.second = range.second.second; 79 | --pair.first; 80 | } else { 81 | --pair.second; 82 | } 83 | return *this; 84 | } 85 | 86 | product_iterator operator--(int) { 87 | product_iterator temp = *this; 88 | --(*this); 89 | return temp; 90 | } 91 | 92 | product_iterator& operator+=( difference_type offset ) { 93 | difference_type N2 = std::distance( range.second.first, range.second.second ); 94 | difference_type k = index(N2) + offset; 95 | difference_type i = k / N2; 96 | difference_type j = k % N2; 97 | pair.first = range.first.first + i; 98 | pair.second = range.second.first + j; 99 | return *this; 100 | } 101 | 102 | product_iterator operator+( difference_type offset ) const { 103 | product_iterator temp = *this; 104 | return temp += offset; 105 | } 106 | 107 | product_iterator& operator-=( difference_type offset ) { 108 | return *this += -offset; 109 | } 110 | 111 | product_iterator operator-( difference_type offset ) const { 112 | product_iterator temp = *this; 113 | return temp -= offset; 114 | } 115 | 116 | difference_type operator-( const product_iterator& rhs ) const { 117 | difference_type dfirst = std::distance( rhs.pair.first, pair.first ); 118 | difference_type dsecond = std::distance( rhs.pair.second, pair.second ); 119 | difference_type N2 = std::distance( range.second.first, range.second.second ); 120 | return dfirst * N2 + dsecond; 121 | } 122 | 123 | reference operator[]( difference_type offset ) const { 124 | return *(*this + offset); 125 | } 126 | 127 | difference_type index() const { 128 | difference_type N2 = std::distance( range.second.first, range.second.second ); 129 | return index(N2); 130 | } 131 | 132 | bool operator==( const product_iterator& rhs ) const { 133 | return pair == rhs.pair; 134 | } 135 | 136 | bool operator!=( const product_iterator& rhs ) const { 137 | return !(*this == rhs); 138 | } 139 | 140 | bool operator<( const product_iterator& rhs ) const { 141 | return rhs - *this > 0; 142 | } 143 | 144 | bool operator>( const product_iterator& rhs ) const { 145 | return rhs < *this; 146 | } 147 | 148 | bool operator<=( const product_iterator& rhs ) const { 149 | return !( *this > rhs ); 150 | } 151 | 152 | bool operator>=( const product_iterator& rhs ) const { 153 | return !( *this < rhs ); 154 | } 155 | 156 | protected: 157 | range_type range; 158 | pair_type pair; 159 | 160 | difference_type index( difference_type N2 ) const { 161 | return index( 162 | std::distance( range.first.first, pair.first ), 163 | std::distance( range.second.first, pair.second ), 164 | N2 165 | ); 166 | } 167 | 168 | difference_type index( difference_type i, difference_type j, difference_type N2 ) const { 169 | return N2*i + j; 170 | } 171 | 172 | }; 173 | 174 | template 175 | struct product_range { 176 | typedef typename std::iterator_traits::value_type value_type_1; 177 | typedef typename std::iterator_traits::value_type value_type_2; 178 | typedef typename std::iterator_traits::difference_type difference_type_1; 179 | typedef typename std::iterator_traits::difference_type difference_type_2; 180 | typedef typename std::common_type::type difference_type; 181 | typedef It1 iterator_1; 182 | typedef It2 iterator_2; 183 | typedef product_iterator iterator; 184 | typedef std::reverse_iterator reverse_iterator; 185 | typedef std::pair pair_type_1; 186 | typedef std::pair pair_type_2; 187 | typedef std::pair range_type; 188 | typedef std::pair value_type; 189 | 190 | explicit product_range( const range_type& range ) : range(range) {} 191 | 192 | product_range( const pair_type_1& range_1, const pair_type_2& range_2 ) : range(range_type(range_1,range_2)) {} 193 | 194 | difference_type size() const { 195 | difference_type N1 = std::distance( range.first.first, range.first.second ); 196 | difference_type N2 = std::distance( range.second.first, range.second.second ); 197 | return N1 * N2; 198 | } 199 | 200 | iterator begin() const { 201 | return iterator( range ); 202 | } 203 | 204 | iterator end() const { 205 | return iterator( 206 | range, 207 | std::make_pair( range.first.second, range.second.first ) 208 | ); 209 | } 210 | 211 | protected: 212 | range_type range; 213 | }; 214 | 215 | template 216 | inline product_range product( It1&& first_1, It1&& last_1, It2&& first_2, It2&& last_2 ) { 217 | return product_range( 218 | std::make_pair( 219 | std::forward(first_1), 220 | std::forward(last_1) 221 | ), 222 | std::make_pair( 223 | std::forward(first_2), 224 | std::forward(last_2) 225 | ) 226 | ); 227 | } 228 | 229 | template 230 | inline auto product( R1&& r1, R2&& r2 ) { 231 | return product( 232 | begin( std::forward(r1) ), 233 | end( std::forward(r1) ), 234 | begin( std::forward(r2) ), 235 | end( std::forward(r2) ) 236 | ); 237 | } 238 | 239 | template 240 | inline auto cproduct( const R1& r1, const R2& r2 ) { 241 | return product( 242 | cbegin( r1 ), 243 | cend( r1 ), 244 | cbegin( r2 ), 245 | cend( r2 ) 246 | ); 247 | } 248 | 249 | template 250 | inline auto pairs( Range&& r ) { 251 | return product( std::forward(r), std::forward(r) ); 252 | } 253 | 254 | template 255 | inline auto cpairs( const Range& r ) { 256 | return cproduct( r, r ); 257 | } 258 | 259 | #endif 260 | --------------------------------------------------------------------------------