Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GroupBy.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file GroupBy.hpp
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 
12 
13 #include <algorithm>
14 #include <iterator>
15 #include <utility>
16 
17 namespace ActsExamples {
18 
38 template <typename Iterator, typename KeyGetter>
39 class GroupBy {
40  public:
42  using Key = std::decay_t<decltype(KeyGetter()(*Iterator()))>;
44  using Group = std::pair<Key, Range<Iterator>>;
50  using GroupEndIterator = Iterator;
52  class GroupIterator {
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)) {}
65  constexpr GroupIterator& operator++() {
66  // make the current end the new group beginning
68  // find the end of the next group starting from the new beginning
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)
82  : Key();
83  return {key, makeRange(m_groupBegin, m_groupEnd)};
84  }
85 
86  private:
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 
135 template <typename Container, typename KeyGetter>
136 auto makeGroupBy(const Container& container, KeyGetter keyGetter)
138  return {std::begin(container), std::end(container), std::move(keyGetter)};
139 }
140 
141 } // namespace ActsExamples