GCC Code Coverage Report


Directory: ./
File: include/CXXIter/src/op/Reverse.h
Date: 2023-01-04 16:32:12
Exec Total Coverage
Lines: 17 17 100.0%
Functions: 15 15 100.0%
Branches: 13 20 65.0%

Line Branch Exec Source
1 #pragma once
2
3 #include <cstdlib>
4 #include <optional>
5
6 #include "../Common.h"
7 #include "../sources/ContainerSources.h"
8 #include "../util/TraitImpl.h"
9
10 namespace CXXIter {
11
12 // ################################################################################################
13 // SORTER
14 // ################################################################################################
15 namespace op {
16 /** @private */
17 template<typename TChainInput>
18 class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] Reverse : public IterApi<Reverse<TChainInput>> {
19 friend struct trait::Iterator<Reverse<TChainInput>>;
20 friend struct trait::DoubleEndedIterator<Reverse<TChainInput>>;
21 friend struct trait::ExactSizeIterator<Reverse<TChainInput>>;
22
23 using InputItem = typename TChainInput::Item;
24
25 struct NoReverseCache {};
26 using ReverseCacheContainer = std::conditional_t<
27 std::is_reference_v<InputItem>,
28 std::vector<std::reference_wrapper<InputItem>>,
29 std::vector<InputItem>>;
30 using ReverseCache = SrcMov<ReverseCacheContainer>;
31
32 private:
33 // If the underlying iterator pipeline is double-ended, we don't need to use the reverseCache
34 static constexpr bool USE_CACHE = !CXXIterDoubleEndedIterator<TChainInput>;
35 TChainInput input;
36 std::conditional_t<USE_CACHE, std::optional<ReverseCache>, NoReverseCache> reverseCache;
37
38 public:
39 14 constexpr Reverse(TChainInput&& input) : input(std::move(input)) {}
40 };
41 }
42 // ------------------------------------------------------------------------------------------------
43 /** @private */
44 template<typename TChainInput>
45 struct trait::Iterator<op::Reverse<TChainInput>> {
46 using ChainInputIterator = trait::Iterator<TChainInput>;
47 using InputItem = typename TChainInput::Item;
48 // CXXIter Interface
49 using Self = op::Reverse<TChainInput>;
50 using Item = InputItem;
51
52 6 static void initReverseCache(Self& self) {
53 // drain input iterator into reverse cache
54 6 typename Self::ReverseCacheContainer reverseCache;
55
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
6 reverseCache.reserve(self.input.sizeHint().expectedResultSize());
56
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
66 while(true) {
57
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 auto item = ChainInputIterator::next(self.input);
58
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 15 times.
36 if(!item.has_value()) { break; }
59
2/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
30 reverseCache.push_back(std::move(item.value()));
60 }
61
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 self.reverseCache = typename Self::ReverseCache(std::move(reverseCache));
62 6 }
63
64 80 static constexpr inline IterValue<Item> next(Self& self) {
65 if constexpr(Self::USE_CACHE) {
66
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 15 times.
36 if(!self.reverseCache.has_value()) [[unlikely]] { initReverseCache(self); }
67 36 return trait::DoubleEndedIterator<typename Self::ReverseCache>::nextBack(self.reverseCache.value());
68 } else {
69 44 return trait::DoubleEndedIterator<TChainInput>::nextBack(self.input);
70 }
71 }
72 16 static constexpr inline SizeHint sizeHint(const Self& self) { return ChainInputIterator::sizeHint(self.input); }
73 static constexpr inline size_t advanceBy(Self& self, size_t n) { return util::advanceByPullBack(self, n); }
74 };
75 /** @private */
76 template<CXXIterDoubleEndedIterator TChainInput>
77 struct trait::DoubleEndedIterator<op::Reverse<TChainInput>> {
78 using ChainInputIterator = trait::Iterator<TChainInput>;
79 using InputItem = typename TChainInput::Item;
80 // CXXIter Interface
81 using Self = op::Reverse<TChainInput>;
82 using Item = InputItem;
83
84 11 static constexpr inline IterValue<Item> nextBack(Self& self) {
85 if constexpr(Self::USE_CACHE) {
86 if(!self.reverseCache.has_value()) [[unlikely]] { initReverseCache(self); }
87 return trait::Iterator<typename Self::ReverseCache>::next(self.reverseCache.value());
88 } else {
89 11 return ChainInputIterator::next(self.input);
90 }
91 }
92 };
93 /** @private */
94 template<CXXIterExactSizeIterator TChainInput>
95 struct trait::ExactSizeIterator<op::Reverse<TChainInput>> {
96 static constexpr inline size_t size(const op::Reverse<TChainInput>& self) {
97 return trait::ExactSizeIterator<TChainInput>::size(self.input);
98 }
99 };
100
101 }
102