range_input.h

Back to Input

pastel/sys/input/

// Description: Range input
// Documentation: input.txt

#ifndef PASTELSYS_RANGE_INPUT_H
#define PASTELSYS_RANGE_INPUT_H

#include "pastel/sys/range.h"
#include "pastel/sys/mytypes.h"
#include "pastel/sys/ensure.h"

#include <type_traits>
#include <iterator>

namespace Pastel
{

    //! Range input
    template <typename Range>
    class Range_Input
    {
    private:
        using Iterator = typename boost::range_iterator<const Range>::type;
        using Type = typename boost::range_value<Range>::type;
        using Return = decltype(*std::declval<Iterator>());

        static constexpr bool IsRandomAccess =
            std::is_same<
                typename boost::iterator_traversal<Iterator>::type,
                boost::random_access_traversal_tag>::value;

    public:
        Range_Input()
            : begin_()
            , end_()
        {
        }

        Range_Input(const Range& range)
            : begin_(std::begin(range))
            , end_(std::end(range))
        {
        }

        integer nHint() const
        {
            if (IsRandomAccess)
            {
                return std::distance(begin_, end_);
            }

            return 0;
        }

        template <
            typename Type = void,
            typename = EnableIfC<IsRandomAccess, Type>
        >
        integer n() const
        {
            return nHint();
        }

        bool empty() const
        {
            return begin_ == end_;
        }

        // FIX: Change to use decltype(auto) fter
        // Visual Studio 2015 fixes its bugs.
        Return get() const
        {
            PENSURE(!empty());
            return *begin_;
        }

        // FIX: Change to use decltype(auto) fter
        // Visual Studio 2015 fixes its bugs.
        template <
            typename Type = void,
            typename = EnableIfC<IsRandomAccess, Type>
        >
        Return operator[](integer i) const
        {
            PENSURE_OP(i, >=, 0);
            PENSURE_OP(i, <, n());

            return begin_[i];
        }

        void pop()
        {
            PENSURE(!empty());
            ++begin_;
        }

    private:
        Iterator begin_;
        Iterator end_;
    };

    template <typename Range>
    Range_Input<Range> rangeInput(
        const Range& range)
    {
        return range;
    }

    template <typename Iterator>
    Range_Input<boost::iterator_range<Iterator>> rangeInput(
        const Iterator& begin, const Iterator& end)
    {
        return Pastel::rangeInput(range(begin, end));
    }

}

#endif