source: src/Common/Iterate.hpp @ 9feb34b

ADTast-experimental
Last change on this file since 9feb34b was 8f06277, checked in by Andrew Beach <ajbeach@…>, 16 months ago

Some clean-up in Common/utility.h. Deleted some unused declarations and moved others to one of two new headers.

  • Property mode set to 100644
File size: 7.6 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// it's nice to actually be able to increment iterators by an arbitrary amount
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// -----------------------------------------------------------------------------
52template< typename T >
53struct enumerate_t {
54        template<typename val_t>
55        struct value_t {
56                val_t & val;
57                size_t idx;
58        };
59
60        template< typename iter_t, typename val_t >
61        struct iterator_t {
62                iter_t it;
63                size_t idx;
64
65                iterator_t( iter_t _it, size_t _idx ) : it(_it), idx(_idx) {}
66
67                value_t<val_t> operator*() const { return value_t<val_t>{ *it, idx }; }
68
69                bool operator==(const iterator_t & o) const { return o.it == it; }
70                bool operator!=(const iterator_t & o) const { return o.it != it; }
71
72                iterator_t & operator++() {
73                        it++;
74                        idx++;
75                        return *this;
76                }
77
78                using difference_type   = typename std::iterator_traits< iter_t >::difference_type;
79                using value_type        = value_t<val_t>;
80                using pointer           = value_t<val_t> *;
81                using reference         = value_t<val_t> &;
82                using iterator_category = std::forward_iterator_tag;
83        };
84
85        T & ref;
86
87        using iterator = iterator_t< typename T::iterator, typename T::value_type >;
88        using const_iterator = iterator_t< typename T::const_iterator, const typename T::value_type >;
89
90        iterator begin() { return iterator( ref.begin(), 0 ); }
91        iterator end()   { return iterator( ref.end(), ref.size() ); }
92
93        const_iterator begin() const { return const_iterator( ref.cbegin(), 0 ); }
94        const_iterator end()   const { return const_iterator( ref.cend(), ref.size() ); }
95
96        const_iterator cbegin() const { return const_iterator( ref.cbegin(), 0 ); }
97        const_iterator cend()   const { return const_iterator( ref.cend(), ref.size() ); }
98};
99
100template< typename T >
101enumerate_t<T> enumerate( T & ref ) {
102        return enumerate_t< T >{ ref };
103}
104
105template< typename T >
106const enumerate_t< const T > enumerate( const T & ref ) {
107        return enumerate_t< const T >{ ref };
108}
109
110// -----------------------------------------------------------------------------
111template< typename OutType, typename Range, typename Functor >
112OutType map_range( const Range& range, Functor&& functor ) {
113        OutType out;
114
115        std::transform(
116                begin( range ),
117                end( range ),
118                std::back_inserter( out ),
119                std::forward< Functor >( functor )
120        );
121
122        return out;
123}
124
125// -----------------------------------------------------------------------------
126// Helper struct and function to support:
127// for ( auto val : group_iterate( container1, container2, ... ) ) { ... }
128// This iteraters through multiple containers of the same size.
129
130template<typename... Args>
131class group_iterate_t {
132        using Iterables = std::tuple<Args...>;
133        Iterables iterables;
134
135        // Getting the iterator and value types this way preserves const.
136        template<size_t I> using Iter = decltype(std::get<I>(iterables).begin());
137        template<size_t I> using Data = decltype(*std::get<I>(iterables).begin());
138        template<typename> struct base_iterator;
139
140        // This inner template puts the sequence of `0, 1, ... sizeof...(Args)-1`
141        // into a pack. These are the indexes into the tuples, so unpacking can
142        // go over each element of the tuple.
143        // The std::integer_sequence is just used to build that sequence.
144        // A library reference will probably explain it better than I can.
145        template<std::size_t... Indices>
146        struct base_iterator<std::integer_sequence<std::size_t, Indices...>> {
147                using value_type = std::tuple< Data<Indices>... >;
148                std::tuple<Iter<Indices>...> iterators;
149
150                base_iterator( Iter<Indices>... is ) : iterators( is... ) {}
151                base_iterator operator++() {
152                        return base_iterator( ++std::get<Indices>( iterators )... );
153                }
154                bool operator!=( const base_iterator& other ) const {
155                        return iterators != other.iterators;
156                }
157                value_type operator*() const {
158                        return std::tie( *std::get<Indices>( iterators )... );
159                }
160
161                static base_iterator make_begin( Iterables & data ) {
162                        return base_iterator( std::get<Indices>( data ).begin()... );
163                }
164                static base_iterator make_end( Iterables & data ) {
165                        return base_iterator( std::get<Indices>( data ).end()... );
166                }
167        };
168
169public:
170        group_iterate_t( const Args &... args ) : iterables( args... ) {}
171
172        using iterator = base_iterator<decltype(
173                std::make_integer_sequence<std::size_t, sizeof...(Args)>())>;
174
175        iterator begin() { return iterator::make_begin( iterables ); }
176        iterator end() { return iterator::make_end( iterables ); }
177};
178
179// Helpers for the bounds checks (the non-varatic part of group_iterate):
180static inline void runGroupBoundsCheck(size_t size0, size_t size1) {
181        assertf( size0 == size1,
182                "group iteration requires containers of the same size: <%zd, %zd>.",
183                size0, size1 );
184}
185
186static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) {
187        assertf( size0 == size1 && size1 == size2,
188                "group iteration requires containers of the same size: <%zd, %zd, %zd>.",
189                size0, size1, size2 );
190}
191
192/// Performs bounds check to ensure that all arguments are of the same length.
193template< typename... Args >
194group_iterate_t<Args...> group_iterate( Args &&... args ) {
195        runGroupBoundsCheck( args.size()... );
196        return group_iterate_t<Args...>( std::forward<Args>( args )... );
197}
198
199/// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
200template< typename... Args >
201group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
202        return group_iterate_t<Args...>( std::forward<Args>( args )... );
203}
204
205// -----------------------------------------------------------------------------
206// Helper struct and function to support
207// for ( val : lazy_map( container1, f ) ) {}
208// syntax to have a for each that iterates a container, mapping each element by applying f
209template< typename T, typename Func >
210struct lambda_iterate_t {
211        const T & ref;
212        std::function<Func> f;
213
214        struct iterator {
215                typedef decltype(begin(ref)) Iter;
216                Iter it;
217                std::function<Func> f;
218                iterator( Iter it, std::function<Func> f ) : it(it), f(f) {}
219                iterator & operator++() {
220                        ++it; return *this;
221                }
222                bool operator!=( const iterator &other ) const { return it != other.it; }
223                auto operator*() const -> decltype(f(*it)) { return f(*it); }
224        };
225
226        lambda_iterate_t( const T & ref, std::function<Func> f ) : ref(ref), f(f) {}
227
228        auto begin() const -> decltype(iterator(std::begin(ref), f)) { return iterator(std::begin(ref), f); }
229        auto end() const   -> decltype(iterator(std::end(ref), f)) { return iterator(std::end(ref), f); }
230};
231
232template< typename... Args >
233lambda_iterate_t<Args...> lazy_map( const Args &... args ) {
234        return lambda_iterate_t<Args...>( args...);
235}
236
237// Local Variables: //
238// tab-width: 4 //
239// mode: c++ //
240// compile-command: "make install" //
241// End: //
Note: See TracBrowser for help on using the repository browser.