#ifndef ITERATORRANGE_H
#define ITERATORRANGE_H

#include <utility>
#include <iterator>

template <typename It>
struct iterator_range : std::pair<It, It>
{
    using std::pair<It, It>::first;
    using std::pair<It, It>::second;

    iterator_range(std::pair<It, It> const& pair)
        : std::pair<It, It>(pair)
    {}
    iterator_range(It begin, It end)
        : std::pair<It, It>(begin, end)
    {}

    It begin() const { return first; }
    It end() const { return second; }

    bool empty() const { return first == second; }

    typedef typename std::iterator_traits<It>::value_type      value_type;
    typedef typename std::iterator_traits<It>::difference_type difference_type;
    typedef typename std::iterator_traits<It>::pointer         pointer;
    typedef typename std::iterator_traits<It>::reference       reference;

    difference_type size() const { return std::distance(first, second); }

    reference front() const { return *first; }
    reference back() const { return *(second - 1); }
};

template <typename It>
iterator_range<It> make_range(It begin, It end) {
    return iterator_range<It>(begin, end);
}

template <typename It>
iterator_range<It> as_range(std::pair<It, It> const& pair) {
    return iterator_range<It>(pair);
}

template <typename Range>
auto in_reverse(Range&& range)->iterator_range<decltype(range.rbegin())> {
    return make_range(range.rbegin(), range.rend());
}

#endif // ITERATORRANGE_H
