IPRHelper.h
Go to the documentation of this file.
1 #ifndef canvas_Persistency_Common_detail_IPRHelper_h
2 #define canvas_Persistency_Common_detail_IPRHelper_h
3 
4 // Helper class and associated gubbins for populating the FindOne and
5 // FindMany query objects for inter-product references.
6 
13 
14 #include <type_traits>
15 #include <unordered_map>
16 
17 namespace art {
18  namespace detail {
19 
20  inline InputTag
22  {
23  return tag;
24  }
25 
26  template <typename T>
27  inline InputTag
29  {
30  return token.inputTag_;
31  }
32 
33  template <typename T>
34  inline InputTag
36  {
37  return token.inputTag_;
38  }
39 
40  class IPRHelperDef {};
41 
42  template <typename ProdA,
43  typename ProdB,
44  typename Data,
45  typename DATACOLL,
46  typename EVENT>
47  class IPRHelper;
48 
49  template <typename DATA>
51  public:
52  void init(size_t size, std::vector<DATA const*>& data) const;
53  template <typename ASSNS>
54  void fill(ptrdiff_t assns_index,
55  ASSNS const& assns,
56  size_t data_index,
57  std::vector<DATA const*>& data) const;
58 
59  void init(size_t size, std::vector<std::vector<DATA const*>>& data) const;
60  template <typename ASSNS>
61  void fill(ptrdiff_t assns_index,
62  ASSNS const& assns,
63  size_t data_index,
64  std::vector<std::vector<DATA const*>>& data) const;
65 
66  void init(size_t, IPRHelperDef&) const;
67  template <typename ASSNS>
68  void fill(ptrdiff_t, ASSNS const&, size_t, IPRHelperDef&) const;
69  };
70 
71  // Note that the template parameter Bcoll is determined by the
72  // IPRHelper's use by the FindOne and FindMany classes, and is not
73  // as free-ranging as one might naively imagine.
74  template <typename ProdB>
75  class BcollHelper {
76  public:
77  BcollHelper(InputTag const& assnsTag);
78  template <typename Bcoll>
79  void init(size_t size, Bcoll& bColl);
80 
81  // 1. When Bcoll is a collection of pointer to const B -- one to one.
82  template <typename Bcoll>
83  std::enable_if_t<
85  fill(size_t index, Ptr<ProdB> const& item, Bcoll& bColl);
86 
87  // 2. When Bcoll is a collection of Ptr<B> -- one to one.
88  template <typename Bcoll>
89  std::enable_if_t<
90  std::is_convertible<typename Bcoll::value_type, Ptr<ProdB>>::value>
91  fill(size_t index, Ptr<ProdB> const& item, Bcoll& bColl);
92 
93  template <typename Bcoll>
94  void init(size_t size, std::vector<Bcoll>& bColls) const;
95 
96  // 3. When Bcoll is a collection of pointer to const B -- one to many.
97  template <typename Bcoll>
98  std::enable_if_t<
100  fill(size_t index,
101  Ptr<ProdB> const& item,
102  std::vector<Bcoll>& bColls) const;
103 
104  // 4. When Bcoll is a collection of Ptr<B> -- one to many.
105  template <typename Bcoll>
106  std::enable_if_t<
107  std::is_convertible<typename Bcoll::value_type, Ptr<ProdB>>::value>
108  fill(size_t index,
109  Ptr<ProdB> const& item,
110  std::vector<Bcoll>& bColls) const;
111 
112  private:
114  std::vector<uint8_t> seen_;
115  };
116  }
117 }
118 
119 template <typename ProdA,
120  typename ProdB,
121  typename Data,
122  typename DATACOLL,
123  typename EVENT>
125 private:
126  // We use IPRHelperDef in place of DATACOLL if Data is void.
129 
130 public:
131  typedef std::shared_ptr<art::Exception const> shared_exception_t;
132 
133  IPRHelper(EVENT const& e, InputTag const& tag) : event_(e), assnsTag_(tag) {}
134 
135  // template <typename A, typename B> shared_exception_t operator()(A const& a,
136  // B const& b) const
137  // (1) fills in b, and
138  // (2) returns a (shared pointer to) an exception. The pointer is
139  // non-null on failure. Note that the returned 'b' might be empty.
140  //
141  // 1. When dColl not wanted.
142  template <typename Acoll, typename Bcoll>
143  shared_exception_t operator()(Acoll const& aColl, Bcoll& bColl) const;
144 
145  // 2. Algorithm useful when dealing with collections of Ptrs.
146  template <typename Acoll, typename Bcoll>
147  shared_exception_t operator()(Acoll const& aColl,
148  Bcoll& bColl,
149  dataColl_t& dColl) const;
150 
151 private:
152  EVENT const& event_;
154 };
155 
156 // 1.
157 template <typename ProdA,
158  typename ProdB,
159  typename Data,
160  typename DATACOLL,
161  typename EVENT>
162 template <typename Acoll, typename Bcoll>
163 inline auto
165  Acoll const& aColl,
166  Bcoll& bColl) const -> shared_exception_t
167 {
169  return (*this)(aColl, bColl, dummy);
170 }
171 
172 // 2.
173 ////////////////////////////////////////////////////////////////////////
174 // Implementation notes.
175 //
176 // The current implementation does not verify the that ProductID of the
177 // item in the association collection matches that of the item in the
178 // reference collection before attempting to dereference its Ptr
179 // (although it does verify ptr.isAvailable()). This means that in the
180 // case where an association collection refers to multiple available
181 // AProd collections, all of those collections will be read from file
182 // even if the reference collection does not include items from one or
183 // more of those AProd collections.
184 //
185 // If one were to provide an implementation that did this, one would
186 // change the unordered_multimap to key on the full ptr instead of the
187 // pointer. There is a specialization of std::hash<T> for T =
188 // art::Ptr<X> to support this.
189 //
190 // However, it would be problematic to do the lookup if the reference
191 // item was not in fact a Ptr. Maybe it would be relatively efficient if
192 // one were able to do a lookup in the table against an entity not a Ptr
193 // for which I could write a comparison function that compared the
194 // ProductID and only if they matched, the pointer with suitable get().
195 //
196 // For now however, no-one has requested this,
197 ////////////////////////////////////////////////////////////////////////
198 template <typename ProdA,
199  typename ProdB,
200  typename Data,
201  typename DATACOLL,
202  typename EVENT>
203 template <typename Acoll, typename Bcoll>
204 auto
206 operator()(Acoll const& aColl, Bcoll& bColl, dataColl_t& dColl) const
208 {
209  detail::BcollHelper<ProdB> bh(assnsTag_);
211  typename EVENT::template HandleT<Assns<ProdA, ProdB, Data>> assnsHandle;
212  event_.getByLabel(assnsTag_, assnsHandle);
213  if (!assnsHandle.isValid()) {
214  return assnsHandle.whyFailed(); // Failed to get Assns product.
215  }
216  bh.init(aColl.size(), bColl);
217  dh.init(aColl.size(), dColl);
218  // Answer cache.
219  std::unordered_multimap<typename Ptr<ProdA>::const_pointer,
220  std::pair<Ptr<ProdB>, ptrdiff_t>>
221  lookupCache;
222  ptrdiff_t counter{0};
223  for (auto const& apair : *assnsHandle) {
224  if (apair.first.isAvailable()) {
225  lookupCache.emplace(
226  apair.first.get(),
227  typename decltype(lookupCache)::mapped_type(apair.second, counter));
228  }
229  ++counter;
230  }
231  // Now use the cache.
232  size_t bIndex{0};
233  for (typename Acoll::const_iterator i = aColl.begin(), e = aColl.end();
234  i != e;
235  ++i, ++bIndex) {
236  auto foundItems = lookupCache.equal_range(
238  if (foundItems.first != lookupCache.cend()) {
239  std::for_each(
240  foundItems.first,
241  foundItems.second,
242  [&bh, &dh, &bColl, bIndex, &assnsHandle, &dColl](
243  typename decltype(lookupCache)::const_reference itemPair) {
244  bh.fill(bIndex, itemPair.second.first, bColl);
245  dh.fill(itemPair.second.second, *assnsHandle, bIndex, dColl);
246  });
247  }
248  }
249  return shared_exception_t();
250 }
251 
252 template <typename DATA>
253 inline void
255  std::vector<DATA const*>& data) const
256 {
257  data.assign(size, 0);
258 }
259 
260 template <typename DATA>
261 template <typename ASSNS>
262 inline void
264  ASSNS const& assns,
265  size_t data_index,
266  std::vector<DATA const*>& data) const
267 {
268  data[data_index] = &assns.data(assns_index);
269 }
270 
271 template <typename DATA>
272 inline void
274  size_t size,
275  std::vector<std::vector<DATA const*>>& data) const
276 {
277  data.resize(size);
278 }
279 
280 template <typename DATA>
281 template <typename ASSNS>
282 inline void
284  ptrdiff_t assns_index,
285  ASSNS const& assns,
286  size_t data_index,
287  std::vector<std::vector<DATA const*>>& data) const
288 {
289  data[data_index].push_back(&assns.data(assns_index));
290 }
291 
292 template <typename DATA>
293 inline void
295 {}
296 
297 template <typename DATA>
298 template <typename ASSNS>
299 inline void
301  ASSNS const&,
302  size_t,
303  IPRHelperDef&) const
304 {}
305 
306 template <typename ProdB>
308  : assnsTag_(assnsTag), seen_()
309 {}
310 
311 template <typename ProdB>
312 template <typename Bcoll>
313 inline void
315 {
316  // This works if BColl is a collection of pointers or Ptrs.
317  bColl.assign(size, typename Bcoll::value_type());
318  seen_.assign(size, uint8_t(0u));
319 }
320 
321 // 1.
322 template <typename ProdB>
323 template <typename Bcoll>
324 inline std::enable_if_t<
327  Ptr<ProdB> const& item,
328  Bcoll& bColl)
329 {
330  // This works if BColl is a collection of pointers or Ptrs.
331  if (seen_[index] == uint8_t(1u)) {
333  << "Attempted to create a FindOne object for a one-many or many-many"
334  << " association specified in collection " << assnsTag_ << ".\n";
335  } else if (item) {
336  bColl[index] = item.get();
337  seen_[index] = uint8_t(1u);
338  } else {
340  << "Attempted to create a FindOne object where an associated item is "
341  << "\nunavailable.\n";
342  }
343 }
344 
345 // 2.
346 template <typename ProdB>
347 template <typename Bcoll>
348 inline std::enable_if_t<
349  std::is_convertible<typename Bcoll::value_type, art::Ptr<ProdB>>::value>
351  Ptr<ProdB> const& item,
352  Bcoll& bColl)
353 {
354  // This works if BColl is a collection of pointers or Ptrs.
355  if (seen_[index] == uint8_t(1u)) {
357  << "Attempted to create a FindOne object for a one-many or many-many"
358  << " association specified in collection " << assnsTag_ << ".\n";
359  }
360  bColl[index] = item;
361  seen_[index] = uint8_t(1u);
362 }
363 
364 template <typename ProdB>
365 template <typename Bcoll>
366 inline void
368  std::vector<Bcoll>& bColls) const
369 {
370  bColls.resize(size);
371 }
372 
373 // 3.
374 template <typename ProdB>
375 template <typename Bcoll>
376 inline std::enable_if_t<
379  Ptr<ProdB> const& item,
380  std::vector<Bcoll>& bColls) const
381 {
382  bColls[index].push_back(item ? item.get() : nullptr);
383 }
384 
385 // 4.
386 template <typename ProdB>
387 template <typename Bcoll>
388 inline std::enable_if_t<
389  std::is_convertible<typename Bcoll::value_type, art::Ptr<ProdB>>::value>
391  Ptr<ProdB> const& item,
392  std::vector<Bcoll>& bColls) const
393 {
394  bColls[index].push_back(item);
395 }
396 
397 #endif /* canvas_Persistency_Common_detail_IPRHelper_h */
398 
399 // Local Variables:
400 // mode: c++
401 // End:
InputTag input_tag(InputTag const &tag)
Definition: IPRHelper.h:21
BcollHelper(InputTag const &assnsTag)
Definition: IPRHelper.h:307
void init(size_t size, std::vector< DATA const * > &data) const
Definition: IPRHelper.h:254
std::conditional_t< std::is_void< Data >::value, IPRHelperDef, DATACOLL > dataColl_t
Definition: IPRHelper.h:128
void init(size_t size, Bcoll &bColl)
Definition: IPRHelper.h:314
void fill(ptrdiff_t assns_index, ASSNS const &assns, size_t data_index, std::vector< DATA const * > &data) const
Definition: IPRHelper.h:263
InputTag const assnsTag_
Definition: IPRHelper.h:153
std::enable_if_t< std::is_same< typename Bcoll::value_type, ProdB const * >::value > fill(size_t index, Ptr< ProdB > const &item, Bcoll &bColl)
Definition: IPRHelper.h:326
const XML_Char const XML_Char * data
Definition: expat.h:268
EVENT const & event_
Definition: IPRHelper.h:152
shared_exception_t operator()(Acoll const &aColl, Bcoll &bColl) const
const XML_Char int const XML_Char * value
Definition: expat.h:331
std::vector< uint8_t > seen_
Definition: IPRHelper.h:114
InputTag inputTag_
Definition: ProductToken.h:87
InputTag const assnsTag_
Definition: IPRHelper.h:113
InputTag inputTag_
Definition: ProductToken.h:65
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
T const * get() const
Definition: Ptr.h:321
std::shared_ptr< art::Exception const > shared_exception_t
Definition: IPRHelper.h:131
Service to store calibration data products (CDP) in the SQLite3 metadatabase of a file...
Definition: FillParentInfo.h:8
void fill(std::vector< T > &x, const S &y)
Definition: fill.hpp:22
Float_t e
Definition: plot.C:35
::xsd::cxx::tree::token< char, normalized_string > token
Definition: Database.h:156
Definition: fwd.h:28
WANTED_POINTER ensurePointer(InputIterator it)
Definition: ensurePointer.h:77
T const * const_pointer
Definition: Ptr.h:104
IPRHelper(EVENT const &e, InputTag const &tag)
Definition: IPRHelper.h:133