withAssociated.h
Go to the documentation of this file.
1 /**
2  * @file lardata/RecoBaseProxy/ProxyBase/withAssociated.h
3  * @brief Functions to add associated data to a collection proxy.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date July 27, 2017
6  * @see lardata/RecoBaseProxy/ProxyBase.h
7  *
8  * This library is header-only. It provides two classes of functions:
9  *
10  * * `proxy::withAssociated()`: reads and parses an association from the event
11  * * `proxy::wrapAssociated()`: parses an already existing association object
12  *
13  */
14 
15 #ifndef LARDATA_RECOBASEPROXY_PROXYBASE_WITHASSOCIATED_H
16 #define LARDATA_RECOBASEPROXY_PROXYBASE_WITHASSOCIATED_H
17 
18 // LArSoft libraries
21 
22 // C/C++ standard libraries
23 #include <tuple>
24 #include <utility> // std::forward(), std::move()
25 
26 
27 namespace proxy {
28 
29  //----------------------------------------------------------------------------
30  namespace details {
31 
32  //--------------------------------------------------------------------------
33  /**
34  * @class WithAssociatedStruct
35  * @brief Helper to create associated data proxy.
36  * @tparam Aux type of data associated to the main one
37  * @tparam Metadata type of metadata of the association
38  * @tparam ArgTuple type of arguments required for the creation of proxy
39  * @tparam AuxTag tag for the associated data (default: as `Aux`)
40  * @ingroup LArSoftProxiesAssociatedData
41  *
42  * This class stores user arguments for the construction of a proxy to
43  * associated data of type `Aux` and with metadata `Metadata`.
44  * It can use that information plus some additional one to create the
45  * associated data itself. This additional information is provided by
46  * `getCollection()`.
47  *
48  * The association will be identified by type `AuxTag`.
49  *
50  * This is not a customization point: to have a custom associated data
51  * produced, specialize `proxy::AssociatedDataProxyMaker` class
52  */
53  template <
54  typename Aux, typename Metadata,
55  typename ArgTuple, typename AuxTag = Aux
56  >
57  using WithAssociatedStruct = WithAssociatedStructBase<
58  Aux,
59  Metadata,
60  ArgTuple,
61  AssociatedDataProxyMakerWrapper<Aux, Metadata, AuxTag>::template maker_t,
62  AuxTag
63  >;
64 
65  //--------------------------------------------------------------------------
66 
67  } // namespace details
68 
69 
70  // --- BEGIN One-to-many sequential associations -----------------------------
71  /**
72  * @name One-to-many sequential associations
73  *
74  * These functions allow to merge into a data collection proxy auxiliary data
75  * via an _art_ association fulfilling the
76  * @ref LArSoftProxyDefinitionOneToManySeqAssn "one-to-many sequential association requirement".
77  *
78  * Two categories of functions are available depending on the data source:
79  * * `proxy::withAssociated()` reads the relevant association from an event
80  * * `proxy::wrapAssociated()` uses an existing association objects
81  *
82  * Variants of `proxy::withAssociated()` called `proxy::withAssociatedMeta()`
83  * allow merging the metadata of an association too. The
84  * `proxy::wrapAssociated()` functions always merge the metadata if the
85  * wrapped association has it.
86  *
87  * Also, variants are available to customize the tag class.
88  *
89  * The implementation of this feature is documented in
90  * @ref LArSoftProxiesAssociatedData "its own doxygen module".
91  *
92  * @{
93  */
94 
95  //----------------------------------------------------------------------------
96  /**
97  * @brief Helper function to merge associated data with metadata.
98  * @tparam Aux type of associated data requested
99  * @tparam Metadata type of associated metadata requested
100  * @tparam AuxTag tag to access the associated data within the proxy
101  * @tparam Args types of constructor arguments for associated data collection
102  * @param args constructor arguments for the associated data collection
103  * @return a temporary object that `getCollection()` knows to handle
104  * @see `withAssociatedMeta()`, `withAssociatedMetaAs()`, `wrapAssociated()`
105  * @ingroup LArSoftProxyBase
106  *
107  * This function is similar to `withAssociated()`, but it also merges the
108  * specified metadata and defines a tag for the data.
109  * In this example we fetch from `event` an association between `recob::Track`
110  * (which is the @ref LArSoftProxyDefinitionMainDataColl "main type" of the
111  * collection proxy `proxy::Tracks`) and `recob::Cluster` objects, each one
112  * with an index as metadata:
113  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
114  * struct MyClusters {};
115  *
116  * void analyze(art::Event const& event) {
117  *
118  * // ...
119  * auto tracks = proxy::getCollection<proxy::Tracks>
120  * (event, trackTag, withAssociatedMetaAs<int, MyCluster>(clusterTag));
121  *
122  * // ...
123  * for (auto const& track: tracks) {
124  *
125  * auto const& clusters = track.get<MyCluster>();
126  *
127  * for (auto const& clusterInfo: clusters) {
128  *
129  * // implicit conversion:
130  * art::Ptr<recob::Cluster> const& clusterPtr = clusterInfo;
131  *
132  * // access to the cluster itself
133  * recob::Cluster const& cluster = *clusterInfo;
134  *
135  * // access to the metadata
136  * int index = clusterInfo.data();
137  *
138  * } // for clusters
139  *
140  * } // for tracks
141  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142  * The interface of `clusters` is documented in `lar::CollectionView`.
143  * The interface of `clusterInfo` is documented in
144  * `proxy::details::AssnsNode`.
145  *
146  * For more extensive information, see `proxy::withAssociatedMeta()`.
147  */
148  template <typename Aux, typename Metadata, typename AuxTag, typename... Args>
149  auto withAssociatedMetaAs(Args&&... args) {
150  using ArgTuple_t = std::tuple<Args&&...>;
151  ArgTuple_t argsTuple(std::forward<Args>(args)...);
153  (std::move(argsTuple));
154  } // withAssociatedMetaAs()
155 
156 
157  //----------------------------------------------------------------------------
158  /**
159  * @brief Helper function to merge associated data with no metadata.
160  * @tparam Aux type of associated data requested
161  * @tparam AuxTag tag to access the associated data within the proxy
162  * @tparam Args types of constructor arguments for associated data collection
163  * @param args constructor arguments for the associated data collection
164  * @return a temporary object that `getCollection()` knows to handle
165  * @see `withAssociatedMeta()`, `withAssociatedAs()`, `wrapAssociatedAs()`
166  * @ingroup LArSoftProxyBase
167  *
168  * This function is similar to `withAssociated()`, but it defines a tag for
169  * the data.
170  * In this example we fetch from `event` an association between `recob::Track`
171  * (which is the @ref LArSoftProxyDefinitionMainDataColl "main type" of the
172  * collection proxy `proxy::Tracks`) and `recob::Cluster` objects:
173  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
174  * struct MyClusters {};
175  *
176  * void analyze(art::Event const& event) {
177  *
178  * // ...
179  * auto tracks = proxy::getCollection<proxy::Tracks>
180  * (event, trackTag, withAssociatedAs<MyCluster>(clusterTag));
181  *
182  * // ...
183  * for (auto const& track: tracks) {
184  *
185  * auto const& clusters = track.get<MyCluster>();
186  *
187  * for (auto const& clusterInfo: clusters) {
188  *
189  * // implicit conversion:
190  * art::Ptr<recob::Cluster> const& clusterPtr = clusterInfo;
191  *
192  * // access to the cluster itself
193  * recob::Cluster const& cluster = *clusterInfo;
194  *
195  * } // for clusters
196  *
197  * } // for tracks
198  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
199  * The interface of `clusters` is documented in `lar::CollectionView`.
200  * The interface of `clusterInfo` is documented in
201  * `proxy::details::AssnsNode`.
202  *
203  * For more extensive information, see `proxy::withAssociatedMeta()`.
204  */
205  template <typename Aux, typename AuxTag, typename... Args>
206  auto withAssociatedAs(Args&&... args)
207  {
208  return withAssociatedMetaAs<Aux, void, AuxTag>
209  (std::forward<Args>(args)...);
210  }
211 
212 
213  //----------------------------------------------------------------------------
214  /**
215  * @brief Helper function to merge associated data.
216  * @tparam Aux type of associated data requested
217  * @tparam Metadata type of associated metadata requested
218  * @tparam Args types of constructor arguments for associated data collection
219  * @param args constructor arguments for the associated data collection
220  * @return a temporary object that `getCollection()` knows to handle
221  * @ingroup LArSoftProxyBase
222  * @see `withAssociated()`, `withAssociatedAs()`, `withAssociatedMetaAs()`
223  *
224  * This function is meant to convey to `getCollection()` function the request
225  * for the delivered collection proxy to carry
226  * @ref LArSoftProxyDefinitionAuxiliaryData "data from an association".
227  * This association _must_ fulfil the
228  * @ref LArSoftProxyDefinitionOneToManySeqAssn "one-to-many sequential association"
229  * requirement. The associated data is normally extracted from an _art_
230  * association `art::Assns<Main, Aux, Metadata>`, where `Main` is the
231  * @ref LArSoftProxyDefinitionMainDataColl "main type" of the proxy
232  * collection. If no metadata is required, `Metadata` can be set to `void`, or
233  * `withAssociated()` can be used instead.
234  *
235  * The function also transfers the information required to create a proxy to
236  * that auxiliary data.
237  *
238  * This data will be tagged with the type `Aux`. To use a different type as
239  * tag, use `withAssociatedAs()` or `withAssociatedMetaAs()` instead,
240  * specifying the tag as second template argument, e.g.:
241  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
242  * struct DubiousClusters {};
243  * auto tracks = proxy::getCollection<proxy::Tracks>(event, trackTag,
244  * withAssociatedMeta<recob::Cluster, void>(defaultClusterTag),
245  * withAssociatedMetaAs<recob::Cluster, void, DubiousClusters>
246  * (maybeClusterTag)
247  * );
248  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
249  * or, equivalently (because we asked for no metadata):
250  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
251  * struct DubiousClusters {};
252  * auto tracks = proxy::getCollection<proxy::Tracks>(event, trackTag,
253  * withAssociated<recob::Cluster>(defaultClusterTag),
254  * withAssociatedAs<recob::Cluster, DubiousClusters>(maybeClusterTag)
255  * );
256  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
257  * The first cluster association (`"defaultClusterTag"`) will be accessed by
258  * using the type `recob::Cluster` as tag, while the second one will be
259  * accessed by the `DubiousClusters` tag (which is better not be defined in a
260  * local scope):
261  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
262  * for (auto const& track: tracks) {
263  * auto const& clusters = track.get<recob::Clusters>();
264  * auto const& maybeClusters = track.get<DubiousClusters>();
265  * // ...
266  * }
267  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
268  * The full interface of `track` is documented in `lar::CollectionView`.
269  * The interface of `clusters` and `maybeClusters` is documented in
270  * `proxy::details::AssnsNode`.
271  *
272  *
273  * Customization of the association proxy
274  * =======================================
275  *
276  * To have a call like:
277  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
278  * auto tracks = getCollection<SpecialTracks>
279  * (event, tag, withAssociatedMeta<recob::Hit, void>(hitAssnTag, "special"));
280  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
281  * create something different than the standard association proxy, specialize
282  * `proxy::AssociatedDataProxyMaker`, e.g.:
283  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
284  * namespace proxy {
285  * template <>
286  * struct AssociatedDataProxyMaker
287  * <recob::Track, recob::Hit, void, SpecialTracks>
288  * : public AssociatedDataProxyMakerBase
289  * <recob::Track, recob::Hit, void, SpecialTracks>
290  * {
291  *
292  * template<typename Event, typename MainArgs>
293  * static auto make(
294  * Event const& event,
295  * MainArgs const&,
296  * art::InputTag assnTag,
297  * std::string quality
298  * )
299  * {
300  * ::SpecialTrackHitsProxy myAuxProxy;
301  * // ... make it, and make it right
302  * return myAuxProxy;
303  * }
304  *
305  * }; // struct AssociatedDataProxyMaker<..., SpecialTracks>
306  *
307  * } // namespace proxy
308  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
309  * (the `void` template type signifies the association has no metadata).
310  *
311  *
312  * Technical details
313  * ==================
314  *
315  * The main purpose of this function and the related `WithAssociatedStruct`
316  * class is to save the user from specifying the main type the auxiliary data
317  * is associated with, when using it as `getCollection()` argument:
318  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
319  * auto tracks = getCollection<proxy::Tracks>
320  * (event, tag, withAssociated<recob::Hit>(hitAssnTag));
321  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
322  * While parsing the `withAssociated()` argument (or any argument), the
323  * information of which is the proxy collection type (`proxy::Tracks` in the
324  * example) is not known. In principle, to fully define the association, two
325  * template arguments are needed, e.g.
326  * `withAssociated<recob::Track, recob::Hit>(hitAssnTag)`.
327  * The class `WithAssociatedStruct` holds the information of which associated
328  * type is requested (`recob::Hit`) and the information needed to create a
329  * proxy to such association (all arguments, here just `hitAssnTag`).
330  * The function `getCollection()` will have this object as argument, and when
331  * executing will be able to supply the missing information, that
332  * `recob::Track` is the main data product element we are associating to.
333  */
334  template <typename Aux, typename Metadata, typename... Args>
335  auto withAssociatedMeta(Args&&... args)
336  {
337  return withAssociatedMetaAs<Aux, Metadata, Aux>
338  (std::forward<Args>(args)...);
339  }
340 
341 
342  /**
343  * @brief Helper function to merge associated data with no metadata.
344  * @tparam Aux type of associated data requested
345  * @tparam Args types of constructor arguments for associated data collection
346  * @param args constructor arguments for the associated data collection
347  * @return a temporary object that `getCollection()` knows to handle
348  * @see `withAssociatedMeta()`, `withAssociatedMetaAs()`, `wrapAssociated()`
349  * @ingroup LArSoftProxyBase
350  *
351  * This function is equivalent to `withAssociatedMeta()` but with the request
352  * of no associated metadata (`Metadata` be `void`). Example of usage:
353  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
354  * auto tracks = proxy::getCollection<proxy::Tracks>
355  * (event, trackTag, withAssociated<recob::Cluster>(clusterTag));
356  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
357  * The cluster association (`"clusterTag"`) will be accessed by
358  * using the type `recob::Cluster` as tag:
359  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
360  * for (auto const& track: tracks) {
361  *
362  * auto const& clusters = track.get<recob::Cluster>();
363  *
364  * for (art::Ptr<recob::Cluster> const& cluster: clusters) {
365  *
366  * // ...
367  *
368  * } // for clusters
369  *
370  * } // for tracks
371  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
372  * The interface of `clusters` is documented in `lar::CollectionView`.
373  * The interface of `cluster` is documented in `proxy::details::AssnsNode`.
374  *
375  * For more extensive information, see `proxy::withAssociatedMeta()`.
376  */
377  template <typename Aux, typename... Args>
378  auto withAssociated(Args&&... args)
379  { return withAssociatedMeta<Aux, void>(std::forward<Args>(args)...); }
380 
381 
382  //----------------------------------------------------------------------------
383  /**
384  * @brief Helper function to merge associated data from a given association.
385  * @tparam AuxTag tag to access the associated data within the proxy
386  * @tparam Assns type of the association being merged;
387  * needs `art::Assns` interface
388  * @param assns the association being merged
389  * @return a temporary object that `getCollection()` knows to handle
390  * @see `withAssociatedMeta()`, `withAssociatedMetaAs()`, `wrapAssociated()`
391  * @ingroup LArSoftProxyBase
392  *
393  * This function instructs the proxy to use the specified association `assns`
394  * directly. The specified association `assns` must remain valid for all the
395  * lifetime of the proxy.
396  *
397  * If `Assns` contains metadata, that is also merged into the proxy.
398  *
399  * Usage example:
400  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
401  * struct Clusters {};
402  *
403  * void checkClusters
404  * (art::Assns<recob::Track, recob::Cluster> const& clusters)
405  * {
406  * auto tracks = proxy::getCollection<proxy::Tracks>
407  * (event, trackTag, wrapAssociatedAs<::Clusters>(clusters));
408  *
409  * for (auto const& track: tracks) {
410  *
411  * auto const& clusters = track.get<::Clusters>();
412  *
413  * for (art::Ptr<recob::Cluster> const& cluster: clusters) {
414  *
415  * // ...
416  *
417  * } // for clusters
418  *
419  * } // for tracks
420  *
421  * } // checkClusters()
422  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
423  * For more extensive information, see `proxy::withAssociatedMeta()`.
424  */
425  template <typename AuxTag, typename Assns>
426  auto wrapAssociatedAs(Assns const& assns)
427  {
428  using Aux_t = typename Assns::right_t;
429  using Metadata_t = lar::util::assns_metadata_t<Assns>;
430  return
432  ({});
433  } // wrapAssociatedAs()
434 
435 
436  /**
437  * @brief Helper function to merge associated data from a given association.
438  * @tparam Assns type of the association being merged;
439  * needs `art::Assns` interface
440  * @param assns the association being merged
441  * @return a temporary object that `getCollection()` knows to handle
442  * @see `withAssociatedMeta()`, `wrapAssociatedAs()`
443  * @ingroup LArSoftProxyBase
444  *
445  * This function instructs the proxy to use the specified association `assns`
446  * directly. The specified association `assns` must remain valid for all the
447  * lifetime of the proxy.
448  *
449  * The difference with `wrapAssociated()` is only that the tag is implicitly
450  * assigned to be the one of the associated data.
451  *
452  * If `Assns` contains metadata, that is also merged into the proxy.
453  *
454  * Usage example:
455  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
456  * void checkClusters
457  * (art::Assns<recob::Track, recob::Cluster> const& clusters)
458  * {
459  * auto tracks = proxy::getCollection<proxy::Tracks>
460  * (event, trackTag, wrapAssociated(clusters));
461  *
462  * for (auto const& track: tracks) {
463  *
464  * auto const& clusters = track.get<recob::Cluster>();
465  *
466  * for (art::Ptr<recob::Cluster> const& cluster: clusters) {
467  *
468  * // ...
469  *
470  * } // for clusters
471  *
472  * } // for tracks
473  *
474  * } // checkClusters()
475  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
476  * For more extensive information, see `proxy::withAssociatedMeta()`.
477  */
478  template <typename Assns>
479  auto wrapAssociated(Assns const& assns)
480  { return wrapAssociatedAs<typename Assns::right_t>(assns); }
481 
482 
483  /**
484  * @brief Helper function to merge associated data from a given association.
485  * @tparam AuxTag tag to access the associated data within the proxy
486  * @tparam Assns type of the association being merged;
487  * needs `art::Assns` interface
488  * @param assns the association being merged
489  * @return a temporary object that `getCollection()` knows to handle
490  * @see `withAssociatedMeta()`, `wrapAssociatedAs()`
491  * @ingroup LArSoftProxyBase
492  *
493  * This function instructs the proxy to use the specified association `assns`
494  * directly. It is fully equivalent to `proxy::wrapAssociatedAs()`.
495  */
496  template <typename AuxTag, typename Assns>
497  auto wrapAssociated(Assns const& assns)
498  { return wrapAssociatedAs<AuxTag>(assns); }
499 
500  //----------------------------------------------------------------------------
501 
502 } // namespace proxy
503 
504 
505 #endif // LARDATA_RECOBASEPROXY_PROXYBASE_WITHASSOCIATED_H
Helper to create associated data proxy.
auto withAssociated(Args &&...args)
Helper function to merge associated data with no metadata.
auto withAssociatedMetaAs(Args &&...args)
Helper function to merge associated data with metadata.
typename assns_metadata_type< Assns >::type assns_metadata_t
Trait: type of metadata in Assns (association or its node).
Definition: AssnsTraits.h:62
static QCString args
Definition: declinfo.cpp:674
Infrastructure to add associated data to a collection proxy.
Helper to create associated data proxy.
def move(depos, offset)
Definition: depos.py:107
auto wrapAssociatedAs(Assns const &assns)
Helper function to merge associated data from a given association.
auto withAssociatedMeta(Args &&...args)
Helper function to merge associated data.
auto withAssociatedAs(Args &&...args)
Helper function to merge associated data with no metadata.
Template class to declare addition of associated data to a proxy.
auto wrapAssociated(Assns const &assns)
Helper function to merge associated data from a given association.