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{nullptr};
158  if (productGetter()) {
159  prod = productGetter()->getIt();
160  }
161  if (prod == nullptr) {
163  e << "A request to resolve an Ptr to a product containing items of "
164  "type: "
165  << cet::demangle_symbol(typeid(T).name()) << " with ProductID "
166  << core_.id()
167  << "\ncannot be satisfied because the product cannot be found.\n";
168  if (productGetter() == nullptr) {
169  e << "The productGetter was not set -- are you trying to "
170  "dereference a Ptr during mixing?\n";
171  } else {
172  e << "Probably the branch containing the product is not stored in "
173  "the input file.\n";
174  }
175  throw e;
176  }
177  void const* ad{nullptr};
178  prod->setPtr(typeid(T), key_, ad);
179  core_.setProductPtr(ad);
180  }
181  return reinterpret_cast<T const*>(core_.productPtr());
182  }
183 
184  // Checks for valid key.
185  bool
186  isNonnull() const noexcept
187  {
188  return key_ != key_traits<key_type>::value;
189  }
190 
191  // Checks for valid key.
192  bool
193  isNull() const noexcept
194  {
195  return !isNonnull();
196  }
197 
198  explicit operator bool() const
199  {
200  return (key_ != key_traits<key_type>::value) && core_.isAvailable();
201  }
202 
203  RefCore const&
204  refCore() const noexcept
205  {
206  return core_;
207  }
208 
209  ProductID
210  id() const noexcept
211  {
212  return core_.id();
213  }
214 
215  EDProductGetter const*
216  productGetter() const noexcept
217  {
218  return core_.productGetter();
219  }
220 
221  // Checks if collection is in memory or available
222  // in the event. No type checking is done.
223  bool
224  isAvailable() const
225  {
226  return core_.isAvailable();
227  }
228 
229  bool
230  hasCache() const noexcept
231  {
232  return core_.productPtr() != nullptr;
233  }
234 
235  key_type
236  key() const noexcept
237  {
238  return key_;
239  }
240 
241  // MUST UPDATE WHEN CLASS IS CHANGED!
242  static constexpr short
243  Class_Version() noexcept
244  {
245  return 10;
246  }
247 
248  private:
249  // Used to fetch the container product.
250  RefCore core_{};
251 
252  // Index into the container product.
254  };
255 
256  template <typename T, typename U>
257  std::enable_if_t<std::is_same_v<T, U> || std::is_base_of_v<T, U> ||
258  std::is_base_of_v<U, T>,
259  bool>
260  operator==(Ptr<T> const& lhs, Ptr<U> const& rhs)
261  {
262  return (lhs.refCore() == rhs.refCore()) && (lhs.key() == rhs.key());
263  }
264 
265  template <typename T, typename U>
266  std::enable_if_t<std::is_same_v<T, U> || std::is_base_of_v<T, U> ||
267  std::is_base_of_v<U, T>,
268  bool>
269  operator!=(Ptr<T> const& lhs, Ptr<U> const& rhs)
270  {
271  return !(lhs == rhs);
272  }
273 
274  template <typename T, typename U>
275  std::enable_if_t<std::is_same_v<T, U> || std::is_base_of_v<T, U> ||
276  std::is_base_of_v<U, T>,
277  bool>
278  operator<(Ptr<T> const& lhs, Ptr<U> const& rhs)
279  {
280  // The ordering of integer keys guarantees that the ordering of Ptrs within
281  // a collection will be identical to the ordering of the referenced objects
282  // in the collection.
283  return (lhs.refCore() == rhs.refCore()) ? (lhs.key() < rhs.key()) :
284  (lhs.refCore() < rhs.refCore());
285  }
286 
287  // Fill a vector of Ptrs from a persistent collection.
288  // Alternatively, construct a PtrVector.
289  template <typename T, typename H>
290  void
291  fill_ptr_vector(std::vector<Ptr<T>>& ptrs, H const& h)
292  {
293  for (std::size_t i = 0, sz = h->size(); i != sz; ++i) {
294  ptrs.emplace_back(h, i);
295  }
296  }
297 
298  // Fill a list of Ptrs from a persistent collection.
299  template <typename T, typename H>
300  void
301  fill_ptr_list(std::list<Ptr<T>>& ptrs, H const& h)
302  {
303  for (std::size_t i = 0, sz = h->size(); i != sz; ++i) {
304  ptrs.emplace_back(h, i);
305  }
306  }
307 
308  template <typename T>
309  std::ostream&
310  operator<<(std::ostream& os, Ptr<T> const& p)
311  {
312  os << "(" << p.id() << ", " << p.key() << ")";
313  return os;
314  }
315 
316  namespace detail {
317 
318  // Specialize EnsurePointer for Ptr.
319  template <typename TO, typename PTRVAL>
320  struct EnsurePointer<TO, Ptr<PTRVAL>> {
321 
322  TO
323  operator()(Ptr<PTRVAL>& from) const
324  {
325  return addr<TO, PTRVAL const>(*from);
326  }
327 
328  TO
329  operator()(Ptr<PTRVAL> const& from) const
330  {
331  return addr<TO, PTRVAL const>(*from);
332  }
333  };
334 
335  // FIXME: The code of ItemGetter, including specializations, would
336  // be completely unnecessary if Handle were to provide access to the
337  // setPtr() function of wrapper. As it is, some container-specific
338  // code is duplicated between here and Wrapper, leading to
339  // multiple points of maintenance (and failure).
340 
341  template <typename T, typename C>
342  class ItemGetter {
343 
344  public:
345  T const*
346  operator()(C const* product, typename Ptr<T>::key_type iKey) const
347  {
348  assert(product != nullptr);
349  auto it = product->begin();
350  advance(it, iKey);
352  return address;
353  }
354  };
355 
356  template <typename T>
357  class ItemGetter<T, cet::map_vector<T>> {
358 
359  public:
360  T const*
362  typename Ptr<T>::key_type iKey) const
363  {
364  assert(product != nullptr);
365  cet::map_vector_key k(iKey);
366  return product->getOrNull(k);
367  }
368  };
369 
370  template <typename T>
371  class ItemGetter<std::pair<cet::map_vector_key, T>, cet::map_vector<T>> {
372 
373  public:
374  std::pair<cet::map_vector_key, T> const*
376  typename Ptr<T>::key_type iKey) const
377  {
378  assert(product != nullptr);
379  cet::map_vector_key k(static_cast<unsigned>(iKey));
380  auto it = product->find(k);
381  if (it == product->end()) {
382  return nullptr;
383  }
384  return &*it;
385  }
386  };
387 
388  } // namespace detail
389 
390 } // namespace art
391 
392 // Specialization of std::hash for art::Ptr
393 namespace std {
394  template <typename T>
395  struct hash<art::Ptr<T>> {
397  using key_t = typename ptr_t::key_type;
398 
399  size_t
400  operator()(ptr_t const& p) const noexcept
401  {
402  return std::hash<art::ProductID>{}(p.id()) ^ std::hash<key_t>{}(p.key());
403  }
404  };
405 }
406 
407 #endif /* canvas_Persistency_Common_Ptr_h */
408 
409 // Local Variables:
410 // mode: c++
411 // End:
const XML_Char * name
Definition: expat.h:151
Ptr(Ptr< U > const &pu, std::enable_if_t< std::is_base_of_v< T, U >> *=nullptr)
Definition: Ptr.h:120
set< int >::iterator it
Ptr(ProductID const &productID, T const *item, key_type const itemKey)
Definition: Ptr.h:133
const char * p
Definition: xmltok.h:285
bool hasCache() const noexcept
Definition: Ptr.h:230
iterator find(key_type key)
Definition: map_vector.h:369
iterator end() noexcept
Definition: map_vector.h:190
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:375
size_t operator()(ptr_t const &p) const noexcept
Definition: Ptr.h:400
T const & operator*() const
Definition: Ptr.h:141
bool operator!=(debugging_allocator< X > const &, debugging_allocator< Y > const &)
L value_type
Definition: Ptr.h:80
std::size_t key_type
Definition: Ptr.h:79
Ptr(ProductID const &productID)
Definition: Ptr.h:107
const double C
T const * operator()(cet::map_vector< T > const *product, typename Ptr< T >::key_type iKey) const
Definition: Ptr.h:361
T const * operator->() const
Definition: Ptr.h:154
key_type key() const noexcept
Definition: Ptr.h:236
T const * operator()(C const *product, typename Ptr< T >::key_type iKey) const
Definition: Ptr.h:346
typename ptr_t::key_type key_t
Definition: Ptr.h:397
bool isNull() const noexcept
Definition: Ptr.h:193
ProductID id() const noexcept
Definition: Ptr.h:210
TO operator()(Ptr< PTRVAL > &from) const
Definition: Ptr.h:323
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:186
void fill_ptr_list(std::list< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:301
TO operator()(Ptr< PTRVAL > const &from) const
Definition: Ptr.h:329
EDProductGetter const * productGetter() const noexcept
Definition: Ptr.h:216
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
assert(nhit_max >=nhit_nbins)
bool isAvailable() const
Definition: Ptr.h:224
Service to store calibration data products (CDP) in the SQLite3 metadatabase of a file...
Definition: FillParentInfo.h:8
double T
Definition: Xdiff_gwt.C:5
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:291
bool operator==(Provenance const &a, Provenance const &b)
Float_t e
Definition: plot.C:35
T const * get() const
Definition: Ptr.h:149
L const & const_reference
Definition: Ptr.h:82
static constexpr short Class_Version() noexcept
Definition: Ptr.h:243
L const * const_pointer
Definition: Ptr.h:81
Definition: fwd.h:29
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:204
mapped_type * getOrNull(key_type key)
Definition: map_vector.h:405