GCC Code Coverage Report


Directory: ./
File: include/CXXIter/src/op/ChunkedExact.h
Date: 2023-01-04 16:32:12
Exec Total Coverage
Lines: 36 37 97.3%
Functions: 44 44 100.0%
Branches: 131 252 52.0%

Line Branch Exec Source
1 #pragma once
2
3 #include <array>
4 #include <cstdlib>
5 #include <utility>
6 #include <type_traits>
7
8 #include "../Common.h"
9 #include "../util/TraitImpl.h"
10
11 namespace CXXIter {
12
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>>;
18
19 // ################################################################################################
20 // CHUNKED EXACT
21 // ################################################################################################
22 namespace op {
23 // Empty definition
24 // ------------------------------------------------
25 /** @private */
26 template<typename TChainInput, const size_t CHUNK_SIZE, const size_t STEP_SIZE>
27 class ChunkedExact {};
28
29
30 // Implementation for non-contiguous memory sources
31 // ------------------------------------------------
32 /** @private */
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>>;
38 private:
39 struct source_ended_exception {};
40 TChainInput input;
41 std::optional<ExactChunk<typename TChainInput::Item, CHUNK_SIZE>> chunk;
42 public:
43 60 constexpr ChunkedExact(TChainInput&& input) : input(std::move(input)) {}
44 };
45
46 // Implementation for contiguous memory sources
47 // ------------------------------------------------
48 /** @private */
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>>;
54 private:
55 TChainInput input;
56 size_t remaining = 0;
57 public:
58 50 constexpr ChunkedExact(TChainInput&& input) : input(std::move(input)) {
59 50 remaining = (this->input.size() - CHUNK_SIZE) / STEP_SIZE + 1;
60 50 }
61 };
62 }
63
64
65 // ------------------------------------------------------------------------------------------------
66 /** @private */
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>> {
69
70 static_assert(STEP_SIZE > 0, "STEP_SIZE has to be at least 1");
71
72 private:
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;
77
78 using ChainInputIterator = trait::Iterator<TChainInput>;
79 using InputItem = typename TChainInput::Item;
80 using InputItemOwned = typename TChainInput::ItemOwned;
81
82 static constexpr bool IS_CONTIGUOUS = CXXIterContiguousMemoryIterator<TChainInput>;
83
84 public:
85 // CXXIter Interface
86 using Self = op::ChunkedExact<TChainInput, CHUNK_SIZE, STEP_SIZE>;
87 // If the source is contiguous, copy the const specifier from the InputItem
88 // If the source is non-contiguous, always add a const specifier, since we pass a reference
89 // to our internal chunk buffer, and changing that doesn't make much sense.
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&;
94
95 // non-contiguous
96 86 static constexpr inline IterValue<Item> next(Self& self) requires (!IS_CONTIGUOUS) {
97 137 auto getElementFromChainInput = [&]<size_t IDX>(std::integral_constant<size_t, IDX>) -> typename ItemOwned::value_type {
98
39/78
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 2 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 2 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 2 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 1 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✓ Branch 55 taken 1 times.
✗ Branch 56 not taken.
✓ Branch 58 taken 1 times.
✗ Branch 59 not taken.
✓ Branch 61 taken 1 times.
✗ Branch 62 not taken.
✓ Branch 64 taken 1 times.
✗ Branch 65 not taken.
✓ Branch 67 taken 1 times.
✗ Branch 68 not taken.
✓ Branch 70 taken 1 times.
✗ Branch 71 not taken.
✓ Branch 73 taken 2 times.
✗ Branch 74 not taken.
✓ Branch 76 taken 2 times.
✗ Branch 77 not taken.
✓ Branch 79 taken 2 times.
✗ Branch 80 not taken.
✓ Branch 82 taken 1 times.
✗ Branch 83 not taken.
✓ Branch 85 taken 1 times.
✗ Branch 86 not taken.
✓ Branch 88 taken 1 times.
✗ Branch 89 not taken.
✓ Branch 91 taken 1 times.
✗ Branch 92 not taken.
✓ Branch 94 taken 1 times.
✗ Branch 95 not taken.
✓ Branch 97 taken 1 times.
✗ Branch 98 not taken.
✓ Branch 100 taken 1 times.
✗ Branch 101 not taken.
✓ Branch 103 taken 1 times.
✗ Branch 104 not taken.
✓ Branch 106 taken 1 times.
✗ Branch 107 not taken.
✓ Branch 109 taken 3 times.
✗ Branch 110 not taken.
✓ Branch 112 taken 3 times.
✗ Branch 113 not taken.
✓ Branch 115 taken 3 times.
✗ Branch 116 not taken.
51 auto input = ChainInputIterator::next(self.input);
99
39/78
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 1 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 1 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 2 times.
✗ Branch 37 not taken.
✓ Branch 38 taken 2 times.
✗ Branch 40 not taken.
✓ Branch 41 taken 2 times.
✗ Branch 43 not taken.
✓ Branch 44 taken 1 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 1 times.
✗ Branch 49 not taken.
✓ Branch 50 taken 1 times.
✗ Branch 52 not taken.
✓ Branch 53 taken 1 times.
✗ Branch 55 not taken.
✓ Branch 56 taken 1 times.
✗ Branch 58 not taken.
✓ Branch 59 taken 1 times.
✗ Branch 61 not taken.
✓ Branch 62 taken 1 times.
✗ Branch 64 not taken.
✓ Branch 65 taken 1 times.
✗ Branch 67 not taken.
✓ Branch 68 taken 1 times.
✗ Branch 70 not taken.
✓ Branch 71 taken 1 times.
✗ Branch 73 not taken.
✓ Branch 74 taken 2 times.
✗ Branch 76 not taken.
✓ Branch 77 taken 2 times.
✗ Branch 79 not taken.
✓ Branch 80 taken 2 times.
✗ Branch 82 not taken.
✓ Branch 83 taken 1 times.
✗ Branch 85 not taken.
✓ Branch 86 taken 1 times.
✗ Branch 88 not taken.
✓ Branch 89 taken 1 times.
✗ Branch 91 not taken.
✓ Branch 92 taken 1 times.
✗ Branch 94 not taken.
✓ Branch 95 taken 1 times.
✗ Branch 97 not taken.
✓ Branch 98 taken 1 times.
✗ Branch 100 not taken.
✓ Branch 101 taken 1 times.
✗ Branch 103 not taken.
✓ Branch 104 taken 1 times.
✗ Branch 106 not taken.
✓ Branch 107 taken 1 times.
✗ Branch 109 not taken.
✓ Branch 110 taken 3 times.
✗ Branch 112 not taken.
✓ Branch 113 taken 3 times.
✗ Branch 115 not taken.
✓ Branch 116 taken 3 times.
51 if(!input.has_value()) [[unlikely]] {
100 throw typename Self::source_ended_exception{};
101 }
102
39/78
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 2 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 2 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 2 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 1 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✓ Branch 55 taken 1 times.
✗ Branch 56 not taken.
✓ Branch 58 taken 1 times.
✗ Branch 59 not taken.
✓ Branch 61 taken 1 times.
✗ Branch 62 not taken.
✓ Branch 64 taken 1 times.
✗ Branch 65 not taken.
✓ Branch 67 taken 1 times.
✗ Branch 68 not taken.
✓ Branch 70 taken 1 times.
✗ Branch 71 not taken.
✓ Branch 73 taken 1 times.
✗ Branch 74 not taken.
✓ Branch 76 taken 2 times.
✗ Branch 77 not taken.
✓ Branch 79 taken 2 times.
✗ Branch 80 not taken.
✓ Branch 82 taken 2 times.
✗ Branch 83 not taken.
✓ Branch 85 taken 1 times.
✗ Branch 86 not taken.
✓ Branch 88 taken 1 times.
✗ Branch 89 not taken.
✓ Branch 91 taken 1 times.
✗ Branch 92 not taken.
✓ Branch 94 taken 1 times.
✗ Branch 95 not taken.
✓ Branch 98 taken 1 times.
✗ Branch 99 not taken.
✓ Branch 102 taken 1 times.
✗ Branch 103 not taken.
✓ Branch 106 taken 1 times.
✗ Branch 107 not taken.
✓ Branch 110 taken 1 times.
✗ Branch 111 not taken.
✓ Branch 114 taken 1 times.
✗ Branch 115 not taken.
✓ Branch 118 taken 3 times.
✗ Branch 119 not taken.
✓ Branch 121 taken 3 times.
✗ Branch 122 not taken.
✓ Branch 124 taken 3 times.
✗ Branch 125 not taken.
51 return input.value();
103 };
104 152 auto initializeChunk = [&]<size_t... IDX>(auto& chunkOptional, std::integer_sequence<size_t, IDX...>) {
105 15 chunkOptional = { getElementFromChainInput(std::integral_constant<size_t, IDX>())... };
106 };
107
108
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 28 times.
86 if(!self.chunk.has_value()) [[unlikely]] {
109 // initial loading
110
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
30 initializeChunk(self.chunk, std::make_index_sequence<CHUNK_SIZE>{});
111 30 return *self.chunk;
112 }
113
114 56 auto& chunk = *self.chunk;
115
116 // if step-size is greater than chunk-size, we need to skip some values
117
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
56 ChainInputIterator::advanceBy(self.input, SKIP_SIZE);
118
119 // if step-size is smaller than chunk-size, we have to shift out the first couple of items
120 // so we can push new ones in the back
121
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 13 times.
86 for(size_t i = 0; i < SHIFT_SIZE; ++i) {
122 30 chunk[i] = std::move(chunk[STEP_SIZE + i]);
123 }
124
125 // load new items
126
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 17 times.
160 for(size_t i = 0; i < LOAD_SIZE; ++i) {
127
1/2
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
126 auto item = ChainInputIterator::next(self.input);
128
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 52 times.
126 if(!item.has_value()) [[unlikely]] { return {}; } // reached end. Chunk needs to be full to commit!
129
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
104 chunk[LOAD_START + i] = item.value();
130 }
131 34 return chunk;
132 }
133
134 // contiguous
135 102 static constexpr inline IterValue<Item> next(Self& self) requires IS_CONTIGUOUS {
136
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 37 times.
102 if(self.remaining == 0) [[unlikely]] {
137 28 return {};
138 }
139
140 // next ptr
141 74 auto itemPtr = ContiguousMemoryIterator<TChainInput>::currentPtr(self.input);
142 74 ChainInputIterator::advanceBy(self.input, STEP_SIZE);
143 74 self.remaining -= 1;
144 74 return (Item)(*itemPtr);
145 }
146
147
148 48 static constexpr inline SizeHint sizeHint(const Self& self) {
149 48 SizeHint result = ChainInputIterator::sizeHint(self.input);
150 48 result.lowerBound = (result.lowerBound >= CHUNK_SIZE) ? ((result.lowerBound - CHUNK_SIZE) / STEP_SIZE + 1) : 0;
151 48 if(result.upperBound.has_value()) {
152 48 result.upperBound.value() = (result.upperBound.value() >= CHUNK_SIZE) ? ((result.upperBound.value() - CHUNK_SIZE) / STEP_SIZE + 1) : 0;
153 }
154 48 return result;
155 }
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);
159 } else {
160 return util::advanceByPull(self, n);
161 }
162 }
163 };
164
165 /** @private */
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;
170 }
171 };
172
173 }
174