CXXIter 0.2
Loading...
Searching...
No Matches
GroupBy.h
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
12namespace CXXIter {
13
14 // ################################################################################################
15 // GROUP BY
16 // ################################################################################################
17 namespace op {
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 constexpr GroupBy(TChainInput&& input, TGroupIdentifierFn groupIdentFn) : input(std::move(input)), groupIdentFn(groupIdentFn) {}
31 };
32 }
33 // ------------------------------------------------------------------------------------------------
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 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 if(!self.groupCache.has_value()) [[unlikely]] {
47 std::unordered_map<TGroupIdent, std::vector<OwnedInputItem>> groupCache;
48 while(true) {
49 auto item = ChainInputIterator::next(self.input);
50 if(!item.has_value()) [[unlikely]] { break; } // group cache building complete
51 TGroupIdent itemGroup = self.groupIdentFn(item.value());
52 if(groupCache.contains(itemGroup)) {
53 groupCache[itemGroup].push_back(item.value());
54 } else {
55 groupCache[itemGroup] = { item.value() };
56 }
57 }
58 self.groupCache.emplace(std::move(groupCache));
59 }
60
61 using GroupCacheIterator = trait::Iterator<typename Self::GroupCache>;
62 typename Self::GroupCache& groupedItems = self.groupCache.value();
63 return GroupCacheIterator::next(groupedItems);
64 }
65 static constexpr inline SizeHint sizeHint(const Self& self) {
66 SizeHint input = ChainInputIterator::sizeHint(self.input);
67 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}
CXXIter.
Definition: CXXIter.h:48