source: src/Common/Iterate.hpp@ fb4dc28

ADT ast-experimental
Last change on this file since fb4dc28 was 1b8fc06c, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Updated Iterate.hpp documentation.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Iterate.hpp --
8//
9// Author : Andrew Beach
10// Created On : Fri Feb 17 13:32:00 2023
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Feb 17 13:32:00 2023
13// Update Count : 0
14//
15
16#pragma once
17
18#include <algorithm>
19#include <functional>
20#include <iterator>
21
22// Returns an iterator that is it advanced n times.
23template< class InputIt, class Distance >
24InputIt operator+( InputIt it, Distance n ) {
25 advance(it, n);
26 return it;
27}
28
29// -----------------------------------------------------------------------------
30// Helper struct and function to support
31// for ( val : reverseIterate( container ) ) {}
32// syntax to have a for each that iterates backwards
33
34template< typename T >
35struct reverse_iterate_t {
36 T& ref;
37
38 reverse_iterate_t( T & ref ) : ref(ref) {}
39
40 // this does NOT work on const T!!!
41 // typedef typename T::reverse_iterator iterator;
42 auto begin() { return ref.rbegin(); }
43 auto end() { return ref.rend(); }
44};
45
46template< typename T >
47reverse_iterate_t< T > reverseIterate( T & ref ) {
48 return reverse_iterate_t< T >( ref );
49}
50
51// -----------------------------------------------------------------------------
52// Helper struct and function to support
53// for ( val_and_index : enumerate( container ) ) {}
54// which iterates through the container and tracks the index as well.
55
56template< typename T >
57struct enumerate_t {
58 template<typename val_t>
59 struct value_t {
60 val_t & val;
61 size_t idx;
62 };
63
64 template< typename iter_t, typename val_t >
65 struct iterator_t {
66 iter_t it;
67 size_t idx;
68
69 iterator_t( iter_t _it, size_t _idx ) : it(_it), idx(_idx) {}
70
71 value_t<val_t> operator*() const { return value_t<val_t>{ *it, idx }; }
72
73 bool operator==(const iterator_t & o) const { return o.it == it; }
74 bool operator!=(const iterator_t & o) const { return o.it != it; }
75
76 iterator_t & operator++() {
77 it++;
78 idx++;
79 return *this;
80 }
81
82 using difference_type = typename std::iterator_traits< iter_t >::difference_type;
83 using value_type = value_t<val_t>;
84 using pointer = value_t<val_t> *;
85 using reference = value_t<val_t> &;
86 using iterator_category = std::forward_iterator_tag;
87 };
88
89 T & ref;
90
91 using iterator = iterator_t< typename T::iterator, typename T::value_type >;
92 using const_iterator = iterator_t< typename T::const_iterator, const typename T::value_type >;
93
94 iterator begin() { return iterator( ref.begin(), 0 ); }
95 iterator end() { return iterator( ref.end(), ref.size() ); }
96
97 const_iterator begin() const { return const_iterator( ref.cbegin(), 0 ); }
98 const_iterator end() const { return const_iterator( ref.cend(), ref.size() ); }
99
100 const_iterator cbegin() const { return const_iterator( ref.cbegin(), 0 ); }
101 const_iterator cend() const { return const_iterator( ref.cend(), ref.size() ); }
102};
103
104template< typename T >
105enumerate_t<T> enumerate( T & ref ) {
106 return enumerate_t< T >{ ref };
107}
108
109template< typename T >
110const enumerate_t< const T > enumerate( const T & ref ) {
111 return enumerate_t< const T >{ ref };
112}
113
114// -----------------------------------------------------------------------------
115// Helper function to transform one iterable container into another.
116
117template< typename OutType, typename Range, typename Functor >
118OutType map_range( const Range& range, Functor&& functor ) {
119 OutType out;
120
121 std::transform(
122 begin( range ),
123 end( range ),
124 std::back_inserter( out ),
125 std::forward< Functor >( functor )
126 );
127
128 return out;
129}
130
131// -----------------------------------------------------------------------------
132// Helper struct and function to support:
133// for ( auto val : group_iterate( container1, container2, ... ) ) { ... }
134// This iteraters through multiple containers of the same size.
135
136template<typename... Args>
137class group_iterate_t {
138 using Iterables = std::tuple<Args...>;
139 Iterables iterables;
140
141 // Getting the iterator and value types this way preserves const.
142 template<size_t I> using Iter = decltype(std::get<I>(iterables).begin());
143 template<size_t I> using Data = decltype(*std::get<I>(iterables).begin());
144 template<typename> struct base_iterator;
145
146 // This inner template puts the sequence of `0, 1, ... sizeof...(Args)-1`
147 // into a pack. These are the indexes into the tuples, so unpacking can
148 // go over each element of the tuple.
149 // The std::integer_sequence is just used to build that sequence.
150 // A library reference will probably explain it better than I can.
151 template<std::size_t... Indices>
152 struct base_iterator<std::integer_sequence<std::size_t, Indices...>> {
153 using value_type = std::tuple< Data<Indices>... >;
154 std::tuple<Iter<Indices>...> iterators;
155
156 base_iterator( Iter<Indices>... is ) : iterators( is... ) {}
157 base_iterator operator++() {
158 return base_iterator( ++std::get<Indices>( iterators )... );
159 }
160 bool operator!=( const base_iterator& other ) const {
161 return iterators != other.iterators;
162 }
163 value_type operator*() const {
164 return std::tie( *std::get<Indices>( iterators )... );
165 }
166
167 static base_iterator make_begin( Iterables & data ) {
168 return base_iterator( std::get<Indices>( data ).begin()... );
169 }
170 static base_iterator make_end( Iterables & data ) {
171 return base_iterator( std::get<Indices>( data ).end()... );
172 }
173 };
174
175public:
176 group_iterate_t( const Args &... args ) : iterables( args... ) {}
177
178 using iterator = base_iterator<decltype(
179 std::make_integer_sequence<std::size_t, sizeof...(Args)>())>;
180
181 iterator begin() { return iterator::make_begin( iterables ); }
182 iterator end() { return iterator::make_end( iterables ); }
183};
184
185// Helpers for the bounds checks (the non-varatic part of group_iterate):
186static inline void runGroupBoundsCheck(size_t size0, size_t size1) {
187 assertf( size0 == size1,
188 "group iteration requires containers of the same size: <%zd, %zd>.",
189 size0, size1 );
190}
191
192static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) {
193 assertf( size0 == size1 && size1 == size2,
194 "group iteration requires containers of the same size: <%zd, %zd, %zd>.",
195 size0, size1, size2 );
196}
197
198/// Performs bounds check to ensure that all arguments are of the same length.
199template< typename... Args >
200group_iterate_t<Args...> group_iterate( Args &&... args ) {
201 runGroupBoundsCheck( args.size()... );
202 return group_iterate_t<Args...>( std::forward<Args>( args )... );
203}
204
205/// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
206template< typename... Args >
207group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
208 return group_iterate_t<Args...>( std::forward<Args>( args )... );
209}
210
211// -----------------------------------------------------------------------------
212// Helper struct and function to support
213// for ( val : lazy_map( container1, f ) ) {}
214// syntax to have a for each that iterates a container,
215// mapping each element by applying f.
216
217template< typename T, typename Func >
218struct lambda_iterate_t {
219 const T & ref;
220 std::function<Func> f;
221
222 struct iterator {
223 typedef decltype(begin(ref)) Iter;
224 Iter it;
225 std::function<Func> f;
226 iterator( Iter it, std::function<Func> f ) : it(it), f(f) {}
227 iterator & operator++() {
228 ++it; return *this;
229 }
230 bool operator!=( const iterator &other ) const { return it != other.it; }
231 auto operator*() const -> decltype(f(*it)) { return f(*it); }
232 };
233
234 lambda_iterate_t( const T & ref, std::function<Func> f ) : ref(ref), f(f) {}
235
236 auto begin() const -> decltype(iterator(std::begin(ref), f)) { return iterator(std::begin(ref), f); }
237 auto end() const -> decltype(iterator(std::end(ref), f)) { return iterator(std::end(ref), f); }
238};
239
240template< typename... Args >
241lambda_iterate_t<Args...> lazy_map( const Args &... args ) {
242 return lambda_iterate_t<Args...>( args...);
243}
244
245// Local Variables: //
246// tab-width: 4 //
247// mode: c++ //
248// compile-command: "make install" //
249// End: //
Note: See TracBrowser for help on using the repository browser.