#pragma once

#include <vector>

using namespace std;

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:
    Slicer(It begin_it, It end_it, size_t page_size) {
        while (begin_it != end_it) {
            size_t slice_size = std::min(page_size, static_cast<size_t>(distance(begin_it, end_it)));
            pages_.push_back(IteratorRange<It>(begin_it, begin_it + slice_size));
            begin_it += slice_size;
        }
    }

    auto begin() {
        return pages_.begin();
    }

    auto begin() const {
        return pages_.begin();
    }

    auto end() {
        return pages_.end();
    }

    auto end() const {
        return pages_.end();
    }

    size_t size() const {
        return pages_.size();
    }
 private:
    std::vector<IteratorRange<It>> pages_;
};

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