GCC Code Coverage Report


Directory: ./
File: include/CXXIter/src/op/GroupBy.h
Date: 2023-01-04 16:32:12
Exec Total Coverage
Lines: 18 18 100.0%
Functions: 9 9 100.0%
Branches: 22 36 61.1%

Line Branch Exec Source
1 #pragma once
2
3 #include <vector>
4 #include <utility>
5 #include <optional>
6 #include <unordered_map>
7
8 #include "../Common.h"
9 #include "../sources/ContainerSources.h"
10 #include "../util/TraitImpl.h"
11
12 namespace CXXIter {
13
14 // ################################################################################################
15 // GROUP BY
16 // ################################################################################################
17 namespace op {
18 /** @private */
19 template<typename TChainInput, typename TGroupIdentifierFn, typename TGroupIdent>
20 class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] GroupBy : public IterApi<GroupBy<TChainInput, TGroupIdentifierFn, TGroupIdent>> {
21 friend struct trait::Iterator<GroupBy<TChainInput, TGroupIdentifierFn, TGroupIdent>>;
22 private:
23 using OwnedInputItem = typename TChainInput::ItemOwned;
24 using GroupCache = SrcMov<std::unordered_map<TGroupIdent, std::vector<OwnedInputItem>>>;
25
26 TChainInput input;
27 TGroupIdentifierFn groupIdentFn;
28 std::optional<GroupCache> groupCache;
29 public:
30 10 constexpr GroupBy(TChainInput&& input, TGroupIdentifierFn groupIdentFn) : input(std::move(input)), groupIdentFn(groupIdentFn) {}
31 };
32 }
33 // ------------------------------------------------------------------------------------------------
34 /** @private */
35 template<typename TChainInput, typename TGroupIdentifierFn, typename TGroupIdent>
36 struct trait::Iterator<op::GroupBy<TChainInput, TGroupIdentifierFn, TGroupIdent>> {
37 using ChainInputIterator = trait::Iterator<TChainInput>;
38 using OwnedInputItem = typename TChainInput::ItemOwned;
39 // CXXIter Interface
40 using Self = op::GroupBy<TChainInput, TGroupIdentifierFn, TGroupIdent>;
41 using Item = std::pair<const TGroupIdent, std::vector<OwnedInputItem>>;
42
43 20 static constexpr inline IterValue<Item> next(Self& self) {
44 // we have to drain the input in order to be able to calculate the groups
45 // so we do that on the first invocation, and then yield from the calculated result.
46
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
20 if(!self.groupCache.has_value()) [[unlikely]] {
47 8 std::unordered_map<TGroupIdent, std::vector<OwnedInputItem>> groupCache;
48
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
28 while(true) {
49
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
26 auto item = ChainInputIterator::next(self.input);
50
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 9 times.
26 if(!item.has_value()) [[unlikely]] { break; } // group cache building complete
51
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 TGroupIdent itemGroup = self.groupIdentFn(item.value());
52
3/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 6 times.
18 if(groupCache.contains(itemGroup)) {
53
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 groupCache[itemGroup].push_back(item.value());
54 } else {
55
6/12
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 6 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
24 groupCache[itemGroup] = { item.value() };
56 }
57 }
58
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 self.groupCache.emplace(std::move(groupCache));
59 8 }
60
61 using GroupCacheIterator = trait::Iterator<typename Self::GroupCache>;
62 20 typename Self::GroupCache& groupedItems = self.groupCache.value();
63 20 return GroupCacheIterator::next(groupedItems);
64 }
65 5 static constexpr inline SizeHint sizeHint(const Self& self) {
66 5 SizeHint input = ChainInputIterator::sizeHint(self.input);
67 8 return SizeHint(1, input.upperBound);
68 }
69 static constexpr inline size_t advanceBy(Self& self, size_t n) { return util::advanceByPull(self, n); }
70 };
71
72 }
73