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 // assn_iterator begin() const; // De-referencing an assn_iterator
76 // assn_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(assn_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 assn_iterator = typename ptrs_t::const_iterator;
136  using size_type = typename ptrs_t::size_type;
137 
138  // Constructors, destructor.
139  Assns();
140  Assns(partner_t const& other);
141  virtual ~Assns() = default;
142 
143  // Accessors.
144  assn_iterator begin() const;
145  assn_iterator end() const;
146  assn_t const& operator[](size_type index) const;
147  assn_t const& at(size_type index) const;
148  size_type size() const;
149  std::string className() const;
150 
151  // Modifier.
152  void addSingle(Ptr<left_t> const& left, Ptr<right_t> const& right);
154 
155  std::unique_ptr<EDProduct> makePartner(
156  std::type_info const& wanted_wrapper_type) const;
157 
158  static short
160  {
161  return 11;
162  }
163 
164  void
165  aggregate(Assns const&) const
166  {}
167 
168 protected:
169  virtual void swap_(art::Assns<L, R, void>& other);
170 
171  virtual std::unique_ptr<EDProduct> makePartner_(
172  std::type_info const& wanted_wrapper_type) const;
173 
174 private:
175  friend class detail::AssnsStreamer;
176  friend class art::Assns<right_t, left_t, void>; // partner_t.
177 
178  // FIXME: The only reason this function is virtual is to cause the
179  // correct behavior to occur when the wrong streamer class is
180  // called. In future (>5.30.00) versions of ROOT that can register
181  // ioread rules for class template instantiations using typedefs, this
182  // can be made back into a static function.
183 #ifdef ROOT_CAN_REGISTER_IOREADS_PROPERLY
184  static
185 #else
186  virtual
187 #endif
188  bool
189  left_first()
190 #ifndef ROOT_CAN_REGISTER_IOREADS_PROPERLY
191  const
192 #endif
193  ;
194 
195  void fill_transients() override;
196  void fill_from_transients() override;
197 
198  ptrs_t ptrs_{}; //! transient
199  ptr_data_t ptr_data_1_{};
200  ptr_data_t ptr_data_2_{};
201 };
202 
203 ////////////////////////////////////////////////////////////////////////
204 // Yes, the general implementation inherits from the specific. Head
205 // exploded yet?
206 template <typename L, typename R, typename D>
207 class art::Assns : private art::Assns<L, R> {
208 private:
209  using base = Assns<L, R>;
210 
211 public:
212  using left_t = typename base::left_t;
213  using right_t = typename base::right_t;
214  using data_t = D;
216  using const_iterator =
218  using const_reverse_iterator =
220  using size_type = typename base::size_type;
221 
222  Assns();
223  Assns(partner_t const& other);
224 
225  size_type size() const; // Implemented explicitly only to let Wrapper know.
226  const_iterator begin() const;
227  const_iterator end() const;
228  const_reverse_iterator rbegin() const;
229  const_reverse_iterator rend() const;
230 
231  using base::operator[];
232  using base::at;
233 
234  data_t const& data(typename std::vector<data_t>::size_type index) const;
235  data_t const& data(const_iterator it) const;
236 
237  void addSingle(Ptr<left_t> const& left,
238  Ptr<right_t> const& right,
239  data_t const& data);
240  void swap(art::Assns<L, R, D>& other);
241 
242  // This is needed (as opposed to using base::makePartner) because
243  // enable_if_function_exists_t does not detect the base's function.
244  std::unique_ptr<EDProduct> makePartner(
245  std::type_info const& wanted_wrapper_type) const;
246 
247  static short
249  {
250  return 11;
251  }
252 
253  void
254  aggregate(Assns const&) const
255  {}
256 
257 private:
258  friend class art::Assns<right_t, left_t, data_t>; // partner_t.
259 
260  void swap_(art::Assns<L, R, void>& other) override;
261  std::unique_ptr<EDProduct> makePartner_(
262  std::type_info const& wanted_wrapper_type) const override;
263 
264  std::vector<data_t> data_;
265 };
266 
267 /////
268 
269 ////////////////////////////////////////////////////////////////////////
270 template <typename L, typename R>
272 {}
273 
274 template <typename L, typename R>
276 {
277  ptrs_.reserve(other.ptrs_.size());
279  other.ptrs_, std::back_inserter(ptrs_), [](auto const& pr) {
280  using pr_t = typename ptrs_t::value_type;
281  return pr_t{pr.second, pr.first};
282  });
283 }
284 
285 template <typename L, typename R>
288 {
289  return ptrs_.begin();
290 }
291 
292 template <typename L, typename R>
295 {
296  return ptrs_.end();
297 }
298 
299 template <typename L, typename R>
302 {
303  return ptrs_[index];
304 }
305 
306 template <typename L, typename R>
307 inline typename art::Assns<L, R, void>::assn_t const&
309 {
310  return ptrs_.at(index);
311 }
312 
313 template <typename L, typename R>
314 inline typename art::Assns<L, R, void>::size_type
316 {
317  return ptrs_.size();
318 }
319 
320 template <typename L, typename R>
321 inline std::string
323 {
324  TypeID const assns_type{typeid(Assns<L, R, void>)};
325  return assns_type.className();
326 }
327 
328 template <typename L, typename R>
329 inline void
331  Ptr<right_t> const& right)
332 {
333  ptrs_.emplace_back(left, right);
334 }
335 
336 template <typename L, typename R>
337 inline void
339 {
340  swap_(other);
341 }
342 
343 template <typename L, typename R>
344 inline std::unique_ptr<art::EDProduct>
346  std::type_info const& wanted_wrapper_type) const
347 {
348  return makePartner_(wanted_wrapper_type);
349 }
350 
351 template <typename L, typename R>
352 inline void
354 {
355  using std::swap;
356  swap(ptrs_, other.ptrs_);
357  swap(ptr_data_1_, other.ptr_data_1_);
358  swap(ptr_data_2_, other.ptr_data_2_);
359 }
360 
361 template <typename L, typename R>
362 std::unique_ptr<art::EDProduct>
364  std::type_info const& wanted_wrapper_type) const
365 {
366  if (wanted_wrapper_type != typeid(Wrapper<partner_t>)) {
367  detail::throwPartnerException(typeid(*this), wanted_wrapper_type);
368  }
369  return std::make_unique<Wrapper<partner_t>>(
370  std::make_unique<partner_t>(*this));
371 }
372 
373 template <typename L, typename R>
374 inline bool
376 {
377  static bool lf_s = (art::TypeID{typeid(left_t)}.friendlyClassName() <
378  art::TypeID{typeid(right_t)}.friendlyClassName());
379  return lf_s;
380 }
381 
382 template <typename L, typename R>
383 void
385 {
386  // Precondition: ptr_data_1_.size() = ptr_data_2_.size();
387  ptrs_.clear();
388  ptrs_.reserve(ptr_data_1_.size());
389  ptr_data_t const& l_ref = left_first() ? ptr_data_1_ : ptr_data_2_;
390  ptr_data_t const& r_ref = left_first() ? ptr_data_2_ : ptr_data_1_;
391  for (auto l = cbegin(l_ref), e = cend(l_ref), r = cbegin(r_ref); l != e;
392  ++l, ++r) {
393  ptrs_.emplace_back(
394  Ptr<left_t>{l->first.id(), l->second, l->first.productGetter()},
395  Ptr<right_t>{r->first.id(), r->second, r->first.productGetter()});
396  }
397  // Empty persistent representation.
398  ptr_data_t tmp1, tmp2;
399  ptr_data_1_.swap(tmp1);
400  ptr_data_2_.swap(tmp2);
401 }
402 
403 template <typename L, typename R>
404 void
406 {
407  if (!ptr_data_1_.empty()) {
408  assert(ptr_data_1_.size() == ptr_data_2_.size() &&
409  ptr_data_2_.size() == ptrs_.size() &&
410  "Assns: internal inconsistency between transient and persistent "
411  "member data.");
412  // Multiple output modules: nothing to do on second and subsequent
413  // calls.
414  return;
415  }
416  ptr_data_t& l_ref = left_first() ? ptr_data_1_ : ptr_data_2_;
417  ptr_data_t& r_ref = left_first() ? ptr_data_2_ : ptr_data_1_;
418  l_ref.reserve(ptrs_.size());
419  r_ref.reserve(ptrs_.size());
420  for (auto const& pr : ptrs_) {
421  l_ref.emplace_back(pr.first.refCore(), pr.first.key());
422  r_ref.emplace_back(pr.second.refCore(), pr.second.key());
423  }
424 }
425 
426 template <typename L, typename R, typename D>
428 {
429  static_assert((!std::is_pointer<D>::value),
430  "Data template argument must not be pointer type!");
431 }
432 
433 template <typename L, typename R, typename D>
435  : base(other), data_(other.data_)
436 {}
437 
438 template <typename L, typename R, typename D>
439 inline typename art::Assns<L, R, void>::size_type
441 {
442  return base::size();
443 }
444 
445 template <typename L, typename R, typename D>
448 {
449  return const_iterator{*this, 0};
450 }
451 
452 template <typename L, typename R, typename D>
455 {
456  return const_iterator{*this};
457 }
458 
459 template <typename L, typename R, typename D>
462 {
463  return const_reverse_iterator{*this, size()};
464 }
465 
466 template <typename L, typename R, typename D>
469 {
470  return const_reverse_iterator{*this, 0};
471 }
472 
473 template <typename L, typename R, typename D>
474 inline typename art::Assns<L, R, D>::data_t const&
476 {
477  return data_.at(index);
478 }
479 
480 template <typename L, typename R, typename D>
481 inline typename art::Assns<L, R, D>::data_t const&
483 {
484  return data_.at(it.getIndex());
485 }
486 
487 template <typename L, typename R, typename D>
488 inline void
490  Ptr<right_t> const& right,
491  data_t const& data)
492 {
493  base::addSingle(left, right);
494  data_.push_back(data);
495 }
496 
497 template <typename L, typename R, typename D>
498 inline void
500 {
501  using std::swap;
502  base::swap_(other);
503  swap(data_, other.data_);
504 }
505 
506 template <typename L, typename R, typename D>
507 inline std::unique_ptr<art::EDProduct>
509  std::type_info const& wanted_wrapper_type) const
510 {
511  return makePartner_(wanted_wrapper_type);
512 }
513 
514 template <typename L, typename R, typename D>
515 inline void
517 {
518  try {
519  swap(dynamic_cast<Assns<L, R, D>&>(other));
520  }
521  catch (std::bad_cast const&) {
522  throw Exception(errors::LogicError, "AssnsBadCast")
523  << "Attempt to swap base with derived!\n";
524  }
525 }
526 
527 template <typename L, typename R, typename D>
528 std::unique_ptr<art::EDProduct>
530  std::type_info const& wanted_wrapper_type) const
531 {
532  using bp = typename base::partner_t;
533  std::unique_ptr<art::EDProduct> result;
534  if (wanted_wrapper_type == typeid(Wrapper<partner_t>)) { // Partner.
535  result =
536  std::make_unique<Wrapper<partner_t>>(std::make_unique<partner_t>(*this));
537  } else if (wanted_wrapper_type == typeid(Wrapper<base>)) { // Base.
538  result = std::make_unique<Wrapper<base>>(
539  std::make_unique<base>(static_cast<base>(*this)));
540  } else if (wanted_wrapper_type == typeid(Wrapper<bp>)) { // Base of partner.
541  result = std::make_unique<Wrapper<bp>>(
542  std::make_unique<bp>(static_cast<base>(*this)));
543  } else { // Oops.
544  detail::throwPartnerException(typeid(*this), wanted_wrapper_type);
545  }
546  return result;
547 }
548 #endif /* canvas_Persistency_Common_Assns_h */
549 
550 // Local Variables:
551 // mode: c++
552 // End:
size_type size() const
Definition: Assns.h:440
D data_t
Definition: Assns.h:214
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
typename base::left_t left_t
Definition: Assns.h:212
set< int >::iterator it
typename ptrs_t::const_iterator assn_iterator
Definition: Assns.h:135
void aggregate(Assns const &) const
Definition: Assns.h:165
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:499
std::unique_ptr< EDProduct > makePartner(std::type_info const &wanted_wrapper_type) const
Definition: Assns.h:508
const_iterator begin() const
Definition: Assns.h:447
std::unique_ptr< EDProduct > makePartner_(std::type_info const &wanted_wrapper_type) const override
Definition: Assns.h:529
const XML_Char const XML_Char * data
Definition: expat.h:268
void swap(art::HLTGlobalStatus &lhs, art::HLTGlobalStatus &rhs)
data_t const & data(typename std::vector< data_t >::size_type index) const
Definition: Assns.h:475
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic >::Index size_type
Definition: typedefs.hpp:11
void throwPartnerException(std::type_info const &generator, std::type_info const &wanted_wrapper_type)
const XML_Char int const XML_Char * value
Definition: expat.h:331
static constexpr double L
void swap(Handle< T > &a, Handle< T > &b)
void swap_(art::Assns< L, R, void > &other) override
Definition: Assns.h:516
#define R(x)
Assns()
Definition: Assns.h:427
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:220
const_iterator end() const
Definition: Assns.h:454
typename ptrs_t::size_type size_type
Definition: Assns.h:136
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< data_t > data_
Definition: Assns.h:264
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
::xsd::cxx::tree::string< char, simple_type > string
Definition: Database.h:154
Definition: bp.py:1
const_reverse_iterator rend() const
Definition: Assns.h:468
void addSingle(Ptr< left_t > const &left, Ptr< right_t > const &right, data_t const &data)
Definition: Assns.h:489
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:215
ptr_data_t ptr_data_2_
Definition: Assns.h:200
void aggregate(Assns const &) const
Definition: Assns.h:254
const_reverse_iterator rbegin() const
Definition: Assns.h:461
Float_t e
Definition: plot.C:35
typename art::const_AssnsIter< L, R, D, Direction::Reverse > const_reverse_iterator
Definition: Assns.h:219
ptr_data_t ptr_data_1_
transient
Definition: Assns.h:199
typedef void(XMLCALL *XML_ElementDeclHandler)(void *userData
Definition: fwd.h:28
typename art::const_AssnsIter< L, R, D, Direction::Forward > const_iterator
Definition: Assns.h:217
static short Class_Version()
Definition: Assns.h:159
typename base::right_t right_t
Definition: Assns.h:213
static short Class_Version()
Definition: Assns.h:248