#pragma once

#include <vector>
#include <cmath>

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, std::size_t pageSize) {
    slicedPages = ceil((static_cast<double>(std::distance(begin, end)) / pageSize));
    Slice(begin, end, pageSize);
  }

  std::size_t size() const {
    return slicedPages;
  }

  auto begin() { return std::begin(pages_); }

  auto end() { return std::end(pages_); }

 private:
  void Slice(It begin, It end, std::size_t pageSize) {
    It pageIter = begin;

    for (; pageIter != end;) {
      std::size_t count{};
      begin = pageIter;
      for (; count < pageSize && pageIter != end;) {
        count++;
        pageIter++;
      }
      pages_.push_back({begin, pageIter});
    }

  }
  std::vector<IteratorRange<It>> pages_;
  std::size_t slicedPages = 0;
};

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

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

template<>
auto Slice(const IteratorRange<std::vector<int>::iterator> &c, size_t page_size) {
  return Slicer<std::vector<int>::iterator>(c.begin(), c.end(), page_size);
}