Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:12:03

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