All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AssociatedData.h
Go to the documentation of this file.
1 /**
2  * @file lardata/RecoBaseProxy/ProxyBase/AssociatedData.h
3  * @brief Auxiliary data from one-to-many sequential association.
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.
9  */
10 
11 #ifndef LARDATA_RECOBASEPROXY_PROXYBASE_ASSOCIATEDDATA_H
12 #define LARDATA_RECOBASEPROXY_PROXYBASE_ASSOCIATEDDATA_H
13 
14 // LArSoft libraries
18 #include "lardata/Utilities/TupleLookupByTag.h" // util::add_tag_t, ...
19 #include "larcorealg/CoreUtils/MetaUtils.h" // util::is_not_same<>
20 
21 // framework libraries
22 #include "canvas/Persistency/Common/Assns.h"
23 #include "canvas/Persistency/Common/Ptr.h"
24 
25 // C/C++ standard libraries
26 #include <vector>
27 // #include <tuple> // std::tuple_element_t<>, std::get()
28 #include <iterator> // std::distance(), std::forward_iterator_tag, ...
29 #include <algorithm> // std::min()
30 #include <memory> // std::addressof()
31 #include <utility> // std::forward(), std::declval(), ...
32 #include <type_traits> // std::is_same<>, std::enable_if_t<>, ...
33 #include <cstdlib> // std::size_t
34 #include <cassert>
35 
36 
37 namespace proxy {
38 
39 
40  //----------------------------------------------------------------------------
41  /**
42  * @ingroup LArSoftProxiesAssociatedData
43  * @{
44  */
45 
46  //----------------------------------------------------------------------------
47  namespace details {
48 
49  //--------------------------------------------------------------------------
50  //--- general infrastructure
51  //--------------------------------------------------------------------------
52 
53  /**
54  * @brief Simple iterator wrapper for manipulation of dereferenced result.
55  * @tparam Iter final iterator
56  * @tparam BaseIter base iterator
57  * @tparam ValueType type returned by the new dereference operator
58  *
59  * This class is designed to be used as base class for an iterator that
60  * redefines the dereference operations without changing anything else.
61  * An example of such iterator is:
62  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
63  * using int_iterator_t = std::vector<int>::const_iterator;
64  *
65  * class twice_iterator
66  * : public IteratorWrapperBase<twice_iterator, int_iterator_t, float>
67  * {
68  * using base_iterator_t
69  * = IteratorWrapperBase<twice_iterator, int_iterator_t, float>;
70  *
71  * public:
72  *
73  * using base_iterator_t::base_iterator_t; // inherit constructors
74  *
75  * float operator*() const -> decltype(auto)
76  * { return 2.0F * base_iterator_t::operator*(); }
77  *
78  * }; // twice_iterator
79  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
80  * This new iterator `twice_iterator` effectively inherits `int_iterator_t`
81  * constructors (via `base_iterator_t`). Its `operator++()` returns a
82  * `twice_iterator`, so that operations like `*++it` are correctly handled.
83  *
84  * Note that the derived classes need to redefine all the dereferencing
85  * operators that are supported:
86  *
87  * * operator*()
88  *
89  * The `operator->()` is not supported. Typically, `operator*()` returns a
90  * reference and `operator->()` a pointer to an existing structure.
91  * The `operator*()` is not required to return a reference when the iterator
92  * does not allow to modify the pointed data, and the wrapper can manipulate
93  * values and return temporary results. To have a similar feature for
94  * `operator->()` requires more work, as it should return a smart pointer
95  * that would perform the transformation on dereference.
96  *
97  */
98  template <
99  typename Iter,
100  typename DataIter,
101  typename ValueType = typename DataIter::value_type
102  >
103  class IteratorWrapperBase: private DataIter {
104  protected:
105  using data_iterator_t = DataIter;
106 
107  public:
108  using iterator = Iter; ///!< The type of base iterator wrapper.
109 
110  /// @{
111  /// @name Iterator traits
112  using typename data_iterator_t::difference_type;
114  using pointer = std::add_pointer_t<value_type>;
115  using reference = std::add_lvalue_reference_t<value_type>;
116  using iterator_category = std::forward_iterator_tag;
117  /// @}
118 
119  /// Default constructor: default-constructs the underlying iterator.
120  IteratorWrapperBase() = default;
121 
122  /// Copy-from-base constructor.
124 
125  /// Prefix increment operator.
127  { data_iterator_t::operator++(); return asIterator(); }
128 
129  /// Comparison with a data iterator (makes unnecessary to wrap end iterators).
130  bool operator!=(data_iterator_t const& other) const
131  { return other != asDataIterator(); }
132 
133  /// Comparison with another iterator.
134  bool operator!=(iterator const& other) const
135  { return operator!=(other.asDataIterator()); }
136 
137  auto operator[](std::size_t index) const -> decltype(auto)
138  { return asIterator().transform(asDataIterator() + index); }
139 
140  /// Dereference operator; need to be redefined by derived classes.
141  auto operator*() const -> decltype(auto)
142  { return asIterator().transform(asDataIterator()); }
143 
144  /// Dereference operator; need to be redefined by derived classes.
145  auto operator->() const -> decltype(auto)
146  { return makeValuePointer(operator*()); }
147 
148 
149  protected:
150  /// Transforms and returns the value at the specified data iterator.
151  static auto transform(data_iterator_t const&) -> decltype(auto)
152  { return data_iterator_t::operator*(); }
153 
155  { return static_cast<data_iterator_t const&>(*this); }
156 
157  private:
158  /// Value box for use with pointer dereference `operator->()`.
159  template <typename Value>
160  class ValuePtr {
161  Value value; ///< Value to return the address of (may be reference).
162  public:
163  ValuePtr(Value const& value): value(value) {}
164  /// Access the contained value via its pointer.
165  auto operator->() const -> decltype(auto)
166  { return std::addressof(value); }
167  }; // class ValuePtr<>
168  template <typename Value>
169  static ValuePtr<Value> makeValuePointer(Value&& value)
170  { return { std::forward<Value>(value) }; }
171 
172  iterator const& asIterator() const
173  { return static_cast<iterator const&>(*this); }
174  iterator& asIterator() { return static_cast<iterator&>(*this); }
175 
176  }; // IteratorWrapperBase<>
177 
178 #if 0
179 
180  /// Modified iterator returning the `N`-th element out of the pointed tuple.
181  template <std::size_t N, typename TupleIter>
182  class tuple_element_iterator:
183  public IteratorWrapperBase<
184  tuple_element_iterator<N, TupleIter>,
185  TupleIter,
186  std::tuple_element_t<N, typename TupleIter::value_type>
187  >
188  {
189  using base_iterator_t = IteratorWrapperBase<
190  tuple_element_iterator<N, TupleIter>,
191  TupleIter,
192  std::tuple_element_t<N, typename TupleIter::value_type>
193  >;
194 
195  public:
196  using base_iterator_t::base_iterator_t;
197 
198  /// Constructor from a base iterator (explicitly allowed).
199  tuple_element_iterator(base_iterator_t const& from)
200  : base_iterator_t(from) {}
201 
202  static auto transform(TupleIter const& v) -> decltype(auto)
203  {return std::get<N>(*v); }
204 
205  }; // tuple_element_iterator
206 
207 #endif // 0
208  //--------------------------------------------------------------------------
209  //--- BEGIN iterators for art::Assns
210  //--------------------------------------------------------------------------
211 
212  //--------------------------------------------------------------------------
213 
214  /// This type extends the interface of the art pointer to Assns right side.
215  template <typename ArtAssnsIterValue>
216  class AssnsNode: private ArtAssnsIterValue {
217 
218  using base_t = ArtAssnsIterValue; ///< Base class type.
219  using this_t = AssnsNode<ArtAssnsIterValue>; ///< This class.
220  using node_t = ArtAssnsIterValue; ///< Type of the wrapped node.
221 
222  /// Set of traits of the node.
224 
225  public:
226 
227  /// Type of the main (left) object in the association.
228  using main_t = typename assns_node_traits_t::left_t;
229 
230  /// Type of the associated (right) object.
231  using value_t = typename assns_node_traits_t::right_t;
232 
233  /// Type of the associated additional data (`void` if none).
234  using data_t = typename assns_node_traits_t::data_t;
235 
236  /// Type of _art_ pointer to the main (left) object in the association.
237  using mainptr_t = typename assns_node_traits_t::leftptr_t;
238 
239  /// Type of _art_ pointer to the associated (right) object.
240  using valueptr_t = typename assns_node_traits_t::rightptr_t;
241 
242  /// Type of the pointer to associated additional data.
243  using dataptr_t = typename assns_node_traits_t::dataptr_t;
244 
245  /// @{
246  /// @name Access to the associated (right) value
247 
248  /// Returns the _art_ pointer to the associated value.
249  valueptr_t const& valuePtr() const { return base_t::second; }
250 
251  /// Returns a reference to the associated value.
252  value_t const& value() const { return *valuePtr(); }
253 
254  /// @}
255 
256  /// @{
257  /// @name Access to the key (left) value
258 
259  /// Returns the _art_ pointer to the main value, key of the association.
260  mainptr_t const& mainPtr() const { return base_t::first; }
261 
262  /// Returns the main value, key of the association.
263  main_t const& main() const { return *mainPtr(); }
264 
265  /// @}
266 
267  /// @{
268  /**
269  * @name Metadata access
270  *
271  * The complete interface is available only if the association has
272  * metadata. Otherwise, only the static member `hasMetadata()` is
273  * available.
274  */
275 
276  // the templates are needed to activate "SFINAE" on std::enable_if
277  /// Returns whether this node type supports metadata.
278  template <typename Node = node_t>
279  static constexpr bool hasMetadata()
280  { return lar::util::assns_has_metadata_v<Node>; }
281 
282  /// Returns the pointer to the metadata on this association node.
283  template <typename Node = node_t>
284  std::enable_if_t<hasMetadata<Node>(), dataptr_t> dataPtr() const
285  { return base_t::data; }
286 
287  // this is even more complicate, since if `data_t` is void we can't write
288  // `data_t const&` as type of enable_if, because it does not depend on
289  // templates and therefore it may be unconditionally evaluated;
290  // and C++ does not like references to `void`...
291  /// Returns a reference to the metadata on this association node.
292  template <typename Node = node_t>
294  hasMetadata<Node>(),
296  >
297  data() const { return *dataPtr(); }
298 
299  /// @}
300 
301 
302  /// @{
303  /// @name Interface to the art pointer to the associated (right) value
304 
305  /// Implicit conversion to _art_ pointer of the associated object.
306  operator valueptr_t const& () const& { return valuePtr(); }
307 
308  /// Implicit conversion to _art_ pointer of the associated object.
309  operator valueptr_t() const&& { return valuePtr(); }
310 
311  /// Returns a reference to the associated value (alias of `value()`).
312  value_t const& operator*() const { return value(); }
313 
314  /// Returns the associated value (alias of `valuePtr()`).
315  valueptr_t operator-> () const { return valuePtr(); }
316 
317  /// Returns the key of the _art_ pointer to the value.
318  auto key() const -> decltype(auto) { return valuePtr().key(); }
319 
320  /// Returns the product ID of the _art_ pointer to the value.
321  auto id() const -> decltype(auto) { return valuePtr().id(); }
322  /// @}
323 
324 
325  /// Reinterprets the specified association node as a `AssnsNode`.
326  static this_t const& makeFrom(node_t const& from)
327  { return static_cast<this_t const&>(from); }
328 
329  }; // class AssnsNode<>
330 
331 
332  template <typename ArtAssnsIterValue>
336  )
337  { return A.valuePtr() == B; }
338  template <typename ArtAssnsIterValue>
342  )
343  { return A == B.valuePtr(); }
344  template <typename ArtAssnsIterValue>
348  )
349  { return A.valuePtr() != B; }
350  template <typename ArtAssnsIterValue>
354  )
355  { return A != B.valuePtr(); }
356 
357 
358  /// Reinterprets the specified association node as a `AssnsNode`.
359  template <typename ArtAssnsIterValue>
360  AssnsNode<ArtAssnsIterValue> const& makeAssnsNode(ArtAssnsIterValue const& from)
362 
363  } // namespace details
364 } // namespace proxy
365 
366 // we interrupt this namespace for an urgent specialization...
367 namespace lar {
368  namespace util {
369 
370  // specialization for the art node wrapper
371  template <typename ArtAssnsIterValue>
372  struct assns_metadata_type<proxy::details::AssnsNode<ArtAssnsIterValue>>
373  : assns_metadata_type<ArtAssnsIterValue>
374  {};
375 
376  } // namespace util
377 } // namespace lar
378 
379 // back to what we were doing:
380 namespace proxy {
381  namespace details{
382 
383  //--------------------------------------------------------------------------
384  /// Traits for a association iterator.
385  template <typename ArtAssnsIter>
387  : public lar::util::assns_traits<typename ArtAssnsIter::value_type>
388  {
389  using art_node_t = typename ArtAssnsIter::value_type;
391  }; // struct AssnsIterTraits
392 
393 
394  /// Modified iterator returning a association node interface.
395  /// The basic iterator interface is to the associated (right) _art_ pointer.
396  template <typename ArtAssnsIter>
398  public IteratorWrapperBase<
399  assns_node_iterator<ArtAssnsIter>,
400  ArtAssnsIter,
401  typename AssnsIterTraits<ArtAssnsIter>::node_t
402  >
403  {
406  ArtAssnsIter,
408  >;
409 
410  using art_assns_iter_t = ArtAssnsIter;
412 
413  /// Type of node for this association iterator.
414  using AssnsNode_t = typename traits_t::node_t;
416 
417  public:
418  using base_iterator_t::base_iterator_t;
419 
420  /// Constructor from a base iterator (explicitly allowed).
422  : base_iterator_t(from) {}
423 
424  /// Returns the full information the iterator points to.
425  AssnsNode_t const& info() const { return base_iterator_t::operator*(); }
426 
427  /// Returns the full information the iterator points to.
428  AssnsNode_t const& operator() () const { return info(); }
429 
430  //--- BEGIN Access to the full association information -------------------
431  /// @name Access to the full association information
432  /// This interface is a replica of the one of `AssnsNode_t`.
433  /// @{
434 
435  using main_t = typename AssnsNode_t::main_t;
436  using value_t = typename AssnsNode_t::value_t;
437  using data_t = typename AssnsNode_t::data_t;
438  using mainptr_t = typename AssnsNode_t::mainptr_t;
439  using valueptr_t = typename AssnsNode_t::valueptr_t;
440  using dataptr_t = typename AssnsNode_t::dataptr_t;
441 
442  /// Returns the _art_ pointer to the associated value.
443  valueptr_t valuePtr() const { return info().valuePtr(); }
444 
445  /// Returns the _art_ pointer to the associated value.
446  value_t const& value() const { return info().value(); }
447 
448  /// Returns the _art_ pointer to the main value, key of the association.
449  mainptr_t mainPtr() const { return info().mainPtr(); }
450 
451  /// Returns the main value, key of the association.
452  main_t const& main() const { return info().main(); }
453 
454  // see the comments on AssnsNode for the need of all these decorations
455  /// Returns whether this node type supports metadata.
456  template <typename Node = AssnsNode_t>
457  static constexpr bool hasMetadata()
458  { return lar::util::assns_has_metadata_v<Node>; }
459 
460  /// Returns the pointer to the metadata on this association node.
461  template <typename ArtNode = ArtAssnsNode_t>
462  std::enable_if_t<hasMetadata<ArtNode>(), dataptr_t> dataPtr() const
463  { return info().dataPtr(); }
464 
465  /// Returns a reference to the metadata on this association node.
466  template <typename ArtNode = ArtAssnsNode_t>
468  hasMetadata<ArtNode>(),
470  >
471  data() const
472  { return info().data(); }
473 
474  /// @}
475  //--- END Access to the full association information ---------------------
476 
477  /*
478  * Associations with metadata have an iterator with value type
479  * art::AssnsNode, while the value for the ones without have just a
480  * std::pair.
481  * The std::pair returned by the one without metadata is a reference to an
482  * element of the original collection.
483  * Instead, the art::AssnsNode returned by the art::Assns iterator is a
484  * temporary put together copying information from the original pair
485  * collection and from the parallel metadata collection.
486  * Therefore, in the first case we can return references to the existing
487  * data, while in the latter we can't and we have to return the results by
488  * value.
489  * In this implementation we compromise and return always the data by
490  * value; the values are art pointers, or plain pointers, so the copy
491  * should not be extremely taxing. It is possible to change this, at the
492  * cost of additional complexity of the implementation.
493  */
494  static AssnsNode_t const& transform(art_assns_iter_t const& v)
495  { return makeAssnsNode(*v); }
496 
497  }; // class assns_node_iterator<>
498 
499  //--- END iterators for art::Assns -----------------------------------------
500 
501 
502  //--------------------------------------------------------------------------
503  //--- stuff for associated data (a form of auxiliary data)
504  //--------------------------------------------------------------------------
505 
506  /// Interface providing begin and end iterator of a range.
507  /// @tparam BoundaryIter iterator to the first of the range iterators.
508  template <typename BoundaryIter>
509  class BoundaryListRangeBase: private BoundaryIter {
510  using boundary_iterator_t = BoundaryIter;
511 
512  /// Returns the iterator to the begin iterator.
513  auto boundaryIter() const
514  { return static_cast<BoundaryIter const&>(*this); }
515 
516  public:
517  /// Constructor: copies the specified base iterator.
519  : boundary_iterator_t(it) {}
520 
521  /// Returns the begin iterator of the range.
522  auto begin() const -> decltype(auto)
523  { return *(boundaryIter()); }
524 
525  /// Returns the end iterator of the range (next to the begin iterator).
526  auto end() const -> decltype(auto)
527  { return *(std::next(boundaryIter())); }
528 
529  }; // BoundaryListRangeBase<>
530 
531 
532  /// A `BoundaryListRangeBase` with a full container interface.
533  template <typename BoundaryIter>
535  : public lar::CollectionView<BoundaryListRangeBase<BoundaryIter>>
536  {
537  // A CollectionView can't be constructed except from deriver classes;
538  // we define here such a class.
539 
542  public:
543  using boundary_iterator_t = BoundaryIter;
544 
545  /// Constructor: from an iterator to the begin iterator.
547  : base_t(rangebase_t(iBegin))
548  {}
549 
550  }; // class BoundaryListRange<>
551 
552 
553  /**
554  * @brief Reinterprets a iterator to boundaries list as a range collection.
555  * @tparam BoundaryIter type of iterator to boundary collection
556  * @param iBegin iterator to the begin iterator of a range
557  * @return a collection view (`lar::CollectionView`) of the range
558  *
559  * A range is conceptually defined as a sequence of data between a begin and
560  * and end iterator.
561  * The argument of this function is an iterator to the begin iterator of the
562  * range. The begin iterator itself is obtained by dereferencing the
563  * argument: `*iBegin`. The end iterator of the range is required to be
564  * immediately after the begin iterator (@code *std::next(iBegin) @endcode).
565  * This pair of iterators is exposed via the `lar::CollectionView` view,
566  * that presents a vector-like interface.
567  * For this to fully work, the data iterators (e.g., `*iBegin`) must comply
568  * with the random-access iterator requirements.
569  *
570  * An example of `BoundaryIter` is the iterator to the list of boundaries
571  * in `BoundaryList`: `BoundaryList::boundaries_t::const_iterator`.
572  */
573  template <typename BoundaryIter>
574  BoundaryListRange<BoundaryIter> makeBoundaryListRange
575  (BoundaryIter const& iBegin)
576  { return { iBegin }; }
577 
578 
579  /**
580  * @brief Iterator exposing elements of a boundary list as ranges.
581  * @tparam BoundaryIter type of iterator to boundary iterators
582  *
583  * This iterator wraps an iterator (`BoundaryIter`) to a sequence of
584  * iterators representing ranges of data.
585  * As an example, let the data be a collection of real numbers:
586  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
587  * std::vector<float> data;
588  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
589  * and we have a list of iterators that define subranges within that data:
590  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
591  * using data_iterator_t = std::vector<data>::const_iterator;
592  * std::vector<data_iterator_t> rangeStart;
593  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
594  * Here `rangeStart` holds the begin iterator of each of the subranges,
595  * plus a "global" end iterator, as in the convention described in
596  * `lar::makeBoundaryListRange()` (which takes an iterator to `rangeStart`
597  * as argument).
598  * The `BoundaryIter` type in this example would be
599  * @code std::vector<data_iterator_t>::const_iterator @endcode.
600  *
601  * When dereferenced, this iterator returns a view of the range currently
602  * pointed. This view has a STL-vector-like interface (again, see
603  * `lar::makeBoundaryListRange()`).
604  */
605  template <typename BoundaryIter>
607  : public IteratorWrapperBase
608  <BoundaryListRangeIterator<BoundaryIter>, BoundaryIter>
609  {
612 
613  public:
614  using boundary_iterator_t = BoundaryIter; ///< Type of boundary iterator.
615 
616  /// Type of range returned when dereferencing.
617  using rangeview_t
618  = decltype(makeBoundaryListRange(std::declval<boundary_iterator_t>()));
619 
621  using pointer = std::add_pointer_t<std::decay_t<value_type>>;
622  using reference = std::add_lvalue_reference_t<std::decay_t<value_type>>;
623 
624 
625  using base_t::base_t; // import constructors (explicitly allowed)
626 
627  /**
628  * @brief Returns the pointed range.
629  * @return the pointed range, as a view
630  *
631  * The returned value may be a view object, that is a pure interface
632  * overlaid on a different data structure.
633  * As such, it may be not copiable and need to be propagated by reference.
634  */
635  static auto transform(BoundaryIter const& iter)
636  { return makeBoundaryListRange(iter); }
637 
638  }; // class BoundaryListRangeIterator<>
639 
640 
641  /**
642  * @brief Builds and keeps track of internal boundaries in a sequence.
643  * @tparam Iter type of iterators to the original sequence
644  *
645  * This class manages a sequence of boundary iterators defining the
646  * beginning of contiguous subsequences. Each iterator marks the begin of a
647  * subsequence, whose end is marked by the beginning of the next one.
648  * The last iterator in the boundary list marks the end of the last
649  * subsequence, but it does not mark the beginning of a following one.
650  * Therefore, for a list of _N_ subsequences there will be _N + 1_ boundary
651  * iterators in the list: _N_ marking the beginning of the respective
652  * subsequences, plus another marking the end of the last subsequence.
653  *
654  * It is likely that the first iterator in the boundary list is the begin
655  * iterator of the underlying sequence (usually a container) being
656  * partitioned, while the last one is the end iterator of that sequence.
657  *
658  * This is a data class which does not contain any logic to define the
659  * subsequences, but rather acquires the result of an algorithm which is
660  * expected to have established which the boundaries are.
661  *
662  * The underlying representation of the class is a random-access sequence
663  * of boundaries. The exposed value, `range_t`, is a range of data elements
664  * (a view with the interface of a random access container), which is
665  * internally represented as a single iterator pointing to the begin
666  * iterator of the range.
667  */
668  template <typename Iter>
669  class BoundaryList {
671  public:
672  using data_iterator_t = Iter;
673  using boundaries_t = std::vector<data_iterator_t>;
674 
675  /// Iterator on the ranges contained in the collection.
676  using range_iterator_t
678 
679  /// Structure holding begin and end iterator for a single range.
680  // BoundaryListRange<data_iterator_t> const&
682 
683  /// Range object directly containing the boundary iterators.
685 
686 
687  /// Constructor: steals the specified boundary list.
688  explicit BoundaryList(boundaries_t&& boundaries)
689  : boundaries(std::move(boundaries))
690  { assert(this->boundaries.size() >= 1); }
691 
692  /// Returns the number of ranges contained in the list.
693  std::size_t nRanges() const
694  { return boundaries.size() - 1; }
695  /// Returns the begin iterator of the `i`-th range (end if overflow).
696  data_iterator_t const& rangeBegin(std::size_t i) const
697  { return boundaries[std::min(i, nRanges())]; }
698  /// Returns the end iterator of the `i`-th range (end if overflow).
699  data_iterator_t const& rangeEnd(std::size_t i) const
700  { return rangeBegin(i + 1); }
701 
702  /// Returns the number of ranges contained in the list.
703  std::size_t size() const { return nRanges(); }
704  /// Returns the begin iterator of the first range.
706  { return { boundaries.begin() }; }
707  /// Returns the end iterator of the last range.
709  { return { std::prev(boundaries.end()) }; }
710  /**
711  * @brief Returns the specified range.
712  * @param i index of the range to be returned
713  * @return a proxy object with container interface
714  * @see `range()`
715  *
716  * The returned object exposes the range as a random access container
717  * interface.
718  *
719  * Internally, it refers to the relevant information from this
720  * `BoundaryList` object, and therefore it becomes invalid when this
721  * `BoundaryList` object is destroyed.
722  * If this is not acceptable, use `range()` instead.
723  */
724  range_ref_t rangeRef(std::size_t i) const
725  { return { std::next(boundaries.begin(), i) }; }
726  /**
727  * @brief Returns the specified range in an object holding the iterators.
728  * @param i index of the range to be returned
729  * @return a new object with container interface
730  * @see `rangeRef()`
731  *
732  * The returned object contains copies of the begin and end iterators of
733  * the range. This object is self-contained and valid even after this
734  * BoundaryList object is destroyed.
735  *
736  * Note the content of the range itself is _not_ copied: just the boundary
737  * iterators of the range are.
738  */
739  range_t range(std::size_t i) const
740  { return lar::makeCollectionView(rangeBegin(i), rangeEnd(i)); }
741 
742  /// Returns the begin iterator of the `i`-th range (unchecked).
743  /// @see `range()`
744  auto operator[](std::size_t i) const -> decltype(auto)
745  { return range(i); }
746 
747  private:
748  /// Begin iterator of each range, plus end iterator of whole sequence.
750 
751  }; // class BoundaryList
752 
753 
754  /**
755  * @brief Object to draft associated data interface.
756  * @tparam Main type of the main associated object (one)
757  * @tparam Aux type of the additional associated objects (many)
758  * @tparam Metadata type of metadata in the association (default: `void`)
759  * @tparam Tag tag this data is labeled with
760  *
761  * Allows:
762  * * random access (no index check guarantee)
763  * * forward iteration
764  *
765  * Construction is not part of the interface.
766  *
767  * The `AssociatedData` object, on creation, finds the borders surrounding
768  * the associated `Aux` objects for each `Main` one, and keep a record of
769  * them (this is actually delegated to `BoundaryList` class).
770  * The `AssociatedData` object also provides a container-like view of this
771  * information, where each element in the container is associated to a
772  * single `Main` and it is a container (actually, another view) of `Right`.
773  * Both levels of containers are random access, so that the set of `Right`
774  * objects associated to a `Left` can be accessed by index, and the `Right`
775  * objects within can be accessed with `Right` index in the `Left`.
776  */
777  template <
778  typename Main, typename Aux, typename Metadata /* = void */,
779  typename Tag /* = Aux */
780  >
783 
784  public:
785  /// Type of _art_ association.
786  using assns_t = art::Assns<Main, Aux, Metadata>;
787 
788  private:
791  // = tuple_element_iterator<1U, lar::util::assns_iterator_t<assns_t>>;
792 
793  public:
794  using tag = Tag; ///< Tag of this association proxy.
795 
797 
798  /// Type of collection of auxiliary data associated with a main item.
799  using auxiliary_data_t
801 
802  // constructor is not part of the interface
804  : fGroups(std::move(groups))
805  {}
806 
807  /// Returns an iterator pointing to the first associated data range.
808  auto begin() const -> decltype(auto)
809  { return fGroups.begin(); }
810 
811  /// Returns an iterator pointing past the last associated data range.
812  auto end() const -> decltype(auto)
813  { return fGroups.end(); }
814 
815  /// Returns the range with the specified index (no check performed).
816  auto getRange(std::size_t i) const -> decltype(auto)
817  { return util::makeTagged<tag>(fGroups.range(i)); }
818 
819  /// Returns the range with the specified index (no check performed).
820  auto operator[] (std::size_t index) const -> decltype(auto)
821  {
822  static_assert(
823  std::is_convertible<decltype(getRange(index)), auxiliary_data_t>(),
824  "Inconsistent data types."
825  );
826  return getRange(index);
827  }
828 
829  /// Returns whether this data is labeled with the specified tag.
830  template <typename TestTag>
831  static constexpr bool hasTag() { return std::is_same<TestTag, tag>(); }
832 
833  private:
835 
836  }; // class AssociatedData<>
837 
838  //--------------------------------------------------------------------------
839 
840  } // namespace details
841 
842 
843  //----------------------------------------------------------------------------
844  //@{
845  /**
846  * @brief Processes and returns an associated data object.
847  * @tparam Tag the tag labelling this associated data
848  * (if omitted: second type of the association: `right_t`)
849  * @tparam Assns type of association to be processed
850  * @param assns association object to be processed
851  * @param minSize minimum number of entries in the produced association data
852  * @return a new `AssociatedData` filled with associations from `tag`
853  *
854  * The content of the association object must fulfill the requirements of
855  * @ref LArSoftProxyDefinitionOneToManySeqAssn "one-to-many sequential association".
856  * The `Assns` type is expected to be a `art::Assns` instance. At least,
857  * the `Assns` type is required to have `left_t` and `right_t` definitions
858  * representing respectively the main data type and the associated one, and
859  * to respond to `begin()` and `end()` functions. The iterated object must
860  * also respond to `std::get<0>()` with a `art::Ptr<left_t>` and to
861  * `std::get<1>()` with a `art::Ptr<right_t>`.
862  *
863  * Elements in the main collection not associated with any object will be
864  * recorded as such. If there is information for less than `minSize` main
865  * objects, more records will be added to mark the missing objects as not
866  * associated to anything.
867  *
868  * Example:
869  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
870  * art::Assns<recob::Track, recob::Hit> trackHitAssns;
871  * // ...
872  * auto assData = proxy::makeAssociatedData(assns);
873  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
874  * will have `assData` tagged as `recob::Hit`.
875  */
876  template <typename Tag, typename Assns>
877  auto makeAssociatedData(Assns const& assns, std::size_t minSize = 0);
878 
879  template <typename Assns>
880  auto makeAssociatedData(Assns const& assns, std::size_t minSize = 0)
881  { return makeAssociatedData<typename Assns::right_t>(assns, minSize); }
882  //@}
883 
884 
885  //@{
886  /**
887  * @brief Creates and returns an associated data object.
888  * @tparam Tag the tag labelling this associated data
889  * (if omitted: second type of the association: `right_t`)
890  * @tparam MainColl type of the main collection object
891  * @tparam Assns type of the association object
892  * @param mainColl the main collection object
893  * @param assns association data object
894  * @return a new `AssociatedData` wrapping the information in `assns`
895  * @see `makeAssociatedData(Assns const&, std::size_t)`
896  *
897  * This function operates like
898  * `makeAssociatedData(Assns const&, std::size_t)`, where the size is
899  * extracted from the main data collection.
900  */
901  template <typename Tag, typename MainColl, typename Assns>
902  auto makeAssociatedData(MainColl const& mainColl, Assns const& assns)
903  { return makeAssociatedData<Tag>(assns, mainColl.size()); }
904 
905  template <typename MainColl, typename Assns>
906  auto makeAssociatedData(MainColl const& mainColl, Assns const& assns)
907  { return makeAssociatedData<typename Assns::right_t>(mainColl, assns); }
908  //@}
909 
910 
911  //----------------------------------------------------------------------------
912 
913 
914 } // namespace proxy
915 
916 
917 //------------------------------------------------------------------------------
918 //--- template implementation
919 //------------------------------------------------------------------------------
920 namespace proxy {
921 
922  namespace details {
923 
924  //--------------------------------------------------------------------------
925  //--- associationRangeBoundaries() implementation
926  //--------------------------------------------------------------------------
927  template <std::size_t GroupKey, typename Iter>
928  typename BoundaryList<Iter>::boundaries_t associationRangesImpl
929  (Iter begin, Iter end, std::size_t expectedSize /* = 0 */)
930  {
931  constexpr auto KeyIndex = GroupKey;
932 
933  auto extractKey
934  = [](auto const& assn){ return std::get<KeyIndex>(assn).key(); };
935 
936  typename BoundaryList<Iter>::boundaries_t boundaries;
937  boundaries.reserve(expectedSize + 1);
938  boundaries.push_back(begin);
939  std::size_t current = 0;
940  for (auto it = begin; it != end; ++it) {
941  auto const key = extractKey(*it);
942  if (key == current) continue;
943  if (key < current) {
944  auto index = std::distance(begin, it);
945  throw std::runtime_error("associationRanges() got input element #"
946  + std::to_string(index - 1) + " with key " + std::to_string(current)
947  + " and the next with key " + std::to_string(key) + "!"
948  );
949  }
950  boundaries.insert(boundaries.end(), key - current, it);
951  current = key;
952  } // for
953  boundaries.push_back(end);
954  return boundaries;
955  } // associationRangesImpl()
956 
957 
958  //--------------------------------------------------------------------------
959  template <std::size_t GroupKey, typename Iter>
960  auto associationRangeBoundaries(Iter begin, Iter end)
961  { return associationRangesImpl<GroupKey, Iter>(begin, end); }
962 
963 
964  //--------------------------------------------------------------------------
965  template <std::size_t GroupKey, typename Iter>
966  auto associationRangeBoundaries(Iter begin, Iter end, std::size_t n) {
967  auto boundaries = associationRangesImpl<GroupKey, Iter>(begin, end, n);
968  if (boundaries.size() <= n) {
969  boundaries.insert
970  (boundaries.end(), n + 1 - boundaries.size(), boundaries.back());
971  assert(boundaries.size() == (n + 1));
972  }
973  return boundaries;
974  } // associationRangeBoundaries(Iter, Iter, std::size_t)
975 
976 
977  //--------------------------------------------------------------------------
978  /**
979  * @brief Groups associations by the first key.
980  * @tparam GroupKey index of the key in the tuple pointed by the iterator
981  * @tparam Iter type of iterators delimiting the data (same type required)
982  * @param begin iterator to the first association in the list
983  * @param end iterator past the last association in the list
984  * @return a list of range boundaries marking the different groups.
985  * @throw std::runtime_error if input key is not monotonic
986  *
987  * The input iterators are expected to point to a tuple-like structure whose
988  * key element can be accessed as `std::get<GroupKey>()` and is an _art_
989  * pointer of some sort.
990  *
991  * The index of the grouping key is expected to be monotonically increasing.
992  * Gaps are supported except that at the end: if e.g. an association of 5
993  * keys associates objects to only elements #0, #1 and #3, the resulting
994  * list will cover 4 ranges for elements #0 to #3 included, but excluding
995  * the end elements, the existence of which can't be inferred from the
996  * association list in input. In this example, the range #2 will exist and
997  * be empty. To enforce a minimum number of elements, use
998  * `associationRanges(Iter, Iter, std::size_t)`.
999  */
1000  template <std::size_t GroupKey, typename Iter>
1002  {
1003  return BoundaryList<Iter>
1004  (associationRangeBoundaries<GroupKey>(begin, end));
1005  }
1006 
1007  /**
1008  * @brief Groups associations by the first key.
1009  * @tparam GroupKey index of the key in the tuple pointed by the iterator
1010  * @tparam Iter type of iterators delimiting the data (same type required)
1011  * @param begin iterator to the first association in the list
1012  * @param end iterator past the last association in the list
1013  * @param n minimum number of ranges to be produced.
1014  * @return a list of range boundaries marking the different groups.
1015  * @throw std::runtime_error if input key is not monotonic
1016  * @see `associationRanges(Iter, Iter)`
1017  *
1018  * This function operates almost like `associationRanges(Iter, Iter)`.
1019  * The only difference is that at least `n` ranges are guaranteed to be
1020  * produced: if the input defines less than `n`, the missing ones will be
1021  * added at the end, empty.
1022  * This allows to work around the possibility of empty ranges at the end,
1023  * which the `associationRanges(Iter, Iter)` algorithm does not support.
1024  */
1025  template <std::size_t GroupKey, typename Iter>
1026  BoundaryList<Iter> associationRanges(Iter begin, Iter end, std::size_t n)
1027  {
1028  return BoundaryList<Iter>
1029  (associationRangeBoundaries<GroupKey>(begin, end, n));
1030  }
1031 
1032 
1033  //--------------------------------------------------------------------------
1034 
1035  } // namespace details
1036 
1037 
1038  //----------------------------------------------------------------------------
1039  template <typename Tag, typename Assns>
1040  auto makeAssociatedData(Assns const& assns, std::size_t minSize /* = 0 */)
1041  {
1042  using Main_t = typename Assns::left_t;
1043  using Aux_t = typename Assns::right_t;
1044  using Metadata_t = lar::util::assns_metadata_t<Assns>;
1045  using AssociatedData_t
1047 
1048  // associationRangeBoundaries() produces iterators to association elements,
1049  // (i.e. tuples)
1050  using std::begin;
1051  using std::end;
1052  auto ranges = details::associationRangeBoundaries<0U>
1053  (begin(assns), end(assns), minSize);
1054  // we convert those iterators into iterators to the right associated item
1055  // (it takes a few steps)
1056  using group_ranges_t = typename AssociatedData_t::group_ranges_t;
1057  return AssociatedData_t(
1058  group_ranges_t
1059  (typename group_ranges_t::boundaries_t(ranges.begin(), ranges.end()))
1060  );
1061  } // makeAssociatedDataFrom(assns)
1062 
1063 
1064  //----------------------------------------------------------------------------
1065 
1066 } // namespace proxy
1067 //------------------------------------------------------------------------------
1068 
1069 #endif // LARDATA_RECOBASEPROXY_PROXYBASE_ASSOCIATEDDATA_H
auto operator->() const -> decltype(auto)
Dereference operator; need to be redefined by derived classes.
boundaries_t boundaries
Begin iterator of each range, plus end iterator of whole sequence.
IteratorWrapperBase(data_iterator_t const &from)
Copy-from-base constructor.
BoundaryIter boundary_iterator_t
Type of boundary iterator.
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
static auto transform(data_iterator_t const &) -> decltype(auto)
Transforms and returns the value at the specified data iterator.
Provides features of a collections, from begin and end iterators.
decltype(makeBoundaryListRange(std::declval< boundary_iterator_t >())) rangeview_t
Type of range returned when dereferencing.
static AssnsNode_t const & transform(art_assns_iter_t const &v)
value_t const & value() const
Returns a reference to the associated value.
Builds and keeps track of internal boundaries in a sequence.
value_t
the JSON type enumeration
Definition: json.hpp:2854
range_ref_t rangeRef(std::size_t i) const
Returns the specified range.
Basic C++ metaprogramming utilities.
typename AssnsNode_t::main_t main_t
BoundaryList< Iter >::boundaries_t associationRangesImpl(Iter begin, Iter end, std::size_t expectedSize)
main_t const & main() const
Returns the main value, key of the association.
AssnsNode< ArtAssnsIterValue > const & makeAssnsNode(ArtAssnsIterValue const &from)
Reinterprets the specified association node as a AssnsNode.
bool operator==(AssnsNode< ArtAssnsIterValue > const &A, typename AssnsNode< ArtAssnsIterValue >::valueptr_t const &B)
data_iterator_t const & asDataIterator() const
BoundaryListRange(boundary_iterator_t const &iBegin)
Constructor: from an iterator to the begin iterator.
BoundaryListRange< BoundaryIter > makeBoundaryListRange(BoundaryIter const &iBegin)
Reinterprets a iterator to boundaries list as a range collection.
decltype(makeCollectionView(std::declval< BeginIter >(), std::declval< EndIter >())) RangeAsCollection_t
Type of collection view owning the two range boundary iterators.
typename assns_node_traits_t::leftptr_t mainptr_t
Type of art pointer to the main (left) object in the association.
auto boundaryIter() const
Returns the iterator to the begin iterator.
auto operator*() const -> decltype(auto)
Dereference operator; need to be redefined by derived classes.
typename assns_metadata_type< Assns >::type assns_metadata_t
Trait: type of metadata in Assns (association or its node).
Definition: AssnsTraits.h:62
Trait: type is metadata in Assns (association or its node).
Definition: AssnsTraits.h:57
typename assns_node_traits_t::right_t value_t
Type of the associated (right) object.
iterator const & asIterator() const
typename range_iterator_t::value_type range_ref_t
Structure holding begin and end iterator for a single range.
Specializations of STL tuple utilities for art::AssnsNode.
std::add_lvalue_reference_t< std::decay_t< value_type >> reference
typename add_tag< T, Tag >::type add_tag_t
struct node_s node_t
Definition: DBScan3DAlg.h:61
typename assns_node_traits_t::rightptr_t valueptr_t
Type of art pointer to the associated (right) object.
data_iterator_t const & rangeBegin(std::size_t i) const
Returns the begin iterator of the i-th range (end if overflow).
BoundaryListRangeBase(boundary_iterator_t const &it)
Constructor: copies the specified base iterator.
typename AssnsNode_t::value_t value_t
auto end() const -> decltype(auto)
Returns the end iterator of the range (next to the begin iterator).
range_iterator_t begin() const
Returns the begin iterator of the first range.
static this_t const & makeFrom(node_t const &from)
Reinterprets the specified association node as a AssnsNode.
auto associationRangeBoundaries(Iter begin, Iter end)
typename AssnsNode_t::valueptr_t valueptr_t
valueptr_t const & valuePtr() const
Returns the art pointer to the associated value.
Object to draft associated data interface.
A BoundaryListRangeBase with a full container interface.
std::size_t size() const
Returns the number of ranges contained in the list.
static constexpr bool hasMetadata()
Returns whether this node type supports metadata.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
Value box for use with pointer dereference operator-&gt;().
Tag tag
Tag of this association proxy.
Traits for a association iterator.
std::enable_if_t< hasMetadata< ArtNode >), typename lar::util::assns_traits< ArtNode >::data_t const & > data() const
Returns a reference to the metadata on this association node.
std::size_t nRanges() const
Returns the number of ranges contained in the list.
ArtAssnsIterValue node_t
Type of the wrapped node.
main_t const & main() const
Returns the main value, key of the association.
AssnsNode_t const & info() const
Returns the full information the iterator points to.
typename ArtAssnsIter::value_type art_node_t
std::add_pointer_t< std::decay_t< value_type >> pointer
typename AssnsNode_t::mainptr_t mainptr_t
BoundaryList(boundaries_t &&boundaries)
Constructor: steals the specified boundary list.
std::enable_if_t< hasMetadata< Node >), typename lar::util::assns_traits< Node >::data_t const & > data() const
Returns a reference to the metadata on this association node.
Simple iterator wrapper for manipulation of dereferenced result.
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
mainptr_t mainPtr() const
Returns the art pointer to the main value, key of the association.
assns_node_iterator(base_iterator_t const &from)
Constructor from a base iterator (explicitly allowed).
typename std::enable_if< B, T >::type enable_if_t
Definition: json.hpp:2191
util::add_tag_t< typename group_ranges_t::range_t, tag > auxiliary_data_t
Type of collection of auxiliary data associated with a main item.
Value value
Value to return the address of (may be reference).
auto begin() const -> decltype(auto)
Returns an iterator pointing to the first associated data range.
auto operator->() const -> decltype(auto)
Access the contained value via its pointer.
Data types for the specified association type (or its node).
Definition: AssnsTraits.h:102
IteratorWrapperBase()=default
Default constructor: default-constructs the underlying iterator.
valueptr_t valuePtr() const
Returns the art pointer to the associated value.
typename assns_node_traits_t::left_t main_t
Type of the main (left) object in the association.
auto key() const -> decltype(auto)
Returns the key of the art pointer to the value.
lar::RangeAsCollection_t< data_iterator_t > range_t
Range object directly containing the boundary iterators.
mainptr_t const & mainPtr() const
Returns the art pointer to the main value, key of the association.
iterator & operator++()
Prefix increment operator.
std::enable_if_t< hasMetadata< Node >), dataptr_t > dataPtr() const
Returns the pointer to the metadata on this association node.
Provides the features of a collections, from begin and end iterators.
static constexpr bool hasMetadata()
Returns whether this node type supports metadata.
auto makeCollectionView(BeginIter const &b, EndIter const &e)
Creates a CollectionView from the specified iterators.
typename AssnsNode_t::data_t data_t
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
static ValuePtr< Value > makeValuePointer(Value &&value)
std::enable_if_t< hasMetadata< ArtNode >), dataptr_t > dataPtr() const
Returns the pointer to the metadata on this association node.
typename traits_t::node_t AssnsNode_t
Type of node for this association iterator.
bool operator!=(iterator const &other) const
Comparison with another iterator.
This type extends the interface of the art pointer to Assns right side.
value_t const & value() const
Returns the art pointer to the associated value.
AssociatedData(group_ranges_t &&groups)
auto operator[](std::size_t index) const -> decltype(auto)
range_iterator_t end() const
Returns the end iterator of the last range.
typename assns_node_traits_t::data_t data_t
Type of the associated additional data (void if none).
typename assns_node_traits_t::dataptr_t dataptr_t
Type of the pointer to associated additional data.
range_t range(std::size_t i) const
Returns the specified range in an object holding the iterators.
bool operator!=(data_iterator_t const &other) const
Comparison with a data iterator (makes unnecessary to wrap end iterators).
std::string to_string(WindowPattern const &pattern)
Iterator exposing elements of a boundary list as ranges.
Utilities to address elements of a tuple-like class by tag.
auto makeAssociatedData(Assns const &assns, std::size_t minSize=0)
Processes and returns an associated data object.
typename traits_t::art_node_t ArtAssnsNode_t
art::Assns< Main, Aux, Metadata > assns_t
Type of art association.
Traits for art associations.
static constexpr bool hasTag()
Returns whether this data is labeled with the specified tag.
data_iterator_t const & rangeEnd(std::size_t i) const
Returns the end iterator of the i-th range (end if overflow).
temporary value
ArtAssnsIterValue base_t
Base class type.
auto begin() const -> decltype(auto)
Returns the begin iterator of the range.
auto operator[](std::size_t i) const -> decltype(auto)
float A
Definition: dedx.py:137
value_t const & operator*() const
Returns a reference to the associated value (alias of value()).
QuadExpr operator*(double v, const QuadExpr &e)
Definition: QuadExpr.h:39
typename AssnsNode_t::dataptr_t dataptr_t
static auto transform(BoundaryIter const &iter)
Returns the pointed range.
auto getRange(std::size_t i) const -> decltype(auto)
Returns the range with the specified index (no check performed).
ValueType
Definition: value.h:9
auto id() const -> decltype(auto)
Returns the product ID of the art pointer to the value.
BoundaryList< Iter > associationRanges(Iter begin, Iter end)
Groups associations by the first key.
auto end() const -> decltype(auto)
Returns an iterator pointing past the last associated data range.