| 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 |