| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <cstdlib> | ||
| 4 | #include <utility> | ||
| 5 | |||
| 6 | #include "../Common.h" | ||
| 7 | |||
| 8 | namespace CXXIter { | ||
| 9 | |||
| 10 | // ################################################################################################ | ||
| 11 | // CHAINER | ||
| 12 | // ################################################################################################ | ||
| 13 | namespace op { | ||
| 14 | /** @private */ | ||
| 15 | template<typename TChainInput1, typename TChainInput2> | ||
| 16 | class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] Chainer : public IterApi<Chainer<TChainInput1, TChainInput2>> { | ||
| 17 | friend struct trait::Iterator<Chainer<TChainInput1, TChainInput2>>; | ||
| 18 | friend struct trait::DoubleEndedIterator<Chainer<TChainInput1, TChainInput2>>; | ||
| 19 | friend struct trait::ExactSizeIterator<Chainer<TChainInput1, TChainInput2>>; | ||
| 20 | private: | ||
| 21 | TChainInput1 input1; | ||
| 22 | TChainInput2 input2; | ||
| 23 | bool input1Ended = false; | ||
| 24 | bool input2Ended = false; | ||
| 25 | public: | ||
| 26 | 19 | constexpr Chainer(TChainInput1&& input1, TChainInput2 input2) : input1(std::move(input1)), input2(std::move(input2)) {} | |
| 27 | }; | ||
| 28 | } | ||
| 29 | // ------------------------------------------------------------------------------------------------ | ||
| 30 | /** @private */ | ||
| 31 | template<typename TChainInput1, typename TChainInput2> | ||
| 32 | struct trait::Iterator<op::Chainer<TChainInput1, TChainInput2>> { | ||
| 33 | using ChainInputIterator1 = trait::Iterator<TChainInput1>; | ||
| 34 | using ChainInputIterator2 = trait::Iterator<TChainInput2>; | ||
| 35 | using InputItem = typename trait::Iterator<TChainInput1>::Item; | ||
| 36 | // CXXIter Interface | ||
| 37 | using Self = op::Chainer<TChainInput1, TChainInput2>; | ||
| 38 | using Item = InputItem; | ||
| 39 | |||
| 40 | 51 | static constexpr inline IterValue<Item> next(Self& self) { | |
| 41 | 9 | while(true) { | |
| 42 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 17 times.
|
51 | if(self.input1Ended == false) { |
| 43 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
22 | auto item = ChainInputIterator1::next(self.input1); |
| 44 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 8 times.
|
22 | if(!item.has_value()) [[unlikely]] { |
| 45 | 9 | self.input1Ended = true; | |
| 46 | 9 | continue; | |
| 47 | } | ||
| 48 | 13 | return item; | |
| 49 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 8 times.
|
22 | } else { |
| 50 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
29 | auto item = ChainInputIterator2::next(self.input2); |
| 51 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 10 times.
|
29 | if(!item.has_value()) [[unlikely]] { self.input2Ended = true; } |
| 52 | 29 | return item; | |
| 53 | 29 | } | |
| 54 | } | ||
| 55 | } | ||
| 56 | 8 | static constexpr inline SizeHint sizeHint(const Self& self) { | |
| 57 | 8 | SizeHint result = ChainInputIterator1::sizeHint(self.input1); | |
| 58 | 8 | result.add(ChainInputIterator2::sizeHint(self.input2)); | |
| 59 | 8 | return result; | |
| 60 | } | ||
| 61 | 1 | static constexpr inline size_t advanceBy(Self& self, size_t n) { | |
| 62 | 1 | size_t skipped = 0; | |
| 63 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(!self.input1Ended) { |
| 64 | 1 | skipped += ChainInputIterator1::advanceBy(self.input1, n); | |
| 65 | } | ||
| 66 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(!self.input2Ended) { |
| 67 | 1 | skipped += ChainInputIterator2::advanceBy(self.input2, (n - skipped)); | |
| 68 | } | ||
| 69 | 1 | return skipped; | |
| 70 | } | ||
| 71 | }; | ||
| 72 | /** @private */ | ||
| 73 | template<CXXIterDoubleEndedIterator TChainInput1, CXXIterDoubleEndedIterator TChainInput2> | ||
| 74 | struct trait::DoubleEndedIterator<op::Chainer<TChainInput1, TChainInput2>> { | ||
| 75 | using ChainInputIterator1 = trait::DoubleEndedIterator<TChainInput1>; | ||
| 76 | using ChainInputIterator2 = trait::DoubleEndedIterator<TChainInput2>; | ||
| 77 | using InputItem = typename trait::Iterator<TChainInput1>::Item; | ||
| 78 | // CXXIter Interface | ||
| 79 | using Self = op::Chainer<TChainInput1, TChainInput2>; | ||
| 80 | using Item = InputItem; | ||
| 81 | |||
| 82 | 10 | static constexpr inline IterValue<Item> nextBack(Self& self) { | |
| 83 | 2 | while(true) { | |
| 84 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | if(self.input2Ended == false) { |
| 85 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | auto item = ChainInputIterator2::nextBack(self.input2); |
| 86 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
|
6 | if(!item.has_value()) [[unlikely]] { |
| 87 | 2 | self.input2Ended = true; | |
| 88 | 2 | continue; | |
| 89 | } | ||
| 90 | 4 | return item; | |
| 91 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
|
6 | } else { |
| 92 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | auto item = ChainInputIterator1::nextBack(self.input1); |
| 93 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if(!item.has_value()) [[unlikely]] { self.input1Ended = true; } |
| 94 | 4 | return item; | |
| 95 | 4 | } | |
| 96 | } | ||
| 97 | } | ||
| 98 | }; | ||
| 99 | /** @private */ | ||
| 100 | template<CXXIterExactSizeIterator TChainInput1, CXXIterExactSizeIterator TChainInput2> | ||
| 101 | struct trait::ExactSizeIterator<op::Chainer<TChainInput1, TChainInput2>> { | ||
| 102 | static constexpr inline size_t size(const op::Chainer<TChainInput1, TChainInput2>& self) { | ||
| 103 | return trait::Iterator<op::Chainer<TChainInput1, TChainInput2>>::sizeHint(self).lowerBound; | ||
| 104 | } | ||
| 105 | }; | ||
| 106 | |||
| 107 | } | ||
| 108 |