#ifndef ITER_BATCHED_HPP_ #define ITER_BATCHED_HPP_ #include "internal/iterator_wrapper.hpp" #include "internal/iteratoriterator.hpp" #include "internal/iterbase.hpp" #include #include #include #include #include #include #include namespace iter { namespace impl { template class Batcher; using BatchedFn = IterToolFnBindSizeTSecond; } constexpr impl::BatchedFn batched{}; } template class iter::impl::Batcher { private: Container container_; std::size_t num_batches_; Batcher(Container&& container, std::size_t const num_batches) : container_(std::forward(container)), num_batches_{num_batches} {} friend BatchedFn; template using IndexVector = std::vector>; template using DerefVec = IterIterWrapper>; public: Batcher(Batcher&&) = default; template class Iterator { private: template friend class Iterator; std::shared_ptr> batch_ = std::make_shared>(); IteratorWrapper sub_iter_; IteratorWrapper sub_end_; std::size_t num_batches_; std::size_t size_; std::size_t count_; bool done() const { return batch_->empty(); } void refill_batch() { batch_->get().clear(); if (count_ < num_batches_) { std::size_t const batch_size(size_ / num_batches_ + std::min(1, (size_ % num_batches_) / (count_ + 1))); batch_->get().reserve(batch_size); for (std::size_t i = 0; i < batch_size; ++i) { batch_->get().push_back(sub_iter_); ++sub_iter_; } ++count_; } } public: using iterator_category = std::input_iterator_tag; using value_type = DerefVec; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; template struct distance_helper { static constexpr difference_type distance(Iter1 it1, Iter2 it2) { difference_type dist(0); for (; it1 != it2; ++it1) ++dist; return dist; } }; template struct distance_helper && std::is_arithmetic_v>> { static constexpr difference_type distance(Iter1 it1, Iter2 it2) { return std::distance(it1, it2); } }; template difference_type distance(Iter1 it1, Iter2 it2) const { return distance_helper::distance(it1, it2); } Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, std::size_t num_batches) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, num_batches_{num_batches}, size_{static_cast(distance(sub_iter_, sub_end_))}, count_{0} { refill_batch(); } Iterator& operator++() { refill_batch(); return *this; } Iterator operator++(int) { auto ret = *this; ++*this; return ret; } template bool operator!=(const Iterator& other) const { return !(*this == other); } template bool operator==(const Iterator& other) const { return done() == other.done() && (done() || !(sub_iter_ != other.sub_iter_)); } DerefVec& operator*() { return *batch_; } DerefVec* operator->() { return batch_.get(); } }; Iterator begin() { return {get_begin(container_), get_end(container_), num_batches_}; } Iterator end() { return {get_end(container_), get_end(container_), num_batches_}; } Iterator> begin() const { return {get_begin(std::as_const(container_)), get_end(std::as_const(container_)), num_batches_}; } Iterator> end() const { return {get_end(std::as_const(container_)), get_end(std::as_const(container_)), num_batches_}; } }; #endif