LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
Handle.h
Go to the documentation of this file.
1 #ifndef art_Framework_Principal_Handle_h
2 #define art_Framework_Principal_Handle_h
3 // vim: set sw=2 expandtab :
4 
5 //==========================================================================
6 // Handle: Non-owning "smart pointer" for reference to EDProducts and
7 // their Provenances.
8 //
9 // ValidHandle: A Handle that can not be invalid, and thus does not check
10 // for validity upon dereferencing.
11 //
12 // If the pointed-to EDProduct or Provenance is destroyed, use of the
13 // Handle becomes undefined. There is no way to query the Handle to
14 // discover if this has happened.
15 //
16 // Handles can have:
17 // -- Product and Provenance pointers both null;
18 // -- Both pointers valid
19 //
20 // ValidHandles must have Product and Provenance pointers valid.
21 //
22 // To check validity, the art::Handle is implicitly convertible to
23 // bool. One can also use the Handle::isValid() function.
24 // ValidHandles cannot be invalid, and so have no validity checks.
25 //
26 // A data product provided by the input source may be removed from
27 // memory by calling removeProduct(), allowing program memory to be
28 // reclaimed when the product is no longer needed.
29 //
30 // If failedToGet() returns true then the requested data is not available
31 // If failedToGet() returns false but isValid() is also false then no
32 // attempt to get data has occurred
33 //==========================================================================
34 
42 #include "cetlib_except/demangle.h"
43 #include "cetlib_except/exception.h"
44 
45 #include <memory>
46 #include <typeinfo>
47 
48 namespace art {
49 
50  template <typename T>
51  class Handle;
52  template <typename T>
53  class ValidHandle;
54  template <typename T>
55  class PutHandle;
56 
57  template <class T>
58  void swap(Handle<T>& a, Handle<T>& b);
59  template <class T>
60  void swap(ValidHandle<T>& a, ValidHandle<T>& b);
61  template <class T>
63 
64  class EDProduct;
65  template <typename T>
66  class Wrapper;
67 
68  namespace detail {
69  template <typename... T>
70  void
71  throw_if_invalid(std::string const& msg, T const&... t)
72  {
73  bool const all_valid = true && (... && t.isValid());
74  if (!all_valid) {
75  throw Exception{art::errors::NullPointerError} << msg << '\n';
76  }
77  }
78  } // namespace detail
79 
80  template <class T>
81  std::enable_if_t<detail::is_handle_v<T>, RangeSet const&> range_of_validity(
82  T const& h);
83  template <class T, class U>
84  std::enable_if_t<detail::are_handles_v<T, U>, bool> same_ranges(T const& a,
85  U const& b);
86  template <class T, class U>
87  std::enable_if_t<detail::are_handles_v<T, U>, bool> disjoint_ranges(
88  T const& a,
89  U const& b);
90  template <class T, class U>
91  std::enable_if_t<detail::are_handles_v<T, U>, bool> overlapping_ranges(
92  T const& a,
93  U const& b);
94 
95 } // namespace art
96 
97 template <typename T>
98 class art::Handle {
99 public:
100  using element_type = T;
101  class HandleTag {};
102 
103  ~Handle() = default;
104  explicit constexpr Handle() =
105  default; // Default-constructed handles are invalid.
106  explicit Handle(GroupQueryResult const&);
107  Handle(Handle const&) = default;
108  Handle(Handle&&) = default;
109  Handle& operator=(Handle const&) = default;
110  Handle& operator=(Handle&&) = default;
111 
112  // pointer behaviors:
113  T const& operator*() const;
114  T const* operator->() const; // alias for product()
115  T const* product() const;
116 
117  // inspectors:
118  explicit operator bool() const noexcept;
119  bool isValid() const noexcept;
120  bool failedToGet()
121  const; // was Handle used in a 'get' call whose data could not be found?
122  Provenance const* provenance() const;
123  ProductID id() const;
124  std::shared_ptr<art::Exception const> whyFailed() const;
125  EDProductGetter const* productGetter() const noexcept;
126 
127  // mutators:
128  void swap(Handle<T>& other);
129  void clear();
130  bool removeProduct();
131 
132 private:
133  T const* prod_{nullptr};
134  cet::exempt_ptr<Group> group_{nullptr};
135  Provenance prov_{};
136  std::shared_ptr<art::Exception const> whyFailed_{nullptr};
137 }; // Handle<>
138 
139 // ----------------------------------------------------------------------
140 // c'tors:
141 
142 template <class T>
144  : group_{gqr.result()}, prov_{group_}, whyFailed_{gqr.whyFailed()}
145 {
146  if (gqr.succeeded()) {
147  auto const wrapperPtr = dynamic_cast<Wrapper<T> const*>(
148  gqr.result()->uniqueProduct(TypeID{typeid(Wrapper<T>)}));
149  if (wrapperPtr != nullptr) {
150  prod_ = wrapperPtr->product();
151  } else {
153  e << "Product retrieval via Handle<T> succeeded for product:\n"
155  << "but an attempt to interpret it as an object of type '"
156  << cet::demangle_symbol(typeid(T).name()) << "' failed.\n";
157  whyFailed_ = std::make_shared<art::Exception const>(std::move(e));
158  }
159  }
160 }
161 
162 // ----------------------------------------------------------------------
163 // pointer behaviors:
164 
165 template <class T>
166 inline T const&
168 {
169  return *product();
170 }
171 
172 template <class T>
173 T const*
175 {
176  if (failedToGet()) {
177  throw *whyFailed_;
178  }
179  if (prod_ == nullptr)
181  << "Attempt to de-reference product that points to 'nullptr'.\n";
182  return prod_;
183 }
184 
185 template <class T>
186 inline T const*
188 {
189  return product();
190 }
191 
192 // ----------------------------------------------------------------------
193 // inspectors:
194 
195 template <class T>
196 inline art::Handle<T>::operator bool() const noexcept
197 {
198  return isValid();
199 }
200 
201 template <class T>
202 bool
203 art::Handle<T>::isValid() const noexcept
204 {
205  return prod_ && prov_.isValid();
206 }
207 
208 template <class T>
209 bool
211 {
212  return whyFailed_.get();
213 }
214 
215 template <class T>
216 inline art::Provenance const*
218 {
219  return &prov_;
220 }
221 
222 template <class T>
223 inline art::ProductID
225 {
226  return prov_.isValid() ? prov_.productID() : ProductID{};
227 }
228 
229 template <class T>
230 inline std::shared_ptr<art::Exception const>
232 {
233  return whyFailed_;
234 }
235 
236 template <typename T>
237 inline art::EDProductGetter const*
239 {
240  return group_.get();
241 }
242 
243 // ----------------------------------------------------------------------
244 // mutators:
245 
246 template <class T>
247 void
249 {
250  std::swap(*this, other);
251 }
252 
253 template <class T>
254 void
256 {
257  Handle<T> tmp;
258  swap(tmp);
259 }
260 
261 template <class T>
262 inline bool
264 {
265  if (isValid() && !prov_.produced()) {
266  assert(group_);
267  group_->removeCachedProduct();
268  clear();
269  return true;
270  }
271  return false;
272 }
273 
274 // ======================================================================
275 // Non-members:
276 
277 // Convert from handle-to-EDProduct to handle-to-T
278 template <class T>
279 void
281 {
282  Handle<T> h{orig};
283  result.swap(h);
284 }
285 
286 // ======================================================================
287 template <typename T>
288 class art::ValidHandle {
289 public:
290  using element_type = T;
291  class HandleTag {};
292 
293  ~ValidHandle() = default;
294  ValidHandle() = delete;
295  explicit ValidHandle(T const* prod,
297  Provenance prov);
298  ValidHandle(ValidHandle const&) = default;
299  ValidHandle(ValidHandle&&) = default;
300  ValidHandle& operator=(ValidHandle const&) & = default;
301  ValidHandle& operator=(ValidHandle&&) & = default;
302 
303  // pointer behaviors
304  operator T const*() const; // conversion to T const*
305  T const& operator*() const;
306  T const* operator->() const; // alias for product()
307  T const* product() const;
308 
309  // inspectors
310  bool isValid() const; // always true
311  bool failedToGet() const; // always false
312  Provenance const* provenance() const;
313  ProductID id() const;
314  std::shared_ptr<art::Exception const> whyFailed() const; // always null
315  EDProductGetter const* productGetter() const noexcept;
316 
317  // mutators
318  void swap(ValidHandle<T>& other);
319 
320  // No clear() function, because a ValidHandle does not have an invalid
321  // state, and that is what the result of clear() would have to be.
322 
323 private:
324  T const* prod_;
327 };
328 
329 template <class T>
332  Provenance prov)
333  : prod_{prod}, productGetter_{productGetter}, prov_{prov}
334 {
335  if (prod_ == nullptr) {
337  << "Attempt to create ValidHandle with null pointer";
338  }
339 }
340 
341 template <class T>
342 inline art::ValidHandle<T>::operator T const*() const
343 {
344  return prod_;
345 }
346 
347 template <class T>
348 inline T const&
350 {
351  return *prod_;
352 }
353 
354 template <class T>
355 inline T const*
357 {
358  return prod_;
359 }
360 
361 template <class T>
362 inline T const*
364 {
365  return prod_;
366 }
367 
368 template <class T>
369 inline bool
371 {
372  return true;
373 }
374 
375 template <class T>
376 inline bool
378 {
379  return false;
380 }
381 
382 template <class T>
383 inline art::Provenance const*
385 {
386  return &prov_;
387 }
388 
389 template <class T>
390 inline art::ProductID
392 {
393  return prov_.productID();
394 }
395 
396 template <class T>
397 inline std::shared_ptr<art::Exception const>
399 {
400  return std::shared_ptr<art::Exception const>();
401 }
402 
403 template <class T>
404 inline void
406 {
407  std::swap(*this, other);
408 }
409 
410 template <typename T>
411 inline art::EDProductGetter const*
413 {
414  return productGetter_;
415 }
416 
417 // ======================================================================
418 // Non-members:
419 
420 template <class T>
421 std::enable_if_t<art::detail::is_handle_v<T>, art::RangeSet const&>
422 art::range_of_validity(T const& h)
423 {
424  std::string const& errMsg =
425  "Attempt to retrieve range set from invalid handle.";
426  detail::throw_if_invalid(errMsg, h);
427  return h.provenance()->rangeOfValidity();
428 }
429 
430 template <class T, class U>
431 std::enable_if_t<art::detail::are_handles_v<T, U>, bool>
432 art::same_ranges(T const& a, U const& b)
433 {
434  std::string const& errMsg =
435  "Attempt to compare range sets where one or both handles are invalid.";
436  detail::throw_if_invalid(errMsg, a, b);
438 }
439 
440 template <class T, class U>
441 std::enable_if_t<art::detail::are_handles_v<T, U>, bool>
442 art::disjoint_ranges(T const& a, U const& b)
443 {
444  std::string const& errMsg =
445  "Attempt to compare range sets where one or both handles are invalid.";
446  detail::throw_if_invalid(errMsg, a, b);
448 }
449 
450 template <class T, class U>
451 std::enable_if_t<art::detail::are_handles_v<T, U>, bool>
452 art::overlapping_ranges(T const& a, U const& b)
453 {
454  std::string const& errMsg =
455  "Attempt to compare range sets where one or both handles are invalid.";
456  detail::throw_if_invalid(errMsg, a, b);
458 }
459 
460 // ======================================================================
461 template <typename T>
462 class art::PutHandle {
463 public:
464  using element_type = T;
465  class HandleTag {};
466 
467  explicit PutHandle(T const* prod,
469  ProductID id);
470 
471  // To be deprecated
472  // ----------------
473  // The following implicit conversion to ProductID is retained for
474  // backwards compatibility--up through art 3.10, the supported
475  // interface is (e.g.):
476  //
477  // ProductID id = e.put(std::move(some_product));
478  //
479  // With art 3.11, the return type of 'put' will be a PutHandle<T>
480  // object. Until users have time to migrate to the new usage, the
481  // PutHandle template will provide a conversion operator to
482  // ProductID.
483  operator ProductID() const;
484 
485  // pointer behaviors
486  T const& operator*() const;
487  T const* operator->() const; // alias for product()
488  T const* product() const;
489 
490  // inspectors
491  ProductID id() const;
492  EDProductGetter const* productGetter() const noexcept;
493 
494 private:
495  T const* prod_;
498 };
499 
500 template <class T>
501 inline art::PutHandle<T>::PutHandle(T const* prod,
503  ProductID id)
504  : prod_{prod}, productGetter_{productGetter}, id_{id}
505 {}
506 
507 template <class T>
509 {
510  return id();
511 }
512 
513 template <class T>
514 inline T const&
516 {
517  return *prod_;
518 }
519 
520 template <class T>
521 inline T const*
523 {
524  return prod_;
525 }
526 
527 template <class T>
528 inline T const*
530 {
531  return prod_;
532 }
533 
534 template <class T>
535 inline art::ProductID
537 {
538  return id_;
539 }
540 
541 template <typename T>
542 inline art::EDProductGetter const*
544 {
545  return productGetter_;
546 }
547 
548 #endif /* art_Framework_Principal_Handle_h */
549 
550 // Local Variables:
551 // mode: c++
552 // End:
Handle & operator=(Handle const &)=default
Provenance prov_
Definition: Handle.h:326
BranchDescription const & productDescription() const noexcept
Definition: Provenance.cc:24
bool isValid() const noexcept
Definition: Provenance.cc:18
EDProductGetter const * productGetter_
Definition: Handle.h:325
ProductID productID() const noexcept
Definition: Provenance.cc:72
T const * prod_
Definition: Handle.h:133
std::shared_ptr< art::Exception const > whyFailed_
Definition: Handle.h:136
std::enable_if_t< detail::are_handles_v< T, U >, bool > overlapping_ranges(T const &a, U const &b)
void swap(Handle< T > &other)
Definition: Handle.h:248
T const & operator*() const
Definition: Handle.h:349
T const * operator->() const
Definition: Handle.h:522
Float_t tmp
Definition: plot.C:35
T const * product() const
Definition: Handle.h:363
T const * product() const
Definition: Handle.h:529
EDProductGetter const * productGetter() const noexcept
Definition: Handle.h:412
bool isValid() const noexcept
Definition: Handle.h:203
ValidHandle()=delete
std::enable_if_t< detail::are_handles_v< T, U >, bool > disjoint_ranges(T const &a, U const &b)
T const * product() const
Definition: Handle.h:174
EDProductGetter const * productGetter_
Definition: Handle.h:496
ProductID id() const
Definition: Handle.h:391
void swap(Handle< T > &a, Handle< T > &b)
Provenance const * provenance() const
Definition: Handle.h:217
T const * operator->() const
Definition: Handle.h:356
void convert_handle(GroupQueryResult const &, Handle< T > &)
Definition: Handle.h:280
Provenance const * provenance() const
Definition: Handle.h:384
constexpr Handle()=default
T const * prod_
Definition: Handle.h:495
void throw_if_invalid(std::string const &msg, T const &...t)
Definition: Handle.h:71
bool removeProduct()
Definition: Handle.h:263
Provenance prov_
Definition: Handle.h:135
T const & operator*() const
Definition: Handle.h:515
cet::exempt_ptr< Group > result() const
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
ProductID id() const
Definition: Handle.h:536
T const * operator->() const
Definition: Handle.h:187
void swap(ValidHandle< T > &a, ValidHandle< T > &b)
T const & operator*() const
Definition: Handle.h:167
std::enable_if_t< detail::are_handles_v< T, U >, bool > same_ranges(T const &a, U const &b)
T const * prod_
Definition: Handle.h:324
void clear()
Definition: Handle.h:255
EDProductGetter const * productGetter() const noexcept
Definition: Handle.h:238
ProductID id_
Definition: Handle.h:497
PutHandle(T const *prod, EDProductGetter const *productGetter, ProductID id)
Definition: Handle.h:501
Definition: MVAAlg.h:12
bool failedToGet() const
Definition: Handle.h:377
std::shared_ptr< art::Exception const > whyFailed() const
Definition: Handle.h:398
bool produced() const noexcept
Definition: Provenance.cc:30
std::shared_ptr< art::Exception const > whyFailed() const
Definition: Handle.h:231
EDProductGetter const * productGetter() const noexcept
Definition: Handle.h:543
Float_t e
Definition: plot.C:35
QuadExpr operator*(double v, const QuadExpr &e)
Definition: QuadExpr.h:44
ProductID id() const
Definition: Handle.h:224
void swap(ValidHandle< T > &other)
Definition: Handle.h:405
vec_iX clear()
bool failedToGet() const
Definition: Handle.h:210
std::enable_if_t< detail::is_handle_v< T >, RangeSet const & > range_of_validity(T const &h)
cet::exempt_ptr< Group > group_
Definition: Handle.h:134
bool isValid() const
Definition: Handle.h:370