/* * foreach.hpp * * This file is part of Algorithms library toolkit. * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) * Algorithms library toolkit is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * Algorithms library toolkit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. * * Created on: Apr 1, 2013 * Author: Jan Travnicek */ #ifndef __FOREACH_HPP_ #define __FOREACH_HPP_ #include <tuple> #include <utility> #include <extensions/container/tuple.hpp> namespace ext { /** * \brief * A class for packing a tuple of iterators and synchronizing them. All are incremented, decremented, dereferenced together. */ template < class ... Iterators > class const_tuple_foreach_iterator { /** * The underlying pack of iterators. */ ext::tuple < Iterators ... > current; /** * \brief * Helper method to dereference all operators. The method collects the results of dereference operator on individual iterators. * * \tparam I ... indexes to the the iterator tuple * * \return a tuple of values the individual iterators refer to */ template < size_t ... I > ext::tuple < const typename Iterators::value_type & ... > callDerefOperator ( const std::index_sequence < I ... > & ) const { return ext::tie ( * std::get < I > ( current ) ... ); } /** * \brief * Helper method to increment all underlying iterators. */ template < size_t ... I > void callIncOperator ( const std::index_sequence < I ... > & ) { ext::tie ( ++std::get < I > ( current ) ... ); } /** * \brief * Helper method to decrement all underlying iterators. */ template < size_t ... I > void callDecOperator ( const std::index_sequence < I ... > & ) { ext::tie ( --std::get < I > ( current ) ... ); } public: /** * \brief * Constructor of the iterator tuple from a pack of iterators. * * \param it ... pack of iterators * */ explicit const_tuple_foreach_iterator ( Iterators ... it ) : current ( it ... ) { } /** * \brief * Getter of an Ith iterator from the tuple of underlying iterators. * * \tparam I the specification of the iterator index. */ template < size_t I > decltype ( std::get < I > ( current ) ) base ( ) const { return std::get < I > ( current ); } /** * \brief * Implementation of dereference operator on all iterators in the tuple. * * \return a tuple of values the individual iterators refer to */ template < size_t ... I > ext::tuple < const typename Iterators::value_type & ... > operator *( ) const { return callDerefOperator ( std::index_sequence_for < Iterators ... > { } ); } /** * \brief * Prefix version of increment operator that propagates the call to all underlying iterators. * * \return this */ const_tuple_foreach_iterator & operator ++( ) { callIncOperator ( std::index_sequence_for < Iterators ... > { } ); return * this; } /** * \brief * Prefix version of decrement operator that propagates the call to all underlying iterators. * * \return this */ const_tuple_foreach_iterator & operator --( ) { callDecOperator ( std::index_sequence_for < Iterators ... > { } ); return * this; } /** * \brief * Postfix version of increment operator that propagates the call to all underlying iterators. * * \return original value */ const_tuple_foreach_iterator operator ++( int ) { const_tuple_foreach_iterator temp = * this; ++( * this ); return temp; } /** * \brief * Postfix version of decrement operator that propagates the call to all underlying iterators. * * \return original value */ const_tuple_foreach_iterator operator --( int ) { const_tuple_foreach_iterator temp = * this; --( * this ); return temp; } /** * \brief * Implementation of equality comparison operator on tuple of iterators * * \param other the other instance to compare with * * \return bool true if iterators of this class are equal to iterators of the other class */ bool operator ==( const const_tuple_foreach_iterator < Iterators ... > & other ) { return this->current == other.current; } /** * \brief * Implementation of inequality comparison operator on tuple of iterators * * \param other the other instance to compare with * * \return bool true if iterators of this class are not equal to iterators of the other class */ bool operator !=( const const_tuple_foreach_iterator < Iterators ... > & other ) { return !( * this == other ); } }; /** * \brief * Function construction of the tuple iterator. * * \tparam Iterators ... the types of interators to pack * * \param its ... the actual iterators to pack * * \return the tuple of iterators itself mimicking the iterator interface to some level */ template < class ... Iterators > const_tuple_foreach_iterator < Iterators ... > make_tuple_foreach_iterator ( Iterators ... its ) { return const_tuple_foreach_iterator < Iterators ... > ( its ... ); } /** * \brief * Class providing begin and end methods to allow simple use of packed iterators in foreach variant of the for loop * * \tparam Types ... the types of begin/end source classes */ template < class ... Types > class const_tuple_foreach { /** * \brief * Source classes to retrieve begin and end iterators from */ const ext::tuple < const Types & ... > data; /** * \brief * Helper to call begin on source classes. * * \tparam I the specification of the iterator index * * \return the iterator tuple class */ 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 ( ) ... ); } /** * \brief * Helper to call end on source classes. * * \tparam I the specification of the iterator index * * \return the iterator tuple class */ 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: /** * \brief * Constructor of foreach tuple pack helper * * \param args ... the actual begin/end source classes */ const_tuple_foreach ( const Types & ... args ) : data ( args ... ) { } /** * \brief * Getter of pack of begin iterators. * * \return the iterator tuple class */ const_tuple_foreach_iterator < typename Types::const_iterator ... > begin ( ) const { return callBegin ( std::index_sequence_for < Types ... > { } ); } /** * \brief * Getter of pack of end iterators. * * \return the iterator tuple class */ const_tuple_foreach_iterator < typename Types::const_iterator ... > end ( ) const { return callEnd ( std::index_sequence_for < Types ... > { } ); } }; /** * \brief * Function construction of foreach tuple pack helper * * \tparam Types ... the types of begin/end source classes * * \param args ... the actual begin/end source classes * * \return the tuple of iterators itself mimicking the iterator interface to some level */ template < class ... Types > const_tuple_foreach < Types ... > make_tuple_foreach ( const Types & ... args ) { return const_tuple_foreach < Types ... > ( args ... ); } /** * \brief * Class wrapping an integral type, but with pointer iterface. * * \tparam IntegralType the type of values the iterator provides */ template < class IntegralType > class virtual_pointer_to_integer { /** * \brief * The value of integral type. */ IntegralType m_data; public: typedef IntegralType value_type; typedef std::ptrdiff_t difference_type; typedef IntegralType * pointer; typedef IntegralType reference; typedef std::bidirectional_iterator_tag iterator_category; /** * \brief * Constructor of the virtual pointer class. * * \param data the value to hold */ virtual_pointer_to_integer ( IntegralType data ) : m_data ( data ) { } /** * \brief * Method to retrieve the integral value. * * \return the current value */ IntegralType operator * ( ) const { return m_data; } /** * \brief * Prefix increment operator to increment the hold value. * * \return this */ virtual_pointer_to_integer & operator ++( ) { m_data ++; return * this; } /** * \brief * Prefix decrement operator to decrement the hold value. * * \return this */ virtual_pointer_to_integer & operator --( ) { m_data --; return * this; } /** * \brief * Postfix increment operator to increment the hold value. * * \return original value */ virtual_pointer_to_integer operator ++( int ) { virtual_pointer_to_integer temp = * this; ++( * this ); return temp; } /** * \brief * Postfix decrement operator to decrement the hold value. * * \return original value */ virtual_pointer_to_integer operator --( int ) { virtual_pointer_to_integer temp = * this; --( * this ); return temp; } /** * \brief * Equality operator. Two classes are equal if the data they hold is the same. * * \param other the other instance to compare with * * \return bool true if this and other classes hold the same value */ bool operator ==( const virtual_pointer_to_integer < IntegralType > & other ) { return this->m_data == other.m_data; } /** * \brief * Inequality operator. Two classes are not equal if the data they hold is different. * * \param other the other instance to compare with * * \return bool true if this and other classes hold different value */ bool operator !=( const virtual_pointer_to_integer < IntegralType > & other ) { return !( * this == other ); } }; /** * \brief * Representation of integer sequence usable in foreach form of for loop. * * The class provides begin and end iterators. */ template < class IntegralType > class sequence { /** * \brief * The start value of the sequence. Included in the sequence. */ IntegralType m_first; /** * \brief * The end value of the sequence. Not included in the sequence. */ IntegralType m_last; public: /** * \brief * The constructor of the sequence based on the range * * \param first the start value of the sequence * \param last the end value of the sequence */ sequence ( IntegralType first, IntegralType last ) : m_first ( first ), m_last ( last ) { } /** * \brief * Constructor of the sequence class based on the size. * * \param size the length of the sequence from zero */ sequence ( IntegralType size ) : m_first ( 0 ), m_last ( size ) { } /** * \brief * Getter of the begin iterator into the sequence. * * \return iterator to the begining of the sequence */ virtual_pointer_to_integer < IntegralType > begin ( ) { return virtual_pointer_to_integer < IntegralType > ( m_first ); } /** * \brief * Getter of the end iterator into the sequence. * * \return iterator to the end of the sequence */ virtual_pointer_to_integer < IntegralType > end ( ) { return virtual_pointer_to_integer < IntegralType > ( m_last ); } }; } /* namespace ext */ #endif /* __FOREACH_HPP_ */