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>
68 
69  template <typename H>
71  T const& t);
72 
73  void clear();
74 
75  // Default-constructed object is invalid. As soon as it is
76  // updated, it becomes valid. No update can invalidate it.
77  bool isValid() const;
78 
79  T const& value() const;
80  RangeSet const& rangeOfValidity() const;
81 
82  private:
83  template <typename H>
84  void
85  update_impl(H const& h, T const& t)
86  {
87  // Precondition: handle must be valid
88  assert(h.isValid());
89 
90  auto const& newRS = h.provenance()->rangeOfValidity();
91  if (!rangeOfValidity_.is_valid() && newRS.is_valid()) {
92  rangeOfValidity_ = newRS;
93  value_ = t;
94  } else if (art::disjoint_ranges(rangeOfValidity_, newRS)) {
95  if (rangeOfValidity_.run() != newRS.run()) {
97  "SummedValue<T>::update"}
98  << "\nThe following ranges corresponding to the type:\n"
99  << " '" << cet::demangle_symbol(typeid(T).name()) << "'"
100  << "\nhave different run numbers (" << rangeOfValidity_.run()
101  << " vs. " << newRS.run() << ") and cannot be aggregated.\n"
102  << "Please contact artists@fnal.gov.\n";
103  }
105  rangeOfValidity_.merge(h.provenance()->rangeOfValidity());
106  } else if (art::same_ranges(rangeOfValidity_, newRS)) {
107  // The ranges are the same, so the behavior is a NOP.
108  // However, we will probably never get here because of the
109  // seenIDs set, which prevents duplicate aggregation. If the
110  // stakeholders decide that products with the same ranges
111  // should be checked for equality, then the seenIDs set needs
112  // to go away, and an extra condition will be added here.
113  } else if (art::overlapping_ranges(rangeOfValidity_, newRS)) {
115  "SummedValue<T>::update"}
116  << "\nThe following ranges corresponding to the type:\n"
117  << " '" << cet::demangle_symbol(typeid(T).name()) << "'"
118  << "\ncannot be aggregated\n"
119  << rangeOfValidity_ << " and\n"
120  << newRS << "\nPlease contact artists@fnal.gov.\n";
121  }
122  // NOP when both RangeSets are invalid
123  }
124 
127  };
128 
129  //===============================================
130  // Implementation
131 
132  template <typename T>
133  template <typename H>
136  {
137  std::string const& errMsg{"Attempt to update " +
138  cet::demangle_symbol(typeid(*this).name()) +
139  " from an invalid handle."};
140  detail::throw_if_invalid(errMsg, h);
141  update_impl(h, *h);
142  }
143 
144  template <typename T>
145  template <typename H>
147  SummedValue<T>::update(H const& h, T const& t)
148  {
149  std::string const& errMsg{"Attempt to update " +
150  cet::demangle_symbol(typeid(*this).name()) +
151  " from an invalid handle.\n"};
152  detail::throw_if_invalid(errMsg, h);
153  update_impl(h, t);
154  }
155 
156  template <typename T>
157  inline void
159  {
161  std::swap(*this, tmp);
162  }
163 
164  template <typename T>
165  inline bool
167  {
168  return rangeOfValidity_.is_valid();
169  }
170 
171  template <typename T>
172  inline T const&
174  {
175  return value_;
176  }
177 
178  template <typename T>
179  RangeSet const&
181  {
182  return rangeOfValidity_;
183  }
184 
185  template <class T, class U>
186  bool
188  {
190  }
191 
192  template <class T, class U>
193  bool
195  {
197  }
198 
199  template <class T, class U>
200  bool
202  {
204  }
205 
206 } // namespace art
207 
208 #endif /* art_Framework_Principal_SummedValue_h */
209 
210 // Local variables:
211 // mode: c++
212 // End:
static QCString name
Definition: declinfo.cpp:673
RangeSet rangeOfValidity_
Definition: SummedValue.h:126
std::string string
Definition: nybbler.cc:12
std::enable_if_t< detail::is_handle< H >::value > update(H const &h)
Definition: SummedValue.h:135
bool is_valid() const
Definition: RangeSet.cc:117
RunNumber_t run() const
Definition: RangeSet.cc:89
void swap(Handle< T > &a, Handle< T > &b)
static void aggregate(T &, T const &)
Definition: aggregate.h:53
const double a
std::enable_if_t< detail::are_handles< T, U >::value, bool > disjoint_ranges(T const &a, U const &b)
RangeSet const & rangeOfValidity() const
Definition: SummedValue.h:180
void throw_if_invalid(std::string const &msg, T const &...t)
Definition: Handle.h:63
string tmp
Definition: languages.py:63
void update_impl(H const &h, T const &t)
Definition: SummedValue.h:85
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
bool isValid() const
Definition: SummedValue.h:166
std::enable_if_t< detail::are_handles< T, U >::value, bool > overlapping_ranges(T const &a, U const &b)
T const & value() const
Definition: SummedValue.h:173
static RangeSet invalid()
Definition: RangeSet.cc:45
std::enable_if_t< detail::are_handles< T, U >::value, bool > same_ranges(T const &a, U const &b)
static bool * b
Definition: config.cpp:1043
RangeSet & merge(RangeSet const &other)
Definition: RangeSet.cc:295