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 where
9 // the collection is in the art::Event.
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(ProductID const&); // Invalid ("null") Ptr.
24 //
25 // Ptr(Product ID const&, key_type, EDProductGetter const*);
26 //
27 // Obtain the ProductID from the collection handle or the result of
28 // Event::put(). Obtain the EDProductGetter from the event using the
29 // ProductID.
30 //
31 // 4. From a Ptr<U> where U is a base or sub class of T.
32 // Ptr(Ptr<U> const&);
33 //
34 // 5. From a ProductID and an existing resolved pointer.
35 // Ptr(ProductID const&, T const*, key_type)
36 //
37 // This signature is for expert-level or internal use only: it is a
38 // pre-condition that the pointer must be the item at the index
39 // specified in product with the given ID. Errors will *not* be
40 // detected.
41 //
42 
51 #include "cetlib_except/demangle.h"
52 
53 #include <cassert>
54 #include <cstddef>
55 #include <functional> // for std::hash
56 #include <list>
57 #include <ostream>
58 #include <type_traits>
59 #include <vector>
60 
61 namespace art {
62 
63  namespace detail {
64 
65  template <typename T, typename C>
66  class ItemGetter;
67 
68  template <typename T>
69  class ItemGetter<T, cet::map_vector<T>>;
70 
71  template <typename T>
72  class ItemGetter<std::pair<cet::map_vector_key, T>, cet::map_vector<T>>;
73 
74  } // namespace detail
75 
76  template <typename T>
77  class Ptr {
78  public:
79  using key_type = std::size_t;
80  using value_type = T;
81  using const_pointer = T const*;
82  using const_reference = T const&;
83 
84  // 1.
85  Ptr() = default;
86 
87  template <typename H>
88  Ptr(H const& handle, typename Ptr<T>::key_type key)
89  : core_{handle.id(),
91  std::remove_const_t<std::remove_pointer_t<
92  decltype(handle.product())>>>()(
93  handle.product(),
94  key),
95  nullptr}
96  , key_{key}
97  {
98  if (core_.isNull()) {
100  << "Attempt to construct a Ptr from a Handle with invalid ProductID. "
101  "Perhaps a\n"
102  "default-constructed Ptr is what you want?";
103  }
104  }
105 
106  // 3A.
107  explicit Ptr(ProductID const& productID)
108  : core_{productID, nullptr, nullptr}
109  {}
110 
111  // 3B.
112  Ptr(ProductID const& productID,
113  key_type itemKey,
114  EDProductGetter const* prodGetter)
115  : core_{productID, nullptr, prodGetter}, key_{itemKey}
116  {}
117 
118  // 4.
119  template <typename U>
120  Ptr(Ptr<U> const& pu, std::enable_if_t<std::is_base_of_v<T, U>>* = nullptr)
121  : core_{pu.id(),
122  (pu.hasCache() ? static_cast<T const*>(pu.get()) : nullptr),
123  pu.productGetter()}
124  , key_{pu.key()}
125  {}
126 
127  template <typename U>
128  Ptr(Ptr<U> const& pu, std::enable_if_t<std::is_base_of_v<U, T>>* = nullptr)
129  : core_{pu.id(), static_cast<T const*>(pu.get()), nullptr}, key_{pu.key()}
130  {}
131 
132  // 5. See notes above.
133  Ptr(ProductID const& productID, T const* item, key_type const itemKey)
134  : core_{productID, item, nullptr}, key_{itemKey}
135  {}
136 
137  //
138  // Accessors.
139  //
140 
141  T const& operator*() const
142  {
143  // FIXME: This causes an nullptr dereference if isNull!
144  // return isNull() ? nullptr : operator->();
145  return *get();
146  }
147 
148  T const*
149  get() const
150  {
151  return isNull() ? nullptr : operator->();
152  }
153 
154  T const* operator->() const
155  {
156  if (core_.productPtr() == nullptr) {
157  EDProduct const* prod = parentProduct_();
158  void const* ad = prod->getElementAddress(typeid(T), key_);
159  core_.setProductPtr(ad);
160  }
161  return reinterpret_cast<T const*>(core_.productPtr());
162  }
163 
164  // Checks for valid key.
165  bool
166  isNonnull() const noexcept
167  {
168  return key_ != key_traits<key_type>::value;
169  }
170 
171  // Checks for valid key.
172  bool
173  isNull() const noexcept
174  {
175  return !isNonnull();
176  }
177 
178  explicit operator bool() const
179  {
180  return (key_ != key_traits<key_type>::value) && core_.isAvailable();
181  }
182 
183  RefCore const&
184  refCore() const noexcept
185  {
186  return core_;
187  }
188 
189  ProductID
190  id() const noexcept
191  {
192  return core_.id();
193  }
194 
195  EDProductGetter const*
196  productGetter() const noexcept
197  {
198  return core_.productGetter();
199  }
200 
201  // Checks if collection is in memory or available
202  // in the event. No type checking is done.
203  bool
204  isAvailable() const
205  {
206  return core_.isAvailable();
207  }
208 
209  bool
210  hasCache() const noexcept
211  {
212  return core_.productPtr() != nullptr;
213  }
214 
215  key_type
216  key() const noexcept
217  {
218  return key_;
219  }
220 
221  // MUST UPDATE WHEN CLASS IS CHANGED!
222  static constexpr short
223  Class_Version() noexcept
224  {
225  return 10;
226  }
227 
228  private:
229  EDProduct const*
231  {
232  EDProduct const* product{nullptr};
233  if (productGetter()) {
234  product = productGetter()->getIt();
235  }
236  if (product == nullptr) {
238  e << "A request to resolve an Ptr to a product containing items of "
239  "type: "
240  << cet::demangle_symbol(typeid(T).name()) << " with ProductID "
241  << core_.id()
242  << "\ncannot be satisfied because the product cannot be found.\n";
243  if (productGetter() == nullptr) {
244  e << "The productGetter was not set -- are you trying to "
245  "dereference a Ptr during mixing?\n";
246  } else {
247  e << "Probably the branch containing the product is not stored in "
248  "the input file.\n";
249  }
250  throw e;
251  }
252  return product;
253  }
254 
255  // Used to fetch the container product.
256  RefCore core_{};
257 
258  // Index into the container product.
260  };
261 
262  template <typename T, typename U>
263  std::enable_if_t<std::is_same_v<T, U> || std::is_base_of_v<T, U> ||
264  std::is_base_of_v<U, T>,
265  bool>
266  operator==(Ptr<T> const& lhs, Ptr<U> const& rhs)
267  {
268  return lhs.refCore() == rhs.refCore() and lhs.key() == rhs.key();
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 == rhs);
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  // The ordering of integer keys guarantees that the ordering of Ptrs within
287  // a collection will be identical to the ordering of the referenced objects
288  // in the collection.
289  return lhs.refCore() == rhs.refCore() ? lhs.key() < rhs.key() :
290  lhs.refCore() < rhs.refCore();
291  }
292 
293  // Fill a vector of Ptrs from a persistent collection.
294  // Alternatively, construct a PtrVector.
295  template <typename T, typename H>
296  void
298  {
299  for (std::size_t i = 0, sz = h->size(); i != sz; ++i) {
300  ptrs.emplace_back(h, i);
301  }
302  }
303 
304  // Fill a list of Ptrs from a persistent collection.
305  template <typename T, typename H>
306  void
307  fill_ptr_list(std::list<Ptr<T>>& ptrs, H const& h)
308  {
309  for (std::size_t i = 0, sz = h->size(); i != sz; ++i) {
310  ptrs.emplace_back(h, i);
311  }
312  }
313 
314  template <typename T>
315  std::ostream&
316  operator<<(std::ostream& os, Ptr<T> const& p)
317  {
318  os << "(" << p.id() << ", " << p.key() << ")";
319  return os;
320  }
321 
322  namespace detail {
323 
324  // Specialize EnsurePointer for Ptr.
325  template <typename TO, typename PTRVAL>
326  struct EnsurePointer<TO, Ptr<PTRVAL>> {
327 
328  TO
329  operator()(Ptr<PTRVAL>& from) const
330  {
331  return addr<TO, PTRVAL const>(*from);
332  }
333 
334  TO
335  operator()(Ptr<PTRVAL> const& from) const
336  {
337  return addr<TO, PTRVAL const>(*from);
338  }
339  };
340 
341  // FIXME: The code of ItemGetter, including specializations, would
342  // be completely unnecessary if Handle were to provide access to the
343  // setPtr() function of wrapper. As it is, some container-specific
344  // code is duplicated between here and Wrapper, leading to
345  // multiple points of maintenance (and failure).
346 
347  template <typename T, typename C>
348  class ItemGetter {
349 
350  public:
351  T const*
352  operator()(C const* product, typename Ptr<T>::key_type iKey) const
353  {
354  assert(product != nullptr);
355  auto it = product->begin();
356  advance(it, iKey);
358  return address;
359  }
360  };
361 
362  template <typename T>
363  class ItemGetter<T, cet::map_vector<T>> {
364 
365  public:
366  T const*
368  typename Ptr<T>::key_type iKey) const
369  {
370  assert(product != nullptr);
371  cet::map_vector_key k(iKey);
372  return product->getOrNull(k);
373  }
374  };
375 
376  template <typename T>
377  class ItemGetter<std::pair<cet::map_vector_key, T>, cet::map_vector<T>> {
378 
379  public:
380  std::pair<cet::map_vector_key, T> const*
382  typename Ptr<T>::key_type iKey) const
383  {
384  assert(product != nullptr);
385  cet::map_vector_key k(static_cast<unsigned>(iKey));
386  auto it = product->find(k);
387  if (it == product->end()) {
388  return nullptr;
389  }
390  return &*it;
391  }
392  };
393 
394  } // namespace detail
395 
396 } // namespace art
397 
398 // Specialization of std::hash for art::Ptr
399 namespace std {
400  template <typename T>
401  struct hash<art::Ptr<T>> {
403  using key_t = typename ptr_t::key_type;
404 
405  size_t
406  operator()(ptr_t const& p) const noexcept
407  {
408  return std::hash<art::ProductID>{}(p.id()) ^ std::hash<key_t>{}(p.key());
409  }
410  };
411 }
412 
413 #endif /* canvas_Persistency_Common_Ptr_h */
414 
415 // Local Variables:
416 // mode: c++
417 // End:
static QCString name
Definition: declinfo.cpp:673
Ptr(Ptr< U > const &pu, std::enable_if_t< std::is_base_of_v< T, U >> *=nullptr)
Definition: Ptr.h:120
Ptr(ProductID const &productID, T const *item, key_type const itemKey)
Definition: Ptr.h:133
bool hasCache() const noexcept
Definition: Ptr.h:210
iterator find(key_type key)
Definition: map_vector.h:381
struct vector vector
iterator end() noexcept
Definition: map_vector.h:190
EDProduct const * parentProduct_() const
Definition: Ptr.h:230
STL namespace.
std::pair< cet::map_vector_key, T > const * operator()(cet::map_vector< T > const *product, typename Ptr< T >::key_type iKey) const
Definition: Ptr.h:381
size_t operator()(ptr_t const &p) const noexcept
Definition: Ptr.h:406
T const & operator*() const
Definition: Ptr.h:141
L value_type
Definition: Ptr.h:80
std::size_t key_type
Definition: Ptr.h:79
bool operator!=(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept
Ptr(ProductID const &productID)
Definition: Ptr.h:107
T const * operator()(cet::map_vector< T > const *product, typename Ptr< T >::key_type iKey) const
Definition: Ptr.h:367
const double e
def key(type, name=None)
Definition: graph.py:13
T const * operator->() const
Definition: Ptr.h:154
key_type key() const noexcept
Definition: Ptr.h:216
T const * operator()(C const *product, typename Ptr< T >::key_type iKey) const
Definition: Ptr.h:352
typename ptr_t::key_type key_t
Definition: Ptr.h:403
bool isNull() const noexcept
Definition: Ptr.h:173
p
Definition: test.py:223
ProductID id() const noexcept
Definition: Ptr.h:190
TO operator()(Ptr< PTRVAL > &from) const
Definition: Ptr.h:329
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:166
void fill_ptr_list(std::list< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:307
TO operator()(Ptr< PTRVAL > const &from) const
Definition: Ptr.h:335
EDProductGetter const * productGetter() const noexcept
Definition: Ptr.h:196
Ptr(H const &handle, typename Ptr< T >::key_type key)
Definition: Ptr.h:88
Ptr(ProductID const &productID, key_type itemKey, EDProductGetter const *prodGetter)
Definition: Ptr.h:112
bool isAvailable() const
Definition: Ptr.h:204
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:297
T const * get() const
Definition: Ptr.h:149
L const & const_reference
Definition: Ptr.h:82
void const * getElementAddress(std::type_info const &toType, unsigned long index) const
Definition: EDProduct.cc:13
int bool
Definition: qglobal.h:345
static constexpr short Class_Version() noexcept
Definition: Ptr.h:223
L const * const_pointer
Definition: Ptr.h:81
Definition: fwd.h:31
Ptr(Ptr< U > const &pu, std::enable_if_t< std::is_base_of_v< U, T >> *=nullptr)
Definition: Ptr.h:128
RefCore const & refCore() const noexcept
Definition: Ptr.h:184
mapped_type * getOrNull(key_type key)
Definition: map_vector.h:417
bool operator==(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept