9#include "../util/TraitImpl.h"
13 template<
typename TItem, const
size_t CHUNK_SIZE>
14 using ExactChunk = std::conditional_t<
15 std::is_reference_v<TItem>,
16 std::array<std::reference_wrapper<std::remove_reference_t<TItem>>, CHUNK_SIZE>,
17 std::array<TItem, CHUNK_SIZE>>;
26 template<
typename TChainInput, const
size_t CHUNK_SIZE, const
size_t STEP_SIZE>
27 class ChunkedExact {};
33 template<
typename TChainInput, const
size_t CHUNK_SIZE, const
size_t STEP_SIZE>
34 requires (!CXXIterContiguousMemoryIterator<TChainInput>)
35 class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE> :
public IterApi<ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>> {
36 friend struct trait::Iterator<ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>>;
37 friend struct trait::ExactSizeIterator<ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>>;
39 struct source_ended_exception {};
41 std::optional<ExactChunk<typename TChainInput::Item, CHUNK_SIZE>> chunk;
43 constexpr ChunkedExact(TChainInput&& input) : input(std::move(input)) {}
49 template<
typename TChainInput, const
size_t CHUNK_SIZE, const
size_t STEP_SIZE>
50 requires CXXIterContiguousMemoryIterator<TChainInput>
51 class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE> :
public IterApi<ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>> {
52 friend struct trait::Iterator<ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>>;
53 friend struct trait::ExactSizeIterator<ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>>;
58 constexpr ChunkedExact(TChainInput&& input) : input(std::move(input)) {
59 remaining = (this->input.size() - CHUNK_SIZE) / STEP_SIZE + 1;
67 template<
typename TChainInput, const
size_t CHUNK_SIZE, const
size_t STEP_SIZE>
68 struct trait::Iterator<op::ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>> {
70 static_assert(STEP_SIZE > 0,
"STEP_SIZE has to be at least 1");
73 static constexpr size_t LOAD_SIZE = std::min(CHUNK_SIZE, STEP_SIZE);
74 static constexpr size_t SHIFT_SIZE = (STEP_SIZE < CHUNK_SIZE) ? (CHUNK_SIZE - STEP_SIZE) : 0;
75 static constexpr size_t LOAD_START = SHIFT_SIZE;
76 static constexpr size_t SKIP_SIZE = (STEP_SIZE > CHUNK_SIZE) ? (STEP_SIZE - CHUNK_SIZE) : 0;
78 using ChainInputIterator = trait::Iterator<TChainInput>;
79 using InputItem =
typename TChainInput::Item;
80 using InputItemOwned =
typename TChainInput::ItemOwned;
82 static constexpr bool IS_CONTIGUOUS = CXXIterContiguousMemoryIterator<TChainInput>;
86 using Self = op::ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>;
90 using ItemOwned = std::conditional_t<IS_CONTIGUOUS,
91 copy_const_from<InputItem, ExactChunk<InputItemOwned, CHUNK_SIZE>>,
92 const ExactChunk<InputItem, CHUNK_SIZE>>;
93 using Item = ItemOwned&;
96 static constexpr inline IterValue<Item> next(Self& self)
requires (!IS_CONTIGUOUS) {
97 auto getElementFromChainInput = [&]<
size_t IDX>(std::integral_constant<size_t, IDX>) ->
typename ItemOwned::value_type {
98 auto input = ChainInputIterator::next(self.input);
99 if(!input.has_value()) [[unlikely]] {
100 throw typename Self::source_ended_exception{};
102 return input.value();
104 auto initializeChunk = [&]<
size_t... IDX>(
auto& chunkOptional, std::integer_sequence<size_t, IDX...>) {
105 chunkOptional = { getElementFromChainInput(std::integral_constant<size_t, IDX>())... };
108 if(!self.chunk.has_value()) [[unlikely]] {
110 initializeChunk(self.chunk, std::make_index_sequence<CHUNK_SIZE>{});
114 auto& chunk = *self.chunk;
117 ChainInputIterator::advanceBy(self.input, SKIP_SIZE);
121 for(
size_t i = 0; i < SHIFT_SIZE; ++i) {
122 chunk[i] = std::move(chunk[STEP_SIZE + i]);
126 for(
size_t i = 0; i < LOAD_SIZE; ++i) {
127 auto item = ChainInputIterator::next(self.input);
128 if(!item.has_value()) [[unlikely]] {
return {}; }
129 chunk[LOAD_START + i] = item.value();
135 static constexpr inline IterValue<Item> next(Self& self)
requires IS_CONTIGUOUS {
136 if(self.remaining == 0) [[unlikely]] {
141 auto itemPtr = ContiguousMemoryIterator<TChainInput>::currentPtr(self.input);
142 ChainInputIterator::advanceBy(self.input, STEP_SIZE);
144 return (Item)(*itemPtr);
148 static constexpr inline SizeHint sizeHint(
const Self& self) {
149 SizeHint result = ChainInputIterator::sizeHint(self.input);
150 result.lowerBound = (result.lowerBound >= CHUNK_SIZE) ? ((result.lowerBound - CHUNK_SIZE) / STEP_SIZE + 1) : 0;
151 if(result.upperBound.has_value()) {
152 result.upperBound.value() = (result.upperBound.value() >= CHUNK_SIZE) ? ((result.upperBound.value() - CHUNK_SIZE) / STEP_SIZE + 1) : 0;
156 static constexpr inline size_t advanceBy(Self& self,
size_t n) {
157 if constexpr(IS_CONTIGUOUS) {
158 ChainInputIterator::advanceBy(self.input, n * STEP_SIZE);
160 return util::advanceByPull(self, n);
166 template<CXXIterExactSizeIterator TChainInput, const
size_t CHUNK_SIZE, const
size_t STEP_SIZE>
167 struct trait::ExactSizeIterator<op::ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>> {
168 static constexpr inline size_t size(
const op::ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>& self) {
169 return trait::Iterator<op::ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>>::sizeHint(self).lowerBound;