6#include <unordered_map>
9#include "../sources/ContainerSources.h"
10#include "../util/TraitImpl.h"
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>>;
23 using OwnedInputItem =
typename TChainInput::ItemOwned;
24 using GroupCache = SrcMov<std::unordered_map<TGroupIdent, std::vector<OwnedInputItem>>>;
27 TGroupIdentifierFn groupIdentFn;
28 std::optional<GroupCache> groupCache;
30 constexpr GroupBy(TChainInput&& input, TGroupIdentifierFn groupIdentFn) : input(std::move(input)), groupIdentFn(groupIdentFn) {}
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;
40 using Self = op::GroupBy<TChainInput, TGroupIdentifierFn, TGroupIdent>;
41 using Item = std::pair<const TGroupIdent, std::vector<OwnedInputItem>>;
43 static constexpr inline IterValue<Item> next(Self& self) {
46 if(!self.groupCache.has_value()) [[unlikely]] {
47 std::unordered_map<TGroupIdent, std::vector<OwnedInputItem>> groupCache;
49 auto item = ChainInputIterator::next(self.input);
50 if(!item.has_value()) [[unlikely]] {
break; }
51 TGroupIdent itemGroup = self.groupIdentFn(item.value());
52 if(groupCache.contains(itemGroup)) {
53 groupCache[itemGroup].push_back(item.value());
55 groupCache[itemGroup] = { item.value() };
58 self.groupCache.emplace(std::move(groupCache));
61 using GroupCacheIterator = trait::Iterator<typename Self::GroupCache>;
62 typename Self::GroupCache& groupedItems = self.groupCache.value();
63 return GroupCacheIterator::next(groupedItems);
65 static constexpr inline SizeHint sizeHint(
const Self& self) {
66 SizeHint input = ChainInputIterator::sizeHint(self.input);
67 return SizeHint(1, input.upperBound);
69 static constexpr inline size_t advanceBy(Self& self,
size_t n) {
return util::advanceByPull(self, n); }