All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sortBy.h
Go to the documentation of this file.
1 /**
2  * @file icarusalg/Utilities/sortBy.h
3  * @brief Provides `sortBy()` class of utilities.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date April 3, 2020
6  *
7  * This is a header-only library.
8  */
9 
10 #ifndef ICARUSALG_UTILITIES_SORTBY_H
11 #define ICARUSALG_UTILITIES_SORTBY_H
12 
13 
14 // C/C++ standard libraries
15 #include <algorithm> // std::transform(), std::sort()
16 #include <functional> // std::less<>
17 #include <vector>
18 #include <iterator> // std::back_inserter()
19 #include <utility> // std::pair>?
20 #include <type_traits> // std::is_base_of_v
21 
22 
23 // -----------------------------------------------------------------------------
24 namespace util {
25 
26  // ---------------------------------------------------------------------------
27  /**
28  * @brief Returns a vectors to pointers to `coll` elements, sorted by `key`.
29  * @tparam BIter type of begin iterator to objects to be sorted
30  * @tparam EIter type of end iterator to objects to be sorted
31  * @tparam Key type of functor extracting the key from an element
32  * @tparam Sorter (default: `std::less`) type of functor comparing two keys
33  * @param coll collection of objects to be sorted
34  * @param key functor extracting the key from an element
35  * @param sorter (default: `std::less{}`) functor comparing two keys
36  * @return a vector of pointers to `coll` elements, sorted by `key`
37  * @see `sortCollBy()`
38  *
39  * A vector of pointers to all elements of `coll` is returned.
40  * The pointers are constant only if `Coll` is a constant type.
41  * The order of the pointed elements is driven by `sorter` applied to the
42  * key of each element (`key(item)`).
43  *
44  * @note As an exception, if the elements of `Coll` are already C pointers,
45  * the returned collection is a copy of those pointers rather than
46  * pointers to them.
47  */
48  template <
49  typename BIter, typename EIter,
50  typename Key, typename Sorter = std::less<void>
51  >
52  auto sortBy(BIter begin, EIter end, Key key, Sorter sorter = {});
53 
54 
55  // ---------------------------------------------------------------------------
56  /**
57  * @brief Returns a vectors to pointers to `coll` elements, sorted by `key`.
58  * @tparam Coll type of collection of objects to be sorted
59  * @tparam Key type of functor extracting the key from an element
60  * @tparam Sorter (default: `std::less`) type of functor comparing two keys
61  * @param coll collection of objects to be sorted
62  * @param key functor extracting the key from an element
63  * @param sorter (default: `std::less{}`) functor comparing two keys
64  * @return a vector of pointers to `coll` elements, sorted by `key`
65  * @see `sortBy()`
66  *
67  * A vector of pointers to all elements of `coll` is returned.
68  * The pointers are constant only if `Coll` is a constant type.
69  * The order of the pointed elements is driven by `sorter` applied to the
70  * key of each element (`key(item)`).
71  *
72  * @note As an exception, if the elements of `Coll` are already C pointers,
73  * the returned collection is a copy of those pointers rather than
74  * pointers to them.
75  */
76  template <typename Coll, typename Key, typename Sorter = std::less<void>>
77  auto sortCollBy(Coll& coll, Key key, Sorter sorter = {});
78 
79  // ---------------------------------------------------------------------------
80 
81 } // namespace util
82 
83 
84 
85 // -----------------------------------------------------------------------------
86 // --- template implementation
87 // -----------------------------------------------------------------------------
88 namespace util::details {
89 
90  template <typename Iter>
91  constexpr bool is_random_access_iterator_v = std::is_base_of_v<
92  std::random_access_iterator_tag,
93  typename std::iterator_traits<Iter>::iterator_category
94  >;
95 
96 } // namespace util::details
97 
98 // -----------------------------------------------------------------------------
99 template <
100  typename BIter, typename EIter,
101  typename Key, typename Sorter /* = std::less<void> */
102  >
103 auto util::sortBy
104  (BIter begin, EIter end, Key key, Sorter sorter /* = {} */)
105 {
106 
107  /*
108  * 0. establish whether we are dealing with pointers or not
109  * 1. create a collection of pairs { key, pointer to element }
110  * 2. sort that collection on the first element (key)
111  * 3. create a collection of the pointer to element (second element of the
112  * pairs from the collection just sorted), and return it
113  */
114  using value_type = typename BIter::value_type;
115 
116  //
117  // 0. establish whether we are dealing with pointers or not
118  //
119  static constexpr bool isPointer = std::is_pointer_v<value_type>;
120 
121  using pointer_type = std::conditional_t
122  <isPointer, value_type, typename std::iterator_traits<BIter>::pointer>;
123 
124  using Key_t = std::decay_t<decltype(key(*begin))>;
125  using SortingPair_t = std::pair<Key_t, pointer_type>;
126 
127  //
128  // 1. create a collection of pairs { key, pointer to element }
129  //
130  auto getPointer = [](auto& elem)
131  { if constexpr(isPointer) return elem; else return &elem; };
132  auto makePair = [&key, getPointer](auto&& item)
133  { return SortingPair_t(key(item), getPointer(item)); };
134 
135  std::vector<SortingPair_t> sortingColl;
136 
137  // reserve size, but only if to discover the size is fast
138  if constexpr(details::is_random_access_iterator_v<BIter>)
139  sortingColl.reserve(std::distance(begin, end));
140  std::transform(begin, end, back_inserter(sortingColl), makePair);
141 
142  //
143  // 2. sort that collection on the first element (key)
144  //
145  auto pair_sorter
146  = [&sorter](SortingPair_t const& a, SortingPair_t const& b)
147  { return sorter(a.first, b.first); }
148  ;
149  std::sort(sortingColl.begin(), sortingColl.end(), pair_sorter);
150 
151  //
152  // 3. create a collection of the pointer to element (second element of the
153  // pairs from the collection just sorted), and return it
154  //
155  std::vector<pointer_type> sortedColl;
156  sortedColl.reserve(sortingColl.size());
158  sortingColl.begin(), sortingColl.end(), back_inserter(sortedColl),
159  [](SortingPair_t const& pair){ return pair.second; }
160  );
161 
162  return sortedColl;
163 
164 } // util::sortBy()
165 
166 
167 //------------------------------------------------------------------------------
168 template <typename Coll, typename Key, typename Sorter /* = std::less<void> */>
169 auto util::sortCollBy(Coll& coll, Key key, Sorter sorter /* = {} */) {
170  using std::begin, std::end;
171  return sortBy(begin(coll), end(coll), key, sorter);
172 } // util::sortCollBy()
173 
174 
175 // -----------------------------------------------------------------------------
176 
177 
178 #endif // ICARUSALG_UTILITIES_SORTBY_H
auto sortBy(BIter begin, EIter end, Key key, Sorter sorter={})
Returns a vectors to pointers to coll elements, sorted by key.
Definition: sortBy.h:104
static constexpr Sample_t transform(Sample_t sample)
process_name gaushit a
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
auto sortCollBy(Coll &coll, Key key, Sorter sorter={})
Returns a vectors to pointers to coll elements, sorted by key.
Definition: sortBy.h:169
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
constexpr bool is_random_access_iterator_v
Definition: sortBy.h:91