Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-08-30 04:05:52

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