Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-04-30 22:24:06

0001 // -*- C++ -*-
0002 #ifndef FWCore_Framework_ESProducer_h
0003 #define FWCore_Framework_ESProducer_h
0004 //
0005 // Package:     Framework
0006 // Class  :     ESProducer
0007 //
0008 /**\class edm::ESProducer
0009 
0010  Description: An EventSetup algorithmic Provider that encapsulates the algorithm as a member method
0011 
0012  Usage:
0013     Inheriting from this class is the simplest way to create an algorithm which gets called when a new
0014   data item is needed for the EventSetup.  This class is designed to call a member method of inheriting
0015   classes each time the algorithm needs to be run.  (A more flexible system in which the algorithms can be
0016   set at run-time instead of compile time can be obtained by inheriting from ESProductResolverFactoryProducer instead.)
0017 
0018     If only one algorithm is being encapsulated then the user needs to
0019       1) add a method named 'produce' to the class.  The 'produce' takes as its argument a const reference
0020          to the record that is to hold the data item being produced.  If only one data item is being produced,
0021          the 'produce' method must return either an 'std::unique_ptr' or 'std::shared_ptr' to the object being
0022          produced.  (The choice depends on if the EventSetup or the ESProducer is managing the lifetime of
0023          the object).  If multiple items are being Produced then the 'produce' method must return an
0024          ESProducts<> object which holds all of the items.
0025       2) add 'setWhatProduced(this);' to their classes constructor
0026 
0027 Example: one algorithm creating only one object
0028 \code
0029     class FooProd : public edm::ESProducer {
0030        std::unique_ptr<Foo> produce(const FooRecord&);
0031        ...
0032     };
0033     FooProd::FooProd(const edm::ParameterSet&) {
0034        setWhatProduced(this);
0035        ...
0036     }
0037 \endcode
0038 Example: one algorithm creating two objects
0039 \code
0040    class FoosProd : public edm::ESProducer {
0041       edm::ESProducts<std::unique_ptr<Foo1>, std::unique_ptr<Foo2>> produce(const FooRecord&);
0042       ...
0043    };
0044 \endcode
0045 
0046   If multiple algorithms are being encapsulated then
0047       1) like 1 above except the methods can have any names you want
0048       2) add 'setWhatProduced(this, &<class name>::<method name>);' for each method in the class' constructor
0049    NOTE: the algorithms can put data into the same record or into different records
0050 
0051 Example: two algorithms each creating only one objects
0052 \code
0053    class FooBarProd : public edm::eventsetup::ESProducer {
0054       std::unique_ptr<Foo> produceFoo(const FooRecord&);
0055       std::unique_ptr<Bar> produceBar(const BarRecord&);
0056       ...
0057    };
0058    FooBarProd::FooBarProd(const edm::ParameterSet&) {
0059       setWhatProduced(this,&FooBarProd::produceFoo);
0060       setWhatProduced(this,&FooBarProd::produceBar);
0061       ...
0062    }
0063 \endcode
0064 
0065 */
0066 //
0067 // Author:      Chris Jones
0068 // Created:     Thu Apr  7 17:08:14 CDT 2005
0069 //
0070 
0071 // system include files
0072 #include <memory>
0073 #include <string>
0074 #include <optional>
0075 #include <vector>
0076 
0077 // user include files
0078 #include "FWCore/Framework/interface/ESConsumesCollector.h"
0079 #include "FWCore/Framework/interface/es_impl/MayConsumeChooserBase.h"
0080 #include "FWCore/Framework/interface/es_impl/ReturnArgumentTypes.h"
0081 #include "FWCore/Framework/interface/ESProductResolverFactoryProducer.h"
0082 #include "FWCore/Framework/interface/ESProductResolverArgumentFactoryTemplate.h"
0083 
0084 #include "FWCore/Framework/interface/CallbackProductResolver.h"
0085 #include "FWCore/Framework/interface/Callback.h"
0086 #include "FWCore/Framework/interface/produce_helpers.h"
0087 #include "FWCore/Framework/interface/eventsetup_dependsOn.h"
0088 #include "FWCore/Framework/interface/es_Label.h"
0089 
0090 #include "FWCore/Framework/interface/SharedResourcesAcquirer.h"
0091 #include "FWCore/ServiceRegistry/interface/ServiceRegistryfwd.h"
0092 
0093 // forward declarations
0094 namespace edm {
0095   namespace eventsetup {
0096     struct ComponentDescription;
0097     class ESRecordsToProductResolverIndices;
0098     struct ESModuleConsumesMinimalInfo;
0099 
0100     //used by ESProducer to create the proper Decorator based on the
0101     //  argument type passed.  The default it to just 'pass through'
0102     //  the argument as the decorator itself
0103     template <typename T, typename TRecord, typename TDecorator>
0104     inline const TDecorator& createDecoratorFrom(T*, const TRecord*, const TDecorator& iDec) {
0105       return iDec;
0106     }
0107   }  // namespace eventsetup
0108 
0109   class ESProducer : public ESProductResolverFactoryProducer {
0110   public:
0111     ESProducer();
0112     ~ESProducer() noexcept(false) override;
0113     ESProducer(const ESProducer&) = delete;
0114     ESProducer& operator=(const ESProducer&) = delete;
0115     ESProducer(ESProducer&&) = delete;
0116     ESProducer& operator=(ESProducer&&) = delete;
0117 
0118     void updateLookup(eventsetup::ESRecordsToProductResolverIndices const&) final;
0119     ESResolverIndex const* getTokenIndices(unsigned int iIndex) const {
0120       if (itemsToGetFromRecords_.empty()) {
0121         return nullptr;
0122       }
0123       return (itemsToGetFromRecords_[iIndex].empty()) ? static_cast<ESResolverIndex const*>(nullptr)
0124                                                       : &(itemsToGetFromRecords_[iIndex].front());
0125     }
0126     ESRecordIndex const* getTokenRecordIndices(unsigned int iIndex) const {
0127       if (recordsUsedDuringGet_.empty()) {
0128         return nullptr;
0129       }
0130       return (recordsUsedDuringGet_[iIndex].empty()) ? static_cast<ESRecordIndex const*>(nullptr)
0131                                                      : &(recordsUsedDuringGet_[iIndex].front());
0132     }
0133     size_t numberOfTokenIndices(unsigned int iIndex) const {
0134       if (itemsToGetFromRecords_.empty()) {
0135         return 0;
0136       }
0137       return itemsToGetFromRecords_[iIndex].size();
0138     }
0139 
0140     bool hasMayConsumes() const noexcept { return hasMayConsumes_; }
0141 
0142     template <typename Record>
0143     std::optional<std::vector<ESResolverIndex>> updateFromMayConsumes(unsigned int iIndex,
0144                                                                       const Record& iRecord) const {
0145       if (not hasMayConsumes()) {
0146         return {};
0147       }
0148       std::vector<ESResolverIndex> ret = itemsToGetFromRecords_[iIndex];
0149       auto const info = consumesInfos_[iIndex].get();
0150       for (size_t i = 0; i < info->size(); ++i) {
0151         auto chooserBase = (*info)[i].chooser_.get();
0152         if (chooserBase) {
0153           auto chooser = static_cast<eventsetup::impl::MayConsumeChooserBase<Record>*>(chooserBase);
0154           ret[i] = chooser->makeChoice(iRecord);
0155         }
0156       }
0157       return ret;
0158     }
0159 
0160     SerialTaskQueueChain& queue() { return acquirer_.serialQueueChain(); }
0161 
0162     std::vector<std::vector<ESModuleConsumesInfo>> esModuleConsumesInfos(
0163         eventsetup::ESRecordsToProductResolverIndices const&) const;
0164 
0165     /** Returns a vector of ESModuleConsumesMinimalInfo.
0166         Each entry contains minimal information about the products that a method consumes.
0167     */
0168     std::vector<eventsetup::ESModuleConsumesMinimalInfo> esModuleConsumesMinimalInfos() const;
0169 
0170   protected:
0171     /** Specify the names of the shared resources used by this ESProducer */
0172     void usesResources(std::vector<std::string> const&);
0173 
0174     /** \param iThis the 'this' pointer to an inheriting class instance
0175         The method determines the Record argument and return value of the 'produce'
0176         method in order to do the registration with the EventSetup
0177     */
0178     template <typename T>
0179     auto setWhatProduced(T* iThis, const es::Label& iLabel = {}) {
0180       return setWhatProduced(iThis, &T::produce, iLabel);
0181     }
0182 
0183     template <typename T>
0184     auto setWhatProduced(T* iThis, const char* iLabel) {
0185       return setWhatProduced(iThis, es::Label(iLabel));
0186     }
0187 
0188     template <typename T>
0189     auto setWhatProduced(T* iThis, const std::string& iLabel) {
0190       return setWhatProduced(iThis, es::Label(iLabel));
0191     }
0192 
0193     template <typename T, typename TDecorator>
0194     auto setWhatProduced(T* iThis, const TDecorator& iDec, const es::Label& iLabel = {}) {
0195       return setWhatProduced(iThis, &T::produce, iDec, iLabel);
0196     }
0197     /** \param iThis the 'this' pointer to an inheriting class instance
0198         \param iMethod a member method of the inheriting class
0199         The TRecord and TReturn template parameters can be deduced
0200         from iMethod in order to do the registration with the EventSetup
0201     */
0202     template <typename T, typename TReturn, typename TRecord>
0203     auto setWhatProduced(T* iThis, TReturn (T::*iMethod)(const TRecord&), const es::Label& iLabel = {}) {
0204       return setWhatProduced(iThis, iMethod, eventsetup::CallbackSimpleDecorator<TRecord>(), iLabel);
0205     }
0206     /** \param iDecorator a class with 'pre'&'post' methods which are placed around the method call
0207         This function has the same template parameters and arguments as the previous function
0208         except for the addition of the decorator.
0209     */
0210     template <typename T, typename TReturn, typename TRecord, typename TDecorator>
0211     auto setWhatProduced(T* iThis,
0212                          TReturn (T ::*iMethod)(const TRecord&),
0213                          const TDecorator& iDec,
0214                          const es::Label& iLabel = {}) {
0215       return setWhatProduced<TReturn, TRecord>(
0216           [iThis, iMethod](TRecord const& iRecord) { return (iThis->*iMethod)(iRecord); },
0217           createDecoratorFrom(iThis, static_cast<const TRecord*>(nullptr), iDec),
0218           iLabel);
0219     }
0220 
0221     /**
0222      * This overload allows lambdas (functors) to be used as the
0223      * production function. As of now it is not intended for wide use
0224      * (we are thinking for a better API for users)
0225      *
0226      * The main use case of the decorator functionality was
0227      * dependsOn(), but in practice that became unused with
0228      * concurrent IOVs, so it is not clear if the
0229      * decorator functionality is still needed.
0230      */
0231     template <typename TFunc>
0232     auto setWhatProduced(TFunc&& func, const es::Label& iLabel = {}) {
0233       using Types = eventsetup::impl::ReturnArgumentTypes<TFunc>;
0234       using TReturn = typename Types::return_type;
0235       using TRecord = typename Types::argument_type;
0236       using DecoratorType = eventsetup::CallbackSimpleDecorator<TRecord>;
0237       return setWhatProduced<TReturn, TRecord>(std::forward<TFunc>(func), DecoratorType(), iLabel);
0238     }
0239 
0240     template <typename TReturn, typename TRecord, typename TFunc, typename TDecorator>
0241     ESConsumesCollectorT<TRecord> setWhatProduced(TFunc&& func, TDecorator&& iDec, const es::Label& iLabel = {}) {
0242       const auto produceMethodID = consumesInfoSize();
0243       using DecoratorType = std::decay_t<TDecorator>;
0244       using CallbackType = eventsetup::Callback<ESProducer, TFunc, TReturn, TRecord, DecoratorType>;
0245       unsigned int iovIndex = 0;  // Start with 0, but later will cycle through all of them
0246       auto temp = std::make_shared<CallbackType>(
0247           this, std::forward<TFunc>(func), produceMethodID, std::forward<TDecorator>(iDec));
0248       auto callback =
0249           std::make_shared<std::pair<unsigned int, std::shared_ptr<CallbackType>>>(iovIndex, std::move(temp));
0250       registerProducts(std::move(callback),
0251                        static_cast<const typename eventsetup::produce::product_traits<TReturn>::type*>(nullptr),
0252                        static_cast<const TRecord*>(nullptr),
0253                        iLabel);
0254       return ESConsumesCollectorT<TRecord>(consumesInfoPushBackNew(), produceMethodID);
0255     }
0256 
0257     // These next four functions are intended for use in this class and
0258     // class ESProducerExternalWork only. They should not be used in
0259     // other classes derived from them.
0260     unsigned int consumesInfoSize() const { return consumesInfos_.size(); }
0261 
0262     ESConsumesInfo* consumesInfoPushBackNew() {
0263       consumesInfos_.push_back(std::make_unique<ESConsumesInfo>());
0264       return consumesInfos_.back().get();
0265     }
0266 
0267     template <typename CallbackT, typename TList, typename TRecord>
0268     void registerProducts(std::shared_ptr<std::pair<unsigned int, std::shared_ptr<CallbackT>>> iCallback,
0269                           const TList*,
0270                           const TRecord* iRecord,
0271                           const es::Label& iLabel) {
0272       registerProduct(iCallback, static_cast<const typename TList::tail_type*>(nullptr), iRecord, iLabel);
0273       registerProducts(std::move(iCallback), static_cast<const typename TList::head_type*>(nullptr), iRecord, iLabel);
0274     }
0275 
0276     template <typename CallbackT, typename TRecord>
0277     void registerProducts(std::shared_ptr<std::pair<unsigned int, std::shared_ptr<CallbackT>>>,
0278                           const eventsetup::produce::Null*,
0279                           const TRecord*,
0280                           const es::Label&) {
0281       //do nothing
0282     }
0283 
0284   private:
0285     template <typename CallbackT, typename TProduct, typename TRecord>
0286     void registerProduct(std::shared_ptr<std::pair<unsigned int, std::shared_ptr<CallbackT>>> iCallback,
0287                          const TProduct*,
0288                          const TRecord*,
0289                          const es::Label& iLabel) {
0290       using ResolverType = eventsetup::CallbackProductResolver<CallbackT, TRecord, TProduct>;
0291       using FactoryType = eventsetup::ESProductResolverArgumentFactoryTemplate<ResolverType, CallbackT>;
0292       registerFactory(std::make_unique<FactoryType>(std::move(iCallback)), iLabel.default_);
0293     }
0294 
0295     template <typename CallbackT, typename TProduct, typename TRecord, int IIndex>
0296     void registerProduct(std::shared_ptr<std::pair<unsigned int, std::shared_ptr<CallbackT>>> iCallback,
0297                          const es::L<TProduct, IIndex>*,
0298                          const TRecord*,
0299                          const es::Label& iLabel) {
0300       if (iLabel.labels_.size() <= IIndex || iLabel.labels_[IIndex] == es::Label::def()) {
0301         Exception::throwThis(errors::Configuration,
0302                              "Unnamed Label\nthe index ",
0303                              IIndex,
0304                              " was never assigned a name in the 'setWhatProduced' method");
0305       }
0306       using ResolverType = eventsetup::CallbackProductResolver<CallbackT, TRecord, es::L<TProduct, IIndex>>;
0307       using FactoryType = eventsetup::ESProductResolverArgumentFactoryTemplate<ResolverType, CallbackT>;
0308       registerFactory(std::make_unique<FactoryType>(std::move(iCallback)), iLabel.labels_[IIndex]);
0309     }
0310 
0311     std::vector<std::unique_ptr<ESConsumesInfo>> consumesInfos_;
0312     std::vector<std::vector<ESResolverIndex>> itemsToGetFromRecords_;
0313     //need another structure to say which record to get the data from in
0314     // order to make prefetching work
0315     std::vector<std::vector<ESRecordIndex>> recordsUsedDuringGet_;
0316 
0317     SharedResourcesAcquirer acquirer_;
0318     std::unique_ptr<std::vector<std::string>> sharedResourceNames_;
0319     bool hasMayConsumes_ = false;
0320   };
0321 }  // namespace edm
0322 #endif