All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ArtHandleTrackerManager.h
Go to the documentation of this file.
1 /**
2  * @file icaruscode/Utilities/ArtHandleTrackerManager.h
3  * @brief Tracks handles for cache deletion.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date July 31, 2022
6  *
7  * This is a header-only library.
8  */
9 
10 #ifndef ICARUSCORE_UTILITIES_ARTHANDLETRACKERMANAGER_H
11 #define ICARUSCORE_UTILITIES_ARTHANDLETRACKERMANAGER_H
12 
13 
14 // framework libraries
15 #include "art/Framework/Principal/Handle.h"
16 #include "art/Framework/Principal/Provenance.h"
17 #include "canvas/Utilities/InputTag.h"
18 #include "messagefacility/MessageLogger/MessageLogger.h"
19 
20 // C/C++ standard libraries
21 #include <algorithm> // std::count_if()
22 #include <vector>
23 #include <memory> // std::unique_ptr<>
24 #include <any>
25 #include <utility> // std::forward()
26 #include <typeinfo>
27 
28 
29 // -----------------------------------------------------------------------------
30 namespace util {
31  template <typename Event> struct ArtHandleTrackerInterface;
32  template <typename Event> class ArtHandleTrackerManager;
33  template <typename Event> class LocalArtHandleTrackerManager;
34 }
35 
36 // -----------------------------------------------------------------------------
37 /**
38  * @brief Manages handle trackers for an easy call of `removeCachedProduct()`.
39  * @tparam Event the type of data product source (the "principal") to serve
40  *
41  * This handle manager is designed to simplify the usage of
42  * `art::Event::removeCachedProduct()` on multiple data products.
43  *
44  * The envisioned usage model in a single-thread module is the following:
45  * 1. The manager is a data member of the module (in alternative, it should be
46  * passed down to the places where data products are read, and at a minimum
47  * it needs to register all the handles it is supposed to "manage").
48  * 2. The manager can ask the event to read a data product anew, and get an
49  * handle for it. It will register the handle, and return it.
50  * * The manager can also register an existing handle.
51  * 3. The manager can deliver a stored handle (but that's a slow process in the
52  * current implementation and it requires the input tag to resolve
53  * ambiguities).
54  * 4. Upon request, all handles are asked to remove their cached products.
55  * This request presumably happens at the end of the event-processing
56  * function (`produce()`, `filter()`, `analyze()`).
57  * Note that after an handle has its cached data removed, it's `clear()`'ed.
58  *
59  * An handle manager can serve only one _art_ event at a time.
60  * All handles come from that event (or are assumed to).
61  *
62  * Example:
63  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
64  * class MyModule: public art::EDAnalyzer {
65  *
66  * util::ArtHandleTrackerManager<art::Event> fDataCacheRemover;
67  *
68  * art::InputTag const fTag;
69  *
70  * // ...
71  *
72  * void analyze(art::Event const & event) override
73  * {
74  * fDataCacheRemover.useEvent(event);
75  *
76  * auto const& handle = fDataCacheRemover.getHandle<MyDataProduct>(fTag);
77  *
78  * auto results = processData(*handle); // ... or whatever
79  *
80  * fDataCacheRemover.removeCachedProducts(); // free caches after use
81  *
82  * results.Write(); // ... or another portion of whatever
83  * }
84  *
85  * };
86  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87  *
88  * Or one can create the handle as preferred, and then register it:
89  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
90  * class MyModule: public art::EDAnalyzer {
91  *
92  * util::ArtHandleTrackerManager<art::Event> fDataCacheRemover;
93  *
94  * art::InputTag const fTag;
95  *
96  * // ...
97  *
98  * void analyze(art::Event const & event) override
99  * {
100  * fDataCacheRemover.useEvent(event);
101  *
102  * auto const& handle = event.getValidHandle<MyDataProduct>(fTag);
103  *
104  * fDataCacheRemover.registerHandle(handle);
105  *
106  * auto results = processData(*handle); // ... or whatever
107  *
108  * fDataCacheRemover.removeCachedProducts(); // free caches after use
109  *
110  * results.Write(); // ... or another portion of whatever
111  * }
112  *
113  * };
114  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115  *
116  *
117  * Technical notes
118  * ================
119  *
120  * Support for different types of handles
121  * ---------------------------------------
122  *
123  * Currently, both `art::Handle` and `art::ValidHandle` (and nothing else)
124  * can be created by `ArtHandleTrackerManager`.
125  * The code can be extended to support any object that can be
126  * passed to `art::Event::removeCachedProduct()` (e.g. `art::ProductID`,
127  * if it will ever happen).
128  *
129  * The current implementation is expected to be able to recognize handles
130  * pointing to the same data product even if they are of different type
131  * (e.g. `art::Handle<T>` and `art::ValidHandle<T>`).
132  * The manager stores a copy of the first type of handle registered for a given
133  * data product; then, if another handle of any type to the same data product
134  * is requested or registered, `registerHandle()` will return the same handle
135  * in argument, and the `getHandle()` family of functions will get and return a
136  * new handle. In both cases, no new registration will happen.
137  *
138  *
139  * Multithreading
140  * ---------------
141  *
142  * The current implementation is inherently not safe for _art_ multithreading.
143  * While the inner data structure don't need global state, and the interface
144  * can easily be extended to allow for no global state as well, the operations
145  * are still performed on all the registered handles at once (meaning, when one
146  * thread asks for `removeCachedProduct()` or `forgetAllHandles()`, data from
147  * all events is affected).
148  * This can be overcome by changing the internal storage (to be reentrant and
149  * possibly by event) and a bit of the interface.
150  *
151  * The object as it is now can be implemented on top of such object, preserving
152  * the current event information and delivering it to the new manager under the
153  * hood, with minimal overhead.
154  *
155  * If such feature is needed, ask the author (and be prepared to test it).
156  *
157  */
158 template <typename Event>
160 
161  public:
162 
163  using Event_t = Event; ///< Type of data viewer object to operate with.
164 
165  /// Configuration record.
166  struct Config_t {
167 
168  /// Name of the output category for messages.
169  std::string logCategory = "ArtHandleTrackerManager";
170 
171  }; // Config_t
172 
173 
174  /**
175  * @brief Constructs a handle manager.
176  * @param config (optional) the configuration to be used
177  * @see `useEvent()`
178  *
179  * An event must be later assigned to it (`useEvent()`) to make it functional.
180  */
181  ArtHandleTrackerManager(Config_t config = {});
182 
183  /**
184  * @brief Constructs a handle manager covering `event`.
185  * @param event the first data viewer (event) object to operate on
186  */
187  ArtHandleTrackerManager(Event_t const& event, Config_t config = {});
188 
189 
190  // --- BEGIN -- Queries ------------------------------------------------------
191  ///@name Queries
192  ///@{
193 
194  /// Returns the number of handles currently tracked.
195  unsigned int nTrackedHandles() const;
196 
197  /// Returns whether the object is associated to an event.
198  bool hasEvent() const;
199 
200 
201  /// @}
202  // --- END ---- Queries ------------------------------------------------------
203 
204 
205  // --- BEGIN -- Registration of data products --------------------------------
206  /// @name Registration of data products
207  /// @{
208 
209  /**
210  * @brief Retrieves an handle from the event, and registers it.
211  * @tparam T type of data product to retrieve
212  * @tparam Args types of the arguments needed by `art::getHandle()`
213  * @param args all the arguments that `art::getHandle()` requires
214  * @return the handle just read and being managed
215  * @see `getValidHandle()`, `registerHandle()`
216  *
217  * This function wraps `art::Event::getHandle()`, calling it to obtain the
218  * handle and then registering it (like with `registerHandle()`).
219  */
220  template <typename T, typename... Args>
221  art::Handle<T> getHandle(Args&&... args);
222 
223  /**
224  * @brief Retrieves a valid handle from the event, and registers it.
225  * @tparam T type of data product to retrieve
226  * @tparam Args types of the arguments needed by `art::getValidHandle()`
227  * @param args all the arguments that `art::getValidHandle()` requires
228  * @return the handle just read and being managed
229  * @see `getHandle()`, `registerHandle()`
230  *
231  * This is the `art::ValidHandle` sibling of `getHandle()`.
232  * See that one for details.
233  */
234  template <typename T, typename... Args>
235  art::ValidHandle<T> getValidHandle(Args&&... args);
236 
237  /**
238  * @brief Registers an existing handle.
239  * @tparam Handle the type of handle to register
240  * @param handle the handle to be registered
241  * @return `handle` (pass through)
242  *
243  * This method registers a copy of `handle` into the manager.
244  */
245  template <typename Handle>
246  decltype(auto) registerHandle(Handle&& handle);
247 
248  /// @}
249  // --- END ---- Registration of data products --------------------------------
250 
251 
252  // --- BEGIN -- Operations ---------------------------------------------------
253  /// @name Operations
254  /// @{
255 
256  /**
257  * @brief Changes the event being served.
258  * @param event the new event being served
259  * @throw art::Exception (code: `art::errors::LogicError`) if there are still
260  * registered handles
261  *
262  * The object starts tracking handles of a new event.
263  *
264  * This method requires that any pending handle has been taken care of
265  * (even if the new event happens to be the same as the old one).
266  * Common options are `removeCachedProductsAndForget()` if cache removal is
267  * desired, or `forgetAllHandles()` if it's not.
268  */
269  void useEvent(Event_t const& event);
270 
271 
272  /**
273  * @brief Clears the cached data products for all tracked handles.
274  * @return the number of tracked handles which had their cache removed
275  *
276  * This method calls `Event_t::removeCachedProduct()` for all tracked handles.
277  * This is the core functionality of the manager, which removes the cache
278  * of all tracked handles.
279  *
280  * The _art_ framework always makes the handles used to remove the cache
281  * invalid (`Handle::clear()`).
282  * After the removal, the object stops tracking the handles (like with a call
283  * to `forgetAllHandles()`).
284  *
285  * Calling this method when there are no handles registered has no effect.
286  */
287  unsigned int removeCachedProducts();
288 
289  /// Stops tracking any handle, without removing their cache first.
290  void forgetAllHandles();
291 
292 
293  /**
294  * @brief Completes the work on the associated `event`.
295  * @param removeCache (default: `true`) removes tracked data product caches
296  * @param event if specified, only acts on cache from this `event`
297  * @return the number of cleared data product caches
298  *
299  * This is a shortcut for having optional release of cache in a single call,
300  * depending on the value of `removeCache`:
301  * * if `true`, `removeCachedProducts()` is called and its count is returned;
302  * * if `false`, `forgetAllHandles()` is called and `0` is returned.
303  *
304  * In addition, the object is disassociated from the event, and a call to
305  * `useEvent()` will be needed before this object can be operative again.
306  *
307  * If the `event` parameter is not null, a check is done that the event being
308  * currently used matches `event`, and if not no operation happens (`0` is
309  * returned, but the object is not disassociated from its current event).
310  *
311  */
312  unsigned int doneWithEvent
313  (bool removeCache = true, art::Event const* event = nullptr);
314 
315  /// @}
316  // --- END ---- Operations ---------------------------------------------------
317 
318 
319  private:
320 
321  /// Type of pointer to any handle tracker.
322  using TrackerPtr = std::unique_ptr<util::ArtHandleTrackerInterface<Event_t>>;
323 
324 
325  // --- BEGIN -- Data ---------------------------------------------------------
326  Event_t const* fEvent = nullptr; ///< Event being manager. Must be present!
327 
328  Config_t const fConfig; ///< Configuration.
329 
330 
331  std::vector<TrackerPtr> fTrackers; ///< List of managed handle trackers.
332 
333  // --- END ---- Data ---------------------------------------------------------
334 
335 
336  /**
337  * @brief Returns the pointer to an handle equivalent to `like`.
338  * @tparam Handle the type of the handle being queried
339  * @return a pointer to the handle, or `nullptr` if not found
340  *
341  * This is an half-assed method since it needs to know already the exact type
342  * of the handle being queried (it's not even agnostic to the difference
343  * between `art::Handle` and `art::ValidHandle`).
344  * For this reason, it's not really useful to the users, who would probably
345  * want to know if the data product is cached, via any mean.
346  *
347  *
348  * ### Technical note
349  *
350  * Delegating the matching to `util::ArtHandleTrackerInterface` is not possible
351  * (`like` is a template parameter and can't be passed via virtual interface)
352  * and even working around that and finding the match, the returned value needs
353  * to be of type `Handle`, which is not necessarily the type of handle stored
354  * in the tracker.
355  *
356  * For the full functionality of knowing if a data product is tracked, a
357  * separate registry may be kept, still complicated by the fact that part of
358  * the registry entry is a C++ type (we may need to store a sanitized
359  * `std::type_info` for that).
360  */
361  template <typename Handle>
362  Handle const* findHandle(Handle const& like) const;
363 
364 
365  /// Returns whether `tracker` tracks the same product that `handle` handles.
366  template <typename Handle>
367  static bool handleSameProduct(TrackerPtr tracker, Handle const& handle);
368 
369 
370  /// Checks that the object is in a state where it can perform operations.
371  /// @param where identification of the calling function for error messages
372  /// @throw art::Exception (code: `art::errors::LogicError`) on failure
373  void canOperate(const char* where) const;
374 
375 
376 }; // util::ArtHandleTrackerManager
377 
378 
379 // -----------------------------------------------------------------------------
380 /**
381  * @brief Variant of `util::ArtHandleTrackerManager` in local scope.
382  * @tparam Event the type of data product source (the "principal") to serve
383  *
384  * This class allows the removal of data products cached in an event.
385  * The general functionality is described in `util::ArtHandleTrackerManager`.
386  *
387  * This class in particular offers a tuned interface for the case where the
388  * object is local (which is convenient for multithreading and if all the
389  * reading and usage happens in the same scope):
390  * * the object supports being associated to only one event in its lifetime,
391  * and the association must be established on construction;
392  * * removal is automatically performed on destruction at the exit of the
393  * scope of the object (this is "Resource Acquisition Is Initialization"
394  * idiom)
395  *
396  * Whether the object will actually remove the caches can be decided on
397  * construction (by default it does), and then changed with
398  * `setRemoveCachedProducts()`.
399  * The removal can also be anticipated by explicitly calling `doneWithEvent()`
400  * (no `event` parameter is supported), after which the destruction will not
401  * do anything.
402  *
403  * Example:
404  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
405  * void MyModule::analyze(art::Event const & event) override {
406  *
407  * util::LocalArtHandleTrackerManager dataCacheRemover{ event };
408  *
409  * auto const& handle = dataCacheRemover.getHandle<MyDataProduct>(fTag);
410  *
411  * auto results = processData(*handle); // ... or whatever
412  *
413  * results.Write(); // ... or another portion of whatever
414  * }
415  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
416  *
417  */
418 template <typename Event>
419 class util::LocalArtHandleTrackerManager {
420 
421  /// The actual manager doing the work.
423 
424  bool fRemoveCache; ///< Whether to remove cache on destructor.
425 
426  public:
427 
428  /// Type of the _art_ event.
429  using Event_t = typename ArtHandleTrackerManager<Event>::Event_t;
430 
431  /**
432  * @brief Constructor: operates on the specified `event`.
433  * @param event the event this object will operate on
434  * @param removeCache (default: `true`) remove tracked data caches when done
435  *
436  *
437  * The parameter `removeCache` controls whether the data caches are removed
438  * on destruction. It may be changed along the way with
439  * `setRemoveCachedProducts()`.
440  *
441  */
442  LocalArtHandleTrackerManager(Event const& event, bool removeCache = true);
443 
444  /// Destructor; will implement the RAII pattern (i.e. call `doneWithEvent()`).
445  ~LocalArtHandleTrackerManager();
446 
447 
448  // --- BEGIN -- Queries ------------------------------------------------------
449  ///@name Queries
450  ///@{
451 
452  /// Returns the number of handles currently tracked.
453  unsigned int nTrackedHandles() const;
454 
455  /// Returns whether caches will be removed on destruction.
456  /// @see `setRemoveCachedProducts()`
457  bool willRemoveCachedProducts() const;
458 
459  /// @}
460  // --- END ---- Queries ------------------------------------------------------
461 
462 
463  // --- BEGIN -- Registration of data products --------------------------------
464  /// @name Registration of data products
465  /// @{
466 
467  /**
468  * @brief Retrieves an handle from the event, and registers it.
469  * @tparam T type of data product to retrieve
470  * @tparam Args types of the arguments needed by `art::getHandle()`
471  * @param args all the arguments that `art::getHandle()` requires
472  * @return the handle just read and being managed
473  * @see `getValidHandle()`, `registerHandle()`
474  *
475  * This function wraps `art::Event::getHandle()`, calling it to obtain the
476  * handle and then registering it (like with `registerHandle()`).
477  */
478  template <typename T, typename... Args>
479  art::Handle<T> getHandle(Args&&... args);
480 
481  /**
482  * @brief Retrieves a valid handle from the event, and registers it.
483  * @tparam T type of data product to retrieve
484  * @tparam Args types of the arguments needed by `art::getValidHandle()`
485  * @param args all the arguments that `art::getValidHandle()` requires
486  * @return the handle just read and being managed
487  * @see `getHandle()`, `registerHandle()`
488  *
489  * This is the `art::ValidHandle` sibling of `getHandle()`.
490  * See that one for details.
491  */
492  template <typename T, typename... Args>
493  art::ValidHandle<T> getValidHandle(Args&&... args);
494 
495  /**
496  * @brief Registers an existing handle.
497  * @tparam Handle the type of handle to register
498  * @param handle the handle to be registered
499  * @return the same `handle` is passed through
500  *
501  * This method registers a copy of `handle` into the manager.
502  */
503  template <typename Handle>
504  decltype(auto) registerHandle(Handle&& handle);
505 
506  /// @}
507  // --- END ---- Registration of data products --------------------------------
508 
509 
510  // --- BEGIN -- Operations ---------------------------------------------------
511  /// @name Operations
512  /// @{
513 
514  /// @brief Sets whether to remove tracked data caches on destruction or not.
515  /// @param removeCache if `true`, data caches will be removed on destruction
516  void setRemoveCachedProducts(bool removeCache);
517 
518  /**
519  * @brief Clears the cached data products for all tracked handles.
520  * @return the number of tracked handles which had their cache removed
521  *
522  * This method calls `Event_t::removeCachedProduct()` for all tracked handles.
523  * This is the core functionality of the manager, which removes the cache
524  * of all tracked handles.
525  *
526  * The _art_ framework always makes the handles used to remove the cache
527  * invalid (`Handle::clear()`).
528  * After the removal, the object stops tracking the handles (like with a call
529  * to `forgetAllHandles()`).
530  *
531  * Calling this method when there are no handles registered has no effect.
532  */
533  unsigned int removeCachedProducts();
534 
535  /// Stops tracking any handle, without removing their cache first.
536  void forgetAllHandles();
537 
538 
539  /**
540  * @brief Completes the work on the associated `event`.
541  * @param removeCache (default: `true`) removes tracked data product caches
542  * @return the number of cleared data product caches
543  * @see `doneWithEvent()`
544  *
545  * This is a shortcut for having optional release of cache in a single call,
546  * depending on the value of `removeCache`:
547  * * if `true`, `removeCachedProducts()` is called and its count is returned;
548  * * if `false`, `forgetAllHandles()` is called and `0` is returned.
549  *
550  * Differently from `util::ArtHandleTrackerManager`, the object is _not_
551  * disassociated from the event: new handles can be registered and the
552  * clearing settings are preserved as they are.
553  * To be really done with the event, `setRemoveCachedProducts()` needs to be
554  * set to `false`, and users should refrain from calling
555  * `removeCachedProducts().
556  *
557  * This method ignores and overrides the value set by
558  * `setRemoveCachedProducts()` and the one at construction.
559  */
560  unsigned int doneWithEvent(bool removeCache);
561 
562 
563  /**
564  * @brief Completes the work on the associated `event`.
565  * @return the number of cleared data product caches
566  * @see `doneWithEvent(bool)`, `setRemoveCachedProducts()`
567  *
568  * This is a shortcut for having optional release of cache in a single call,
569  * depending on the value of `willRemoveCachedProducts()`:
570  * * if `true`, `removeCachedProducts()` is called and its count is returned;
571  * * if `false`, `forgetAllHandles()` is called and `0` is returned.
572  *
573  * In addition, the object is disassociated from the event, and the object
574  * will not be available for use any more.
575  */
576  unsigned int doneWithEvent();
577 
578  /// @}
579  // --- END ---- Operations ---------------------------------------------------
580 
581 }; // util::LocalArtHandleTrackerManager
582 
583 
584 // -----------------------------------------------------------------------------
585 /**
586  * @brief Interface to facilitate the use of `util::ArtHandleTracker`
587  * specializations.
588  *
589  * This is NOT able to return the type of handle it's handling.
590  *
591  */
592 template <typename Event>
593 struct util::ArtHandleTrackerInterface {
594 
595  /// Virtual destructor (does nothing).
596  virtual ~ArtHandleTrackerInterface() = default;
597 
598  /// Removes the cached data product from `event`.
599  /// Handle is cleared and won't be valid any more.
600  bool removeCachedProduct() { return doRemoveCachedProduct(); }
601 
602 
603  /// Returns a container for a pointer to the managed handle. Caveat emptor.
604  std::any handlePtr() const { return doHandlePtr(); }
605 
606  /// Returns the name of the class of handled data product.
607  std::string productClass() const { return doProductClass(); }
608 
609  /// Returns the name of the class of handled data product.
610  std::type_info const* productType() const { return doProductType(); }
611 
612  /// Returns the tag of handled data product.
613  art::InputTag inputTag() const { return doInputTag(); }
614 
615  /// Returns whether this and the `other` objects handle the same data product.
616  bool hasSameDataProduct
618  {
619  return inputTag() == other.inputTag()
620  && productType() == other.productType();
621  }
622 
623  protected:
624 
625  /// Deferred implementation of `removeCachedProduct()`.
626  virtual bool doRemoveCachedProduct() = 0;
627 
628  /// Deferred implementation of `handlePtr()`.
629  virtual std::any doHandlePtr() const = 0;
630 
631  /// Deferred implementation of `productClass()`.
632  virtual std::string doProductClass() const = 0;
633 
634  /// Deferred implementation of `productType()`.
635  virtual std::type_info const* doProductType() const = 0;
636 
637  /// Deferred implementation of `inputTag()`.
638  virtual art::InputTag doInputTag() const = 0;
639 
640 }; // ArtHandleTrackerInterface<>
641 
642 
643 // -----------------------------------------------------------------------------
644 // --- Template implementation
645 // -----------------------------------------------------------------------------
646 // --- util::details::ArtHandleTracker
647 // -----------------------------------------------------------------------------
648 namespace util::details {
649  template <typename Handle, typename Enable = void> class ProvenanceGetter;
650  template <typename T, typename Event> class ArtHandleTracker;
651 
652  /// use candy
653  template <typename Handle>
654  std::string productClassOf(Handle const& handle);
655  template <typename Handle>
656  std::type_info const* productTypeOf(Handle const& handle);
657  template <typename Handle>
658  art::InputTag inputTagOf(Handle const& handle);
659 
660 } // namespace util::details
661 
662 // -----------------------------------------------------------------------------
663 /// Helper to extract basic information from one handle.
664 /// The default implementation supports `art::Handle` and `art::ValidHandle`.
665 template <typename Handle, typename>
667 
668  static art::Provenance const* provenance(Handle const& handle)
669  { return handle.provenance(); }
670 
671  public:
672  /// Returns the name of the class pointed by the handle.
673  static std::string productClass(Handle const& handle)
674  {
675  auto const* prov = provenance(handle);
676  return prov? prov->producedClassName(): "";
677  }
678 
679  /// Returns the C++ type of the handled data product.
680  static std::type_info const* productType()
681  { return &typeid(typename Handle::element_type); }
682 
683  /// Returns the C++ type of the handled data product.
684  static std::type_info const* productType(Handle const&)
685  { return productType(); }
686 
687  /// Returns the input tag of the handled data product.
688  /// Deferred implementation of `inputTag()`.
689  static art::InputTag inputTag(Handle const& handle)
690  {
691  auto const* prov = provenance(handle);
692  return prov? prov->inputTag(): art::InputTag{};
693  }
694 
695 
696 }; // util::details::ProvenanceGetter
697 
698 
699 template <typename Handle>
700 std::string util::details::productClassOf(Handle const& handle)
701  { return ProvenanceGetter<Handle>::productClass(handle); }
702 
703 template <typename Handle>
704 std::type_info const* util::details::productTypeOf(Handle const& handle)
705  { return ProvenanceGetter<Handle>::productType(handle); }
706 
707 template <typename Handle>
708 art::InputTag util::details::inputTagOf(Handle const& handle)
709  { return ProvenanceGetter<Handle>::inputTag(handle); }
710 
711 
712 // -----------------------------------------------------------------------------
713 /**
714  * @brief Tracks _art_ handle objects.
715  * @tparam Handle type of handle being tracked
716  *
717  * @note Due to my limited expertise with metaprogramming (and/or for C++
718  * limitations?) I need one tracker per data type.
719  * The `util::ArtHandleTrackerManager` class should mitigate the hassle
720  * deriving from this limitation.
721  *
722  */
723 template <typename Event, typename Handle>
724 class util::details::ArtHandleTracker: public ArtHandleTrackerInterface<Event> {
725 
726  Event const* fEvent = nullptr;
727 
728  Handle fHandle;
729 
730  // --- BEGIN -- Virtual method implementation --------------------------------
731  /// @name Virtual method implementation
732  /// @{
733 
734  /// Actually removes the cache.
735  virtual bool doRemoveCachedProduct() override
736  {
737  mf::LogDebug{ "ArtHandleTracker" } << "Removing cache for handle<"
738  << fHandle.provenance()->producedClassName()
739  << ">(" << fHandle.provenance()->inputTag().encode() << ").";
740  return fEvent->removeCachedProduct(fHandle);
741  }
742 
743  /// Returns a pointer to the managed handle, wrapped in `std::any`.
744  virtual std::any doHandlePtr() const override
745  { return { &handle() }; }
746 
747  /// Returns the name of the class pointed by the handle.
748  virtual std::string doProductClass() const override
749  { return productClassOf(fHandle); }
750 
751  /// Returns the C++ type of the handled data product.
752  virtual std::type_info const* doProductType() const override
754 
755  /// Returns the input tag of the handled data product.
756  /// Deferred implementation of `inputTag()`.
757  virtual art::InputTag doInputTag() const override
758  { return inputTagOf(fHandle); }
759 
760  /// @}
761  // --- END ---- Virtual method implementation --------------------------------
762 
763  public:
764 
765  /// Constructor: records all the needed information.
766  ArtHandleTracker(Event const& event, Handle handle)
767  : fEvent(&event), fHandle(std::move(handle)) {}
768 
769  /// Returns the tracked handle.
770  Handle const& handle() const { return fHandle; }
771 
772  /// Returns the provenance information of the handle.
773  art::Provenance const* provenance() const { return fHandle.provenance(); }
774 
775 }; // util::details::ArtHandleTracker<>
776 
777 
778 // -----------------------------------------------------------------------------
779 // --- util::ArtHandleTrackerManager
780 // -----------------------------------------------------------------------------
781 template <typename Event>
783  (Config_t config /* = {} */)
784  : fConfig{ std::move(config) }
785 {}
786 
787 
788 // -----------------------------------------------------------------------------
789 template <typename Event>
791  (Event_t const& event, Config_t config /* = {} */)
792  : fEvent{ &event }, fConfig{ std::move(config) }
793 {}
794 
795 
796 // -----------------------------------------------------------------------------
797 template <typename Event>
799 
800  if (nTrackedHandles() > 0) {
801  // since fEvent might be invalid, we don't attempt to figure out which ID
802  // that event might have had
803  throw art::Exception{ art::errors::LogicError }
804  << "ArtHandleTrackerManager attempted to change event to "
805  << event.id() << " when " << nTrackedHandles()
806  << " handles are still tracked.\n";
807  }
808 
809  fEvent = &event;
810 
811 } // util::ArtHandleTrackerManager<Event>::useEvent()
812 
813 
814 // -----------------------------------------------------------------------------
815 template <typename Event>
816 template <typename T, typename... Args>
818  (Args&&... args)
819 {
820  canOperate("getHandle()");
821  return registerHandle
822  (fEvent->template getHandle<T>(std::forward<Args>(args)...));
823 }
824 
825 
826 // -----------------------------------------------------------------------------
827 template <typename Event>
828 template <typename T, typename... Args>
830  (Args&&... args)
831 {
832  canOperate("getValidHandle()");
833  return registerHandle
834  (fEvent->template getValidHandle<T>(std::forward<Args>(args)...));
835 }
836 
837 
838 // -----------------------------------------------------------------------------
839 template <typename Event>
840 template <typename Handle>
842  (Handle&& handle) -> decltype(auto)
843 {
845 
846  using Handle_t = std::decay_t<Handle>;
847 
848  canOperate("registerHandle()");
849 
851 
852  // if it's already registered, we don't want to have it again
853  if (auto ptr = findHandle(handle)) {
854  auto const& registeredHandle = *ptr;
855  mf::LogDebug msg { fConfig.logCategory };
856  msg
857  << "Handle<" << details::productClassOf(registeredHandle)
858  << ">(" << details::inputTagOf(registeredHandle).encode()
859  << ") was already registered";
860  if (typeid(registeredHandle) != typeid(Handle_t)) {
861  msg << " as a different handle type (" << typeid(registeredHandle).name()
862  << ", now " << typeid(Handle_t).name() << ")";
863  }
864  msg << ".";
865  }
866  else {
867  mf::LogDebug{ fConfig.logCategory }
868  << "Registering handle<" << details::productClassOf(handle)
869  << ">(" << details::inputTagOf(handle).encode()
870  << ") (handle type: " << typeid(Handle_t).name() << ")."
871  ;
872 
873  fTrackers.push_back(std::make_unique<Tracker_t>(*fEvent, handle));
874  }
875 
876  return std::forward<Handle>(handle);
877 
878 } // util::ArtHandleTrackerManager<>::registerHandle()
879 
880 
881 // -----------------------------------------------------------------------------
882 template <typename Event>
884  { return fTrackers.size(); }
885 
886 
887 // -----------------------------------------------------------------------------
888 template <typename Event>
890  { return fEvent; }
891 
892 
893 // -----------------------------------------------------------------------------
894 template <typename Event>
896 
897  // we remove cache in opposite order to registration: it's a C++ tradition.
898  unsigned int const nRemoved = std::count_if(
899  fTrackers.crbegin(), fTrackers.crend(),
900  [](auto const& tracker){ return tracker->removeCachedProduct(); }
901  );
902 
904 
905  return nRemoved;
906 } // util::ArtHandleTrackerManager<Event>::removeCachedProducts()
907 
908 
909 // -----------------------------------------------------------------------------
910 template <typename Event>
912  { fTrackers.clear(); }
913 
914 
915 
916 
917 // -----------------------------------------------------------------------------
918 template <typename Event>
920  (bool removeCache /* = true */, art::Event const* event /* = nullptr */)
921 {
922  if (event && (fEvent != event)) return 0;
923 
924  unsigned int count = 0;
925  if (removeCache) count = removeCachedProducts();
926  else count = forgetAllHandles();
927 
928  fEvent = nullptr;
929 
930  return count;
931 } // util::ArtHandleTrackerManager<Event>::doneWithEvent()
932 
933 
934 // -----------------------------------------------------------------------------
935 template <typename Event>
936 template <typename Handle>
938  (Handle const& like) const
939 {
940 
941  // look for it, one by one
942  for (TrackerPtr const& tracker: fTrackers) {
943 
944 
945 
946  std::any anyHandlePtr = tracker->handlePtr();
947  Handle const** handlePtr = std::any_cast<Handle const*>(&anyHandlePtr);
948  if (!handlePtr) continue; // not the right type
949 
950  if ((*handlePtr)->provenance()->inputTag() != like.provenance()->inputTag())
951  continue; // different tag
952 
953  return *handlePtr;
954  } // for
955 
956  return nullptr; // failed
957 
958 } // util::ArtHandleTrackerManager<Event>::findTracker()
959 
960 
961 // -----------------------------------------------------------------------------
962 template <typename Event>
963 template <typename Handle>
965  (TrackerPtr tracker, Handle const& handle)
966 {
968 
969  if (!tracker) return false;
970  if (ProvenanceGetter<Handle>::productType() != tracker->productType())
971  return false;
972  if (ProvenanceGetter<Handle>::inputTag() != tracker->inputTag())
973  return false;
974 
975  return true;
976 } // util::ArtHandleTrackerManager<>::handleSameProduct()
977 
978 
979 // -----------------------------------------------------------------------------
980 template <typename Event>
982 
983  if (fEvent) return;
984 
985  throw art::Exception(art::errors::LogicError)
986  << "util::ArtHandleTrackerManager attempted an operation without a valid"
987  " event.\nThe operation was: " << where << "\n";
988 
989 } // util::ArtHandleTrackerManager<Event>::canOperate()
990 
991 
992 // -----------------------------------------------------------------------------
993 // --- util::LocalArtHandleTrackerManager
994 // -----------------------------------------------------------------------------
995 template <typename Event>
997  (Event const& event, bool removeCache /* = true */)
998  : fManager{ event }, fRemoveCache{ removeCache }
999  {}
1000 
1001 
1002 // -----------------------------------------------------------------------------
1003 template <typename Event>
1005  { doneWithEvent(); }
1006 
1007 
1008 // -----------------------------------------------------------------------------
1009 template <typename Event>
1011  {return fManager.nTrackedHandles(); }
1012 
1013 
1014 // -----------------------------------------------------------------------------
1015 template <typename Event>
1017  { return fRemoveCache; }
1018 
1019 
1020 // -----------------------------------------------------------------------------
1021 template <typename Event>
1022 template <typename T, typename... Args>
1024  (Args&&... args)
1025  { return fManager.template getHandle<T>(std::forward<Args>(args)...); }
1026 
1027 
1028 // -----------------------------------------------------------------------------
1029 template <typename Event>
1030 template <typename T, typename... Args>
1032  (Args&&... args)
1033  { return fManager.template getValidHandle<T>(std::forward<Args>(args)...); }
1034 
1035 
1036 // -----------------------------------------------------------------------------
1037 template <typename Event>
1038 template <typename Handle>
1040  (Handle&& handle) -> decltype(auto)
1041 {
1042  return fManager.template registerHandle<Handle>(std::forward<Handle>(handle));
1043 }
1044 
1045 
1046 // -----------------------------------------------------------------------------
1047 template <typename Event>
1049  (bool removeCache)
1050  { fRemoveCache = removeCache; }
1051 
1052 
1053 // -----------------------------------------------------------------------------
1054 template <typename Event>
1056  { return fManager.removeCachedProducts(); }
1057 
1058 
1059 // -----------------------------------------------------------------------------
1060 template <typename Event>
1062  { return fManager.forgetAllHandles(); }
1063 
1064 
1065 // -----------------------------------------------------------------------------
1066 template <typename Event>
1068  (bool removeCache)
1069 {
1070  assert(fManager.hasEvent());
1071 
1072  if (removeCache) return removeCachedProducts();
1073 
1074  forgetAllHandles();
1075  return 0;
1076 } // util::LocalArtHandleTrackerManager<Event>::doneWithEvent()
1077 
1078 
1079 // -----------------------------------------------------------------------------
1080 template <typename Event>
1082  { return doneWithEvent(willRemoveCachedProducts()); }
1083 
1084 
1085 // -----------------------------------------------------------------------------
1086 
1087 
1088 #endif // ICARUSCORE_UTILITIES_ARTHANDLETRACKERMANAGER_H
virtual std::type_info const * doProductType() const override
Returns the C++ type of the handled data product.
unsigned int nTrackedHandles() const
Returns the number of handles currently tracked.
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
Event Event_t
Type of data viewer object to operate with.
std::any handlePtr() const
Returns a container for a pointer to the managed handle. Caveat emptor.
bool fRemoveCache
Whether to remove cache on destructor.
unsigned int removeCachedProducts()
Clears the cached data products for all tracked handles.
~LocalArtHandleTrackerManager()
Destructor; will implement the RAII pattern (i.e. call doneWithEvent()).
ArtHandleTracker(Event const &event, Handle handle)
Constructor: records all the needed information.
art::ValidHandle< T > getValidHandle(Args &&...args)
Retrieves a valid handle from the event, and registers it.
Interface to facilitate the use of util::ArtHandleTracker specializations.
std::vector< TrackerPtr > fTrackers
List of managed handle trackers.
void forgetAllHandles()
Stops tracking any handle, without removing their cache first.
static art::InputTag inputTag(Handle const &handle)
virtual art::InputTag doInputTag() const override
static art::Provenance const * provenance(Handle const &handle)
Config_t const fConfig
Configuration.
void useEvent(Event_t const &event)
Changes the event being served.
bool hasEvent() const
Returns whether the object is associated to an event.
ArtHandleTrackerManager< Event > fManager
The actual manager doing the work.
static std::type_info const * productType()
Returns the C++ type of the handled data product.
std::unique_ptr< util::ArtHandleTrackerInterface< Event_t >> TrackerPtr
Type of pointer to any handle tracker.
virtual std::string doProductClass() const override
Returns the name of the class pointed by the handle.
art::Provenance const * provenance() const
Returns the provenance information of the handle.
art::ValidHandle< T > getValidHandle(Args &&...args)
Retrieves a valid handle from the event, and registers it.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
unsigned int doneWithEvent()
Completes the work on the associated event.
Manages handle trackers for an easy call of removeCachedProduct().
virtual std::any doHandlePtr() const override
Returns a pointer to the managed handle, wrapped in std::any.
decltype(auto) registerHandle(Handle &&handle)
Registers an existing handle.
LocalArtHandleTrackerManager(Event const &event, bool removeCache=true)
Constructor: operates on the specified event.
std::type_info const * productType() const
Returns the name of the class of handled data product.
static bool handleSameProduct(TrackerPtr tracker, Handle const &handle)
Returns whether tracker tracks the same product that handle handles.
static std::type_info const * productType(Handle const &)
Returns the C++ type of the handled data product.
std::string logCategory
Name of the output category for messages.
art::InputTag inputTag() const
Returns the tag of handled data product.
static std::string productClass(Handle const &handle)
Returns the name of the class pointed by the handle.
unsigned int doneWithEvent(bool removeCache=true, art::Event const *event=nullptr)
Completes the work on the associated event.
void canOperate(const char *where) const
Handle const * findHandle(Handle const &like) const
Returns the pointer to an handle equivalent to like.
art::Handle< T > getHandle(Args &&...args)
Retrieves an handle from the event, and registers it.
art::InputTag inputTagOf(Event const &event, art::ProductID const &productID)
Reads and returns the input tag of the producer of productID.
Definition: CanvasUtils.h:108
std::string productClassOf(Handle const &handle)
use candy
unsigned int nTrackedHandles() const
Returns the number of handles currently tracked.
art::InputTag inputTagOf(Handle const &handle)
void forgetAllHandles()
Stops tracking any handle, without removing their cache first.
Event_t const * fEvent
Event being manager. Must be present!
unsigned int removeCachedProducts()
Clears the cached data products for all tracked handles.
std::type_info const * productTypeOf(Handle const &handle)
ArtHandleTrackerManager(Config_t config={})
Constructs a handle manager.
then echo fcl name
decltype(auto) registerHandle(Handle &&handle)
Registers an existing handle.
std::size_t count(Cont const &cont)
art::Handle< T > getHandle(Args &&...args)
Retrieves an handle from the event, and registers it.
virtual bool doRemoveCachedProduct() override
Actually removes the cache.
std::string productClass() const
Returns the name of the class of handled data product.
void setRemoveCachedProducts(bool removeCache)
Sets whether to remove tracked data caches on destruction or not.
Variant of util::ArtHandleTrackerManager in local scope.
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
Handle const & handle() const
Returns the tracked handle.