File indexing completed on 2024-08-25 23:07:06
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 requires requires { requires I == sizeof...(CacheTypes); }
0085 void fillTuple(std::tuple<CacheHandle<CacheTypes>...>&, Event const&) const {}
0086
0087 template <std::size_t I>
0088 requires requires { requires I < sizeof...(CacheTypes); }
0089 void fillTuple(std::tuple<CacheHandle<CacheTypes>...>& cacheHandles, Event const& event) const {
0090 unsigned int index = eventProcessBlockIndex(event, processNames_[I]);
0091
0092
0093
0094
0095
0096
0097 if (index != ProcessBlockHelperBase::invalidCacheIndex()) {
0098 std::get<I>(cacheHandles) = CacheHandle(std::get<I>(caches_.at(index).cacheTuple_).get());
0099 }
0100 fillTuple<I + 1>(cacheHandles, event);
0101 }
0102
0103 std::tuple<CacheHandle<CacheTypes>...> processBlockCaches(Event const& event) const {
0104 std::tuple<CacheHandle<CacheTypes>...> cacheHandles;
0105
0106
0107 if (!processNames_.empty()) {
0108 fillTuple<0>(cacheHandles, event);
0109 }
0110 return cacheHandles;
0111 }
0112
0113 void selectInputProcessBlocks(ProductRegistry const& productRegistry,
0114 ProcessBlockHelperBase const& processBlockHelperBase,
0115 EDConsumerBase const& edConsumerBase) {
0116 unsigned int i = 0;
0117 for (auto const& tokenInfo : tokenInfos_) {
0118 if (!tokenInfo.token_.isUninitialized()) {
0119 ProductLabels productLabels;
0120 edConsumerBase.labelsForToken(tokenInfo.token_, productLabels);
0121
0122 processNames_[i] = processBlockHelperBase.selectProcess(productRegistry, productLabels, tokenInfo.typeID_);
0123 }
0124 ++i;
0125 }
0126 tokenInfos_.clear();
0127 }
0128
0129 template <std::size_t N>
0130 using CacheTypeT = typename std::tuple_element<N, std::tuple<CacheTypes...>>::type;
0131
0132 template <std::size_t ICacheType, typename DataType, typename Func>
0133 void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
0134 registerProcessBlockCacheFiller<ICacheType, CacheTypeT<ICacheType>, DataType, Func>(token,
0135 std::forward<Func>(func));
0136 }
0137
0138 template <typename CacheType, typename DataType, typename Func>
0139 void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
0140 static_assert(countTypeInParameterPack<CacheType, CacheTypes...>() == 1u,
0141 "If registerProcessBlockCacheFiller is called with a type template parameter\n"
0142 "then that type must appear exactly once in the template parameters of InputProcessBlockCache");
0143
0144
0145 constexpr unsigned int I = indexInputProcessBlockCache<CacheType, CacheTypes...>();
0146
0147 registerProcessBlockCacheFiller<I, CacheType, DataType, Func>(token, std::forward<Func>(func));
0148 }
0149
0150
0151
0152
0153
0154 void moveProcessBlockCacheFiller(std::vector<edm::impl::TokenInfo>& tokenInfos,
0155 std::tuple<edm::impl::CacheFiller<CacheTypes>...>& functors) {
0156 tokenInfos_ = std::move(tokenInfos);
0157 functors_ = std::move(functors);
0158 if (!tokenInfos_.empty()) {
0159 processNames_.resize(sizeof...(CacheTypes));
0160 }
0161 }
0162
0163
0164
0165
0166 class CacheTuple {
0167 public:
0168 std::tuple<std::shared_ptr<CacheTypes>...> cacheTuple_;
0169 };
0170
0171 template <std::size_t I>
0172 typename std::enable_if<I == sizeof...(CacheTypes), void>::type fillCache(ProcessBlock const&,
0173 CacheTuple const&,
0174 CacheTuple&) {}
0175
0176 template <std::size_t I>
0177 typename std::enable_if < I<sizeof...(CacheTypes), void>::type fillCache(ProcessBlock const& pb,
0178 CacheTuple const& previousCacheTuple,
0179 CacheTuple& cacheTuple) {
0180 if (pb.processName() == processNames_[I]) {
0181 auto const& previousSharedPtr = std::get<I>(previousCacheTuple.cacheTuple_);
0182 std::get<I>(cacheTuple.cacheTuple_) = std::get<I>(functors_).func_(pb, previousSharedPtr);
0183 }
0184 fillCache<I + 1>(pb, previousCacheTuple, cacheTuple);
0185 }
0186
0187 void accessInputProcessBlock(ProcessBlock const& pb) {
0188 if (sizeof...(CacheTypes) > 0 && !processNames_.empty()) {
0189 CacheTuple cacheTuple;
0190 if (caches_.empty()) {
0191 CacheTuple firstCacheTuple;
0192 fillCache<0>(pb, firstCacheTuple, cacheTuple);
0193 } else {
0194 CacheTuple const& previousCacheTuple = caches_.back();
0195 fillCache<0>(pb, previousCacheTuple, cacheTuple);
0196 }
0197 caches_.push_back(std::move(cacheTuple));
0198 }
0199 }
0200
0201 void clearCaches() { caches_.clear(); }
0202 auto cacheSize() const { return caches_.size(); }
0203
0204 private:
0205 template <std::size_t ICacheType, typename CacheType, typename DataType, typename Func>
0206 void registerProcessBlockCacheFiller(EDGetTokenT<DataType> const& token, Func&& func) {
0207 static_assert(ICacheType < sizeof...(CacheTypes), "ICacheType out of range");
0208 processNames_.resize(sizeof...(CacheTypes));
0209 tokenInfos_.resize(sizeof...(CacheTypes));
0210 if (!tokenInfos_[ICacheType].token_.isUninitialized()) {
0211 throw Exception(errors::LogicError)
0212 << "registerProcessBlockCacheFiller should only be called once per cache type";
0213 }
0214
0215 tokenInfos_[ICacheType] = TokenInfo{EDGetToken(token), TypeID(typeid(DataType))};
0216
0217 std::get<ICacheType>(functors_).func_ = std::forward<Func>(func);
0218 }
0219
0220
0221
0222
0223 std::vector<CacheTuple> caches_;
0224
0225
0226 std::tuple<CacheFiller<CacheTypes>...> functors_;
0227 std::vector<std::string> processNames_;
0228 std::vector<TokenInfo> tokenInfos_;
0229 };
0230
0231 }
0232 }
0233 #endif