LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
FindAllP.h
Go to the documentation of this file.
1 
11 #ifndef FINDALLP_H
12 #define FINDALLP_H 1
13 
14 // C/C++ standard libraries
15 #include <climits> // CHAR_BIT
16 #include <stdexcept> // std::out_of_range
17 #include <vector>
18 #include <unordered_map>
19 #include <functional> // std::hash<>
20 
21 
22 // framework libraries
30 
32 namespace lar {
33 
35  namespace util {
36 
38  namespace details {
39 
41  template <typename T>
42  struct hash {
43  using result_type = size_t;
44  using argument_type = T;
45 
46  result_type operator() (argument_type const& v) const;
47 
48  }; // class hash<>
49 
50 
51 
52 
64  template <typename Source, typename Dest>
66  public:
67  using Source_t = Source;
68  using Dest_t = Dest;
69 
72 
74  using InProductCache_t = std::vector<DestPtr_t>;
75 
78 
80  using Cache_t
81  = std::unordered_map<art::ProductID, InProductCache_t, Hash_t>;
82 
84 
85 
87  UniqueAssociationCache() = default;
88 
94  DestPtr_t operator[] (SourcePtr_t const& src) const
95  { return AssnCache[src.id()][src.key()]; }
96 
98  void clear() { AssnCache.clear(); }
99 
100  size_t NProductIDs() const { return AssnCache.size(); }
101 
102  }; // class UniqueAssociationCache<>
103 
104 
116  template <typename Source, typename Dest>
117  class FindAllP {
118  public:
119  using Source_t = Source;
120  using Dest_t = Dest;
121 
123  FindAllP() = default;
124 
126  FindAllP(art::Event& event): FindAllP() { Read(event); }
127 
130  { Read(event, assnTag); }
131 
132 
138  art::Ptr<Dest_t> const& operator[] (art::Ptr<Dest_t> const& src) const;
139 
140 
142  bool hasProduct(art::ProductID const& id) const;
143 
145  bool hasProduct(art::Ptr<Source_t> const& ptr) const;
146 
152  unsigned int Read(art::Event& event);
153 
165  unsigned int Read(art::Event& event, art::InputTag const& assnTag);
166 
167 
181  unsigned int Add(art::Event& event, art::InputTag const& assnTag);
182 
183 
184  protected:
186 
189 
191 
193  unsigned int Merge(art::Handle<Assns_t>& handle);
194  }; // class FindAllP<>
195 
196 
197 
198 
208  template <typename T>
209  void ResizeToPower2(std::vector<T>& v, size_t min_size);
210 
211 
212  } // namespace details
213  } // namespace util
214 } // namespace lar
215 
216 
217 
218 //******************************************************************************
219 //*** Template implementation
220 //******************************************************************************
221 
222 namespace lar {
223  namespace util {
224  namespace details {
225  //------------------------------------------------------------------------
226  //--- FindAllP
227 
228  template <typename Source, typename Dest>
230  (art::Ptr<Dest_t> const& src) const -> art::Ptr<Dest_t> const&
231  {
232  // we expect a missing match to be exceptional
233  try {
234  return cache.AssnCache.at(src.id()).at(src.key());
235  }
236  catch (std::out_of_range) {
237  return {};
238  }
239  } // FindAllP<>::operator[]
240 
241 
242  template <typename Source, typename Dest>
244  (art::ProductID const& id) const
245  { return cache.AssnCache.count(id) > 0; }
246 
247 
248  template <typename Source, typename Dest>
250  (art::Ptr<Source_t> const& ptr) const
251  { return hasProduct(ptr.id()); }
252 
253 
254  template <typename Source, typename Dest>
255  unsigned int FindAllP<Source, Dest>::Read
257  {
258 
259  // read all the associations between source and destination class types
260  std::vector<art::Handle<Assns_t>> assns_list;
261  event.getManyByType(assns_list);
262 
263  LOG_DEBUG("FindAllP") << "Read(): read " << assns_list.size()
264  << " association sets";
265 
266  unsigned int count = 0;
267  // parse all the associations, and translate them into a local cache
268  for (art::Handle<Assns_t> handle: assns_list)
269  count += Merge(handle);
270 
271  LOG_DEBUG("FindAllP") << "Read " << count << " associations for "
272  << cache.NProductIDs() << " product IDs";
273 
274  return count;
275  } // FindAllP::Read(Event)
276 
277 
278 
279  template <typename Source, typename Dest>
280  unsigned int FindAllP<Source, Dest>::Read
281  (art::Event& event, art::InputTag const& assnTag)
282  {
283  cache.clear();
284  return Add(event, assnTag);
285  } // FindAllP::Read(Event, InputTag)
286 
287 
288 
289  template <typename Source, typename Dest>
290  unsigned int FindAllP<Source, Dest>::Add
291  (art::Event& event, art::InputTag const& assnTag)
292  {
293 
294  // read the association between source and destination class types
295  art::Handle<Assns_t> handle;
296  if (!event.getByLabel(assnTag, handle)) {
298  << "no association found with input tag '" << assnTag << "'";
299  }
300 
301  return Merge(handle);
302  } // FindAllP::Add(Event, InputTag)
303 
304 
305  template <typename Source, typename Dest>
306  unsigned int FindAllP<Source, Dest>::Merge
308  {
309  // product ID of the last source object; initialized invalid
310  art::ProductID LastProductID = art::Ptr<Source_t>().id();
311  typename Cache_t::InProductCache_t const* AssnsList = nullptr;
312 
313  unsigned int count = 0;
314 
315  LOG_DEBUG("FindAllP") << "Merge(): importing " << handle->size()
316  << " associations from " << handle.provenance();
317 
318  for (auto const& assn: *handle) {
319  // assn is a std::pair<art::Ptr<Source_t>, art::Ptr<Dest_t>>
320  art::Ptr<Source_t> const& src = assn.first;
321 
322  if (src.isNull()) {
323  LOG_ERROR("FindAllP") << "Empty pointer found in association "
324  << handle.provenance();
325  continue; // this should not happen
326  }
327 
328  art::Ptr<Dest_t> const& dest = assn.second;
329 
330  // if we have changed product (that should be fairly rare),
331  // update the running pointers
332  if (src.id() != LastProductID) {
333  LastProductID = src.id();
334  AssnsList = &(cache.AssnCache[LastProductID]);
335 
336  // if the list is empty, it means we have just created it!
337  if (AssnsList->empty()) {
338  // allocate enough space to accomodate all the associations,
339  // (provided that source IDs are sequencial);
340  // in fact typically all the associations in the same handle
341  // have the same product ID
342  ResizeToPower2(*AssnsList, handle->size());
343  }
344  } // if different product ID
345 
346  // make sure there is enough room in the vector
347  typename art::Ptr<Source_t>::key_type key = src.key();
348  if (key >= AssnsList->size()) ResizeToPower2(*AssnsList, key + 1);
349 
350  // store the association to dest
351  art::Ptr<Dest_t>& dest_cell = (*AssnsList)[key];
352  if (dest_cell.isNonnull() && (dest_cell != dest)) {
354  << "Object Ptr" << src
355  << " is associated with at least two objects: "
356  << dest << " and " << dest_cell;
357  }
358  dest_cell = dest;
359  ++count;
360  } // for all associations in a list
361 
362  LOG_DEBUG("FindAllP")
363  << "Merged " << count << " associations from " << handle.provenance();
364  return count;
365  } // FindAllP::Merge()
366 
367 
368 
369  //------------------------------------------------------------------------
370  template <>
372  (argument_type const& id) const -> result_type
373  {
374  // make sure we have enough bits in result_type;
375  // if not, we need a more clever algorithm
376  //static_assert(
377  // sizeof(id.processIndex()) + sizeof(id.productIndex())
378  // <= sizeof(result_type),
379  // "hash return type not large enough for hashing art::ProductID"
380  //);
381  // stack the process and product IDs in one integer
382  //return result_type(
383  //(id.processIndex() << sizeof(id.productIndex() * CHAR_BIT))
384  //+ id.productIndex()
385  //);
386  return result_type( id.value() );
387  } // hash<art::ProductID>::operator()
388 
389 
390 
391  //------------------------------------------------------------------------
392  template <typename T>
393  void ResizeToPower2(std::vector<T>& v, size_t min_size) {
394  if (min_size == 0) {
395  v.clear();
396  return;
397  }
398  size_t new_size = 1;
399  while (new_size < min_size) new_size *= 2;
400 
401  v.resize(new_size);
402  } // ResizeToPower2()
403 
404  } // namespace details
405  } // namespace util
406 } // namespace lar
407 
408 
409 //------------------------------------------------------------------------------
410 #endif // FINDALLP_H 1
key_type key() const
Definition: Ptr.h:356
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:17
FindAllP(art::Event &event, art::InputTag assnTag)
Constructor: reads one association from the specified event.
Definition: FindAllP.h:129
unsigned int Merge(art::Handle< Assns_t > &handle)
Adds all associations in the specified handle; returns their number.
Definition: FindAllP.h:307
bool isNonnull() const
Definition: Ptr.h:335
bool hasProduct(art::ProductID const &id) const
Returns whether there are associations from objects in product id.
Definition: FindAllP.h:244
A class holding many associations between objects.
Definition: FindAllP.h:65
void clear()
Empties the cache.
Definition: FindAllP.h:98
result_type operator()(argument_type const &v) const
Cache_t AssnCache
association cache, keyed by product ID and index
Definition: FindAllP.h:83
#define LOG_ERROR(category)
Provenance const * provenance() const
Definition: Handle.h:204
Cache_t cache
set of associations, keyed by product ID and key
Definition: FindAllP.h:190
FindAllP(art::Event &event)
Constructor: reads all associations from the specified event.
Definition: FindAllP.h:126
std::vector< DestPtr_t > InProductCache_t
type for a cache of dest products for a given source product ID
Definition: FindAllP.h:74
unsigned int Add(art::Event &event, art::InputTag const &assnTag)
Reads the specified association from the event.
Definition: FindAllP.h:291
ProductID id() const
Definition: Ptr.h:349
unsigned int Read(art::Event &event)
Reads all the associations from the event.
Definition: FindAllP.h:256
Query object reading all the associations between two classes.
Definition: FindAllP.h:117
void ResizeToPower2(std::vector< T > &v, size_t min_size)
Resizes a vector to a size power of 2, with a minimum size.
Definition: FindAllP.h:393
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::string value(boost::any const &)
LArSoft-specific namespace.
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
Hash functions for art and larsoft objects.
Definition: FindAllP.h:42
std::unordered_map< art::ProductID, InProductCache_t, Hash_t > Cache_t
type for the complete cache, keyed by source product ID
Definition: FindAllP.h:81
#define LOG_DEBUG(id)
std::size_t key_type
Definition: Ptr.h:102
bool isNull() const
Definition: Ptr.h:328
Definition: fwd.h:25
Event finding and building.