Line | Branch | Exec | Source |
---|---|---|---|
1 | #pragma once | ||
2 | |||
3 | #include <tuple> | ||
4 | #include <cstdlib> | ||
5 | #include <optional> | ||
6 | #include <limits> | ||
7 | |||
8 | #include "../Common.h" | ||
9 | #include "../util/TraitImpl.h" | ||
10 | |||
11 | namespace CXXIter { | ||
12 | |||
13 | // ################################################################################################ | ||
14 | // ALTERNATER | ||
15 | // ################################################################################################ | ||
16 | namespace op { | ||
17 | /** @private */ | ||
18 | template<typename TChainInput1, typename... TChainInputs> | ||
19 | class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] Alternater : public IterApi<Alternater<TChainInput1, TChainInputs...>> { | ||
20 | friend struct trait::Iterator<Alternater<TChainInput1, TChainInputs...>>; | ||
21 | friend struct trait::ExactSizeIterator<Alternater<TChainInput1, TChainInputs...>>; | ||
22 | private: | ||
23 | static constexpr size_t BATCH_SIZE = 1 + sizeof...(TChainInputs); | ||
24 | std::tuple<TChainInput1, TChainInputs...> inputs; | ||
25 | std::array<IterValue<typename TChainInput1::Item>, BATCH_SIZE> currentBatch; | ||
26 | size_t batchElementIdx = BATCH_SIZE; | ||
27 | public: | ||
28 | 8 | constexpr Alternater(TChainInput1&& input1, TChainInputs&&... inputs) : inputs( std::forward_as_tuple(std::move(input1), std::move(inputs)...) ) {} | |
29 | }; | ||
30 | } | ||
31 | // ------------------------------------------------------------------------------------------------ | ||
32 | /** @private */ | ||
33 | template<typename TChainInput1, typename... TChainInputs> | ||
34 | struct trait::Iterator<op::Alternater<TChainInput1, TChainInputs...>> { | ||
35 | using ChainInputIterators = std::tuple<Iterator<TChainInput1>, trait::Iterator<TChainInputs>...>; | ||
36 | static constexpr size_t INPUT_CNT = 1 + sizeof...(TChainInputs); | ||
37 | // CXXIter Interface | ||
38 | using Self = op::Alternater<TChainInput1, TChainInputs...>; | ||
39 | using Item = typename TChainInput1::Item; | ||
40 | |||
41 | 58 | static constexpr inline IterValue<Item> next(Self& self) { | |
42 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 37 times.
|
58 | if(self.batchElementIdx == Self::BATCH_SIZE) [[unlikely]] { // returned all elements from the batch -> retrieve new batch |
43 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
273 | constexpr_for<0, INPUT_CNT>([&](auto idx) { |
44 | 63 | self.currentBatch[idx] = std::tuple_element_t<idx, ChainInputIterators>::next( std::get<idx>(self.inputs) ); | |
45 | 63 | return true; | |
46 | }); | ||
47 | 21 | self.batchElementIdx = 0; | |
48 | } | ||
49 | 58 | return std::move(self.currentBatch[self.batchElementIdx++]); | |
50 | } | ||
51 | 8 | static constexpr inline SizeHint sizeHint(const Self& self) { | |
52 | 8 | size_t lowerBoundMin = std::numeric_limits<size_t>::max(); | |
53 | 8 | std::optional<size_t> upperBoundMin = {}; | |
54 | 8 | size_t minIdx = 0; | |
55 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
200 | constexpr_for<0, INPUT_CNT>([&](auto idx) { |
56 |
3/6✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
|
24 | SizeHint tmp = std::tuple_element_t<idx, ChainInputIterators>::sizeHint( std::get<idx>(self.inputs) ); |
57 |
5/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
24 | if(lowerBoundMin > tmp.lowerBound) { |
58 | 12 | minIdx = idx; | |
59 | 12 | lowerBoundMin = tmp.lowerBound; | |
60 | } | ||
61 |
3/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
|
24 | upperBoundMin = SizeHint::upperBoundMin(upperBoundMin, tmp.upperBound); |
62 | 24 | return true; | |
63 | }); | ||
64 | // smallest input iterator defines base length. The amount of elements then is that | ||
65 | // length, multiplied by the amount of input iterators + the index of the shortest | ||
66 |
3/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
|
8 | if(upperBoundMin.has_value()) { upperBoundMin.value() = upperBoundMin.value() * Self::BATCH_SIZE + minIdx; } |
67 | 8 | SizeHint result = SizeHint( | |
68 | 8 | lowerBoundMin * Self::BATCH_SIZE + minIdx, | |
69 | upperBoundMin | ||
70 | ); | ||
71 | 16 | return result; | |
72 | } | ||
73 | static constexpr inline size_t advanceBy(Self& self, size_t n) { return util::advanceByPull(self, n); } | ||
74 | }; | ||
75 | /** @private */ | ||
76 | template<CXXIterExactSizeIterator TChainInput1, CXXIterExactSizeIterator... TChainInputs> | ||
77 | struct trait::ExactSizeIterator<op::Alternater<TChainInput1, TChainInputs...>> { | ||
78 | static constexpr inline size_t size(const op::Alternater<TChainInput1, TChainInputs...>& self) { | ||
79 | return trait::Iterator<op::Alternater<TChainInput1, TChainInputs...>>::sizeHint(self).lowerBound; | ||
80 | } | ||
81 | }; | ||
82 | |||
83 | } | ||
84 |