#ifndef ITER_CHUNKED_HPP_ #define ITER_CHUNKED_HPP_ #include "internal/iterbase.hpp" #include "internal/iteratoriterator.hpp" #include #include #include #include #include #include #include namespace iter { namespace impl { template class Chunker; } template impl::Chunker chunked(Container&&, std::size_t); template impl::Chunker> chunked( std::initializer_list, std::size_t); } template class iter::impl::Chunker { private: Container container; std::size_t chunk_size; Chunker(Container&& c, std::size_t sz) : container(std::forward(c)), chunk_size{sz} {} friend Chunker iter::chunked(Container&&, std::size_t); template friend Chunker> iter::chunked( std::initializer_list, std::size_t); using IndexVector = std::vector>; using DerefVec = IterIterWrapper; public: Chunker(Chunker&&) = default; class Iterator : public std::iterator { private: iterator_type sub_iter; iterator_type sub_end; DerefVec chunk; std::size_t chunk_size = 0; bool done() const { return this->chunk.empty(); } void refill_chunk() { this->chunk.get().clear(); std::size_t i{0}; while (i < chunk_size && this->sub_iter != this->sub_end) { chunk.get().push_back(this->sub_iter); ++this->sub_iter; ++i; } } public: Iterator(iterator_type&& in_iter, iterator_type&& in_end, std::size_t s) : sub_iter{std::move(in_iter)}, sub_end{std::move(in_end)}, chunk_size{s} { this->chunk.get().reserve(this->chunk_size); this->refill_chunk(); } Iterator& operator++() { this->refill_chunk(); return *this; } Iterator operator++(int) { auto ret = *this; ++*this; return ret; } bool operator!=(const Iterator& other) const { return !(*this == other); } bool operator==(const Iterator& other) const { return this->done() == other.done() && (this->done() || !(this->sub_iter != other.sub_iter)); } DerefVec& operator*() { return this->chunk; } DerefVec* operator->() { return &this->chunk; } }; Iterator begin() { return {std::begin(this->container), std::end(this->container), chunk_size}; } Iterator end() { return {std::end(this->container), std::end(this->container), chunk_size}; } }; template iter::impl::Chunker iter::chunked( Container&& container, std::size_t chunk_size) { return {std::forward(container), chunk_size}; } template iter::impl::Chunker> iter::chunked( std::initializer_list il, std::size_t chunk_size) { return {std::move(il), chunk_size}; } #endif