LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
SummedValue.h
Go to the documentation of this file.
1 #ifndef art_Framework_Principal_SummedValue_h
2 #define art_Framework_Principal_SummedValue_h
3 
4 // ========================================================================
5 //
6 // SummedValue: Class whose instances own two objects:
7 // - object of type specified as the template argument
8 // - RangeSet corresponding to the object
9 //
10 // The purpose of this auxiliary class is to provide users with a
11 // means of tying an object with its associated range. This can be
12 // important whenever a user needs to assemble (e.g.) product 3 from
13 // products 1 and 2, whose ranges may not correspond to what is
14 // desired due to ouput-file switching artifacts.
15 //
16 // SummedValue<T> objects may not span multiple runs as the contained
17 // RangeSet object corresponds only to a specific run, and a set of
18 // event ranges within that run. An attempt to update such an object
19 // across run boundaries will result in an exception throw.
20 //
21 // ------------------------------------------------------------------------
22 //
23 // The main function of interest is SummedValue::update(Handle const& h),
24 // which updates the owned object (calling its appropriate aggregation
25 // function) and its corresponding RangeSet.
26 //
27 // The type 'T' need not correspond to the type of the data product.
28 // For example, the following are allowed uses of SummedValue:
29 //
30 // class MyModule : public EDProducer {
31 // SummedValue<POTSummary> pots_;
32 // SummedValue<unsigned> count_;
33 // public:
34 // ...
35 // void produce(Run& r) {
36 // auto const& h = r.getValidHandle<POTSummary>(...);
37 // pots_.update(h);
38 // count_.update(h, h->proton_count()); // Ties 'count_' with RangeSet
39 // from 'h'
40 // }
41 // };
42 //
43 // N.B. It is the responsibility of the user to call 'clear' whenever
44 // the owned object has been fully updated for the Run or SubRun
45 // of interest.
46 // ========================================================================
47 
51 #include "cetlib_except/demangle.h"
52 
53 #include <memory>
54 
55 namespace art {
56 
57  template <typename T>
58  class SummedValue {
59  public:
60  static_assert(
62  "\n\n"
63  "art error: SummedValue<T>'s only support types that can be aggregated.\n"
64  " Please contact artists@fnal.gov.\n");
65 
66  template <typename H>
67  std::enable_if_t<detail::is_handle_v<H>> update(H const& h);
68 
69  template <typename H>
70  std::enable_if_t<detail::is_handle_v<H>> update(H const& h, T const& t);
71 
72  void clear();
73 
74  // Default-constructed object is invalid. As soon as it is
75  // updated, it becomes valid. No update can invalidate it.
76  bool isValid() const;
77 
78  T const& value() const;
79  RangeSet const& rangeOfValidity() const;
80 
81  private:
82  template <typename H>
83  void
84  update_impl(H const& h, T const& t)
85  {
86  // Precondition: handle must be valid
87  assert(h.isValid());
88 
89  auto const& newRS = h.provenance()->rangeOfValidity();
90  if (!rangeOfValidity_.is_valid() && newRS.is_valid()) {
91  rangeOfValidity_ = newRS;
92  value_ = t;
93  } else if (art::disjoint_ranges(rangeOfValidity_, newRS)) {
94  if (rangeOfValidity_.run() != newRS.run()) {
96  "SummedValue<T>::update"}
97  << "\nThe following ranges corresponding to the type:\n"
98  << " '" << cet::demangle_symbol(typeid(T).name()) << "'"
99  << "\nhave different run numbers (" << rangeOfValidity_.run()
100  << " vs. " << newRS.run() << ") and cannot be aggregated.\n"
101  << "Please contact artists@fnal.gov.\n";
102  }
104  rangeOfValidity_.merge(h.provenance()->rangeOfValidity());
105  } else if (art::same_ranges(rangeOfValidity_, newRS)) {
106  // The ranges are the same, so the behavior is a NOP.
107  // However, we will probably never get here because of the
108  // seenIDs set, which prevents duplicate aggregation. If the
109  // stakeholders decide that products with the same ranges
110  // should be checked for equality, then the seenIDs set needs
111  // to go away, and an extra condition will be added here.
112  } else if (art::overlapping_ranges(rangeOfValidity_, newRS)) {
114  "SummedValue<T>::update"}
115  << "\nThe following ranges corresponding to the type:\n"
116  << " '" << cet::demangle_symbol(typeid(T).name()) << "'"
117  << "\ncannot be aggregated\n"
118  << rangeOfValidity_ << " and\n"
119  << newRS << "\nPlease contact artists@fnal.gov.\n";
120  }
121  // NOP when both RangeSets are invalid
122  }
123 
124  T value_{};
126  };
127 
128  //===============================================
129  // Implementation
130 
131  template <typename T>
132  template <typename H>
133  std::enable_if_t<detail::is_handle_v<H>>
135  {
136  std::string const& errMsg{"Attempt to update " +
137  cet::demangle_symbol(typeid(*this).name()) +
138  " from an invalid handle."};
139  detail::throw_if_invalid(errMsg, h);
140  update_impl(h, *h);
141  }
142 
143  template <typename T>
144  template <typename H>
145  std::enable_if_t<detail::is_handle_v<H>>
146  SummedValue<T>::update(H const& h, T const& t)
147  {
148  std::string const& errMsg{"Attempt to update " +
149  cet::demangle_symbol(typeid(*this).name()) +
150  " from an invalid handle.\n"};
151  detail::throw_if_invalid(errMsg, h);
152  update_impl(h, t);
153  }
154 
155  template <typename T>
156  inline void
158  {
160  std::swap(*this, tmp);
161  }
162 
163  template <typename T>
164  inline bool
166  {
167  return rangeOfValidity_.is_valid();
168  }
169 
170  template <typename T>
171  inline T const&
173  {
174  return value_;
175  }
176 
177  template <typename T>
178  RangeSet const&
180  {
181  return rangeOfValidity_;
182  }
183 
184  template <class T, class U>
185  bool
187  {
189  }
190 
191  template <class T, class U>
192  bool
194  {
196  }
197 
198  template <class T, class U>
199  bool
201  {
203  }
204 
205 } // namespace art
206 
207 #endif /* art_Framework_Principal_SummedValue_h */
208 
209 // Local variables:
210 // mode: c++
211 // End:
RangeSet rangeOfValidity_
Definition: SummedValue.h:125
std::enable_if_t< detail::are_handles_v< T, U >, bool > overlapping_ranges(T const &a, U const &b)
Float_t tmp
Definition: plot.C:35
bool is_valid() const
Definition: RangeSet.cc:117
RunNumber_t run() const
Definition: RangeSet.cc:89
std::enable_if_t< detail::are_handles_v< T, U >, bool > disjoint_ranges(T const &a, U const &b)
static void aggregate(T &, T const &)
Definition: aggregate.h:53
RangeSet const & rangeOfValidity() const
Definition: SummedValue.h:179
void throw_if_invalid(std::string const &msg, T const &...t)
Definition: Handle.h:71
std::enable_if_t< detail::is_handle_v< H > > update(H const &h)
Definition: SummedValue.h:134
void update_impl(H const &h, T const &t)
Definition: SummedValue.h:84
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
bool isValid() const
Definition: SummedValue.h:165
std::enable_if_t< detail::are_handles_v< T, U >, bool > same_ranges(T const &a, U const &b)
T const & value() const
Definition: SummedValue.h:172
static RangeSet invalid()
Definition: RangeSet.cc:45
Definition: MVAAlg.h:12
RangeSet & merge(RangeSet const &other)
Definition: RangeSet.cc:295