#pragma once

#include <vector>

template<class It>
class IteratorRange {
 public:
    IteratorRange(It b, It e) : begin_(b), end_(e), size_(std::distance(b, e)) {}

    It begin() const {
        return begin_;
    }

    It end() const {
        return end_;
    }

    size_t size() const {
        return size_;
    }


 private:
    It begin_, end_;
    size_t size_;
};

template <typename It>
class Slicer {
public:
    explicit Slicer(It begin, It end, int page_size) {
        It my_it = begin;
        while (my_it < end) {
            IteratorRange<It> *new_IR;
            if (my_it + page_size <= end) {
                new_IR = new IteratorRange<It>(my_it, my_it + page_size);
            } else {
                new_IR = new IteratorRange<It>(my_it, end);
            }
            pages_.push_back(*new_IR);
            my_it += page_size;
        }
    }

    size_t size() const {
        return pages_.size();
    }

    typename std::vector<IteratorRange<It>>::const_iterator begin() const {
        return pages_.begin();
    }

    typename std::vector<IteratorRange<It>>::const_iterator end() const {
        return pages_.end();
    }
private:
    std::vector<IteratorRange<It>> pages_;
};

template <typename C>
auto Slice(C& c, size_t page_size) {
    typedef decltype(c.begin()) type;
    Slicer<type> a(c.begin(), c.end(), page_size);
    return a;
}
template <typename It>
Slicer<It> Slice(const IteratorRange<It>& c, size_t page_size) {
    auto* new_slicer = new Slicer<It>(c.begin(), c.end(), page_size);
    return *new_slicer;
}