LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
CollectionUtilities.h
Go to the documentation of this file.
1 #ifndef art_Persistency_Common_CollectionUtilities_h
2 #define art_Persistency_Common_CollectionUtilities_h
3 // CollectionUtilities.h
5 //
6 // A collection of possibly-useful free function templates for use with
7 // collections. In all the below signatures, the following variables are
8 // used:
9 //
10 // std::vector<COLLECTION<PROD> const*> const& in
11 //
12 // COLLECTION<PROD>& out
13 //
14 // OFFSET_CONTAINER<COLLECTION::size_type>& offsets; // Output.
15 //
16 // OFFSET_CONTAINER<COLLECTION::size_type> const& offsets; // Input.
17 //
18 // OFFSET_CONTAINER and COLLECTION are arbitrary (and not necessarily
19 // identical) container types which satisfy the constraints as specified
20 // below. Most people will probably want std::vector unless they wish to
21 // safely and efficiently expand or shrink their list often (by adding
22 // and removing items, for example).
23 //
24 // OFFSET_CONTAINER must support clear(), reserve() and push_back();
25 //
26 // COLLECTION must support insert() specifying iterators, const and
27 // non-const begin() and end(), and reserve(). Its iterators must support
28 // preincrement (operator++), comparisons and dereferencing (operator*).
29 //
30 // Some functions below expect COLLECTION to be a PtrVector<PROD> or
31 // other collection of Ptr<PROD>. This will be specified in the
32 // documentation for that function.
34 //
35 // concatContainers(out, in)
36 //
37 // A general, simple function to append the contents of the container
38 // specified by the second argument to the container specified by the
39 // first.
40 //
41 // flattenCollections(...)
42 //
43 // A set of function templates to aid in the flattening of multiple
44 // collections (as represented usually as a vector of const pointers to
45 // colletions) into one collection, as required by acitivities such as
46 // product mixing. The interfaces are as follows:
47 //
48 // 1. Flatten a vector of simple collections to a single collection
49 // (*not* a PtrVector or other collection of Ptr -- cf 3. below or
50 // PtrRemapper).
51 //
52 // flattenCollections(in, out)
53 //
54 // 2. Flatten a vector of collections to a single collection, filling a
55 // vector of offests into the resultant collection (eg for use by
56 // PtrRemapper later).
57 //
58 //
59 // 3. Flatten a vector of *compatible* PtrVectors (ie they all point to
60 // the same product) to a single PtrVector. If they require remapping,
61 // do *not* use this method -- use PtrRemapper instead.
62 //
63 //
64 // 4. Flatten a vector of *compatible* PtrVectors, filling a vector of
65 // offsets into the resultant collection (eg for use by a
66 // PtrRemapper). This function is only useful in the (hopefully rare)
67 // case that one has a Ptr *into* a PtrVector.
68 //
70 
74 #include "cetlib/map_vector.h"
75 
76 #include <cstddef>
77 #include <type_traits>
78 #include <utility>
79 #include <vector>
80 
81 namespace art {
82  // Forward declarations.
83  class EDProductGetter;
84 
85  // Append container in to container out.
86  template <typename CONTAINER>
87  void concatContainers(CONTAINER& out, CONTAINER const& in);
88 
89  // 1.
90  template <typename COLLECTION>
91  void flattenCollections(std::vector<COLLECTION const*> const& in,
92  COLLECTION& out);
93 
94  // 2.
95  template <typename COLLECTION, typename OFFSETS>
96  void flattenCollections(std::vector<COLLECTION const*> const& in,
97  COLLECTION& out,
98  OFFSETS& offsets);
99 
100  // 3.
101  template <typename T>
102  void flattenCollections(std::vector<PtrVector<T> const*> const& in,
103  PtrVector<T>& out);
104 
105  // 4.
106  template <typename T, typename OFFSETS>
107  void flattenCollections(std::vector<PtrVector<T> const*> const& in,
108  PtrVector<T>& out,
109  OFFSETS& offsets);
110 } // namespace art
111 
113 // No user-serviceable parts below.
115 
116 namespace art::detail {
117  // A. Verify a collection of PtrVector const*
118  template <typename T>
120 
121  // B. Verify a collection (including PtrVector) of Ptrs.
122  template <typename iterator>
123  bool verifyPtrCollection(iterator beg,
124  iterator end,
125  art::ProductID id = {},
126  art::EDProductGetter const* getter = nullptr);
127 }
128 
129 // A.
130 template <typename T>
131 bool
133  std::vector<art::PtrVector<T> const*> const& in)
134 {
135  return verifyPtrCollection(in.begin(), in.end());
136 }
137 
138 // B.
139 template <typename iterator>
140 bool
142  iterator const end,
143  art::ProductID const id,
144  art::EDProductGetter const* getter)
145 {
146  if (beg == end)
147  return true;
148  if (!id.isValid()) {
149  id = (*beg).id();
150  }
151  if (!getter) {
152  getter = (*beg).productGetter();
153  }
154  for (iterator i = beg; i != end; ++i) {
155  if ((*i) != nullptr &&
156  !((*i)->productGetter() && (*i)->productGetter() == getter &&
157  (*i)->id().isValid() && (*i)->id() == id)) {
158  return false;
159  }
160  }
161  return true;
162 }
163 
164 namespace art::detail {
165 
166  template <typename C>
167  struct mix_offset {
168  static size_t
169  offset(C const& c)
170  {
171  return c.size();
172  }
173  };
174 
175  template <typename P>
176  struct mix_offset<cet::map_vector<P>> {
177  static size_t
178  offset(cet::map_vector<P> const& mv)
179  {
180  return mv.delta();
181  }
182  };
183 
184  template <typename CONTAINER>
185  struct TwoArgInsert {
186  static void
187  concatenate(CONTAINER& out, CONTAINER const& in)
188  {
189  out.insert(in.begin(), in.end());
190  }
191  };
192 
193  template <typename T>
194  struct TwoArgInsert<cet::map_vector<T>> {
195  using mv_t = cet::map_vector<T>;
196  static void
198  {
199  // The offset is necessary for concatenating map_vectors so
200  // that all elements will be preserved.
201  auto const d = detail::mix_offset<mv_t>::offset(out);
202  for (auto& pr : in) {
203  pr.first = cet::map_vector_key{pr.first.asInt() + d};
204  }
205  // Because we can guarantee that entries will not overlap due
206  // to using the offset above, we do not need to call
207  // out.insert(...), which will unnecessarily merge entries.
208  // It is the user's responsibility to ensure that the
209  // map_vector entries are properly sorted.
210  out.append(in.begin(), in.end());
211  }
212  };
213 
214  // Metaprogramming for two-argument insertion
215  template <typename T, typename InIter = typename T::const_iterator>
216  using two_arg_insert_t =
217  decltype(std::declval<T>().insert(std::declval<InIter>(),
218  std::declval<InIter>()));
219 
220  template <typename T, typename = void>
221  struct has_two_arg_insert : std::false_type {};
222 
223  template <typename T>
224  struct has_two_arg_insert<T, std::void_t<two_arg_insert_t<T>>>
225  : std::true_type {};
226 
227  // Metaprogramming for three-argument insertion
228  template <typename T,
229  typename OutIter,
230  typename InIter = typename T::const_iterator>
231  using three_arg_insert_t =
232  decltype(std::declval<T>().insert(std::declval<OutIter>(),
233  std::declval<InIter>(),
234  std::declval<InIter>()));
235 
236  template <typename T, typename OutIter, typename = void>
237  struct has_three_arg_insert_t : std::false_type {};
238 
239  template <typename T, typename OutIter>
241  OutIter,
242  std::void_t<three_arg_insert_t<T, OutIter>>>
243  : std::true_type {};
244 
245  template <typename T>
246  constexpr bool has_three_arg_insert =
249 
250 } // namespace art::detail
251 
252 template <typename CONTAINER>
253 void
254 art::concatContainers(CONTAINER& out, CONTAINER const& in)
255 {
258  } else {
259  static_assert(detail::has_three_arg_insert<CONTAINER>);
260  out.insert(out.end(), in.begin(), in.end());
261  }
262 }
263 
264 // 1.
265 template <typename COLLECTION>
266 void
267 art::flattenCollections(std::vector<COLLECTION const*> const& in,
268  COLLECTION& out)
269 {
270  typename COLLECTION::size_type total_size = 0;
271  for (auto collptr : in) {
272  if (collptr != nullptr) {
273  total_size += collptr->size();
274  }
275  }
276  out.reserve(total_size);
277  for (auto collptr : in) {
278  if (collptr != nullptr) {
279  concatContainers(out, *collptr);
280  }
281  }
282 }
283 
284 // 2.
285 template <typename COLLECTION, typename OFFSETS>
286 void
287 art::flattenCollections(std::vector<COLLECTION const*> const& in,
288  COLLECTION& out,
289  OFFSETS& offsets)
290 {
291  offsets.clear();
292  offsets.reserve(in.size());
293  typename COLLECTION::size_type current_offset{};
294  for (auto collptr : in) {
295  if (collptr == nullptr)
296  continue;
297 
298  auto const delta = detail::mix_offset<COLLECTION>::offset(*collptr);
299  offsets.push_back(current_offset);
300  current_offset += delta;
301  }
302  flattenCollections<COLLECTION>(in, out); // 1.
303 }
304 
305 // 3.
306 template <typename T>
307 void
309  PtrVector<T>& out)
310 {
311  // Extra checks are required to verify that the PtrVectors are
312  // compatible.
315  << "Attempt to flatten incompatible PtrVectors "
316  << "referring to different ProductIDs.\n";
317  }
318  flattenCollections<PtrVector<T>>(in, out); // 1
319 }
320 
321 // 4.
322 template <typename T, typename OFFSETS>
323 void
325  PtrVector<T>& out,
326  OFFSETS& offsets)
327 {
328  // Extra checks are required to verify that the PtrVectors are
329  // compatible.
332  << "Attempt to flatten incompatible PtrVectors "
333  << "referring to different ProductIDs.\n";
334  }
335  flattenCollections<PtrVector<T>>(in, out, offsets); // 2.
336 }
337 
338 #endif /* art_Persistency_Common_CollectionUtilities_h */
339 
340 // Local Variables:
341 // mode: c++
342 // End:
intermediate_table::iterator iterator
static size_t offset(cet::map_vector< P > const &mv)
void concatContainers(CONTAINER &out, CONTAINER const &in)
decltype(std::declval< T >().insert(std::declval< OutIter >(), std::declval< InIter >(), std::declval< InIter >())) three_arg_insert_t
STL namespace.
intermediate_table::const_iterator const_iterator
static size_t offset(C const &c)
decltype(std::declval< T >().insert(std::declval< InIter >(), std::declval< InIter >())) two_arg_insert_t
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
void flattenCollections(std::vector< COLLECTION const * > const &in, COLLECTION &out)
Float_t d
Definition: plot.C:235
bool verifyPtrCollection(std::vector< art::PtrVector< T > const * > const &in)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
ifstream in
Definition: comparison.C:7
static void concatenate(CONTAINER &out, CONTAINER const &in)
Definition: MVAAlg.h:12
constexpr bool has_three_arg_insert