LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
Ptr.h
Go to the documentation of this file.
1 #ifndef canvas_Persistency_Common_Ptr_h
2 #define canvas_Persistency_Common_Ptr_h
3 // vim: set sw=2 expandtab :
4 
5 //
6 // Ptr and related functions.
7 //
8 // A Ptr is a persistent smart pointer to an item in a collection
9 // that is a data product.
10 //
11 // How to construct a Ptr<T>:
12 //
13 // 1. Default constructor.
14 // Ptr();
15 //
16 // Constructs an invalid Ptr.
17 //
18 // 2. From a handle to a collection and an index into that collection.
19 // template<typename H>
20 // Ptr(H const&, key_type);
21 //
22 // 3. From a ProductID.
23 // Ptr(Product ID const&, key_type, EDProductGetter const*);
24 //
25 // Obtain the ProductID from the collection handle or the result of
26 // Event::put(). Obtain the EDProductGetter from the event using the
27 // ProductID.
28 //
29 // 4. From a Ptr<U> where U is a base or sub class of T.
30 // Ptr(Ptr<U> const&);
31 //
32 // 5. From a ProductID and an existing resolved pointer.
33 // Ptr(ProductID const&, T const*, key_type)
34 //
35 // This signature is for expert-level or internal use only: it is a
36 // pre-condition that the pointer must be the item at the index
37 // specified in product with the given ID. Errors will *not* be
38 // detected.
39 //
40 
50 #include "cetlib_except/demangle.h"
51 
52 #include <cassert>
53 #include <cstddef>
54 #include <functional> // for std::hash
55 #include <list>
56 #include <ostream>
57 #include <type_traits>
58 #include <vector>
59 
60 namespace art {
61 
62  namespace detail {
63 
64  template <typename T, typename C>
65  class ItemGetter;
66 
67  template <typename T>
68  class ItemGetter<T, cet::map_vector<T>>;
69 
70  template <typename T>
71  class ItemGetter<std::pair<cet::map_vector_key, T>, cet::map_vector<T>>;
72 
73  } // namespace detail
74 
75  template <typename T>
76  class Ptr {
77  public:
78  using key_type = std::size_t;
79  using value_type = T;
80  using const_pointer = T const*;
81  using const_reference = T const&;
82 
83  // 1.
84  Ptr() = default;
85 
86  template <typename H>
87  Ptr(H const& handle, typename Ptr<T>::key_type key)
88  : core_{handle.id(),
90  handle.product(),
91  key),
92  handle.productGetter()}
93  , key_{key}
94  {
95  if (core_.isNull()) {
97  << "Attempt to construct a Ptr from a Handle with invalid ProductID. "
98  "Perhaps a\n"
99  "default-constructed Ptr is what you want?";
100  }
101  }
102 
103  // 3.
104  Ptr(ProductID const& productID,
105  key_type itemKey,
106  EDProductGetter const* prodGetter)
107  : core_{productID, nullptr, prodGetter}, key_{itemKey}
108  {}
109 
110  // 4.
111  template <typename U>
112  Ptr(Ptr<U> const& pu, std::enable_if_t<std::is_base_of_v<T, U>>* = nullptr)
113  : core_{pu.id(), pu.get(), pu.productGetter()}, key_{pu.key()}
114  {}
115 
116  template <typename U>
117  Ptr(Ptr<U> const& pu, std::enable_if_t<std::is_base_of_v<U, T>>* = nullptr)
118  : core_{pu.id(), static_cast<T const*>(pu.get()), nullptr}, key_{pu.key()}
119  {}
120 
121  // 5. See notes above.
122  Ptr(ProductID const& productID, T const* item, key_type const itemKey)
123  : core_{productID, item, nullptr}, key_{itemKey}
124  {}
125 
126  // =========
127  // Accessors
128  // =========
129 
130  T const&
131  operator*() const
132  {
133  // Warning: This causes a nullptr dereference if isNull!
134  return *get();
135  }
136 
137  T const*
138  get() const
139  {
140  return isNull() ? nullptr : operator->();
141  }
142 
143  T const*
144  operator->() const
145  {
146  if (core_.productPtr() == nullptr) {
147  EDProduct const* prod = parentProduct_();
148  void const* ad = prod->getElementAddress(typeid(T), key_);
149  core_.setProductPtr(ad);
150  }
151  return reinterpret_cast<T const*>(core_.productPtr());
152  }
153 
154  explicit operator bool() const
155  {
156  return isNonnull() && core_.isAvailable();
157  }
158 
159  ProductID
160  id() const noexcept
161  {
162  return core_.id();
163  }
164 
165  key_type
166  key() const noexcept
167  {
168  return key_;
169  }
170 
171  // Retrieve parent collection
172  template <typename Collection>
173  Collection const&
174  parentAs() const
175  {
176  core_.isAvailable();
177  auto product = parentProduct_();
178  auto wrapped_product = dynamic_cast<Wrapper<Collection> const*>(product);
179  if (wrapped_product == nullptr) {
181  << "A request to retrieve the parent collection of type: "
182  << cet::demangle_symbol(typeid(Collection).name())
183  << " with ProductID " << core_.id()
184  << "\ncannot be satisfied due to a type mismatch.\n";
185  }
186  return *wrapped_product->product();
187  }
188 
189  template <template <typename...> class Collection, typename U = T>
190  Collection<U> const&
191  parentAs() const
192  {
193  return parentAs<Collection<U>>();
194  }
195 
196  RefCore const&
197  refCore() const noexcept
198  {
199  return core_;
200  }
201 
202  // Checks for valid key.
203  bool
204  isNonnull() const noexcept
205  {
206  return key_ != key_traits<key_type>::value;
207  }
208 
209  // Checks for valid key.
210  bool
211  isNull() const noexcept
212  {
213  return !isNonnull();
214  }
215 
216  // Checks if collection is in memory or available in the event. No
217  // type checking is done.
218  bool
219  isAvailable() const
220  {
221  return core_.isAvailable();
222  }
223 
224  // MUST UPDATE WHEN CLASS IS CHANGED!
225  static constexpr short
226  Class_Version() noexcept
227  {
228  return 10;
229  }
230 
231  EDProductGetter const*
232  productGetter() const noexcept
233  {
234  return core_.productGetter();
235  }
236 
237  private:
238  EDProduct const*
240  {
241  EDProduct const* product{nullptr};
242  if (productGetter()) {
243  product = productGetter()->getIt();
244  }
245  if (product == nullptr) {
247  e << "A request to resolve an Ptr to a product containing items of "
248  "type: "
249  << cet::demangle_symbol(typeid(T).name()) << " with ProductID "
250  << core_.id()
251  << "\ncannot be satisfied because the product cannot be found.\n";
252  if (productGetter() == nullptr) {
253  e << "The productGetter was not set -- are you trying to "
254  "dereference a Ptr during mixing?\n";
255  } else {
256  e << "Probably the branch containing the product is not stored in "
257  "the input file.\n";
258  }
259  throw e;
260  }
261  return product;
262  }
263 
264  // Used to fetch the container product.
265  mutable RefCore core_{};
266 
267  // Index into the container product.
269  };
270 
271  template <typename T, typename U>
272  std::enable_if_t<std::is_same_v<T, U> || std::is_base_of_v<T, U> ||
273  std::is_base_of_v<U, T>,
274  bool>
275  operator==(Ptr<T> const& lhs, Ptr<U> const& rhs)
276  {
277  return lhs.refCore() == rhs.refCore() and lhs.key() == rhs.key();
278  }
279 
280  template <typename T, typename U>
281  std::enable_if_t<std::is_same_v<T, U> || std::is_base_of_v<T, U> ||
282  std::is_base_of_v<U, T>,
283  bool>
284  operator!=(Ptr<T> const& lhs, Ptr<U> const& rhs)
285  {
286  return !(lhs == rhs);
287  }
288 
289  template <typename T, typename U>
290  std::enable_if_t<std::is_same_v<T, U> || std::is_base_of_v<T, U> ||
291  std::is_base_of_v<U, T>,
292  bool>
293  operator<(Ptr<T> const& lhs, Ptr<U> const& rhs)
294  {
295  // The ordering of integer keys guarantees that the ordering of Ptrs within
296  // a collection will be identical to the ordering of the referenced objects
297  // in the collection.
298  return lhs.refCore() == rhs.refCore() ? lhs.key() < rhs.key() :
299  lhs.refCore() < rhs.refCore();
300  }
301 
302  // Fill a vector of Ptrs from a persistent collection.
303  // Alternatively, construct a PtrVector.
304  template <typename T, typename H>
305  void
306  fill_ptr_vector(std::vector<Ptr<T>>& ptrs, H const& h)
307  {
308  for (std::size_t i = 0, sz = h->size(); i != sz; ++i) {
309  ptrs.emplace_back(h, i);
310  }
311  }
312 
313  // Fill a list of Ptrs from a persistent collection.
314  template <typename T, typename H>
315  void
316  fill_ptr_list(std::list<Ptr<T>>& ptrs, H const& h)
317  {
318  for (std::size_t i = 0, sz = h->size(); i != sz; ++i) {
319  ptrs.emplace_back(h, i);
320  }
321  }
322 
323  template <typename T>
324  std::ostream&
325  operator<<(std::ostream& os, Ptr<T> const& p)
326  {
327  os << "(" << p.id() << ", " << p.key() << ")";
328  return os;
329  }
330 
331  namespace detail {
332 
333  // Specialize EnsurePointer for Ptr.
334  template <typename TO, typename PTRVAL>
335  struct EnsurePointer<TO, Ptr<PTRVAL>> {
336  TO
337  operator()(Ptr<PTRVAL>& from) const
338  {
339  return addr<TO, PTRVAL const>(*from);
340  }
341 
342  TO
343  operator()(Ptr<PTRVAL> const& from) const
344  {
345  return addr<TO, PTRVAL const>(*from);
346  }
347  };
348 
349  // FIXME: The code of ItemGetter, including specializations, would
350  // be completely unnecessary if Handle were to provide access to the
351  // setPtr() function of wrapper. As it is, some container-specific
352  // code is duplicated between here and Wrapper, leading to
353  // multiple points of maintenance (and failure).
354 
355  template <typename T, typename C>
356  class ItemGetter {
357  public:
358  T const*
359  operator()(C const* product, typename Ptr<T>::key_type iKey) const
360  {
361  assert(product != nullptr);
362  auto it = product->begin();
363  advance(it, iKey);
365  }
366  };
367 
368  template <typename T>
369  class ItemGetter<T, cet::map_vector<T>> {
370  public:
371  T const*
372  operator()(cet::map_vector<T> const* product,
373  typename Ptr<T>::key_type key) const
374  {
375  assert(product != nullptr);
376  return product->getOrNull(cet::map_vector_key{key});
377  }
378  };
379 
380  template <typename T>
381  class ItemGetter<std::pair<cet::map_vector_key, T>, cet::map_vector<T>> {
382  public:
383  std::pair<cet::map_vector_key, T> const*
384  operator()(cet::map_vector<T> const* product,
385  typename Ptr<T>::key_type key) const
386  {
387  assert(product != nullptr);
388  auto it = product->find(cet::map_vector_key{key});
389  if (it == product->end()) {
390  return nullptr;
391  }
392  return &*it;
393  }
394  };
395 
396  template <typename T>
397  struct NotMapVector : std::true_type {
398  using type = typename T::value_type;
399  };
400 
401  template <typename T>
402  struct NotMapVector<cet::map_vector<T>> : std::false_type {};
403 
404  template <typename T>
406 
407  } // namespace detail
408 
409  // Deduction guide for handles. We do not support CTAD for
410  // cet::map_vector as it is possible to construct a Ptr to the
411  // map_vector's value_type and mapped_type. We don't want the
412  // default deduction behavior to surprise users of cet::map_vector.
413  template <typename H, typename T>
415 
416 } // namespace art
417 
418 // Specialization of std::hash for art::Ptr
419 namespace std {
420  template <typename T>
421  struct hash<art::Ptr<T>> {
423  using key_t = typename ptr_t::key_type;
424 
425  size_t
426  operator()(ptr_t const& p) const noexcept
427  {
428  return std::hash<art::ProductID>{}(p.id()) ^ std::hash<key_t>{}(p.key());
429  }
430  };
431 }
432 
433 #endif /* canvas_Persistency_Common_Ptr_h */
434 
435 // Local Variables:
436 // mode: c++
437 // End:
Ptr(Ptr< U > const &pu, std::enable_if_t< std::is_base_of_v< T, U >> *=nullptr)
Definition: Ptr.h:112
Ptr(ProductID const &productID, T const *item, key_type const itemKey)
Definition: Ptr.h:122
T const * operator()(cet::map_vector< T > const *product, typename Ptr< T >::key_type key) const
Definition: Ptr.h:372
typename T::value_type type
Definition: Ptr.h:398
EDProduct const * parentProduct_() const
Definition: Ptr.h:239
STL namespace.
size_t operator()(ptr_t const &p) const noexcept
Definition: Ptr.h:426
T const & operator*() const
Definition: Ptr.h:131
L value_type
Definition: Ptr.h:79
std::size_t key_type
Definition: Ptr.h:78
bool operator!=(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept
Collection const & parentAs() const
Definition: Ptr.h:174
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
Ptr(H, T) -> Ptr< detail::not_map_vector_t< typename H::element_type >>
T const * operator->() const
Definition: Ptr.h:144
key_type key() const noexcept
Definition: Ptr.h:166
T const * operator()(C const *product, typename Ptr< T >::key_type iKey) const
Definition: Ptr.h:359
typename ptr_t::key_type key_t
Definition: Ptr.h:423
bool isNull() const noexcept
Definition: Ptr.h:211
typename NotMapVector< T >::type not_map_vector_t
Definition: Ptr.h:405
ProductID id() const noexcept
Definition: Ptr.h:160
TO operator()(Ptr< PTRVAL > &from) const
Definition: Ptr.h:337
static auto const * address(const_iterator const &i)
Definition: GetProduct.h:9
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
bool isNonnull() const noexcept
Definition: Ptr.h:204
void fill_ptr_list(std::list< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:316
TO operator()(Ptr< PTRVAL > const &from) const
Definition: Ptr.h:343
EDProductGetter const * productGetter() const noexcept
Definition: Ptr.h:232
Ptr(H const &handle, typename Ptr< T >::key_type key)
Definition: Ptr.h:87
Ptr(ProductID const &productID, key_type itemKey, EDProductGetter const *prodGetter)
Definition: Ptr.h:104
bool isAvailable() const
Definition: Ptr.h:219
Definition: MVAAlg.h:12
Collection< U > const & parentAs() const
Definition: Ptr.h:191
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:306
Float_t e
Definition: plot.C:35
T const * get() const
Definition: Ptr.h:138
L const & const_reference
Definition: Ptr.h:81
void const * getElementAddress(std::type_info const &toType, unsigned long index) const
Definition: EDProduct.cc:27
static constexpr short Class_Version() noexcept
Definition: Ptr.h:226
L const * const_pointer
Definition: Ptr.h:80
Definition: fwd.h:26
Ptr(Ptr< U > const &pu, std::enable_if_t< std::is_base_of_v< U, T >> *=nullptr)
Definition: Ptr.h:117
std::pair< cet::map_vector_key, T > const * operator()(cet::map_vector< T > const *product, typename Ptr< T >::key_type key) const
Definition: Ptr.h:384
RefCore const & refCore() const noexcept
Definition: Ptr.h:197
bool operator==(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept