#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 <typename It>
class Slicer {
public:
  Slicer(It begin, It end, size_t page_size) {
    for (size_t left = distance(begin, end); left > 0; ) {
      size_t current_page_size = std::min(page_size, left);
      It current_page_end = next(begin, current_page_size);
      pages_.push_back({begin, current_page_end});

      left -= current_page_size;
      begin = current_page_end;
    }
  }

  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_;
};

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