Back to home page

Project CMSSW displayed by LXR

 
 

    


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

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