ATLAS Offline Software
DVL_algorithms.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // $Id$
6 /**
7  * @file AthContainers/tools/DVL_algorithms.icc
8  * @author scott snyder <snyder@bnl.gov>
9  * @date Sep, 2010
10  * @brief Helpers for STL algorithms for @c DataVector/List.
11  */
12 
13 
14 #include "AthContainers/tools/DVLNoBase.h"
15 #include "AthContainers/tools/DVLCast.h"
16 #include "AthContainers/AuxElement.h"
17 #include "AthContainersInterfaces/AuxStore_traits.h"
18 #include <algorithm>
19 
20 
21 template <class DV> class ConstDataVector;
22 
23 
24 namespace DataModel_detail {
25 
26 
27 /**
28  * @brief Comparison helper for @c DataVector/List classes.
29  *
30  * When doing operations such as @c sort on a @c DataVector/List,
31  * we'd like to be able to give to sort the iterators of the underlying
32  * @c BaseContainer container, for the sake of efficiency. But we also
33  * have to make sure that the comparisons see the proper pointer types
34  * for derived @c DataVector/List classes. This can be done with the following
35  * functional wrapper. This wraps a comparison object, putting the
36  * arguments through @c DVLCast before calling the comparison.
37  *
38  * There is also a specialization for the case where no casting
39  * is required.
40  */
41 template <class DVL, class Compare, class DVL_Base=typename DVL::DVL_BASE>
42 struct Compwrapper
43 {
44  typedef typename DVL::BaseContainer::value_type inptr;
45  Compare m_comp;
46  Compwrapper (Compare comp) : m_comp (comp) {}
47  bool operator() (inptr x, inptr y)
48  {
49  return m_comp (DataModel_detail::DVLCast<DVL>::cast (x),
50  DataModel_detail::DVLCast<DVL>::cast (y));
51  }
52 };
53 
54 
55 /**
56  * @brief Comparison helper for @c DataVector/List classes (specialization).
57  *
58  * This is specialized for the case where we're dealing with
59  * a base @c DataVector/List, and thus no casting is required.
60  */
61 template <class DVL, class Compare>
62 struct Compwrapper<DVL, Compare, DataModel_detail::NoBase>
63  : public Compare
64 {
65  Compwrapper (Compare comp) : Compare (comp) {}
66 };
67 
68 
69 /**
70  * @brief Predicate helper for @c DataVector/List classes.
71  *
72  * When doing operations such as @c partition on a @c DataVector/List,
73  * we'd like to be able to give the operation the iterators of the underlying
74  * @c BaseContainer container, for the sake of efficiency. But we also
75  * have to make sure that the predicate sees the proper pointer types
76  * for derived @c DataVector/List classes. This can be done with the following
77  * functional wrapper. This wraps a predicate object, putting the
78  * arguments through @c DVLCast before calling the predicate.
79  *
80  * There is also a specialization for the case where no casting
81  * is required.
82  */
83 template <class DVL, class Predicate, class DVL_Base=typename DVL::DVL_BASE>
84 struct Predwrapper
85 {
86  typedef typename DVL::BaseContainer::value_type inptr;
87  Predicate m_pred;
88  Predwrapper (Predicate pred) : m_pred (pred) {}
89  bool operator() (inptr x)
90  {
91  return m_pred (DataModel_detail::DVLCast<DVL>::cast (x));
92  }
93 };
94 
95 
96 /**
97  * @brief Predicate helper for @c DataVector/List classes (specialization).
98  *
99  * This is specialized for the case where we're dealing with
100  * a base @c DataVector/List, and thus no casting is required.
101  */
102 template <class DV, class Predicate>
103 struct Predwrapper<DV, Predicate, DataModel_detail::NoBase>
104  : public Predicate
105 {
106  Predwrapper (Predicate pred) : Predicate (pred) {}
107 };
108 
109 
110 /**
111  * @brief Specialization of @c remove for @c DataVector/List.
112  * @param beg The start iterator for the remove.
113  * @param end The end iterator for the remove.
114  * @param value The value to remove.
115  *
116  * @c beg and @c end should both be iterators from the same @c DataVector/List.
117  * This performs the remove in a way that doesn't run afoul of
118  * @c DataVector/List's object ownership rules.
119  */
120 template <class Iterator, class T>
121 Iterator
122 dvl_remove (Iterator beg,
123  Iterator end,
124  const T& value)
125 {
126  beg = std::find (beg, end, value);
127  if (beg == end)
128  return end;
129  Iterator res = beg;
130  *beg = 0;
131  ++beg;
132  for (; beg != end; ++beg) {
133  if (!(*beg == value)) {
134  std::iter_swap (res, beg);
135  ++res;
136  }
137  else
138  *beg = 0;
139  }
140  return res;
141 }
142 
143 
144 /**
145  * @brief Specialization of @c remove_if for @c DataVector/List.
146  * @param beg The start iterator for the remove.
147  * @param end The end iterator for the remove.
148  * @param pred The predicate for the removal.
149  *
150  * @c beg and @c end should both be iterators from the same @c DataVector/List.
151  * This performs the remove in a way that doesn't run afoul
152  * of @c DataVector/List's object ownership rules.
153  */
154 template <class Iterator, class Predicate>
155 Iterator
156 dvl_remove_if (Iterator beg,
157  Iterator end,
158  Predicate pred)
159 {
160  beg = std::find_if (beg, end, pred);
161  if (beg == end)
162  return end;
163  Iterator res = beg;
164  *beg = 0;
165  ++beg;
166  for (; beg != end; ++beg) {
167  if (!bool(pred(*beg))) {
168  std::iter_swap (res, beg);
169  ++res;
170  }
171  else
172  *beg = 0;
173  }
174  return res;
175 }
176 
177 
178 /**
179  * @brief Specialization of @c unique for @c DataVector/List.
180  * @param beg The start iterator for the unique operation.
181  * @param end The end iterator for the unique operation.
182  *
183  * @c beg and @c end should both be iterators from the same @c DataVector/List.
184  * This performs the operation in a way
185  * that doesn't run afoul of @c DataVector/List's object ownership rules.
186  */
187 template <class Iterator>
188 Iterator
189 dvl_unique (Iterator beg,
190  Iterator end)
191 {
192  beg = std::adjacent_find (beg, end);
193  if (beg == end)
194  return end;
195  Iterator res = beg;
196  ++beg;
197  *beg = 0;
198  while (++beg != end) {
199  if (!(*res == *beg))
200  std::iter_swap (++res, beg);
201  else
202  *beg = 0;
203  }
204  return ++res;
205 }
206 
207 
208 /**
209  * @brief Specialization of @c unique for @c DataVector/List.
210  * @param beg The start iterator for the unique operation.
211  * @param end The end iterator for the unique operation.
212  * @param pred The predicate for the operation.
213  *
214  * @c beg and @c end should both be iterators from the same @c DataVector/List.
215  * This performs the operation in a way
216  * that doesn't run afoul of @c DataVector/List's
217  * object ownership rules.
218  */
219 template <class Iterator, class BinaryPredicate>
220 Iterator
221 dvl_unique (Iterator beg,
222  Iterator end,
223  BinaryPredicate pred)
224 {
225  beg = std::adjacent_find (beg, end, pred);
226  if (beg == end)
227  return end;
228  Iterator res = beg;
229  ++beg;
230  *beg = 0;
231  while (++beg != end) {
232  if (!pred(*res, *beg))
233  std::iter_swap (++res, beg);
234  else
235  *beg = 0;
236  }
237  return ++res;
238 }
239 
240 
241 /**
242  * @brief Reset indices / reorder aux data after elements have been permuted.
243  * @param beg Start of the range of elements to process.
244  * @param end End of the range of elements to process.
245  *
246  * Call this after some operation that has permuted the elements in the
247  * container (such as sort). The index information in the elements
248  * will be used to permute all auxiliary data in the same way.
249  * Finally, all the indices will be reset in the correct order.
250  *
251  * @c ForwardIterator should be an iterator over the @c DataVector
252  * (not a base iterator).
253  */
254 template <class ForwardIterator>
255 inline
256 void resortAux (ForwardIterator beg,
257  ForwardIterator end)
258 {
259  // Forward to the appropriate specialization, depending on whether
260  // or not aux data is supported.
261  typedef typename std::iterator_traits<ForwardIterator>::value_type valtype;
262  resortAux1 (typename SG::AuxStore_traits<valtype>::flag(), beg, end);
263 }
264 
265 
266 /**
267  * @brief Reset indices / reorder aux data after elements have been permuted.
268  * @param beg Start of the range of elements to process.
269  * @param end End of the range of elements to process.
270  *
271  * Aux data case.
272  */
273 template <class DVL>
274 void resortAux1 (const std::true_type&,
275  typename DataModel_detail::iterator<DVL> beg,
276  typename DataModel_detail::iterator<DVL> end)
277 {
278  if (beg != end) {
279  DVL* cont = dynamic_cast<DVL*> (beg.container());
280  if (cont)
281  cont->resortAux (beg, end);
282  }
283 }
284 
285 
286 /**
287  * @brief Reset indices / reorder aux data after elements have been permuted.
288  * @param beg Start of the range of elements to process.
289  * @param end End of the range of elements to process.
290  *
291  * Aux data case with reverse iterators.
292  */
293 template <class DVL>
294 void resortAux1 (const std::true_type&,
295  typename std::reverse_iterator<typename DataModel_detail::iterator<DVL> > beg,
296  typename std::reverse_iterator<typename DataModel_detail::iterator<DVL> > end)
297 {
298  if (beg != end) {
299  DVL* cont = dynamic_cast<DVL*> (beg.base().container());
300  if (cont)
301  cont->resortAux (end.base(), beg.base());
302  }
303 }
304 
305 
306 /**
307  * @brief Reset indices / reorder aux data after elements have been permuted.
308  * @param beg Start of the range of elements to process.
309  * @param end End of the range of elements to process.
310  *
311  * No-auxdata case; just a no-op.
312  */
313 template <class ForwardIterator>
314 inline
315 void resortAux1 (const std::false_type&,
316  ForwardIterator,
317  ForwardIterator)
318 {
319 }
320 
321 
322 } // namespace DataModel_detail