counting_iterator.h

Back to Iterator

pastel/sys/iterator/

// Description: CountingIterator class
// Detail: An iterator adapter for dereferencing the adapted iterator
// Documentation: iterator.txt

#ifndef PASTELSYS_COUNTING_ITERATOR_H
#define PASTELSYS_COUNTING_ITERATOR_H

#include "pastel/sys/mytypes.h"

#include <boost/operators.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>
#include <boost/iterator/iterator_traits.hpp>

#include <type_traits>
#include <iterator>

namespace Pastel
{
    template <typename Type>
    class CountingIterator;

    namespace CountingIterator_
    {

        template <typename Type_, bool IsArithmetic>
        class Base
        {
        public:
            typedef boost::random_access_iterator_helper<
                CountingIterator<Type_>, Type_, integer, const Type_, const Type_>
                Type;
        };

        template <typename Type_>
        class Base<Type_, false>
        {
        public:
            typedef boost::random_access_iterator_helper<
                CountingIterator<Type_>, Type_, integer, const Type_, const Type_> 
                RandomAccess_Base;

            typedef boost::bidirectional_iterator_helper<
                CountingIterator<Type_>, Type_, integer, const Type_, const Type_>
                Bidirectional_Base;

            typedef boost::forward_iterator_helper<
                CountingIterator<Type_>, Type_, integer, const Type_, const Type_>
                Forward_Base;

            typedef std::is_same<typename boost::iterator_category<Type_>::type,
                std::random_access_iterator_tag> IsRandomAccess;

            typedef std::is_same<typename boost::iterator_category<Type_>::type,
                std::bidirectional_iterator_tag> IsBidirectional;

            typedef typename
                boost::mpl::if_<
                IsRandomAccess,
                RandomAccess_Base,
                typename boost::mpl::if_<
                IsBidirectional,
                Bidirectional_Base, Forward_Base>::type>::type Type;
        };

    }

    template <typename Type>
    class CountingIterator
        : public CountingIterator_::Base<Type, std::is_arithmetic<Type>::value>::Type
    {
    public:
        // Using default copy constructor.
        // Using default assignment.
        // Using default destructor.

        CountingIterator()
            : data_()
        {
        }

        explicit CountingIterator(const Type& data)
            : data_(data)
        {
        }

        CountingIterator& operator++()
        {
            ++data_;
            return *this;
        }

        CountingIterator& operator--()
        {
            --data_;
            return *this;
        }

        CountingIterator& operator+=(integer that)
        {
            data_ += that;
            return *this;
        }

        CountingIterator& operator-=(integer that)
        {
            data_ -= that;
            return *this;
        }

        integer operator-(const CountingIterator& that) const
        {
            return data_ - that.data_;
        }

        Type operator*() const
        {
            // Note: this function must return 'data_' by value,
            // for otherwise *(iter + n) would refer to an already
            // destructed temporary.
            return data_;
        }

        bool operator==(const CountingIterator& that) const
        {
            return data_ == that.data_;
        }

        bool operator<(const CountingIterator& that) const
        {
            return data_ < that.data_;
        }

    private:
        Type data_;
    };

    template <typename Type>
    CountingIterator<Type> countingIterator(const Type& that)
    {
        return CountingIterator<Type>(that);
    }

    template <typename Type>
    using CountingRange = boost::iterator_range<CountingIterator<Type>>;

    template <typename Type>
    CountingRange<Type> countingRange(
        const Type& begin,
        const Type& end)
    {
        return range(
            countingIterator(begin),
            countingIterator(end));
    }

    template <typename Range>
    decltype(auto) countingRange(Range&& range)
    {
        return countingRange(
            std::begin(std::forward<Range>(range)),
            std::end(std::forward<Range>(range)));
    }

}

#endif