Ignore:
Timestamp:
Nov 14, 2022, 11:52:44 AM (3 years ago)
Author:
caparson <caparson@…>
Branches:
ADT, ast-experimental, master
Children:
7d9598d8
Parents:
b77f0e1 (diff), 19a8c40 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Common/utility.h

    rb77f0e1 r63be3387  
    452452
    453453// -----------------------------------------------------------------------------
    454 // Helper struct and function to support
    455 // for ( val : group_iterate( container1, container2, ... ) ) {}
    456 // syntax to have a for each that iterates multiple containers of the same length
    457 // TODO: update to use variadic arguments
    458 
    459 template< typename T1, typename T2 >
    460 struct group_iterate_t {
    461 private:
    462         std::tuple<T1, T2> args;
     454// Helper struct and function to support:
     455// for ( auto val : group_iterate( container1, container2, ... ) ) { ... }
     456// This iteraters through multiple containers of the same size.
     457
     458template<typename... Args>
     459class group_iterate_t {
     460        using Iterables = std::tuple<Args...>;
     461        Iterables iterables;
     462
     463        // Getting the iterator and value types this way preserves const.
     464        template<size_t I> using Iter = decltype(std::get<I>(iterables).begin());
     465        template<size_t I> using Data = decltype(*std::get<I>(iterables).begin());
     466        template<typename> struct base_iterator;
     467
     468        // This inner template puts the sequence of `0, 1, ... sizeof...(Args)-1`
     469        // into a pack. These are the indexes into the tuples, so unpacking can
     470        // go over each element of the tuple.
     471        // The std::integer_sequence is just used to build that sequence.
     472        // A library reference will probably explain it better than I can.
     473        template<std::size_t... Indices>
     474        struct base_iterator<std::integer_sequence<std::size_t, Indices...>> {
     475                using value_type = std::tuple< Data<Indices>... >;
     476                std::tuple<Iter<Indices>...> iterators;
     477
     478                base_iterator( Iter<Indices>... is ) : iterators( is... ) {}
     479                base_iterator operator++() {
     480                        return base_iterator( ++std::get<Indices>( iterators )... );
     481                }
     482                bool operator!=( const base_iterator& other ) const {
     483                        return iterators != other.iterators;
     484                }
     485                value_type operator*() const {
     486                        return std::tie( *std::get<Indices>( iterators )... );
     487                }
     488
     489                static base_iterator make_begin( Iterables & data ) {
     490                        return base_iterator( std::get<Indices>( data ).begin()... );
     491                }
     492                static base_iterator make_end( Iterables & data ) {
     493                        return base_iterator( std::get<Indices>( data ).end()... );
     494                }
     495        };
     496
    463497public:
    464         group_iterate_t( bool skipBoundsCheck, const T1 & v1, const T2 & v2 ) : args(v1, v2) {
    465                 assertf(skipBoundsCheck || v1.size() == v2.size(), "group iteration requires containers of the same size: <%zd, %zd>.", v1.size(), v2.size());
    466         };
    467 
    468         typedef std::tuple<decltype(*std::get<0>(args).begin()), decltype(*std::get<1>(args).begin())> value_type;
    469         typedef decltype(std::get<0>(args).begin()) T1Iter;
    470         typedef decltype(std::get<1>(args).begin()) T2Iter;
    471 
    472         struct iterator {
    473                 typedef std::tuple<T1Iter, T2Iter> IterTuple;
    474                 IterTuple it;
    475                 iterator( T1Iter i1, T2Iter i2 ) : it( i1, i2 ) {}
    476                 iterator operator++() {
    477                         return iterator( ++std::get<0>(it), ++std::get<1>(it) );
    478                 }
    479                 bool operator!=( const iterator &other ) const { return it != other.it; }
    480                 value_type operator*() const { return std::tie( *std::get<0>(it), *std::get<1>(it) ); }
    481         };
    482 
    483         iterator begin() { return iterator( std::get<0>(args).begin(), std::get<1>(args).begin() ); }
    484         iterator end() { return iterator( std::get<0>(args).end(), std::get<1>(args).end() ); }
    485 };
    486 
    487 /// performs bounds check to ensure that all arguments are of the same length.
     498        group_iterate_t( const Args &... args ) : iterables( args... ) {}
     499
     500        using iterator = base_iterator<decltype(
     501                std::make_integer_sequence<std::size_t, sizeof...(Args)>())>;
     502
     503        iterator begin() { return iterator::make_begin( iterables ); }
     504        iterator end() { return iterator::make_end( iterables ); }
     505};
     506
     507// Helpers for the bounds checks (the non-varatic part of group_iterate):
     508static inline void runGroupBoundsCheck(size_t size0, size_t size1) {
     509        assertf( size0 == size1,
     510                "group iteration requires containers of the same size: <%zd, %zd>.",
     511                size0, size1 );
     512}
     513
     514static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) {
     515        assertf( size0 == size1 && size1 == size2,
     516                "group iteration requires containers of the same size: <%zd, %zd, %zd>.",
     517                size0, size1, size2 );
     518}
     519
     520/// Performs bounds check to ensure that all arguments are of the same length.
    488521template< typename... Args >
    489522group_iterate_t<Args...> group_iterate( Args &&... args ) {
    490         return group_iterate_t<Args...>(false, std::forward<Args>( args )...);
    491 }
    492 
    493 /// does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
     523        runGroupBoundsCheck( args.size()... );
     524        return group_iterate_t<Args...>( std::forward<Args>( args )... );
     525}
     526
     527/// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
    494528template< typename... Args >
    495529group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
    496         return group_iterate_t<Args...>(true, std::forward<Args>( args )...);
     530        return group_iterate_t<Args...>( std::forward<Args>( args )... );
    497531}
    498532
Note: See TracChangeset for help on using the changeset viewer.