#pragma once
#include <vector>

template <typename It>
class IteratorRange {
 public:
    IteratorRange<It>(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 bgn, It end, const size_t p_sz) {
        const size_t sz = std::distance(bgn, end);

        for (size_t i = sz; i > 0;) {
            size_t temp = min(p_sz, i);
            auto last = std::next(bgn, temp);
            pages_.push_back(IteratorRange<It>(bgn, last));

            i -= temp;
            bgn = last;
        }
    }

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

    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 sz) { 
    return Slicer(c.begin(), c.end(), sz); 
}