Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-02-14 03:16:30

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 
0099     //used by ESProducer to create the proper Decorator based on the
0100     //  argument type passed.  The default it to just 'pass through'
0101     //  the argument as the decorator itself
0102     template <typename T, typename TRecord, typename TDecorator>
0103     inline const TDecorator& createDecoratorFrom(T*, const TRecord*, const TDecorator& iDec) {
0104       return iDec;
0105     }
0106   }  // namespace eventsetup
0107 
0108   class ESProducer : public ESProductResolverFactoryProducer {
0109   public:
0110     ESProducer();
0111     ~ESProducer() noexcept(false) override;
0112     ESProducer(const ESProducer&) = delete;
0113     ESProducer& operator=(const ESProducer&) = delete;
0114     ESProducer(ESProducer&&) = delete;
0115     ESProducer& operator=(ESProducer&&) = delete;
0116 
0117     void updateLookup(eventsetup::ESRecordsToProductResolverIndices const&) final;
0118     ESResolverIndex const* getTokenIndices(unsigned int iIndex) const {
0119       if (itemsToGetFromRecords_.empty()) {
0120         return nullptr;
0121       }
0122       return (itemsToGetFromRecords_[iIndex].empty()) ? static_cast<ESResolverIndex const*>(nullptr)
0123                                                       : &(itemsToGetFromRecords_[iIndex].front());
0124     }
0125     ESRecordIndex const* getTokenRecordIndices(unsigned int iIndex) const {
0126       if (recordsUsedDuringGet_.empty()) {
0127         return nullptr;
0128       }
0129       return (recordsUsedDuringGet_[iIndex].empty()) ? static_cast<ESRecordIndex const*>(nullptr)
0130                                                      : &(recordsUsedDuringGet_[iIndex].front());
0131     }
0132     size_t numberOfTokenIndices(unsigned int iIndex) const {
0133       if (itemsToGetFromRecords_.empty()) {
0134         return 0;
0135       }
0136       return itemsToGetFromRecords_[iIndex].size();
0137     }
0138 
0139     bool hasMayConsumes() const noexcept { return hasMayConsumes_; }
0140 
0141     template <typename Record>
0142     std::optional<std::vector<ESResolverIndex>> updateFromMayConsumes(unsigned int iIndex,
0143                                                                       const Record& iRecord) const {
0144       if (not hasMayConsumes()) {
0145         return {};
0146       }
0147       std::vector<ESResolverIndex> ret = itemsToGetFromRecords_[iIndex];
0148       auto const info = consumesInfos_[iIndex].get();
0149       for (size_t i = 0; i < info->size(); ++i) {
0150         auto chooserBase = (*info)[i].chooser_.get();
0151         if (chooserBase) {
0152           auto chooser = static_cast<eventsetup::impl::MayConsumeChooserBase<Record>*>(chooserBase);
0153           ret[i] = chooser->makeChoice(iRecord);
0154         }
0155       }
0156       return ret;
0157     }
0158 
0159     SerialTaskQueueChain& queue() { return acquirer_.serialQueueChain(); }
0160 
0161     void esModulesWhoseProductsAreConsumed(std::vector<eventsetup::ComponentDescription const*>& esModules,
0162                                            eventsetup::ESRecordsToProductResolverIndices const&) const;
0163 
0164     std::vector<std::vector<ESModuleConsumesInfo>> esModuleConsumesInfos(
0165         eventsetup::ESRecordsToProductResolverIndices const&) const;
0166 
0167   protected:
0168     /** Specify the names of the shared resources used by this ESProducer */
0169     void usesResources(std::vector<std::string> const&);
0170 
0171     /** \param iThis the 'this' pointer to an inheriting class instance
0172         The method determines the Record argument and return value of the 'produce'
0173         method in order to do the registration with the EventSetup
0174     */
0175     template <typename T>
0176     auto setWhatProduced(T* iThis, const es::Label& iLabel = {}) {
0177       return setWhatProduced(iThis, &T::produce, iLabel);
0178     }
0179 
0180     template <typename T>
0181     auto setWhatProduced(T* iThis, const char* iLabel) {
0182       return setWhatProduced(iThis, es::Label(iLabel));
0183     }
0184 
0185     template <typename T>
0186     auto setWhatProduced(T* iThis, const std::string& iLabel) {
0187       return setWhatProduced(iThis, es::Label(iLabel));
0188     }
0189 
0190     template <typename T, typename TDecorator>
0191     auto setWhatProduced(T* iThis, const TDecorator& iDec, const es::Label& iLabel = {}) {
0192       return setWhatProduced(iThis, &T::produce, iDec, iLabel);
0193     }
0194     /** \param iThis the 'this' pointer to an inheriting class instance
0195         \param iMethod a member method of the inheriting class
0196         The TRecord and TReturn template parameters can be deduced
0197         from iMethod in order to do the registration with the EventSetup
0198     */
0199     template <typename T, typename TReturn, typename TRecord>
0200     auto setWhatProduced(T* iThis, TReturn (T::*iMethod)(const TRecord&), const es::Label& iLabel = {}) {
0201       return setWhatProduced(iThis, iMethod, eventsetup::CallbackSimpleDecorator<TRecord>(), iLabel);
0202     }
0203     /** \param iDecorator a class with 'pre'&'post' methods which are placed around the method call
0204         This function has the same template parameters and arguments as the previous function
0205         except for the addition of the decorator.
0206     */
0207     template <typename T, typename TReturn, typename TRecord, typename TDecorator>
0208     auto setWhatProduced(T* iThis,
0209                          TReturn (T ::*iMethod)(const TRecord&),
0210                          const TDecorator& iDec,
0211                          const es::Label& iLabel = {}) {
0212       return setWhatProduced<TReturn, TRecord>(
0213           [iThis, iMethod](TRecord const& iRecord) { return (iThis->*iMethod)(iRecord); },
0214           createDecoratorFrom(iThis, static_cast<const TRecord*>(nullptr), iDec),
0215           iLabel);
0216     }
0217 
0218     /**
0219      * This overload allows lambdas (functors) to be used as the
0220      * production function. As of now it is not intended for wide use
0221      * (we are thinking for a better API for users)
0222      *
0223      * The main use case of the decorator functionality was
0224      * dependsOn(), but in practice that became unused with
0225      * concurrent IOVs, so it is not clear if the
0226      * decorator functionality is still needed.
0227      */
0228     template <typename TFunc>
0229     auto setWhatProduced(TFunc&& func, const es::Label& iLabel = {}) {
0230       using Types = eventsetup::impl::ReturnArgumentTypes<TFunc>;
0231       using TReturn = typename Types::return_type;
0232       using TRecord = typename Types::argument_type;
0233       using DecoratorType = eventsetup::CallbackSimpleDecorator<TRecord>;
0234       return setWhatProduced<TReturn, TRecord>(std::forward<TFunc>(func), DecoratorType(), iLabel);
0235     }
0236 
0237     template <typename TReturn, typename TRecord, typename TFunc, typename TDecorator>
0238     ESConsumesCollectorT<TRecord> setWhatProduced(TFunc&& func, TDecorator&& iDec, const es::Label& iLabel = {}) {
0239       const auto produceMethodID = consumesInfoSize();
0240       using DecoratorType = std::decay_t<TDecorator>;
0241       using CallbackType = eventsetup::Callback<ESProducer, TFunc, TReturn, TRecord, DecoratorType>;
0242       unsigned int iovIndex = 0;  // Start with 0, but later will cycle through all of them
0243       auto temp = std::make_shared<CallbackType>(
0244           this, std::forward<TFunc>(func), produceMethodID, std::forward<TDecorator>(iDec));
0245       auto callback =
0246           std::make_shared<std::pair<unsigned int, std::shared_ptr<CallbackType>>>(iovIndex, std::move(temp));
0247       registerProducts(std::move(callback),
0248                        static_cast<const typename eventsetup::produce::product_traits<TReturn>::type*>(nullptr),
0249                        static_cast<const TRecord*>(nullptr),
0250                        iLabel);
0251       return ESConsumesCollectorT<TRecord>(consumesInfoPushBackNew(), produceMethodID);
0252     }
0253 
0254     // These next four functions are intended for use in this class and
0255     // class ESProducerExternalWork only. They should not be used in
0256     // other classes derived from them.
0257     unsigned int consumesInfoSize() const { return consumesInfos_.size(); }
0258 
0259     ESConsumesInfo* consumesInfoPushBackNew() {
0260       consumesInfos_.push_back(std::make_unique<ESConsumesInfo>());
0261       return consumesInfos_.back().get();
0262     }
0263 
0264     template <typename CallbackT, typename TList, typename TRecord>
0265     void registerProducts(std::shared_ptr<std::pair<unsigned int, std::shared_ptr<CallbackT>>> iCallback,
0266                           const TList*,
0267                           const TRecord* iRecord,
0268                           const es::Label& iLabel) {
0269       registerProduct(iCallback, static_cast<const typename TList::tail_type*>(nullptr), iRecord, iLabel);
0270       registerProducts(std::move(iCallback), static_cast<const typename TList::head_type*>(nullptr), iRecord, iLabel);
0271     }
0272 
0273     template <typename CallbackT, typename TRecord>
0274     void registerProducts(std::shared_ptr<std::pair<unsigned int, std::shared_ptr<CallbackT>>>,
0275                           const eventsetup::produce::Null*,
0276                           const TRecord*,
0277                           const es::Label&) {
0278       //do nothing
0279     }
0280 
0281   private:
0282     template <typename CallbackT, typename TProduct, typename TRecord>
0283     void registerProduct(std::shared_ptr<std::pair<unsigned int, std::shared_ptr<CallbackT>>> iCallback,
0284                          const TProduct*,
0285                          const TRecord*,
0286                          const es::Label& iLabel) {
0287       using ResolverType = eventsetup::CallbackProductResolver<CallbackT, TRecord, TProduct>;
0288       using FactoryType = eventsetup::ESProductResolverArgumentFactoryTemplate<ResolverType, CallbackT>;
0289       registerFactory(std::make_unique<FactoryType>(std::move(iCallback)), iLabel.default_);
0290     }
0291 
0292     template <typename CallbackT, typename TProduct, typename TRecord, int IIndex>
0293     void registerProduct(std::shared_ptr<std::pair<unsigned int, std::shared_ptr<CallbackT>>> iCallback,
0294                          const es::L<TProduct, IIndex>*,
0295                          const TRecord*,
0296                          const es::Label& iLabel) {
0297       if (iLabel.labels_.size() <= IIndex || iLabel.labels_[IIndex] == es::Label::def()) {
0298         Exception::throwThis(errors::Configuration,
0299                              "Unnamed Label\nthe index ",
0300                              IIndex,
0301                              " was never assigned a name in the 'setWhatProduced' method");
0302       }
0303       using ResolverType = eventsetup::CallbackProductResolver<CallbackT, TRecord, es::L<TProduct, IIndex>>;
0304       using FactoryType = eventsetup::ESProductResolverArgumentFactoryTemplate<ResolverType, CallbackT>;
0305       registerFactory(std::make_unique<FactoryType>(std::move(iCallback)), iLabel.labels_[IIndex]);
0306     }
0307 
0308     std::vector<std::unique_ptr<ESConsumesInfo>> consumesInfos_;
0309     std::vector<std::vector<ESResolverIndex>> itemsToGetFromRecords_;
0310     //need another structure to say which record to get the data from in
0311     // order to make prefetching work
0312     std::vector<std::vector<ESRecordIndex>> recordsUsedDuringGet_;
0313 
0314     SharedResourcesAcquirer acquirer_;
0315     std::unique_ptr<std::vector<std::string>> sharedResourceNames_;
0316     bool hasMayConsumes_ = false;
0317   };
0318 }  // namespace edm
0319 #endif