#pragma once

#include <vector>

namespace std {
    template<class It>
    class IteratorRange {
    public:
        IteratorRange(It b, It e) : begin_(b), end_(e), size_(std::distance(b, e)) {}
        typedef It iterator;
        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 end, size_t page_size) {
            auto lastPtr = begin;
            while (true) {
                if (lastPtr + page_size >= end) {
                    pages_.push_back(IteratorRange<It>(lastPtr, end));
                    break;
                }
                else {
                    pages_.push_back(IteratorRange<It>(lastPtr, lastPtr + page_size));
                }
                lastPtr += page_size;
            }
        }

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

        typename vector<IteratorRange<It>>::iterator end() {
            return pages_.end();
        }

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

    private:
        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);
    }
}