/* * iterator_range.hpp as proposed http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3350.html by Jeffrey Yasskin <jyasskin@google.com> * * Created on: May 28, 2015 * Author: Jan Travnicek */ #ifndef __RANGE_HPP_ #define __RANGE_HPP_ #include <utility> #include "iterator.hpp" namespace ext { /** * \brief * Implementation of iterator_range, i.e. pair of iterators. The class provides most notably begin and end methods to allow the class be used in foreach context. * * \tparam Iterator the type of wrapped pair of iterators */ template<typename Iterator> class iterator_range { /** * \brief * The begin iterator */ Iterator m_begin; /** * \brief * The end iterator */ Iterator m_end; public: /** * \brief * Copy of iterator_category from the wrapped iterators */ typedef typename std::iterator_traits< Iterator >::iterator_category iterator_category; /** * \brief * Copy of value_type from the wrapped iterators */ typedef typename std::iterator_traits< Iterator >::value_type value_type; /** * \brief * Copy of difference_type from the wrapped iterators */ typedef typename std::iterator_traits< Iterator >::difference_type difference_type; /** * \brief * Copy of reference from the wrapped iterators */ typedef typename std::iterator_traits< Iterator >::reference reference; /** * \brief * Copy of pointer from the wrapped iterators */ typedef typename std::iterator_traits< Iterator >::pointer pointer; /** * \brief * Constructor of empty iterator_range. Both iterators are initialized to default (same) value. */ iterator_range ( ) { } /** * \brief * Constructor to make iterator_range from pair of iterators * * \param begin the begining of the wrapped iterator_range * \param end the end of the wrapped iterator_range */ constexpr iterator_range(Iterator begin, Iterator end) : m_begin ( begin ), m_end ( end ) { } /** * \brief * Accessor of the iterator to the begining. * * \return the begin iterator */ constexpr Iterator begin() const { return m_begin; } /** * \brief * Accessor of the iterator to the end. * * \return the end iterator */ constexpr Iterator end() const { return m_end; } /** * \brief * Getter of the first value in the iterator_range. * * \return reference to the first value */ constexpr reference front() const { return * m_begin; } /** * \brief * Getter of the last value in the iterator_range. * * \return reference to the last value */ constexpr reference back() const { return * ( m_end - 1 ); } /** * \brief * Array subscript operator implementation. * * \return reference to the value at given distance from the begining */ constexpr reference operator[](difference_type index) const { return m_begin [ index ]; } /** * \brief * Test whether the iterator_range is empty. * * \return true of the two iterators representing iterator_range are equal. */ constexpr bool empty() const { return m_begin == m_end; } /** * \brief * Getter of the distance between begin and end iterators. * * \return the distance between begin and end iterators */ constexpr size_t size() const { return std::distance ( m_begin, m_end ); } /** * \brief * Advances the begin iterator. */ void pop_front() { ++ m_begin; } /** * \brief * Advances the begin iterator \p n times. */ void pop_front(difference_type n) { m_begin = m_begin + n; } /** * \brief * Retracts the end iterator. */ void pop_back() { -- m_end; } /** * \brief * Retracts the end iterator \p n times. */ void pop_back(difference_type n) { m_end = m_end - n; } /** * \brief * Creates two sub ranges based on middle position. The element at the middle position is included in the second iterator_range. * * \param index the place where to cut the iterator_range in two * * \return two subranges */ std::pair< iterator_range, iterator_range > split(difference_type index) const { return std::make_pair ( slice ( 0, index ), slice ( index, 0 ) ); } /** * \brief * Creates a subrange of the iterator_range representing interaval of values from \p start to \p stop. * * If the \p start is positive or zero, the actual cut position is calcuated relative to the begining of the iterator_range. * If the \p start is negative, the actual cut position is calculated relative to the end of the iterator_range. * * If the \p end is positive, the actual cut position is calcuated relative to the begining of the iterator_range. * If the \p start is negative or zero, the actual cut position is calculated relative to the end of the iterator_range. * * Example iterator_range ( 0, 1, 2, 3, 4, 5 ).slice ( 1, 3 ) produces iterator_range ( 1, 2 ); * Example iterator_range ( 0, 1, 2, 3, 4, 5 ).slice ( -4, -1 ) produces iterator_range ( 2, 3, 4 ); * * \param start the begin position of the resulting subrange * \param end the end position of the resulting subrange * * \return subrange of the iterator_range. */ iterator_range slice(difference_type start, difference_type stop) const { return iterator_range ( ( start >= 0 ? m_begin : m_end ) + start, ( stop > 0 ? m_begin : m_end ) + stop ); } /** * \brief * Creates a subrange of the iterator_range representing interaval of values from \p start to the end of the iterator_range. * * If the \p start is positive or zero, the actual cut position is calcuated relative to the begining of the iterator_range. * If the \p start is negative, the actual cut position is calculated relative to the end of the iterator_range. * * The call is equivalent to slice ( begin, 0 ). * * Example iterator_range ( 0, 1, 2, 3, 4, 5 ).slice ( 1 ) produces iterator_range ( 1, 2, 3, 4, 5 ); * Example iterator_range ( 0, 1, 2, 3, 4, 5 ).slice ( -4 ) produces iterator_range ( 2, 3, 4, 5 ); * * \param start the begin position of the resulting subrange * * \return subrange of the iterator_range. */ iterator_range slice(difference_type start) const { return slice ( start, 0 ); } }; /** * \brief * Helper to create iterator_range from two iterators. * * \return the iterator_range instance from two iterators */ template < typename Iter > iterator_range < Iter > make_iterator_range ( Iter begin, Iter end ) { return iterator_range < Iter > ( begin, end ); } /** * Generalization of range for universaly referenced containers. * * \param cont the container to call end on * * \result the range over all elements of the array */ template <class Container> auto range ( Container && cont ) -> decltype ( std::forward < Container > ( cont ).range ( ) ) { return ext::make_iterator_range ( std::forward < Container > ( cont ).begin ( ), std::forward < Container > ( cont ).end ( ) ); } /** * Specialization of range for static array. * * \param arr the static array * * \result the range over all elements of the array */ template < class T, size_t N > constexpr ext::iterator_range < T * > range ( T ( & arr ) [ N ] ) noexcept { return ext::make_iterator_range ( begin ( arr ), end ( arr ) ); } } /* namespace ext */ #endif /* __RANGE_HPP_ */