SortByPointers.h
Go to the documentation of this file.
1 /**
2  * @file larcorealg/CoreUtils/SortByPointers.h
3  * @brief Silly utility to sort vectors indirectly.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date September 28, 2017
6  *
7  * This library is header-only.
8  */
9 
10 #ifndef LARCOREALG_COREUTILS_SORTBYPOINTER_H
11 #define LARCOREALG_COREUTILS_SORTBYPOINTER_H
12 
13 // LArSoft libraries
15 #include "larcorealg/CoreUtils/MetaUtils.h" // util::is_unique_ptr_v<>
16 
17 // C/C++ standard libraries
18 #include <vector>
19 #include <algorithm> // std::transform(), std::sort()
20 #include <memory> // std::addressof()
21 #include <iterator> // std::back_inserter()
22 #include <utility> // std::move()
23 #include <type_traits> // std::add_pointer_t
24 
25 
26 namespace util {
27 
28  namespace details {
29 
30  template <typename Coll, typename PtrColl>
32 
33  } // namespace details
34 
35 
36  //----------------------------------------------------------------------------
37  /**
38  * @brief Creates a STL vector with pointers to data from another collection.
39  * @tparam Coll type of collection of data
40  * @param coll data collection
41  * @return a STL vector with pointers to `coll` data elements, with same order
42  */
43  template <typename Coll>
44  auto makePointerVector(Coll& coll);
45 
46 
47  //----------------------------------------------------------------------------
48  /**
49  * @brief Moves the content from a collection of pointers to one of data.
50  * @tparam Coll type of collection of data
51  * @tparam PtrColl type of collection of pointers to data
52  * @param dest collection to be filled
53  * @param src collection with the pointers to data to be moved
54  *
55  * The data pointed from each pointer in `src` is moved into `dest`.
56  * The destination collection is cleared first, and `Coll` must support both
57  * `clear()` and `push_back()`
58  *
59  */
60  template <typename Coll, typename PtrColl>
61  void MoveFromPointers(Coll& dest, PtrColl& src)
63 
64 
65  //----------------------------------------------------------------------------
66  /**
67  * @brief Applies sorting indirectly, minimizing data copy.
68  * @tparam Coll type of collection to be sorted
69  * @tparam Sorter type of sorter
70  * @param coll collection to be sorted
71  * @param sorter functor sorting a vector of pointers (`makePointerVector()`)
72  *
73  * The `sorter` functor can receive a reference to a vector as the one
74  * produced by `makePointerVector(coll)` (that is, a C++ STL vector of
75  * pointers to the value type of `Coll`), and sort it "in place".
76  * The container `Comp` must implement `push_back()` call in a `std::vector`
77  * fashion.
78  *
79  * The algorithm is equivalent to the following:
80  * -# create a parallel vector of pointers to the data
81  * -# sort the data pointers (delegating to `sorter`)
82  * -# move the data, sorted, from the original collection to a new one
83  * -# replace the content of cont with the one from the sorted collection
84  *
85  * Single elements are moved from the original collection to a new one.
86  *
87  * The data elements of `Coll` must be moveable, as `Coll` itself must be.
88  *
89  * @note Use this algorithm only as a last resort, as there are usually better
90  * ways to sort collections than this one, which is not even
91  * particularly optimized.
92  *
93  */
94  template <typename Coll, typename Sorter>
95  void SortByPointers(Coll& coll, Sorter sorter);
96 
97 
98  //----------------------------------------------------------------------------
99  /**
100  * @brief Sorts a vector of unique pointers using a C pointer sorter.
101  * @tparam Coll type of collection to be sorted
102  * @tparam Sorter type of sorter function
103  * @param coll collection to be sorted
104  * @param sorter sorting procedure
105  *
106  * This adapter moves the unique pointers around to match a sorted version of
107  * source.
108  * This is an expensive procedure, implying the creation of a temporary
109  * vector and of additional supporting data: avoid it if at all possible.
110  */
111  template <typename Coll, typename Sorter>
112  void SortUniquePointers(Coll& coll, Sorter&& sorter);
113 
114 
115  //----------------------------------------------------------------------------
116 
117 } // namespace util
118 
119 
120 //------------------------------------------------------------------------------
121 //--- Template implementation
122 //------------------------------------------------------------------------------
123 namespace util::details {
124 
125  //----------------------------------------------------------------------------
126  template <typename Coll, typename = void>
128 
129  static auto make(Coll& coll) {
130 
131  using std::begin, std::end;
132 
133  using pointer_type = decltype(&*begin(coll));
134  using ptr_coll_t = std::vector<pointer_type>;
135 
136  auto const n = coll.size();
137 
138  //
139  // create the collection of pointers to data
140  //
141  ptr_coll_t ptrs;
142  ptrs.reserve(n);
143  std::transform(begin(coll), end(coll), std::back_inserter(ptrs),
144  [](auto& obj){ return &obj; });
145 
146  return ptrs;
147 
148  } // make()
149 
150  }; // struct PointerVectorMaker<>
151 
152 
153  template <typename Coll>
155  <Coll, std::enable_if_t<util::is_unique_ptr_v<typename Coll::value_type>>>
156  {
157 
158 
159  static auto make(Coll& coll) {
160 
161 
162  using coll_t = Coll;
163  using unique_ptr_t = typename coll_t::value_type;
164  using value_type = typename unique_ptr_t::element_type;
165  using pointer_type = std::add_pointer_t<value_type>;
166  using ptr_coll_t = std::vector<pointer_type>;
167 
168  static_assert(util::is_unique_ptr_v<unique_ptr_t>); // kind of silly now
169 
170  using std::size;
171  auto const n = size(coll);
172 
173  //
174  // create the collection of pointers to data
175  //
176  ptr_coll_t ptrs;
177  ptrs.reserve(n);
178  std::transform(coll.begin(), coll.end(), std::back_inserter(ptrs),
179  [](auto& obj){ return obj.get(); });
180 
181  return ptrs;
182 
183  } // make()
184 
185  }; // struct PointerVectorMaker<unique_ptr>
186 
187 
188 
189  //----------------------------------------------------------------------------
190 
191 
192 } // namespace util::details
193 
194 
195 
196 //------------------------------------------------------------------------------
197 template <typename Coll>
198 auto util::makePointerVector(Coll& coll)
200 
201 
202 //------------------------------------------------------------------------------
203 template <typename Coll, typename Sorter>
204 void util::SortByPointers(Coll& coll, Sorter sorter) {
205 
206  using coll_t = Coll;
207 
208  //
209  // create the collection of pointers to data
210  //
211  auto ptrs = makePointerVector(coll);
212 
213  //
214  // delegate the sorting by pointers
215  //
216  sorter(ptrs);
217 
218  //
219  // create a sorted collection moving the content from the original one
220  //
221  coll_t sorted;
222  MoveFromPointers(sorted, ptrs);
223 
224  //
225  // replace the old container with the new one
226  //
227  coll = std::move(sorted);
228 
229 } // util::SortByPointers()
230 
231 
232 //------------------------------------------------------------------------------
233 template <typename Coll, typename Sorter>
234 void util::SortUniquePointers(Coll& coll, Sorter&& sorter) {
235 
236  using Collection_t = Coll;
237  using UPtr_t = typename Collection_t::value_type;
238 
239  static_assert(util::is_unique_ptr_v<UPtr_t>);
240 
241  //
242  // create the collection of pointers to data
243  //
244  auto ptrs = makePointerVector(coll);
245 
246  // data pointer -> index
247  auto const ptrIndex = util::makeValueIndex(ptrs);
248 
249  //
250  // delegate the sorting by pointers
251  //
252  sorter(ptrs);
253 
254  //
255  // create a sorted collection moving the content from the original one
256  //
257  Collection_t sorted;
258  for (auto const& dataPtr: ptrs) {
259  std::size_t const originalIndex = ptrIndex.at(dataPtr);
260  sorted.emplace_back(std::move(coll[originalIndex]));
261  }
262 
263  //
264  // replace the old container with the new one
265  //
266  coll = std::move(sorted);
267 
268 } // util::SortUniquePointers()
269 
270 
271 //------------------------------------------------------------------------------
272 namespace util {
273  namespace details {
274 
275  template <typename Coll, typename PtrColl>
276  void moveFromPointersImplBase(Coll& dest, PtrColl& src)
277  { for (auto&& ptr: src) dest.push_back(std::move(*ptr)); }
278 
279 
280  template <typename Coll, typename PtrColl>
281  struct MoveFromPointersImpl {
282  static void move(Coll& dest, PtrColl& src)
283  {
284  dest.clear();
285  moveFromPointersImplBase(dest, src);
286  }
287  }; // struct MoveFromPointersImpl
288 
289 
290  template <typename Data, typename PtrColl>
291  struct MoveFromPointersImpl<std::vector<Data>, PtrColl> {
292  static void move(std::vector<Data>& dest, PtrColl& src)
293  {
294  dest.clear();
295  dest.reserve(src.size());
296  moveFromPointersImplBase(dest, src);
297  }
298  }; // struct MoveFromPointersImpl
299 
300  } // namespace details
301 } // namespace util
302 
303 
304 //------------------------------------------------------------------------------
305 
306 #endif // LARCOREALG_COREUTILS_SORTBYPOINTER_H
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
static void move(std::vector< Data > &dest, PtrColl &src)
static void move(Coll &dest, PtrColl &src)
Namespace for general, non-LArSoft-specific utilities.
Basic C++ metaprogramming utilities.
Provides util::makeValueIndex() helper function.
auto makePointerVector(Coll &coll)
Creates a STL vector with pointers to data from another collection.
STL namespace.
void SortUniquePointers(Coll &coll, Sorter &&sorter)
Sorts a vector of unique pointers using a C pointer sorter.
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
void SortByPointers(Coll &coll, Sorter sorter)
Applies sorting indirectly, minimizing data copy.
std::void_t< T > n
def move(depos, offset)
Definition: depos.py:107
void moveFromPointersImplBase(Coll &dest, PtrColl &src)
static auto make(Coll &coll)
void MoveFromPointers(Coll &dest, PtrColl &src)
Moves the content from a collection of pointers to one of data.
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
decltype(auto) makeValueIndex(Coll const &coll, Extractor getter)
Returns a map of value to index.