diff --git a/alib2std/src/extensions/foreach.hpp b/alib2std/src/extensions/foreach.hpp index 7937c60aadb6e44e6b7d62ba4b897f9ff0a41346..fb382dac3aa525d5376d4d40cd4c4c3ef1b76924 100644 --- a/alib2std/src/extensions/foreach.hpp +++ b/alib2std/src/extensions/foreach.hpp @@ -10,116 +10,118 @@ namespace std { -template <class Iterator1, class Iterator2> -class const_pair_foreach_iterator { - Iterator1 current1; - Iterator2 current2; +template < class ... Iterators > +class const_tuple_foreach_iterator { + std::tuple < Iterators ... > current; -public: - typedef Iterator1 iterator_type1; - typedef typename iterator_traits<Iterator1>::iterator_category iterator_category1; - typedef typename iterator_traits<Iterator1>::value_type value_type1; - typedef Iterator1 pointer1; - typedef const value_type1& reference1; - - typedef Iterator2 iterator_type2; - typedef typename iterator_traits<Iterator2>::iterator_category iterator_category2; - typedef typename iterator_traits<Iterator2>::value_type value_type2; - typedef Iterator2 pointer2; - typedef const value_type2& reference2; - - explicit const_pair_foreach_iterator() { + template < size_t ... I > + std::tuple < const typename Iterators::value_type & ... > callDerefOperator ( const std::index_sequence < I ... > & ) const { + return std::tie ( * std::get < I > ( current ) ... ); } - explicit const_pair_foreach_iterator (Iterator1 it1, Iterator2 it2) : current1(it1), current2(it2) { + template < size_t ... I > + void callIncOperator ( const std::index_sequence < I ... > & ) { + std::tie ( ++std::get < I > ( current ) ... ); } - const_pair_foreach_iterator (const const_pair_foreach_iterator<Iterator1, Iterator2>& it) : current1(it.current1), current2(it.current2) { + template < size_t ... I > + void callDecOperator ( const std::index_sequence < I ... > & ) { + std::tie ( --std::get < I > ( current ) ... ); } - const_pair_foreach_iterator& operator= (const const_pair_foreach_iterator<Iterator1, Iterator2>& it) { - current1 = it.current1; - current2 = it.current2; +public: + explicit const_tuple_foreach_iterator ( ) { } - iterator_type1 base1() const { - return current1; + explicit const_tuple_foreach_iterator ( Iterators ... it ) : current ( it ... ) { } - iterator_type2 base2() const { - return current2; + template < int number > + decltype ( std::get < number > ( current ) )base ( ) const { + return std::get < number > ( current ); } - std::tuple<reference1, reference2> operator*() const { - return std::tie(*current1, *current2); + template < size_t ... I > + std::tuple < const typename Iterators::value_type & ... > operator *( ) const { + return callDerefOperator ( std::index_sequence_for < Iterators ... > { } ); } - const_pair_foreach_iterator& operator++() { - ++current1; - ++current2; - return *this; + template < size_t ... I > + const_tuple_foreach_iterator & operator ++( ) { + callIncOperator ( std::index_sequence_for < Iterators ... > { } ); + return * this; } - const_pair_foreach_iterator& operator--() { - --current1; - --current2; - return *this; + template < size_t ... I > + const_tuple_foreach_iterator & operator --( ) { + callDecOperator ( std::index_sequence_for < Iterators ... > { } ); + return * this; } - const_pair_foreach_iterator operator++(int) { - const_pair_foreach_iterator temp = *this; - ++current1; - ++current2; + const_tuple_foreach_iterator operator ++( int ) { + const_tuple_foreach_iterator temp = * this; + + ++( * this ); return temp; } - const_pair_foreach_iterator operator--(int) { - const_pair_foreach_iterator temp = *this; - --current1; - --current2; + const_tuple_foreach_iterator operator --( int ) { + const_tuple_foreach_iterator temp = * this; + + --( * this ); return temp; } - bool operator== (const const_pair_foreach_iterator<Iterator1, Iterator2>& other) { - return this->current1 == other.current1 && this->current2 == other.current2; + bool operator ==( const const_tuple_foreach_iterator < Iterators ... > & other ) { + return this->current == other.current; } - bool operator!= (const const_pair_foreach_iterator<Iterator1, Iterator2>& other) { - return ! ( *this == other ); + bool operator !=( const const_tuple_foreach_iterator < Iterators ... > & other ) { + return !( * this == other ); } }; -template<class Iterator1, class Iterator2> -const_pair_foreach_iterator<Iterator1, Iterator2> make_pair_foreach_iterator (Iterator1 it1, Iterator2 it2) { - return const_pair_foreach_iterator<Iterator1, Iterator2>(it1, it2); +template < class ... Iterators > +const_tuple_foreach_iterator < Iterators ... > make_tuple_foreach_iterator ( Iterators ... its ) { + return const_tuple_foreach_iterator < Iterators ... > ( its ... ); } -template<class T, class R> -class const_pair_foreach { +template < class ... Types > +class const_tuple_foreach { - const T& first; - const R& second; + const std::tuple < const Types & ... > data; + + template < size_t ... I > + const_tuple_foreach_iterator < typename Types::const_iterator ... > callBegin ( const std::index_sequence < I ... > & ) const { + return make_tuple_foreach_iterator ( std::get < I > ( data ).cbegin ( ) ... ); + } + + template < size_t ... I > + const_tuple_foreach_iterator < typename Types::const_iterator ... > callEnd ( const std::index_sequence < I ... > & ) const { + return make_tuple_foreach_iterator ( std::get < I > ( data ).cend ( ) ... ); + } public: - const_pair_foreach(const T& first, const R& second) : first(first), second(second) {} + const_tuple_foreach ( const Types & ... args ) : data ( args ... ) { } - const_pair_foreach_iterator<typename T::const_iterator, typename R::const_iterator> begin() const { - return make_pair_foreach_iterator(first.begin(), second.begin()); + template < int ... I > + const_tuple_foreach_iterator < typename Types::const_iterator ... > begin ( ) const { + return callBegin ( std::index_sequence_for < Types ... > { } ); } - const_pair_foreach_iterator<typename T::const_iterator, typename R::const_iterator> end() const { - return make_pair_foreach_iterator(first.end(), second.end()); + template < int ... I > + const_tuple_foreach_iterator < typename Types::const_iterator ... > end ( ) const { + return callEnd ( std::index_sequence_for < Types ... > { } ); } }; -template<class T, class R> -const_pair_foreach<T, R> make_pair_foreach(const T& first, const R& second) { - return const_pair_foreach<T, R>(first, second); +template < class ... Types > +const_tuple_foreach < Types ... > make_tuple_foreach ( const Types & ... args ) { + return const_tuple_foreach < Types ... > ( args ... ); } } /* namespace std */ #endif /* __FOREACH_HPP_ */ - diff --git a/alib2std/src/extensions/utility.hpp b/alib2std/src/extensions/utility.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1c3b8335ab5bd7d71f30e730445e9631536f2efb --- /dev/null +++ b/alib2std/src/extensions/utility.hpp @@ -0,0 +1,38 @@ +/* + * utility.hpp + * + * Created on: Apr 7, 2016 + * Author: Jan Travnicek + */ + +#ifndef __UTILITY_HPP_ +#define __UTILITY_HPP_ + +namespace std { + + // TODO remove after switching to c++14 +template < size_t ... I > +struct index_sequence { + typedef index_sequence < I ... > type; +}; + +template < size_t N, size_t ... I > +struct make_index_sequence_helper : make_index_sequence_helper < N - 1, N - 1, I ... > { +}; + +template < size_t ... I > +struct make_index_sequence_helper < 0, I ... > { + typedef index_sequence < I ... > type; +}; + +template < size_t N > +struct make_index_sequence : make_index_sequence_helper < N >::type { +}; + +template < typename ... T > +struct index_sequence_for : make_index_sequence < sizeof ... ( T ) > { +}; + +} /* namespace std */ + +#endif /* __UTILITY_HPP_ */ diff --git a/alib2std/src/foreach b/alib2std/src/foreach index ebe1467f89cce2273385a6a4924bbddec819c9b4..b7b651779b8363361150cc26f2224eb885d25853 100644 --- a/alib2std/src/foreach +++ b/alib2std/src/foreach @@ -2,6 +2,7 @@ #define __FOREACH_HEADER_WRAPPER_ #include "tuple" +#include "utility" #include "extensions/foreach.hpp" #endif /* __FOREACH_HEADER_WRAPPER_ */ diff --git a/alib2std/src/utility b/alib2std/src/utility new file mode 100644 index 0000000000000000000000000000000000000000..4ff6cbc171882d3ec6fae271d11ab0bb3e32b730 --- /dev/null +++ b/alib2std/src/utility @@ -0,0 +1,9 @@ +#ifndef __UTILITY_HEADER_WRAPPER_ +#define __UTILITY_HEADER_WRAPPER_ + +#include <bits/../utility> +#include <cstddef> +#include "extensions/utility.hpp" + +#endif /* __UTILITY_HEADER_WRAPPER_ */ + diff --git a/alib2std/test-src/extensions/ForeachTest.cpp b/alib2std/test-src/extensions/ForeachTest.cpp index a0f4051edad94c09efa944e22949b76385c06b8f..8ebe838d7fb73cb052d2a4b312bf4ba64f6123bc 100644 --- a/alib2std/test-src/extensions/ForeachTest.cpp +++ b/alib2std/test-src/extensions/ForeachTest.cpp @@ -15,13 +15,27 @@ void ForeachTest::tearDown() { void ForeachTest::testForeach() { std::vector<int> vector1 {1, 2, 3}; - std::list<int> vector2 {2, 3, 4}; + std::list<int> list1 {2, 3, 4}; int i = 1; - for(const std::tuple<const int&, const int&>& elements : std::make_pair_foreach(vector1, vector2)) { + for(const std::tuple<const int&, const int&>& elements : std::make_tuple_foreach(vector1, list1)) { CPPUNIT_ASSERT(std::get<0>(elements) == i); CPPUNIT_ASSERT(std::get<1>(elements) == i + 1); i++; } } +void ForeachTest::testForeach2() { + std::vector<int> vector1 {1, 2, 3}; + std::list<int> list1 {2, 3, 4}; + std::set<int> set1 {3, 4, 5}; + + int i = 1; + for(const std::tuple<const int&, const int&, const int&>& elements : std::make_tuple_foreach(vector1, list1, set1)) { + CPPUNIT_ASSERT(std::get<0>(elements) == i); + CPPUNIT_ASSERT(std::get<1>(elements) == i + 1); + CPPUNIT_ASSERT(std::get<2>(elements) == i + 2); + i++; + } +} + diff --git a/alib2std/test-src/extensions/ForeachTest.h b/alib2std/test-src/extensions/ForeachTest.h index e64820a28bb0ce2b3f8486bf5e4bcba58d03ad02..8eabed1cdeec970fafbf0ca2d68b1a80a6827bb5 100644 --- a/alib2std/test-src/extensions/ForeachTest.h +++ b/alib2std/test-src/extensions/ForeachTest.h @@ -7,6 +7,7 @@ class ForeachTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ForeachTest ); CPPUNIT_TEST( testForeach ); + CPPUNIT_TEST( testForeach2 ); CPPUNIT_TEST_SUITE_END(); public: @@ -14,6 +15,7 @@ public: void tearDown(); void testForeach(); + void testForeach2(); }; #endif // COMPARE_TEST_H_