File indexing completed on 2023-03-17 11:02:03
0001 #ifndef FWCore_Framework_InputProcessBlockCacheImpl_h
0002 #define FWCore_Framework_InputProcessBlockCacheImpl_h
0003
0004
0005
0006
0007
0008
0009
0010 #include "DataFormats/Provenance/interface/ProvenanceFwd.h"
0011 #include "FWCore/Common/interface/ProcessBlockHelperBase.h"
0012 #include "FWCore/Framework/interface/CacheHandle.h"
0013 #include "FWCore/Framework/interface/EDConsumerBase.h"
0014 #include "FWCore/Framework/interface/ProcessBlock.h"
0015 #include "FWCore/Framework/interface/processBlockUtilities.h"
0016 #include "FWCore/Utilities/interface/EDGetToken.h"
0017 #include "FWCore/Utilities/interface/EDMException.h"
0018 #include "FWCore/Utilities/interface/ProductLabels.h"
0019 #include "FWCore/Utilities/interface/TypeID.h"
0020
0021 #include <cstddef>
0022 #include <functional>
0023 #include <memory>
0024 #include <string>
0025 #include <tuple>
0026 #include <type_traits>
0027 #include <utility>
0028 #include <vector>
0029
0030 namespace edm {
0031
0032 class Event;
0033
0034 namespace impl {
0035
0036 template <typename M>
0037 constexpr std::size_t countTypeInParameterPack() {
0038 return 0;
0039 }
0040
0041 template <typename M, typename V1, typename... Vs>
0042 constexpr std::size_t countTypeInParameterPack() {
0043 return std::is_same<M, V1>::value ? 1 + countTypeInParameterPack<M, Vs...>()
0044 : countTypeInParameterPack<M, Vs...>();
0045 }
0046
0047 class InvalidCacheType {};
0048
0049 template <typename W, typename U = InvalidCacheType, typename... Types>
0050 constexpr std::size_t indexInputProcessBlockCache() {
0051 if constexpr (std::is_same<W, U>::value) {
0052 return 0;
0053 } else {
0054 if constexpr (sizeof...(Types) > 0) {
0055 return 1 + indexInputProcessBlockCache<W, Types...>();
0056 } else {
0057 static_assert(sizeof...(Types) > 0,
0058 "CacheType used with registerProcessBlockCacheFiller does not match any template parameters of "
0059 "InputProcessBlockCache");
0060 return 0;
0061 }
0062 }
0063 }
0064
0065 struct TokenInfo {
0066 EDGetToken token_;
0067 TypeID typeID_;
0068 };
0069
0070 template <typename CacheType>
0071 class CacheFiller {
0072 public:
0073 std::function<std::shared_ptr<CacheType>(ProcessBlock const&, std::shared_ptr<CacheType> const&)> func_;
0074 };
0075
0076 template <typename... CacheTypes>
0077 class InputProcessBlockCacheImpl {
0078 public:
0079 InputProcessBlockCacheImpl() = default;
0080 InputProcessBlockCacheImpl(InputProcessBlockCacheImpl const&) = delete;
0081 InputProcessBlockCacheImpl& operator=(InputProcessBlockCacheImpl const&) = delete;
0082
0083 template <std::size_t I>
0084 typename std::enable_if<I == sizeof...(CacheTypes), void>::type fillTuple(std::tuple<CacheHandle<CacheTypes>...>&,
0085 Event const&) const {}
0086
0087 template <std::size_t I>
0088 typename std::enable_if <
0089 I<sizeof...(CacheTypes), void>::type fillTuple(std::tuple<CacheHandle<CacheTypes>...>& cacheHandles,
0090 Event const& event) const {
0091 unsigned int index = eventProcessBlockIndex(event, processNames_[I]);
0092
0093
0094
0095
0096
0097
0098 if (index != ProcessBlockHelperBase::invalidCacheIndex()) {
0099 std::get<I>(cacheHandles) = CacheHandle(std::get<I>(caches_.at(index).cacheTuple_).get());
0100 }
0101 fillTuple<I + 1>(cacheHandles, event);
0102 }
0103
0104 std::tuple<CacheHandle<CacheTypes>...> processBlockCaches(Event const& event) const {
0105 std::tuple<CacheHandle<CacheTypes>...> cacheHandles;
0106
0107
0108 if (!processNames_.empty()) {
0109 fillTuple<0>(cacheHandles, event);
0110 }
0111 return cacheHandles;
0112 }
0113
0114 void selectInputProcessBlocks(ProductRegistry const& productRegistry,
0115 ProcessBlockHelperBase const& processBlockHelperBase,
0116 EDConsumerBase const& edConsumerBase) {
0117 unsigned int i = 0;
0118 for (auto const& tokenInfo : tokenInfos_) {
0119 if (!tokenInfo.token_.isUninitialized()) {
0120 ProductLabels productLabels;
0121 edConsumerBase.labelsForToken(tokenInfo.token_, productLabels);
0122
0123 processNames_[i] = processBlockHelperBase.selectProcess(productRegistry, productLabels, tokenInfo.typeID_);
0124 }
0125 ++i;
0126 }
0127 tokenInfos_.clear();
0128 }
0129
0130 template <std::size_t N>
0131 using CacheTypeT = typename std::tuple_element<N, std::tuple<CacheTypes...>>::type;
0132
0133 template <std::size_t ICacheType, typename DataType, typename Func>
0134 void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
0135 registerProcessBlockCacheFiller<ICacheType, CacheTypeT<ICacheType>, DataType, Func>(token,
0136 std::forward<Func>(func));
0137 }
0138
0139 template <typename CacheType, typename DataType, typename Func>
0140 void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
0141 static_assert(countTypeInParameterPack<CacheType, CacheTypes...>() == 1u,
0142 "If registerProcessBlockCacheFiller is called with a type template parameter\n"
0143 "then that type must appear exactly once in the template parameters of InputProcessBlockCache");
0144
0145
0146 constexpr unsigned int I = indexInputProcessBlockCache<CacheType, CacheTypes...>();
0147
0148 registerProcessBlockCacheFiller<I, CacheType, DataType, Func>(token, std::forward<Func>(func));
0149 }
0150
0151
0152
0153
0154
0155 void moveProcessBlockCacheFiller(std::vector<edm::impl::TokenInfo>& tokenInfos,
0156 std::tuple<edm::impl::CacheFiller<CacheTypes>...>& functors) {
0157 tokenInfos_ = std::move(tokenInfos);
0158 functors_ = std::move(functors);
0159 if (!tokenInfos_.empty()) {
0160 processNames_.resize(sizeof...(CacheTypes));
0161 }
0162 }
0163
0164
0165
0166
0167 class CacheTuple {
0168 public:
0169 std::tuple<std::shared_ptr<CacheTypes>...> cacheTuple_;
0170 };
0171
0172 template <std::size_t I>
0173 typename std::enable_if<I == sizeof...(CacheTypes), void>::type fillCache(ProcessBlock const&,
0174 CacheTuple const&,
0175 CacheTuple&) {}
0176
0177 template <std::size_t I>
0178 typename std::enable_if < I<sizeof...(CacheTypes), void>::type fillCache(ProcessBlock const& pb,
0179 CacheTuple const& previousCacheTuple,
0180 CacheTuple& cacheTuple) {
0181 if (pb.processName() == processNames_[I]) {
0182 auto const& previousSharedPtr = std::get<I>(previousCacheTuple.cacheTuple_);
0183 std::get<I>(cacheTuple.cacheTuple_) = std::get<I>(functors_).func_(pb, previousSharedPtr);
0184 }
0185 fillCache<I + 1>(pb, previousCacheTuple, cacheTuple);
0186 }
0187
0188 void accessInputProcessBlock(ProcessBlock const& pb) {
0189 if (sizeof...(CacheTypes) > 0 && !processNames_.empty()) {
0190 CacheTuple cacheTuple;
0191 if (caches_.empty()) {
0192 CacheTuple firstCacheTuple;
0193 fillCache<0>(pb, firstCacheTuple, cacheTuple);
0194 } else {
0195 CacheTuple const& previousCacheTuple = caches_.back();
0196 fillCache<0>(pb, previousCacheTuple, cacheTuple);
0197 }
0198 caches_.push_back(std::move(cacheTuple));
0199 }
0200 }
0201
0202 void clearCaches() { caches_.clear(); }
0203 auto cacheSize() const { return caches_.size(); }
0204
0205 private:
0206 template <std::size_t ICacheType, typename CacheType, typename DataType, typename Func>
0207 void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
0208 static_assert(ICacheType < sizeof...(CacheTypes), "ICacheType out of range");
0209 processNames_.resize(sizeof...(CacheTypes));
0210 tokenInfos_.resize(sizeof...(CacheTypes));
0211 if (!tokenInfos_[ICacheType].token_.isUninitialized()) {
0212 throw Exception(errors::LogicError)
0213 << "registerProcessBlockCacheFiller should only be called once per cache type";
0214 }
0215
0216 tokenInfos_[ICacheType] = TokenInfo{EDGetToken(token), TypeID(typeid(DataType))};
0217
0218 std::get<ICacheType>(functors_).func_ = std::forward<Func>(func);
0219 }
0220
0221
0222
0223
0224 std::vector<CacheTuple> caches_;
0225
0226
0227 std::tuple<CacheFiller<CacheTypes>...> functors_;
0228 std::vector<std::string> processNames_;
0229 std::vector<TokenInfo> tokenInfos_;
0230 };
0231
0232 }
0233 }
0234 #endif