Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #ifndef FWCore_Framework_ESProductHost_h
0002 #define FWCore_Framework_ESProductHost_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     Framework
0006 // Class:      ESProductHost
0007 //
0008 /**\class edm::ESProductHost
0009 
0010   Description: Helps an ESProducer produce an ESProduct that has
0011 complex dependences on multiple record types. In particular,
0012 it helps it manage what is executed in the produce function
0013 based on which records changed and which did not.
0014 
0015 This was designed as a replacement for the EventSetup "dependsOn"
0016 functionality and is needed in some cases where the "dependsOn"
0017 callbacks would not work well when processing multiple IOVs
0018 concurrently.
0019 
0020   Usage:
0021 
0022 An ESProducer class would use this class.
0023 
0024 1. Add to the ESProducer header
0025 
0026     #include "FWCore/Framework/interface/ESProductHost.h"
0027     #include "FWCore/Utilities/interface/ReusableObjectHolder.h"
0028 
0029 2. Assume the following only for purposes of this usage example
0030 (the actual types in your case would be different). If the produced
0031 function was defined as follows:
0032 
0033     std::shared_ptr<ESTestDataB> produce(ESTestRecordB const&);
0034 
0035 and assume there is some special dependence on ESTestRecordC and
0036 ESTestRecordD.
0037 
0038 3. Then you would add a data member to the ESProducer similar
0039 to the following:
0040 
0041     using HostType = edm::ESProductHost<ESTestDataB,
0042                                         ESTestRecordC,
0043                                         ESTestRecordD>;
0044 
0045     edm::ReusableObjectHolder<HostType> holder_;
0046 
0047 4. Then the produce function would be defined something similar
0048 to this:
0049 
0050     std::shared_ptr<ESTestDataB> ESTestProducerBUsingHost::produce(ESTestRecordB const& record) {
0051 
0052       auto host = holder_.makeOrGet([]() {
0053         return new HostType;
0054       });
0055 
0056       host->ifRecordChanges<ESTestRecordC>(record,
0057                                            [this, h=host.get()](auto const& rec) {
0058         // Do whatever special needs to be done only when record C changes
0059         // (If you are using this class to replace a dependsOn callback, you could
0060         // call the function that dependsOn used as a callback here)
0061       });
0062 
0063       host->ifRecordChanges<ESTestRecordD>(record,
0064                                            [this, h=host.get()](auto const& rec) {
0065         // Do whatever special needs to be done only when record D changes
0066       });
0067 
0068     ... repeat for as many record types as you need.
0069 */
0070 //
0071 // Author:      W. David Dagenhart
0072 // Created:     28 August 2018
0073 //
0074 
0075 #include <cstddef>
0076 #include <type_traits>
0077 #include <vector>
0078 
0079 namespace edm {
0080 
0081   // The parameter pack RecordTypes should contain all the
0082   // record types which you want to use when calling the
0083   // function "ifRecordChanges" as the first template parameter
0084   // to that function (the RecordType). The list of types in
0085   // RecordTypes is used only to size the vector of cacheIDs_ and
0086   // to establish an order of the types in RecordTypes. The
0087   // order is only used to establish a one to one correspondence
0088   // between cacheIDs_ and the types. The particular order
0089   // selected does not mattter, just that some order exists
0090   // so we know which cacheID corresponds to which type.
0091 
0092   template <typename Product, typename... RecordTypes>
0093   class ESProductHost final : public Product {
0094   public:
0095     template <typename... Args>
0096     ESProductHost(Args&&... args) : Product(std::forward<Args>(args)...), cacheIDs_(numberOfRecordTypes(), 0) {}
0097 
0098     // Execute FUNC if the cacheIdentifier in the EventSetup RecordType
0099     // has changed since the last time we called FUNC for
0100     // this EventSetup product.
0101 
0102     template <typename RecordType, typename ContainingRecordType, typename FUNC>
0103     void ifRecordChanges(ContainingRecordType const& containingRecord, FUNC func) {
0104       RecordType const& record = containingRecord.template getRecord<RecordType>();
0105       unsigned long long cacheIdentifier = record.cacheIdentifier();
0106       std::size_t iRecord = index<RecordType>();
0107       if (cacheIdentifier != cacheIDs_[iRecord]) {
0108         cacheIDs_[iRecord] = cacheIdentifier;
0109         func(record);
0110       }
0111     }
0112 
0113     // The rest of the functions are not intended for public use.
0114     // The only reason they are not private is that test code
0115     // uses them.
0116 
0117     // Return the number of record types for which we want to check
0118     // if the cache identifier changed.
0119 
0120     constexpr static std::size_t numberOfRecordTypes() { return sizeof...(RecordTypes); }
0121 
0122     // Return the index of a record type in the types in the parameter pack RecordTypes.
0123     // The first type in the template parameters after the Product type
0124     // will have an index of 0, the next 1, and so on.
0125     // (There must be at least one type after Product if you want to call the
0126     // "ifRecordChanges" function).
0127 
0128     template <typename U>
0129     constexpr static std::size_t index() {
0130       static_assert(numberOfRecordTypes() > 0, "no record types in ESProductHost");
0131       return indexLoop<0, U, RecordTypes...>();
0132     }
0133 
0134     template <std::size_t I, typename U, typename TST, typename... M>
0135     constexpr static std::size_t indexLoop() {
0136       if constexpr (std::is_same_v<U, TST>) {
0137         return I;
0138       } else {
0139         static_assert(I + 1 < numberOfRecordTypes(), "unknown record type passed to ESProductHost::index");
0140         return indexLoop<I + 1, U, M...>();
0141       }
0142     }
0143 
0144   private:
0145     // Data member, this holds the cache identifiers from the record which
0146     // are used to determine whether the EventSetup cache for that record has
0147     // been updated since this Product was lasted updated.
0148 
0149     std::vector<unsigned long long> cacheIDs_;
0150   };
0151 }  // namespace edm
0152 #endif