LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
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:
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 //
31 // Interface.
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 type alias:
59 //
60 // using assn_t = std::pair<Ptr<L>, Ptr<R>>;
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 //
84 
86 
93 #include "cetlib/container_algorithms.h"
94 #include "cetlib_except/demangle.h"
95 
96 #include <iostream>
97 #include <typeinfo>
98 #include <vector>
99 
100 namespace art {
101  // General template.
102  template <typename L, typename R, typename D = void>
103  class Assns;
104 
105  // Specializations.
106  // 1.
107  template <typename LR>
108  class Assns<LR, LR, void>; // Unimplemented.
109  // 2.
110  template <typename LR, typename D>
111  class Assns<LR, LR, D>; // Unimplemented.
112  // 3.
113  template <typename L, typename R>
114  class Assns<L, R, void>; // No data: base class.
115 
116  namespace detail {
117  class AssnsStreamer;
118  }
119 }
120 
122 // Implementation of the specialization (3).
123 template <typename L, typename R>
124 class art::Assns<L, R, void> : public art::detail::AssnsBase {
125 public:
126  using left_t = L;
127  using right_t = R;
129 
130 private:
131  using ptrs_t = std::vector<std::pair<Ptr<left_t>, Ptr<right_t>>>;
132  using ptr_data_t = std::vector<std::pair<RefCore, std::size_t>>;
133 
134 public:
135  using assn_t = typename ptrs_t::value_type;
137 
138  using size_type = typename ptrs_t::size_type;
139 
140  // Constructors, destructor.
141  Assns();
142  Assns(partner_t const& other);
143  virtual ~Assns() = default;
144 
145  // Accessors.
146  const_iterator begin() const;
147  const_iterator end() const;
148  assn_t const& operator[](size_type index) const;
149  assn_t const& at(size_type index) const;
150  size_type size() const;
151  std::string className() const;
152 
153  // Modifiers.
154  void addSingle(Ptr<left_t> const& left, Ptr<right_t> const& right);
155 
156  template <typename Ls>
157  void addMany(Ls const& lefts, Ptr<right_t> const& right);
158 
159  template <typename Rs>
160  void addMany(Ptr<left_t> const& left, Rs const& rights);
161 
163 
164  std::unique_ptr<EDProduct> makePartner(
165  std::type_info const& wanted_wrapper_type) const;
166 
167  static short
169  {
170  return 11;
171  }
172 
173  void
174  aggregate(Assns const&) const
175  {}
176 
177 protected:
178  virtual void swap_(art::Assns<L, R, void>& other);
179 
180  virtual std::unique_ptr<EDProduct> makePartner_(
181  std::type_info const& wanted_wrapper_type) const;
182 
183 private:
184  friend class detail::AssnsStreamer;
185  friend class art::Assns<right_t, left_t, void>; // partner_t.
186 
187  // FIXME: The only reason this function is virtual is to cause the
188  // correct behavior to occur when the wrong streamer class is
189  // called. In future (>5.30.00) versions of ROOT that can register
190  // ioread rules for class template instantiations using
191  // typedefs/type aliases, this can be made back into a static
192  // function.
193 #ifdef ROOT_CAN_REGISTER_IOREADS_PROPERLY
194  static
195 #else
196  virtual
197 #endif
198  bool
199  left_first()
200 #ifndef ROOT_CAN_REGISTER_IOREADS_PROPERLY
201  const
202 #endif
203  ;
204 
205  void fill_transients() override;
206  void fill_from_transients() override;
207 
208  ptrs_t ptrs_{};
209  ptr_data_t ptr_data_1_{};
210  ptr_data_t ptr_data_2_{};
211 };
212 
214 // Yes, the general implementation inherits from the specific. Head
215 // exploded yet?
216 template <typename L, typename R, typename D>
217 class art::Assns : private art::Assns<L, R> {
218 private:
219  using base = Assns<L, R>;
220 
221 public:
222  // We do not allow D == bool since since the AssnsNode requires
223  // taking the reference to a std::vector<D> element. For
224  // std::vector<bool>::at or operator[], the returned object is a
225  // value type and not a reference type.
226  static_assert(
227  !std::is_same_v<D, bool>,
228  "\n\nart error: An 'Assns<A, B, D>' object with D = bool is not allowed.\n"
229  " If you decide that D must represent a boolean type, then we\n"
230  " recommend that you wrap a boolean value in a struct (e.g.):\n\n"
231  " struct WrappedBool { bool flag; };\n\n"
232  " Please contact artists@fnal.gov for guidance.\n");
233 
234  using left_t = typename base::left_t;
235  using right_t = typename base::right_t;
236  using data_t = D;
238  using const_iterator =
240  using const_reverse_iterator =
242  using size_type = typename base::size_type;
243 
244  Assns();
245  Assns(partner_t const& other);
246 
247  size_type size() const; // Implemented explicitly only to let Wrapper know.
248  const_iterator begin() const;
249  const_iterator end() const;
250  const_reverse_iterator rbegin() const;
251  const_reverse_iterator rend() const;
252 
253  using base::operator[];
254  using base::at;
255 
256  data_t const& data(typename std::vector<data_t>::size_type index) const;
257  data_t const& data(const_iterator it) const;
258 
259  // Modifiers.
260  void addSingle(Ptr<left_t> const& left,
261  Ptr<right_t> const& right,
262  data_t const& data);
263 
264  template <typename Ls, typename Ds>
265  void addMany(Ls const& lefts, Ptr<right_t> const& right, Ds const& data);
266 
267  template <typename Rs, typename Ds>
268  void addMany(Ptr<left_t> const& left, Rs const& rights, Ds const& data);
269 
270  void swap(art::Assns<L, R, D>& other);
271 
272  // This is needed (as opposed to using base::makePartner) because
273  // enable_if_function_exists_t does not detect the base's function.
274  std::unique_ptr<EDProduct> makePartner(
275  std::type_info const& wanted_wrapper_type) const;
276 
277  static short
279  {
280  return 11;
281  }
282 
283  void
284  aggregate(Assns const&) const
285  {}
286 
287 private:
288  friend class art::Assns<right_t, left_t, data_t>; // partner_t.
289 
290  void swap_(art::Assns<L, R, void>& other) override;
291  std::unique_ptr<EDProduct> makePartner_(
292  std::type_info const& wanted_wrapper_type) const override;
293 
294  std::vector<data_t> data_;
295 };
296 
299 
301 template <typename L, typename R>
303 {}
304 
305 template <typename L, typename R>
307 {
308  ptrs_.reserve(other.ptrs_.size());
309  cet::transform_all(
310  other.ptrs_, std::back_inserter(ptrs_), [](auto const& pr) {
311  using pr_t = typename ptrs_t::value_type;
312  return pr_t{pr.second, pr.first};
313  });
314 }
315 
316 template <typename L, typename R>
319 {
320  return ptrs_.begin();
321 }
322 
323 template <typename L, typename R>
326 {
327  return ptrs_.end();
328 }
329 
330 template <typename L, typename R>
331 inline typename art::Assns<L, R, void>::assn_t const&
333 {
334  return ptrs_[index];
335 }
336 
337 template <typename L, typename R>
338 inline typename art::Assns<L, R, void>::assn_t const&
340 {
341  return ptrs_.at(index);
342 }
343 
344 template <typename L, typename R>
345 inline typename art::Assns<L, R, void>::size_type
347 {
348  return ptrs_.size();
349 }
350 
351 template <typename L, typename R>
352 inline std::string
354 {
355  TypeID const assns_type{typeid(Assns<L, R, void>)};
356  return assns_type.className();
357 }
358 
359 template <typename L, typename R>
360 inline void
362  Ptr<right_t> const& right)
363 {
364  ptrs_.emplace_back(left, right);
365 }
366 
367 template <typename L, typename R>
368 template <typename Ls>
369 inline void
371 {
372  static_assert(std::is_same_v<typename Ls::value_type, art::Ptr<L>>,
373  "\n\nart error: The first argument must be a container whose "
374  "value_type is art::Ptr<L>\n"
375  " corresponding to an Assns<L, R(, D)> object.\n");
376  for (auto const& left : lefts) {
377  addSingle(left, right);
378  }
379 }
380 
381 template <typename L, typename R>
382 template <typename Rs>
383 inline void
385 {
386  static_assert(std::is_same_v<typename Rs::value_type, art::Ptr<R>>,
387  "\n\nart error: The second argument must be a container whose "
388  "value_type is art::Ptr<R>\n"
389  " corresponding to an Assns<L, R(, D)> object.\n");
390  for (auto const& right : rights) {
391  addSingle(left, right);
392  }
393 }
394 
395 template <typename L, typename R>
396 inline void
398 {
399  swap_(other);
400 }
401 
402 template <typename L, typename R>
403 inline std::unique_ptr<art::EDProduct>
405  std::type_info const& wanted_wrapper_type) const
406 {
407  return makePartner_(wanted_wrapper_type);
408 }
409 
410 template <typename L, typename R>
411 inline void
413 {
414  using std::swap;
415  swap(ptrs_, other.ptrs_);
416  swap(ptr_data_1_, other.ptr_data_1_);
417  swap(ptr_data_2_, other.ptr_data_2_);
418 }
419 
420 template <typename L, typename R>
421 std::unique_ptr<art::EDProduct>
423  std::type_info const& wanted_wrapper_type) const
424 {
425  if (wanted_wrapper_type != typeid(Wrapper<partner_t>)) {
426  detail::throwPartnerException(typeid(*this), wanted_wrapper_type);
427  }
428  return std::make_unique<Wrapper<partner_t>>(
429  std::make_unique<partner_t>(*this));
430 }
431 
432 template <typename L, typename R>
433 inline bool
435 {
436  static bool const lf_s = (art::TypeID{typeid(left_t)}.friendlyClassName() <
437  art::TypeID{typeid(right_t)}.friendlyClassName());
438  return lf_s;
439 }
440 
441 template <typename L, typename R>
442 void
444 {
445  // Precondition: ptr_data_1_.size() = ptr_data_2_.size();
446  ptrs_.clear();
447  ptrs_.reserve(ptr_data_1_.size());
448  ptr_data_t const& l_ref = left_first() ? ptr_data_1_ : ptr_data_2_;
449  ptr_data_t const& r_ref = left_first() ? ptr_data_2_ : ptr_data_1_;
450 
451  for (auto l = cbegin(l_ref), e = cend(l_ref), r = cbegin(r_ref); l != e;
452  ++l, ++r) {
453  ptrs_.emplace_back(
454  Ptr<left_t>{l->first.id(), l->second, l->first.productGetter()},
455  Ptr<right_t>{r->first.id(), r->second, r->first.productGetter()});
456  }
457  // Empty persistent representation.
458  ptr_data_t tmp1, tmp2;
459  ptr_data_1_.swap(tmp1);
460  ptr_data_2_.swap(tmp2);
461 }
462 
463 template <typename L, typename R>
464 void
466 {
467  if (!ptr_data_1_.empty()) {
468  assert(ptr_data_1_.size() == ptr_data_2_.size() &&
469  ptr_data_2_.size() == ptrs_.size() &&
470  "Assns: internal inconsistency between transient and persistent "
471  "member data.");
472  // Multiple output modules: nothing to do on second and subsequent
473  // calls.
474  return;
475  }
476  ptr_data_t& l_ref = left_first() ? ptr_data_1_ : ptr_data_2_;
477  ptr_data_t& r_ref = left_first() ? ptr_data_2_ : ptr_data_1_;
478  l_ref.reserve(ptrs_.size());
479  r_ref.reserve(ptrs_.size());
480  for (auto const& pr : ptrs_) {
481  l_ref.emplace_back(pr.first.refCore(), pr.first.key());
482  r_ref.emplace_back(pr.second.refCore(), pr.second.key());
483  }
484 }
485 
486 template <typename L, typename R, typename D>
488 {
489  static_assert(!std::is_pointer_v<D>,
490  "Data template argument must not be pointer type!");
491 }
492 
493 template <typename L, typename R, typename D>
495  : base(other), data_(other.data_)
496 {}
497 
498 template <typename L, typename R, typename D>
499 inline typename art::Assns<L, R, D>::size_type
501 {
502  return base::size();
503 }
504 
505 template <typename L, typename R, typename D>
508 {
509  return const_iterator{*this, 0};
510 }
511 
512 template <typename L, typename R, typename D>
515 {
516  return const_iterator{*this};
517 }
518 
519 template <typename L, typename R, typename D>
522 {
523  return const_reverse_iterator{*this, size()};
524 }
525 
526 template <typename L, typename R, typename D>
529 {
530  return const_reverse_iterator{*this, 0};
531 }
532 
533 template <typename L, typename R, typename D>
534 inline typename art::Assns<L, R, D>::data_t const&
535 art::Assns<L, R, D>::data(typename std::vector<data_t>::size_type index) const
536 {
537  return data_.at(index);
538 }
539 
540 template <typename L, typename R, typename D>
541 inline typename art::Assns<L, R, D>::data_t const&
543 {
544  return data_.at(it.getIndex());
545 }
546 
547 template <typename L, typename R, typename D>
548 inline void
550  Ptr<right_t> const& right,
551  data_t const& data)
552 {
553  base::addSingle(left, right);
554  data_.push_back(data);
555 }
556 
557 template <typename L, typename R, typename D>
558 template <typename Ls, typename Ds>
559 inline void
561  Ptr<right_t> const& right,
562  Ds const& data)
563 {
564  static_assert(std::is_same_v<typename Ds::value_type, D>,
565  "\n\nart error: The data argument must be a container whose "
566  "value_type is D corresponding\n"
567  " to an Assns<L, R, D> object.\n");
568  assert(lefts.size() == data.size());
569  base::addMany(lefts, right);
570  data_.insert(data_.end(), data.begin(), data.end());
571 }
572 
573 template <typename L, typename R, typename D>
574 template <typename Rs, typename Ds>
575 void
577  Rs const& rights,
578  Ds const& data)
579 {
580  static_assert(std::is_same_v<typename Ds::value_type, D>,
581  "\n\nart error: The data argument must be a container whose "
582  "value_type is D corresponding\n"
583  " to an Assns<L, R, D> object.\n");
584  assert(rights.size() == data.size());
585  base::addMany(left, rights);
586  data_.insert(data_.end(), data.begin(), data.end());
587 }
588 
589 template <typename L, typename R, typename D>
590 inline void
592 {
593  using std::swap;
594  base::swap_(other);
595  swap(data_, other.data_);
596 }
597 
598 template <typename L, typename R, typename D>
599 inline std::unique_ptr<art::EDProduct>
601  std::type_info const& wanted_wrapper_type) const
602 {
603  return makePartner_(wanted_wrapper_type);
604 }
605 
606 template <typename L, typename R, typename D>
607 inline void
609 {
610  try {
611  swap(dynamic_cast<Assns<L, R, D>&>(other));
612  }
613  catch (std::bad_cast const&) {
614  throw Exception(errors::LogicError, "AssnsBadCast")
615  << "Attempt to swap base with derived!\n";
616  }
617 }
618 
619 template <typename L, typename R, typename D>
620 std::unique_ptr<art::EDProduct>
622  std::type_info const& wanted_wrapper_type) const
623 {
624  using bp = typename base::partner_t;
625  std::unique_ptr<art::EDProduct> result;
626  if (wanted_wrapper_type == typeid(Wrapper<partner_t>)) { // Partner.
627  result =
628  std::make_unique<Wrapper<partner_t>>(std::make_unique<partner_t>(*this));
629  } else if (wanted_wrapper_type == typeid(Wrapper<base>)) { // Base.
630  result = std::make_unique<Wrapper<base>>(
631  std::make_unique<base>(static_cast<base>(*this)));
632  } else if (wanted_wrapper_type == typeid(Wrapper<bp>)) { // Base of partner.
633  result = std::make_unique<Wrapper<bp>>(
634  std::make_unique<bp>(static_cast<base>(*this)));
635  } else { // Oops.
636  detail::throwPartnerException(typeid(*this), wanted_wrapper_type);
637  }
638  return result;
639 }
640 #endif /* canvas_Persistency_Common_Assns_h */
641 
642 // Local Variables:
643 // mode: c++
644 // End:
typename ptrs_t::const_iterator const_iterator
Definition: Assns.h:136
TRandom r
Definition: spectrum.C:23
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:102
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:93
void aggregate(Assns const &) const
Definition: Assns.h:174
std::vector< std::pair< Ptr< left_t >, Ptr< right_t >>> ptrs_t
Definition: Assns.h:131
size_type size() const
Definition: Assns.h:500
intermediate_table::const_iterator const_iterator
void swap(art::Assns< L, R, D > &other)
Definition: Assns.h:591
std::unique_ptr< EDProduct > makePartner(std::type_info const &wanted_wrapper_type) const
Definition: Assns.h:600
void addMany(Ls const &lefts, Ptr< right_t > const &right, Ds const &data)
Definition: Assns.h:560
const_iterator begin() const
Definition: Assns.h:507
std::unique_ptr< EDProduct > makePartner_(std::type_info const &wanted_wrapper_type) const override
Definition: Assns.h:621
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
data_t const & data(typename std::vector< data_t >::size_type index) const
Definition: Assns.h:535
void throwPartnerException(std::type_info const &generator, std::type_info const &wanted_wrapper_type)
void swap(Handle< T > &a, Handle< T > &b)
void swap_(art::Assns< L, R, void > &other) override
Definition: Assns.h:608
ProductID id() const noexcept
Definition: Ptr.h:160
std::string className() const
Definition: TypeID.cc:48
Assns()
Definition: Assns.h:487
typename ptrs_t::value_type assn_t
Definition: Assns.h:135
typename base::size_type size_type
Definition: Assns.h:242
const_iterator end() const
Definition: Assns.h:514
typename ptrs_t::size_type size_type
Definition: Assns.h:138
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< data_t > data_
Definition: Assns.h:294
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:94
const_reverse_iterator rend() const
Definition: Assns.h:528
void addSingle(Ptr< left_t > const &left, Ptr< right_t > const &right, data_t const &data)
Definition: Assns.h:549
std::vector< std::pair< RefCore, std::size_t >> ptr_data_t
Definition: Assns.h:132
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:85
Definition: MVAAlg.h:12
art::Assns< right_t, left_t, data_t > partner_t
Definition: Assns.h:237
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
ptr_data_t ptr_data_2_
Definition: Assns.h:210
void aggregate(Assns const &) const
Definition: Assns.h:284
const_reverse_iterator rbegin() const
Definition: Assns.h:521
Float_t e
Definition: plot.C:35
typename art::const_AssnsIter< recob::Hit, recob::SpacePoint, D, Direction::Reverse > const_reverse_iterator
Definition: Assns.h:241
ptr_data_t ptr_data_1_
transient
Definition: Assns.h:209
Definition: fwd.h:26
typename art::const_AssnsIter< recob::Hit, recob::SpacePoint, D, Direction::Forward > const_iterator
Definition: Assns.h:239
static short Class_Version()
Definition: Assns.h:168
typename base::right_t right_t
Definition: Assns.h:235
static short Class_Version()
Definition: Assns.h:278