Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-08-25 23:07:06

0001 #ifndef FWCore_Framework_InputProcessBlockCacheImpl_h
0002 #define FWCore_Framework_InputProcessBlockCacheImpl_h
0003 
0004 /** \class edm::impl::InputProcessBlockCacheImpl
0005 
0006 \author W. David Dagenhart, created 18 February, 2021
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         // If the branch associated with the token was passed to registerProcessBlockCacheFiller
0093         // was not in the input file, then the index will be invalid. Note the branch (including
0094         // its process name) is selected using the first input file. Also note that even if
0095         // the branch is present and this index is valid, the product might not be there.
0096         // The functor in the CacheFiller must deal with that case.
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         // processNames will be empty if and only if registerProcessBlockCacheFiller
0106         // was never called by the module constructor
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         // Find the index into the parameter pack from the CacheType
0145         constexpr unsigned int I = indexInputProcessBlockCache<CacheType, CacheTypes...>();
0146 
0147         registerProcessBlockCacheFiller<I, CacheType, DataType, Func>(token, std::forward<Func>(func));
0148       }
0149 
0150       // This gets used for stream type modules where the InputProcessBlockCacheImpl
0151       // object is held by the adaptor. For stream modules, we use a registerProcessBlockCacheFiller
0152       // function defined in edm::stream::impl::InputProcessBlockCacheHolder then
0153       // move the information.
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       // These are used to fill the CacheTuples
0164       // One CacheFiller for each CacheType
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       // ------------ Data members --------------------
0221 
0222       // This holds an entry per ProcessBlock
0223       std::vector<CacheTuple> caches_;
0224 
0225       // The following 3 data members have one element for each CacheType
0226       std::tuple<CacheFiller<CacheTypes>...> functors_;
0227       std::vector<std::string> processNames_;
0228       std::vector<TokenInfo> tokenInfos_;
0229     };
0230 
0231   }  // namespace impl
0232 }  // namespace edm
0233 #endif