Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 
0002 #ifndef Framework_eventsetup_dependsOn_h
0003 #define Framework_eventsetup_dependsOn_h
0004 // -*- C++ -*-
0005 //
0006 // Package:     Framework
0007 // Class  :     eventsetup_dependsOn
0008 //
0009 /**\class eventsetup_dependsOn eventsetup_dependsOn.h FWCore/Framework/interface/eventsetup_dependsOn.h
0010 
0011  Description: function used to set what methods to call when a dependent Record changes
0012 
0013  Usage:
0014     The function dependsOn takes a variable number of pointers to member methods as arguments.  These methods are then called 
0015   for the ESProducer whenever the dependent Record (determined by looking at the methods lone argument) has changed since the
0016   last time the ESProducer's produce method was called.
0017 \code
0018        MyProducer : public ESProducer { ... };
0019 
0020        MyProducer::MyProducer(...) {
0021           setWhatProduced(this, eventsetup::dependsOn(&MyProducer::callWhenChanges));
0022           ...
0023       }
0024 \endcode
0025 */
0026 /*
0027  Implementation details:
0028  
0029  The dependsOn function does not have enough information to convert the list of member function pointers directly into the
0030  appropriate Decorator class since it is missing the Record type of the Decorator (all it knows are the Record types the 
0031  Decorator depends on).  Therefore we must defer the creation of the Decorator until that Record type is known (which
0032  happens within the body of the ESProducer::setWhatProduced method).  To allow the deferred construction, 
0033  the dependsOn method returns a compile time linked list created via the TwoHolder class (if there is only one 
0034  node you get a OneHolder).  The dependsOn method always makes sure that the second type of the TwoHolder is the member
0035  function pointer which is needed for the later construction stage.
0036  
0037  Within the body of ESProducer::setWhatProduced, the proper Decorator is created by calling 'createDecoratorFrom' which is given
0038  a pointer to the Producer, a dummy pointer to the proper Record and the linked list of member function pointers.  The
0039  'createDecoratorFrom' uses the makeCaller and createDependsOnCaller functions to recursively create the proper DependsOnCaller 
0040  functor which is then used by the ESPreFunctorDecorator to do the work.  We use  HolderToCaller template class merely to define 
0041  the return type of the 'createDecoratorFrom' and 'makeCaller' functions.
0042  
0043  */
0044 
0045 //
0046 // Original Author:  Chris Jones
0047 //         Created:  Thu Jun 23 14:06:56 EDT 2005
0048 //
0049 
0050 // system include files
0051 
0052 // user include files
0053 #include "FWCore/Framework/interface/ESPreFunctorDecorator.h"
0054 
0055 // forward declarations
0056 
0057 namespace edm {
0058   namespace eventsetup {
0059 
0060     //Simple functor that checks to see if a Record has changed since the last time it was called
0061     // and if so, calls the appropriate member method.  Multiple callers can be chained together using the
0062     // TCallerChain template argument.
0063     template <class T, class TRecord, class TDependsOnRecord, class TCallerChain>
0064     struct DependsOnCaller {
0065       DependsOnCaller(T* iCallee, void (T::*iMethod)(const TDependsOnRecord&), const TCallerChain& iChain)
0066           : callee_(iCallee), method_(iMethod), chain_(iChain), cacheID_(0) {}
0067 
0068       void operator()(const TRecord& iRecord) {
0069         const TDependsOnRecord& record = iRecord.template getRecord<TDependsOnRecord>();
0070         if (record.cacheIdentifier() != cacheID_) {
0071           (callee_->*method_)(record);
0072           cacheID_ = record.cacheIdentifier();
0073         }
0074         //call next 'functor' in our chain
0075         chain_(iRecord);
0076       }
0077 
0078     private:
0079       T* callee_;
0080       void (T::*method_)(const TDependsOnRecord&);
0081       TCallerChain chain_;
0082       unsigned long long cacheID_;
0083     };
0084 
0085     //helper function to help create a DependsOnCaller
0086     template <class T, class TRecord, class TDependsOnRecord, class TCallerChain>
0087     DependsOnCaller<T, TRecord, TDependsOnRecord, TCallerChain> createDependsOnCaller(
0088         T* iCallee, const TRecord*, void (T::*iMethod)(const TDependsOnRecord&), const TCallerChain& iChain) {
0089       return DependsOnCaller<T, TRecord, TDependsOnRecord, TCallerChain>(iCallee, iMethod, iChain);
0090     }
0091 
0092     //A 'do nothing' functor that is used to terminate our chain of functors
0093     template <class TRecord>
0094     struct DependsOnDoNothingCaller {
0095       void operator()(const TRecord&) {}
0096     };
0097 
0098     //put implementation details used to get the dependsOn method to work into their own namespace
0099     namespace depends_on {
0100       //class to hold onto one member method pointer
0101       template <class T, class TDependsOnRecord>
0102       struct OneHolder {
0103         typedef T Prod_t;
0104         typedef TDependsOnRecord DependsOnRecord_t;
0105 
0106         OneHolder(void (T::*iHoldee)(const TDependsOnRecord&)) : holdee_(iHoldee) {}
0107         void (T::*holdee_)(const TDependsOnRecord&);
0108       };
0109 
0110       //class to create a linked list of member method pointers
0111       template <class T, class U>
0112       struct TwoHolder {
0113         typedef T T1_t;
0114         typedef U T2_t;
0115         TwoHolder(const T& i1, const U& i2) : h1_(i1), h2_(i2) {}
0116         T h1_;
0117         U h2_;
0118       };
0119 
0120       //allows one to create the linked list by applying operator & to member method pointers
0121       template <class T, class U>
0122       TwoHolder<T, U> operator&(const T& iT, const U& iU) {
0123         return TwoHolder<T, U>(iT, iU);
0124       }
0125 
0126       //HolderToCaller is used to state how a OneHolder or TwoHolder is converted into the appropriate
0127       // DependsOnCaller.  This class is needed to define the return value of the makeCaller function
0128       template <class TRecord, class THolder>
0129       struct HolderToCaller {};
0130       template <class TRecord, class T, class TDependsOnRecord>
0131       struct HolderToCaller<TRecord, OneHolder<T, TDependsOnRecord> > {
0132         typedef DependsOnCaller<T, TRecord, TDependsOnRecord, DependsOnDoNothingCaller<TRecord> > Caller_t;
0133       };
0134       template <class TRecord, class T, class T1, class T2>
0135       struct HolderToCaller<TRecord, TwoHolder<T1, void (T::*)(const T2&)> > {
0136         typedef DependsOnCaller<T, TRecord, T2, typename HolderToCaller<TRecord, T1>::Caller_t> Caller_t;
0137       };
0138 
0139       //helper function to convert a OneHolder or TwoHolder into a DependsOnCaller.
0140       template <class T, class TDependsOnRecord, class TRecord>
0141       DependsOnCaller<T, TRecord, TDependsOnRecord, DependsOnDoNothingCaller<TRecord> > makeCaller(
0142           T* iT, const TRecord* iRec, const OneHolder<T, TDependsOnRecord>& iHolder) {
0143         return createDependsOnCaller(iT, iRec, iHolder.holdee_, DependsOnDoNothingCaller<TRecord>());
0144       }
0145 
0146       template <class T, class T1, class T2, class TRecord>
0147       DependsOnCaller<T, TRecord, T2, typename HolderToCaller<TRecord, T1>::Caller_t> makeCaller(
0148           T* iT, const TRecord* iRec, const TwoHolder<T1, void (T::*)(const T2&)>& iHolder) {
0149         return createDependsOnCaller(iT, iRec, iHolder.h2_, makeCaller(iT, iRec, iHolder.h1_));
0150       }
0151     }  // namespace depends_on
0152 
0153     //DecoratorFromArg is used to declare the return type of 'createDecoratorFrom' based on the arguments to the function.
0154     template <typename T, typename TRecord, typename TArg>
0155     struct DecoratorFromArg {
0156       typedef TArg Decorator_t;
0157     };
0158 
0159     template <typename T, typename TRecord, typename TDependsOnRecord>
0160     struct DecoratorFromArg<T, TRecord, depends_on::OneHolder<T, TDependsOnRecord> > {
0161       typedef ESPreFunctorDecorator<TRecord,
0162                                     DependsOnCaller<T, TRecord, TDependsOnRecord, DependsOnDoNothingCaller<TRecord> > >
0163           Decorator_t;
0164     };
0165 
0166     template <typename T, typename TRecord, typename TDependsOnRecord>
0167     inline ESPreFunctorDecorator<TRecord,
0168                                  DependsOnCaller<T, TRecord, TDependsOnRecord, DependsOnDoNothingCaller<TRecord> > >
0169     createDecoratorFrom(T* iT, const TRecord* iRec, const depends_on::OneHolder<T, TDependsOnRecord>& iHolder) {
0170       DependsOnDoNothingCaller<TRecord> tCaller;
0171       ESPreFunctorDecorator<TRecord, DependsOnCaller<T, TRecord, TDependsOnRecord, DependsOnDoNothingCaller<TRecord> > >
0172           temp(createDependsOnCaller(iT, iRec, iHolder.holdee_, tCaller));
0173       return temp;
0174     }
0175 
0176     template <typename T, typename TRecord, typename T1, typename T2>
0177     struct DecoratorFromArg<T, TRecord, depends_on::TwoHolder<T1, T2> > {
0178       typedef ESPreFunctorDecorator<
0179           TRecord,
0180           typename depends_on::HolderToCaller<TRecord, depends_on::TwoHolder<T1, T2> >::Caller_t>
0181           Decorator_t;
0182     };
0183     template <typename T, typename TRecord, typename T1, typename T2>
0184     inline ESPreFunctorDecorator<TRecord,
0185                                  typename depends_on::HolderToCaller<TRecord, depends_on::TwoHolder<T1, T2> >::Caller_t>
0186     createDecoratorFrom(T* iT, const TRecord* iRec, const depends_on::TwoHolder<T1, T2>& iHolder) {
0187       return ESPreFunctorDecorator<
0188           TRecord,
0189           typename depends_on::HolderToCaller<TRecord, depends_on::TwoHolder<T1, T2> >::Caller_t>(
0190           createDependsOnCaller(iT, iRec, iHolder.h2_, makeCaller(iT, iRec, iHolder.h1_)));
0191     }
0192 
0193     //The actual dependsOn functions which users call
0194     template <typename T, typename TDependsOnRecord>
0195     depends_on::OneHolder<T, TDependsOnRecord> dependsOn(void (T::*iT)(const TDependsOnRecord&)) {
0196       return iT;
0197     }
0198 
0199     template <typename T, typename T1, typename T2>
0200     depends_on::TwoHolder<depends_on::OneHolder<T, T1>, T2> dependsOn(void (T::*iT1)(const T1&), T2 iT2) {
0201       return depends_on::OneHolder<T, T1>(iT1) & iT2;
0202     }
0203 
0204     template <typename T, typename T1, typename T2, typename T3>
0205     depends_on::TwoHolder<depends_on::TwoHolder<depends_on::OneHolder<T, T1>, T2>, T3> dependsOn(
0206         void (T::*iT1)(const T1&), T2 iT2, T3 iT3) {
0207       return depends_on::OneHolder<T, T1>(iT1) & iT2 & iT3;
0208     }
0209 
0210   }  // namespace eventsetup
0211 }  // namespace edm
0212 
0213 #endif