#pragma once

#include <vector>
#include <cstddef>
template<class It>
class IteratorRange {
 private:
  It begin_, end_;
  std::size_t size_;
  
 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_;
  }
  std::size_t size() const {
    return size_;
  }
};

template<typename It>
class Slicer {
 private:
  It begin_, end_;
  int size_;
  std::vector<IteratorRange<It>> pages_;
  
 public:
  Slicer(It begin, It end, int size) : begin_(begin), end_(end), size_(size) {
    while (std::distance(begin, end) >= size) {
      auto temp = begin;
      advance(begin, size);
      pages_.push_back(IteratorRange<It>(temp, begin));
    }
    if (begin != end) {
      pages_.push_back(IteratorRange<It>(begin, end));
    }
  }
  typename std::vector<IteratorRange<It>>::iterator begin() {
    return pages_.begin();
  }
  typename std::vector<IteratorRange<It>>::iterator end() {
    return pages_.end();
  }
  std::size_t size() const {
    return pages_.size();
  }

};

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