Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Common/utility.h

    r7491f97 r1b65595  
    452452
    453453// -----------------------------------------------------------------------------
    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 
    458 template<typename... Args>
    459 class 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 )... );
     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
     459template< typename T1, typename T2 >
     460struct group_iterate_t {
     461private:
     462        std::tuple<T1, T2> args;
     463public:
     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) );
    481478                }
    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                 }
     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) ); }
    495481        };
    496482
    497 public:
    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):
    508 static 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 
    514 static 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.
     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.
    521488template< typename... Args >
    522489group_iterate_t<Args...> group_iterate( Args &&... args ) {
    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.
     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.
    528494template< typename... Args >
    529495group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
    530         return group_iterate_t<Args...>( std::forward<Args>( args )... );
     496        return group_iterate_t<Args...>(true, std::forward<Args>( args )...);
    531497}
    532498
Note: See TracChangeset for help on using the changeset viewer.