#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 <class It>
class Slicer {
public:
    Slicer(It begin_, It end_, size_t page_size) {
        for (auto it = begin_; it != end_; it = std::next(it, min_check(it, end_, page_size))) {
            pages_.push_back(IteratorRange<It>(it, std::next(it, min_check(it, end_, page_size))));
        }
    }

    Slicer() = default;

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

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

    size_t size() const {
        return pages_.size();
    }
private:
    std::vector<IteratorRange<It>> pages_;
    auto min_check(It iter, It end_, size_t page_size){
        return std::min<size_t>(std::distance(iter, end_), page_size);
    }
};

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