Assns.h
Go to the documentation of this file.
1 #ifndef canvas_Persistency_Common_Assns_h
2 #define canvas_Persistency_Common_Assns_h
3 // vim: set sw=2:
4 ////////////////////////////////////////////////////////////////////////
5 // Assns
6 //
7 // An association collection: a persistable collection of associations
8 // between two items in other persistent collections, with an optional
9 // ancillary object containing information about the association
10 // itself.
11 //
12 // N.B. An Assns<A, B> only makes sense when A and B are distinct:
13 // otherwise, there are ordering ambiguities when making and accessing
14 // associations. An attempt to specify an Assns<A,A> or <A, A, D> will
15 // fail with "... has incomplete type and cannot be defined."
16 //
17 // Note that the associations may be one-to-one, one-to-many or
18 // many-to-many.
19 //
20 // An Assns need only be used directly:
21 //
22 // 1. When being filled and put into the event; or
23 //
24 // 2. When the emphasis is on the associations themselves (and
25 // possibly their order) rather than particularly the associated
26 // objects. When it is desired to loop over A (or B) objects and
27 // access their counterparts and/or extra data objects a FindOne or
28 // FindMany would be more suitable.
29 //
30 ////////////////////////////////////
31 // Interface.
32 //////////
33 //
34 // Note that the structure of the Assns template is non-trivial
35 // because there is a variant that has an extra data object attached
36 // to each association, and a variant that does not. In order to
37 // minimize code duplication then, a fairly advanced specialization
38 // technique is used.
39 //
40 // In order that the user of an Assns does not need to be able to
41 // parse and understand this mechanism, the interface is presented
42 // below:
43 //
44 // Notes:
45 //
46 // * L and R below are the types of two objects to be found in
47 // collections in the event. D where used is an arbitrary
48 // user-supplied type wherein information is stored about the
49 // association between a particular L and a particular R.
50 //
51 // * An Assns operates essentially as a vector of pairs of Ptr, with
52 // auxiliary methods for accessing the attached extra data object for
53 // an association, if applicable.
54 //
55 // * An attempt to create an Assns with a template argument D of
56 // pointer-type will result in a compile-time assertion failure.
57 //
58 // Useful typedefs:
59 //
60 // typedef std::pair<Ptr<L>, Ptr<R>> assn_t;
61 //
62 // Constructors:
63 //
64 // Assns<L, R>();
65 // Assns<L, R, D>();
66 //
67 // Modifiers:
68 //
69 // void swap(Assns& other);
70 // void addSingle(Ptr<L> const&, Ptr<R> const&); // Assns<L, R> only.
71 // void addSingle(Ptr<L> const&, Ptr<R> const&, D const&);
72 //
73 // Accessors:
74 //
75 // const_iterator begin() const; // De-referencing an const_iterator
76 // const_iterator end() const; // yields an assn_t const&.
77 // assn_t const& operator [] (size_type i) const;
78 // assn_t const& at(size_type i) const; // Bounds-checked.
79 // size_type size() const;
80 // D const& data(std::size_t index) const;
81 // D const& data(const_iterator it) const;
82 //
83 ////////////////////////////////////////////////////////////////////////
84 
93 #include "cetlib_except/demangle.h"
94 
95 #include <iostream>
96 #include <typeinfo>
97 #include <vector>
98 
99 namespace art {
100  // General template.
101  template <typename L, typename R, typename D = void>
102  class Assns;
103 
104  // Specializations.
105  // 1.
106  template <typename LR>
107  class Assns<LR, LR, void>; // Unimplemented.
108  // 2.
109  template <typename LR, typename D>
110  class Assns<LR, LR, D>; // Unimplemented.
111  // 3.
112  template <typename L, typename R>
113  class Assns<L, R, void>; // No data: base class.
114 
115  namespace detail {
116  class AssnsStreamer;
117  }
118 }
119 
120 ////////////////////////////////////////////////////////////////////////
121 // Implementation of the specialization (3).
122 template <typename L, typename R>
124 public:
125  using left_t = L;
126  using right_t = R;
128 
129 private:
130  using ptrs_t = std::vector<std::pair<Ptr<left_t>, Ptr<right_t>>>;
131  using ptr_data_t = std::vector<std::pair<RefCore, std::size_t>>;
132 
133 public:
134  using assn_t = typename ptrs_t::value_type;
135  using const_iterator = typename ptrs_t::const_iterator;
136 
137  using size_type = typename ptrs_t::size_type;
138 
139  // Constructors, destructor.
140  Assns();
141  Assns(partner_t const& other);
142  virtual ~Assns() = default;
143 
144  // Accessors.
145  const_iterator begin() const;
146  const_iterator end() const;
147  assn_t const& operator[](size_type index) const;
148  assn_t const& at(size_type index) const;
149  size_type size() const;
150  std::string className() const;
151 
152  // Modifiers.
153  void addSingle(Ptr<left_t> const& left, Ptr<right_t> const& right);
154 
155  template <typename Ls>
156  void addMany(Ls const& lefts, Ptr<right_t> const& right);
157 
158  template <typename Rs>
159  void addMany(Ptr<left_t> const& left, Rs const& rights);
160 
162 
163  std::unique_ptr<EDProduct> makePartner(
164  std::type_info const& wanted_wrapper_type) const;
165 
166  static short
168  {
169  return 11;
170  }
171 
172  void
173  aggregate(Assns const&) const
174  {}
175 
176 protected:
177  virtual void swap_(art::Assns<L, R, void>& other);
178 
179  virtual std::unique_ptr<EDProduct> makePartner_(
180  std::type_info const& wanted_wrapper_type) const;
181 
182 private:
183  friend class detail::AssnsStreamer;
184  friend class art::Assns<right_t, left_t, void>; // partner_t.
185 
186  // FIXME: The only reason this function is virtual is to cause the
187  // correct behavior to occur when the wrong streamer class is
188  // called. In future (>5.30.00) versions of ROOT that can register
189  // ioread rules for class template instantiations using typedefs, this
190  // can be made back into a static function.
191 #ifdef ROOT_CAN_REGISTER_IOREADS_PROPERLY
192  static
193 #else
194  virtual
195 #endif
196  bool
197  left_first()
198 #ifndef ROOT_CAN_REGISTER_IOREADS_PROPERLY
199  const
200 #endif
201  ;
202 
203  void fill_transients() override;
204  void fill_from_transients() override;
205 
206  ptrs_t ptrs_{}; //! transient
207  ptr_data_t ptr_data_1_{};
208  ptr_data_t ptr_data_2_{};
209 };
210 
211 ////////////////////////////////////////////////////////////////////////
212 // Yes, the general implementation inherits from the specific. Head
213 // exploded yet?
214 template <typename L, typename R, typename D>
215 class art::Assns : private art::Assns<L, R> {
216 private:
217  using base = Assns<L, R>;
218 
219 public:
220  // We do not allow D == bool since since the AssnsNode requires
221  // taking the reference to a std::vector<D> element. For
222  // std::vector<bool>::at or operator[], the returned object is a
223  // value type and not a reference type.
224  static_assert(
225  !std::is_same_v<D, bool>,
226  "\n\nart error: An 'Assns<A, B, D>' object with D = bool is not allowed.\n"
227  " If you decide that D must represent a boolean type, then we\n"
228  " recommend that you wrap a boolean value in a struct (e.g.):\n\n"
229  " struct WrappedBool { bool flag; };\n\n"
230  " Please contact artists@fnal.gov for guidance.\n");
231 
232  using left_t = typename base::left_t;
233  using right_t = typename base::right_t;
234  using data_t = D;
236  using const_iterator =
238  using const_reverse_iterator =
240  using size_type = typename base::size_type;
241 
242  Assns();
243  Assns(partner_t const& other);
244 
245  size_type size() const; // Implemented explicitly only to let Wrapper know.
246  const_iterator begin() const;
247  const_iterator end() const;
248  const_reverse_iterator rbegin() const;
249  const_reverse_iterator rend() const;
250 
251  using base::operator[];
252  using base::at;
253 
254  data_t const& data(typename std::vector<data_t>::size_type index) const;
255  data_t const& data(const_iterator it) const;
256 
257  // Modifiers.
258  void addSingle(Ptr<left_t> const& left,
259  Ptr<right_t> const& right,
260  data_t const& data);
261 
262  template <typename Ls, typename Ds>
263  void addMany(Ls const& lefts, Ptr<right_t> const& right, Ds const& data);
264 
265  template <typename Rs, typename Ds>
266  void addMany(Ptr<left_t> const& left, Rs const& rights, Ds const& data);
267 
268  void swap(art::Assns<L, R, D>& other);
269 
270  // This is needed (as opposed to using base::makePartner) because
271  // enable_if_function_exists_t does not detect the base's function.
272  std::unique_ptr<EDProduct> makePartner(
273  std::type_info const& wanted_wrapper_type) const;
274 
275  static short
277  {
278  return 11;
279  }
280 
281  void
282  aggregate(Assns const&) const
283  {}
284 
285 private:
286  friend class art::Assns<right_t, left_t, data_t>; // partner_t.
287 
288  void swap_(art::Assns<L, R, void>& other) override;
289  std::unique_ptr<EDProduct> makePartner_(
290  std::type_info const& wanted_wrapper_type) const override;
291 
292  std::vector<data_t> data_;
293 };
294 
295 /////
296 
297 ////////////////////////////////////////////////////////////////////////
298 template <typename L, typename R>
300 {}
301 
302 template <typename L, typename R>
304 {
305  ptrs_.reserve(other.ptrs_.size());
307  other.ptrs_, std::back_inserter(ptrs_), [](auto const& pr) {
308  using pr_t = typename ptrs_t::value_type;
309  return pr_t{pr.second, pr.first};
310  });
311 }
312 
313 template <typename L, typename R>
316 {
317  return ptrs_.begin();
318 }
319 
320 template <typename L, typename R>
323 {
324  return ptrs_.end();
325 }
326 
327 template <typename L, typename R>
330 {
331  return ptrs_[index];
332 }
333 
334 template <typename L, typename R>
335 inline typename art::Assns<L, R, void>::assn_t const&
337 {
338  return ptrs_.at(index);
339 }
340 
341 template <typename L, typename R>
342 inline typename art::Assns<L, R, void>::size_type
344 {
345  return ptrs_.size();
346 }
347 
348 template <typename L, typename R>
349 inline std::string
351 {
352  TypeID const assns_type{typeid(Assns<L, R, void>)};
353  return assns_type.className();
354 }
355 
356 template <typename L, typename R>
357 inline void
359  Ptr<right_t> const& right)
360 {
361  ptrs_.emplace_back(left, right);
362 }
363 
364 template <typename L, typename R>
365 template <typename Ls>
366 inline void
368 {
369  static_assert(std::is_same_v<typename Ls::value_type, art::Ptr<L>>,
370  "\n\nart error: The first argument must be a container whose "
371  "value_type is art::Ptr<L>\n"
372  " corresponding to an Assns<L, R(, D)> object.\n");
373  for (auto const& left : lefts) {
374  addSingle(left, right);
375  }
376 }
377 
378 template <typename L, typename R>
379 template <typename Rs>
380 inline void
382 {
383  static_assert(std::is_same_v<typename Rs::value_type, art::Ptr<R>>,
384  "\n\nart error: The second argument must be a container whose "
385  "value_type is art::Ptr<R>\n"
386  " corresponding to an Assns<L, R(, D)> object.\n");
387  for (auto const& right : rights) {
388  addSingle(left, right);
389  }
390 }
391 
392 template <typename L, typename R>
393 inline void
395 {
396  swap_(other);
397 }
398 
399 template <typename L, typename R>
400 inline std::unique_ptr<art::EDProduct>
402  std::type_info const& wanted_wrapper_type) const
403 {
404  return makePartner_(wanted_wrapper_type);
405 }
406 
407 template <typename L, typename R>
408 inline void
410 {
411  using std::swap;
412  swap(ptrs_, other.ptrs_);
413  swap(ptr_data_1_, other.ptr_data_1_);
414  swap(ptr_data_2_, other.ptr_data_2_);
415 }
416 
417 template <typename L, typename R>
418 std::unique_ptr<art::EDProduct>
420  std::type_info const& wanted_wrapper_type) const
421 {
422  if (wanted_wrapper_type != typeid(Wrapper<partner_t>)) {
423  detail::throwPartnerException(typeid(*this), wanted_wrapper_type);
424  }
425  return std::make_unique<Wrapper<partner_t>>(
426  std::make_unique<partner_t>(*this));
427 }
428 
429 template <typename L, typename R>
430 inline bool
432 {
433  static bool const lf_s = (art::TypeID{typeid(left_t)}.friendlyClassName() <
434  art::TypeID{typeid(right_t)}.friendlyClassName());
435  return lf_s;
436 }
437 
438 template <typename L, typename R>
439 void
441 {
442  // Precondition: ptr_data_1_.size() = ptr_data_2_.size();
443  ptrs_.clear();
444  ptrs_.reserve(ptr_data_1_.size());
445  ptr_data_t const& l_ref = left_first() ? ptr_data_1_ : ptr_data_2_;
446  ptr_data_t const& r_ref = left_first() ? ptr_data_2_ : ptr_data_1_;
447 
448  for (auto l = cbegin(l_ref), e = cend(l_ref), r = cbegin(r_ref); l != e;
449  ++l, ++r) {
450  ptrs_.emplace_back(
451  Ptr<left_t>{l->first.id(), l->second, l->first.productGetter()},
452  Ptr<right_t>{r->first.id(), r->second, r->first.productGetter()});
453  }
454  // Empty persistent representation.
455  ptr_data_t tmp1, tmp2;
456  ptr_data_1_.swap(tmp1);
457  ptr_data_2_.swap(tmp2);
458 }
459 
460 template <typename L, typename R>
461 void
463 {
464  if (!ptr_data_1_.empty()) {
465  assert(ptr_data_1_.size() == ptr_data_2_.size() &&
466  ptr_data_2_.size() == ptrs_.size() &&
467  "Assns: internal inconsistency between transient and persistent "
468  "member data.");
469  // Multiple output modules: nothing to do on second and subsequent
470  // calls.
471  return;
472  }
473  ptr_data_t& l_ref = left_first() ? ptr_data_1_ : ptr_data_2_;
474  ptr_data_t& r_ref = left_first() ? ptr_data_2_ : ptr_data_1_;
475  l_ref.reserve(ptrs_.size());
476  r_ref.reserve(ptrs_.size());
477  for (auto const& pr : ptrs_) {
478  l_ref.emplace_back(pr.first.refCore(), pr.first.key());
479  r_ref.emplace_back(pr.second.refCore(), pr.second.key());
480  }
481 }
482 
483 template <typename L, typename R, typename D>
485 {
486  static_assert(!std::is_pointer_v<D>,
487  "Data template argument must not be pointer type!");
488 }
489 
490 template <typename L, typename R, typename D>
492  : base(other), data_(other.data_)
493 {}
494 
495 template <typename L, typename R, typename D>
496 inline typename art::Assns<L, R, void>::size_type
498 {
499  return base::size();
500 }
501 
502 template <typename L, typename R, typename D>
505 {
506  return const_iterator{*this, 0};
507 }
508 
509 template <typename L, typename R, typename D>
512 {
513  return const_iterator{*this};
514 }
515 
516 template <typename L, typename R, typename D>
519 {
520  return const_reverse_iterator{*this, size()};
521 }
522 
523 template <typename L, typename R, typename D>
526 {
527  return const_reverse_iterator{*this, 0};
528 }
529 
530 template <typename L, typename R, typename D>
531 inline typename art::Assns<L, R, D>::data_t const&
532 art::Assns<L, R, D>::data(typename std::vector<data_t>::size_type index) const
533 {
534  return data_.at(index);
535 }
536 
537 template <typename L, typename R, typename D>
538 inline typename art::Assns<L, R, D>::data_t const&
540 {
541  return data_.at(it.getIndex());
542 }
543 
544 template <typename L, typename R, typename D>
545 inline void
547  Ptr<right_t> const& right,
548  data_t const& data)
549 {
550  base::addSingle(left, right);
551  data_.push_back(data);
552 }
553 
554 template <typename L, typename R, typename D>
555 template <typename Ls, typename Ds>
556 inline void
558  Ptr<right_t> const& right,
559  Ds const& data)
560 {
561  static_assert(std::is_same_v<typename Ds::value_type, D>,
562  "\n\nart error: The data argument must be a container whose "
563  "value_type is D corresponding\n"
564  " to an Assns<L, R, D> object.\n");
565  assert(lefts.size() == data.size());
566  base::addMany(lefts, right);
567  data_.insert(data_.end(), data.begin(), data.end());
568 }
569 
570 template <typename L, typename R, typename D>
571 template <typename Rs, typename Ds>
572 void
574  Rs const& rights,
575  Ds const& data)
576 {
577  static_assert(std::is_same_v<typename Ds::value_type, D>,
578  "\n\nart error: The data argument must be a container whose "
579  "value_type is D corresponding\n"
580  " to an Assns<L, R, D> object.\n");
581  assert(rights.size() == data.size());
582  base::addMany(left, rights);
583  data_.insert(data_.end(), data.begin(), data.end());
584 }
585 
586 template <typename L, typename R, typename D>
587 inline void
589 {
590  using std::swap;
591  base::swap_(other);
592  swap(data_, other.data_);
593 }
594 
595 template <typename L, typename R, typename D>
596 inline std::unique_ptr<art::EDProduct>
598  std::type_info const& wanted_wrapper_type) const
599 {
600  return makePartner_(wanted_wrapper_type);
601 }
602 
603 template <typename L, typename R, typename D>
604 inline void
606 {
607  try {
608  swap(dynamic_cast<Assns<L, R, D>&>(other));
609  }
610  catch (std::bad_cast const&) {
611  throw Exception(errors::LogicError, "AssnsBadCast")
612  << "Attempt to swap base with derived!\n";
613  }
614 }
615 
616 template <typename L, typename R, typename D>
617 std::unique_ptr<art::EDProduct>
619  std::type_info const& wanted_wrapper_type) const
620 {
621  using bp = typename base::partner_t;
622  std::unique_ptr<art::EDProduct> result;
623  if (wanted_wrapper_type == typeid(Wrapper<partner_t>)) { // Partner.
624  result =
625  std::make_unique<Wrapper<partner_t>>(std::make_unique<partner_t>(*this));
626  } else if (wanted_wrapper_type == typeid(Wrapper<base>)) { // Base.
627  result = std::make_unique<Wrapper<base>>(
628  std::make_unique<base>(static_cast<base>(*this)));
629  } else if (wanted_wrapper_type == typeid(Wrapper<bp>)) { // Base of partner.
630  result = std::make_unique<Wrapper<bp>>(
631  std::make_unique<bp>(static_cast<base>(*this)));
632  } else { // Oops.
633  detail::throwPartnerException(typeid(*this), wanted_wrapper_type);
634  }
635  return result;
636 }
637 #endif /* canvas_Persistency_Common_Assns_h */
638 
639 // Local Variables:
640 // mode: c++
641 // End:
typename ptrs_t::const_iterator const_iterator
Definition: Assns.h:135
size_type size() const
Definition: Assns.h:497
D data_t
Definition: Assns.h:234
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
typename base::left_t left_t
Definition: Assns.h:232
set< int >::iterator it
void aggregate(Assns const &) const
Definition: Assns.h:173
std::vector< std::pair< Ptr< left_t >, Ptr< right_t >>> ptrs_t
Definition: Assns.h:130
std::string className() const
void swap(art::Assns< L, R, D > &other)
Definition: Assns.h:588
std::unique_ptr< EDProduct > makePartner(std::type_info const &wanted_wrapper_type) const
Definition: Assns.h:597
void addMany(Ls const &lefts, Ptr< right_t > const &right, Ds const &data)
Definition: Assns.h:557
const_iterator begin() const
Definition: Assns.h:504
std::unique_ptr< EDProduct > makePartner_(std::type_info const &wanted_wrapper_type) const override
Definition: Assns.h:618
const XML_Char const XML_Char * data
Definition: expat.h:268
data_t const & data(typename std::vector< data_t >::size_type index) const
Definition: Assns.h:532
void throwPartnerException(std::type_info const &generator, std::type_info const &wanted_wrapper_type)
static constexpr double L
void swap(Handle< T > &a, Handle< T > &b)
void swap_(art::Assns< L, R, void > &other) override
Definition: Assns.h:605
#define R(x)
Assns()
Definition: Assns.h:484
auto transform_all(Container &, OutputIt, UnaryOp)
typename ptrs_t::value_type assn_t
Definition: Assns.h:134
typename base::size_type size_type
Definition: Assns.h:240
const_iterator end() const
Definition: Assns.h:511
typename ptrs_t::size_type size_type
Definition: Assns.h:137
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< data_t > data_
Definition: Assns.h:292
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:96
Definition: bp.py:1
const_reverse_iterator rend() const
Definition: Assns.h:525
void addSingle(Ptr< left_t > const &left, Ptr< right_t > const &right, data_t const &data)
Definition: Assns.h:546
std::vector< std::pair< RefCore, std::size_t >> ptr_data_t
Definition: Assns.h:131
assert(nhit_max >=nhit_nbins)
TRandom3 r(0)
Service to store calibration data products (CDP) in the SQLite3 metadatabase of a file...
Definition: FillParentInfo.h:8
art::Assns< right_t, left_t, data_t > partner_t
Definition: Assns.h:235
ptr_data_t ptr_data_2_
Definition: Assns.h:208
void aggregate(Assns const &) const
Definition: Assns.h:282
const_reverse_iterator rbegin() const
Definition: Assns.h:518
Float_t e
Definition: plot.C:35
typename art::const_AssnsIter< L, R, D, Direction::Reverse > const_reverse_iterator
Definition: Assns.h:239
ptr_data_t ptr_data_1_
transient
Definition: Assns.h:207
typedef void(XMLCALL *XML_ElementDeclHandler)(void *userData
Definition: fwd.h:29
typename art::const_AssnsIter< L, R, D, Direction::Forward > const_iterator
Definition: Assns.h:237
static short Class_Version()
Definition: Assns.h:167
typename base::right_t right_t
Definition: Assns.h:233
static short Class_Version()
Definition: Assns.h:276
enum BeamMode string