LDMX Software
GroupBy.h
1// This file is part of the Acts project.
2//
3// Copyright (C) 2020 CERN for the benefit of the Acts project
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
9#pragma once
10
11#include <algorithm>
12#include <iterator>
13#include <utility>
14
15#include "Tracking/Sim/Range.h"
16
17namespace ActsExamples {
18
38template <typename Iterator, typename KeyGetter>
39class GroupBy {
40 public:
42 using Key = std::decay_t<decltype(KeyGetter()(*Iterator()))>;
44 using Group = std::pair<Key, Range<Iterator>>;
50 using GroupEndIterator = Iterator;
53 public:
54 using iterator_category = std::input_iterator_tag;
55 using value_type = Group;
56 using difference_type = std::ptrdiff_t;
57 using pointer = Group*;
58 using reference = Group&;
59
60 constexpr GroupIterator(const GroupBy& groupBy, Iterator groupBegin)
61 : m_groupBy(groupBy),
62 m_groupBegin(groupBegin),
63 m_groupEnd(groupBy.findEndOfGroup(groupBegin)) {}
66 // make the current end the new group beginning
67 std::swap(m_groupBegin, m_groupEnd);
68 // find the end of the next group starting from the new beginning
69 m_groupEnd = m_groupBy.findEndOfGroup(m_groupBegin);
70 return *this;
71 }
73 constexpr GroupIterator operator++(int) {
74 GroupIterator retval = *this;
75 ++(*this);
76 return retval;
77 }
79 constexpr Group operator*() const {
80 const Key key = (m_groupBegin != m_groupEnd)
81 ? m_groupBy.m_keyGetter(*m_groupBegin)
82 : Key();
83 return {key, makeRange(m_groupBegin, m_groupEnd)};
84 }
85
86 private:
87 const GroupBy& m_groupBy;
88 Iterator m_groupBegin;
89 Iterator m_groupEnd;
90
91 friend constexpr bool operator==(const GroupIterator& lhs,
92 const GroupEndIterator& rhs) {
93 return lhs.m_groupBegin == rhs;
94 }
95 friend constexpr bool operator!=(const GroupIterator& lhs,
96 const GroupEndIterator& rhs) {
97 return not(lhs == rhs);
98 }
99 };
100
102 constexpr GroupBy(Iterator begin, Iterator end,
103 KeyGetter keyGetter = KeyGetter())
104 : m_begin(begin), m_end(end), m_keyGetter(std::move(keyGetter)) {}
105 constexpr GroupIterator begin() const {
106 return GroupIterator(*this, m_begin);
107 }
108 constexpr GroupEndIterator end() const { return m_end; }
109 constexpr bool empty() const { return m_begin == m_end; }
110
111 private:
112 Iterator m_begin;
113 Iterator m_end;
114 KeyGetter m_keyGetter;
115
121 constexpr Iterator findEndOfGroup(Iterator start) const {
122 // check for end so we can safely dereference the start iterator.
123 if (start == m_end) {
124 return start;
125 }
126 // search the first element that does not share a key with the start.
127 return std::find_if_not(std::next(start), m_end,
128 [this, start](const auto& x) {
129 return m_keyGetter(x) == m_keyGetter(*start);
130 });
131 }
132};
133
135template <typename Container, typename KeyGetter>
136auto makeGroupBy(const Container& container, KeyGetter keyGetter)
137 -> GroupBy<decltype(std::begin(container)), KeyGetter> {
138 return {std::begin(container), std::end(container), std::move(keyGetter)};
139}
140
141} // namespace ActsExamples
Iterator type representing a group of elements.
Definition GroupBy.h:52
constexpr GroupIterator & operator++()
Pre-increment operator to advance to the next group.
Definition GroupBy.h:65
constexpr Group operator*() const
Derefence operator that returns the pointed-to group of elements.
Definition GroupBy.h:79
constexpr GroupIterator operator++(int)
Post-increment operator to advance to the next group.
Definition GroupBy.h:73
Proxy for iterating over groups of elements within a container.
Definition GroupBy.h:39
constexpr Iterator findEndOfGroup(Iterator start) const
Find the end of the group that starts at the given position.
Definition GroupBy.h:121
constexpr GroupBy(Iterator begin, Iterator end, KeyGetter keyGetter=KeyGetter())
Construct the group-by proxy for an iterator range.
Definition GroupBy.h:102
std::decay_t< decltype(KeyGetter()(*Iterator()))> Key
The key type that identifies elements within a group.
Definition GroupBy.h:42
Iterator GroupEndIterator
Iterator type representing the end of the groups.
Definition GroupBy.h:50
std::pair< Key, Range< Iterator > > Group
A Group is an iterator range with the associated key.
Definition GroupBy.h:44