CMS 3D CMS Logo

InputProcessBlockCacheImpl.h
Go to the documentation of this file.
1 #ifndef FWCore_Framework_InputProcessBlockCacheImpl_h
2 #define FWCore_Framework_InputProcessBlockCacheImpl_h
3 
20 
21 #include <cstddef>
22 #include <functional>
23 #include <memory>
24 #include <string>
25 #include <tuple>
26 #include <type_traits>
27 #include <utility>
28 #include <vector>
29 
30 namespace edm {
31 
32  class Event;
33 
34  namespace impl {
35 
36  template <typename M>
37  constexpr std::size_t countTypeInParameterPack() {
38  return 0;
39  }
40 
41  template <typename M, typename V1, typename... Vs>
42  constexpr std::size_t countTypeInParameterPack() {
44  : countTypeInParameterPack<M, Vs...>();
45  }
46 
47  class InvalidCacheType {};
48 
49  template <typename W, typename U = InvalidCacheType, typename... Types>
50  constexpr std::size_t indexInputProcessBlockCache() {
51  if constexpr (std::is_same<W, U>::value) {
52  return 0;
53  } else {
54  if constexpr (sizeof...(Types) > 0) {
55  return 1 + indexInputProcessBlockCache<W, Types...>();
56  } else {
57  static_assert(sizeof...(Types) > 0,
58  "CacheType used with registerProcessBlockCacheFiller does not match any template parameters of "
59  "InputProcessBlockCache");
60  return 0;
61  }
62  }
63  }
64 
65  struct TokenInfo {
68  };
69 
70  template <typename CacheType>
71  class CacheFiller {
72  public:
73  std::function<std::shared_ptr<CacheType>(ProcessBlock const&, std::shared_ptr<CacheType> const&)> func_;
74  };
75 
76  template <typename... CacheTypes>
78  public:
79  InputProcessBlockCacheImpl() = default;
82 
83  template <std::size_t I>
84  typename std::enable_if<I == sizeof...(CacheTypes), void>::type fillTuple(std::tuple<CacheHandle<CacheTypes>...>&,
85  Event const&) const {}
86 
87  template <std::size_t I>
88  typename std::enable_if <
89  I<sizeof...(CacheTypes), void>::type fillTuple(std::tuple<CacheHandle<CacheTypes>...>& cacheHandles,
90  Event const& event) const {
91  unsigned int index = eventProcessBlockIndex(event, processNames_[I]);
92 
93  // If the branch associated with the token was passed to registerProcessBlockCacheFiller
94  // was not in the input file, then the index will be invalid. Note the branch (including
95  // its process name) is selected using the first input file. Also note that even if
96  // the branch is present and this index is valid, the product might not be there.
97  // The functor in the CacheFiller must deal with that case.
99  std::get<I>(cacheHandles) = CacheHandle(std::get<I>(caches_.at(index).cacheTuple_).get());
100  }
101  fillTuple<I + 1>(cacheHandles, event);
102  }
103 
104  std::tuple<CacheHandle<CacheTypes>...> processBlockCaches(Event const& event) const {
105  std::tuple<CacheHandle<CacheTypes>...> cacheHandles;
106  // processNames will be empty if and only if registerProcessBlockCacheFiller
107  // was never called by the module constructor
108  if (!processNames_.empty()) {
109  fillTuple<0>(cacheHandles, event);
110  }
111  return cacheHandles;
112  }
113 
114  void selectInputProcessBlocks(ProductRegistry const& productRegistry,
115  ProcessBlockHelperBase const& processBlockHelperBase,
116  EDConsumerBase const& edConsumerBase) {
117  unsigned int i = 0;
118  for (auto const& tokenInfo : tokenInfos_) {
119  if (!tokenInfo.token_.isUninitialized()) {
120  ProductLabels productLabels;
121  edConsumerBase.labelsForToken(tokenInfo.token_, productLabels);
122 
123  processNames_[i] = processBlockHelperBase.selectProcess(productRegistry, productLabels, tokenInfo.typeID_);
124  }
125  ++i;
126  }
127  tokenInfos_.clear();
128  }
129 
130  template <std::size_t N>
131  using CacheTypeT = typename std::tuple_element<N, std::tuple<CacheTypes...>>::type;
132 
133  template <std::size_t ICacheType, typename DataType, typename Func>
134  void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
135  registerProcessBlockCacheFiller<ICacheType, CacheTypeT<ICacheType>, DataType, Func>(token,
136  std::forward<Func>(func));
137  }
138 
139  template <typename CacheType, typename DataType, typename Func>
140  void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
141  static_assert(countTypeInParameterPack<CacheType, CacheTypes...>() == 1u,
142  "If registerProcessBlockCacheFiller is called with a type template parameter\n"
143  "then that type must appear exactly once in the template parameters of InputProcessBlockCache");
144 
145  // Find the index into the parameter pack from the CacheType
146  constexpr unsigned int I = indexInputProcessBlockCache<CacheType, CacheTypes...>();
147 
148  registerProcessBlockCacheFiller<I, CacheType, DataType, Func>(token, std::forward<Func>(func));
149  }
150 
151  // This gets used for stream type modules where the InputProcessBlockCacheImpl
152  // object is held by the adaptor. For stream modules, we use a registerProcessBlockCacheFiller
153  // function defined in edm::stream::impl::InputProcessBlockCacheHolder then
154  // move the information.
155  void moveProcessBlockCacheFiller(std::vector<edm::impl::TokenInfo>& tokenInfos,
157  tokenInfos_ = std::move(tokenInfos);
158  functors_ = std::move(functors);
159  if (!tokenInfos_.empty()) {
160  processNames_.resize(sizeof...(CacheTypes));
161  }
162  }
163 
164  // These are used to fill the CacheTuples
165  // One CacheFiller for each CacheType
166 
167  class CacheTuple {
168  public:
169  std::tuple<std::shared_ptr<CacheTypes>...> cacheTuple_;
170  };
171 
172  template <std::size_t I>
173  typename std::enable_if<I == sizeof...(CacheTypes), void>::type fillCache(ProcessBlock const&,
174  CacheTuple const&,
175  CacheTuple&) {}
176 
177  template <std::size_t I>
178  typename std::enable_if < I<sizeof...(CacheTypes), void>::type fillCache(ProcessBlock const& pb,
179  CacheTuple const& previousCacheTuple,
180  CacheTuple& cacheTuple) {
181  if (pb.processName() == processNames_[I]) {
182  auto const& previousSharedPtr = std::get<I>(previousCacheTuple.cacheTuple_);
183  std::get<I>(cacheTuple.cacheTuple_) = std::get<I>(functors_).func_(pb, previousSharedPtr);
184  }
185  fillCache<I + 1>(pb, previousCacheTuple, cacheTuple);
186  }
187 
188  void accessInputProcessBlock(ProcessBlock const& pb) {
189  if (sizeof...(CacheTypes) > 0 && !processNames_.empty()) {
190  CacheTuple cacheTuple;
191  if (caches_.empty()) {
192  CacheTuple firstCacheTuple;
193  fillCache<0>(pb, firstCacheTuple, cacheTuple);
194  } else {
195  CacheTuple const& previousCacheTuple = caches_.back();
196  fillCache<0>(pb, previousCacheTuple, cacheTuple);
197  }
198  caches_.push_back(std::move(cacheTuple));
199  }
200  }
201 
202  void clearCaches() { caches_.clear(); }
203  auto cacheSize() const { return caches_.size(); }
204 
205  private:
206  template <std::size_t ICacheType, typename CacheType, typename DataType, typename Func>
207  void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
208  static_assert(ICacheType < sizeof...(CacheTypes), "ICacheType out of range");
209  processNames_.resize(sizeof...(CacheTypes));
210  tokenInfos_.resize(sizeof...(CacheTypes));
211  if (!tokenInfos_[ICacheType].token_.isUninitialized()) {
213  << "registerProcessBlockCacheFiller should only be called once per cache type";
214  }
215 
216  tokenInfos_[ICacheType] = TokenInfo{EDGetToken(token), TypeID(typeid(DataType))};
217 
218  std::get<ICacheType>(functors_).func_ = std::forward<Func>(func);
219  }
220 
221  // ------------ Data members --------------------
222 
223  // This holds an entry per ProcessBlock
224  std::vector<CacheTuple> caches_;
225 
226  // The following 3 data members have one element for each CacheType
227  std::tuple<CacheFiller<CacheTypes>...> functors_;
228  std::vector<std::string> processNames_;
229  std::vector<TokenInfo> tokenInfos_;
230  };
231 
232  } // namespace impl
233 } // namespace edm
234 #endif
std::function< std::shared_ptr< CacheType >ProcessBlock const &, std::shared_ptr< CacheType > const &)> func_
constexpr std::size_t indexInputProcessBlockCache()
static constexpr unsigned int invalidCacheIndex()
const std::complex< double > I
Definition: I.h:8
unsigned int eventProcessBlockIndex(Event const &event, std::string const &processName)
Definition: Types.py:1
std::enable_if< I==sizeof...(CacheTypes), void >::type fillTuple(std::tuple< CacheHandle< CacheTypes >... > &, Event const &) const
#define N
Definition: blowfish.cc:9
InputProcessBlockCacheImpl & operator=(InputProcessBlockCacheImpl const &)=delete
HLT enums.
constexpr std::size_t countTypeInParameterPack()
def move(src, dest)
Definition: eostools.py:511
Definition: event.py:1