#pragma once

#include <vector>
#include <cstddef>

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

    typedef It iterator;

    It begin() const {
        return begin_;
    }

    It end() const {
        return end_;
    }

    std::size_t size() const {
        return size_;
    }

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

template <typename It>
class Slicer {
 public:
    Slicer(It begin, It end, int page_size) : begin_(begin), end_(end), page_size_(page_size) {
        while (end - begin >= page_size_) {
            auto new_begin = begin;
            begin += page_size_;
            pages_.push_back(IteratorRange<It>(new_begin, begin));
        }
        if (begin != end) {
            pages_.push_back(IteratorRange<It>(begin, end));
        }
    }
    typename std::vector<IteratorRange<It>>::iterator begin() {
        return pages_.begin();
    }
    typename std::vector<IteratorRange<It>>::iterator end() {
        return pages_.end();
    }
    std::size_t size() const {
        return pages_.size();
    }

 private:
    It begin_, end_;
    int page_size_;
    std::vector<IteratorRange<It>> pages_;
};

template <typename C>
Slicer<typename C::iterator> Slice(C& c, std::size_t page_size) {
    return Slicer<typename C::iterator>(c.begin(), c.end(), page_size);
}

template <typename C>
Slicer<typename C::const_iterator> Slice(const C& c, std::size_t page_size) {
    return Slicer<typename C::const_iterator>(c.begin(), c.end(), page_size);
}