Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:22:17

0001 #ifndef CondTools_L1Trigger_RecordHelper_h
0002 #define CondTools_L1Trigger_RecordHelper_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     L1Trigger
0006 // Class  :     RecordHelper
0007 //
0008 /**\class RecordHelper RecordHerlper.h CondTools/L1Trigger/interface/RecordHelper.h
0009 
0010  Description: A microframework to deal with the need to fill rather boring getter/setter classes
0011               from Coral classes.
0012 
0013 
0014 */
0015 
0016 #include <type_traits>
0017 
0018 #include "RelationalAccess/ICursor.h"
0019 #include "CoralBase/AttributeList.h"
0020 #include "CoralBase/AttributeSpecification.h"
0021 #include "CoralBase/Attribute.h"
0022 
0023 /** A C++ version of C's strupper */
0024 std::string upcaseString(std::string aString);
0025 
0026 /** A base class for all field handlers that create TOutput C++ objects. */
0027 template <class TOutput>
0028 class FieldHandlerBase {
0029 public:
0030   typedef coral::AttributeList AttributeList;
0031   /** Construct a new field handler with the C++ field name as its argument */
0032   FieldHandlerBase(const std::string& name) : name_(name) {}
0033   FieldHandlerBase() = delete;
0034 
0035   /** Return the name of the field handled by this object. */
0036   const std::string& getName() { return name_; }
0037 
0038   /** Return the name of the associated database field. For the GMT database,
0039    *  this simply corresponds to the uppercased field name. */
0040   virtual const std::string getColumnName() { return upcaseString(name_); }
0041 
0042   /** The actual extraction function. src contains a CORAL attribute list representing a 
0043    *  query result row, dest is the output object to be filled. */
0044   virtual void extractValue(const AttributeList& src, TOutput& dest) = 0;
0045 
0046   /** Virtual destructor for children. */
0047   virtual ~FieldHandlerBase() {}
0048 
0049 private:
0050   /* The (case sensitive!) name of the field. */
0051   std::string name_;
0052 };
0053 
0054 /** A template field handler that simply 
0055  *    - casts the data field to TCField
0056  *    - converts that value to TCField
0057  *    - passes it to a setter method of a TOutput object
0058  */
0059 template <class TOutput, class TCField, class TDBField>
0060 class FieldHandler : public FieldHandlerBase<TOutput> {
0061 public:
0062   typedef coral::AttributeList AttributeList;
0063   typedef void (TOutput::*TSetMethod)(const TCField);
0064 
0065   FieldHandler(const std::string& fieldName, TSetMethod setter)
0066       : FieldHandlerBase<TOutput>(fieldName), setter_(setter) {}
0067 
0068   FieldHandler() = delete;
0069 
0070   /** Actual data extraction. */
0071   void extractValue(const AttributeList& src, TOutput& dest) override {
0072 #ifdef RECORDHELPER_DEBUG
0073     std::cout << "Parsing field " << this->getName() << " with type " << typeid(TCField).name();
0074 #endif
0075     typedef typename std::remove_cv<typename std::remove_reference<TDBField>::type>::type TDBFieldT;
0076     const TDBFieldT& value = src[this->getColumnName()].template data<TDBFieldT>();
0077     call(dest, TCField(value));
0078 
0079 #ifdef RECORDHELPER_DEBUG
0080     std::cout << "=" << TCField(value) << std::endl;
0081 #endif
0082   }
0083 
0084 protected:
0085   void call(TOutput& dest, const TCField value) { ((dest).*setter_)(value); }
0086   /** Points to the setter method used to stuff the field's value into the
0087      destination object. */
0088   TSetMethod setter_ = nullptr;
0089 };
0090 
0091 /** A special handler for bool fields in the GT/GMT DBs. These can't be imported
0092  *  in the generic way because bool values are returned as char '0' for false and 
0093  * '1' for true from the database. Basically, all values that are != FalseCharacter
0094  *  are treated as true (in adherence to the venerable C tradition).
0095  */
0096 template <class TOutput, char FalseCharacter>
0097 class ASCIIBoolFieldHandler : public FieldHandler<TOutput, bool, char> {
0098 public:
0099   typedef coral::AttributeList AttributeList;
0100   ASCIIBoolFieldHandler(const std::string& fieldName, typename FieldHandler<TOutput, bool, char>::TSetMethod setter)
0101       : FieldHandler<TOutput, bool, char>(fieldName, setter) {}
0102 
0103   ASCIIBoolFieldHandler() = delete;
0104 
0105   /** Extract value as char, then see compare it to '0' to get its truth value. */
0106   void extractValue(const AttributeList& src, TOutput& dest) override {
0107     char value = src[this->getColumnName()].template data<char>();
0108 #ifdef RECORDHELPER_DEBUG
0109     std::cout << " .. and " << this->getColumnName() << " is (in integers) " << (int)value << std::endl;
0110 #endif
0111     this->call(dest, value != FalseCharacter);
0112   }
0113 };
0114 
0115 /** Tag class: Allow overriding of field type -> field handler type mapping
0116                according to the group that a type is added to. This means that
0117            we can override the standard type mappings for some functions. */
0118 
0119 /** The standard group: All types for which no explicit group is defined end up 
0120     here. */
0121 class TStandardGroup;
0122 
0123 /** Generic mapping - all types get TStandardGroup. */
0124 template <typename TOutput>
0125 struct Group {
0126   typedef TStandardGroup Type;
0127 };
0128 
0129 /** A macro that assigns a record type to a group. */
0130 #define RH_ASSIGN_GROUP(TOutput, TGroup) \
0131   template <>                            \
0132   struct Group<TOutput> {                \
0133     typedef TGroup Type;                 \
0134   };
0135 
0136 /** What is all this group stuff good for? It provides a layer of indirection
0137     between output types and field handlers that is not specific to each type,
0138     so that it's possible to handle a bunch of types with a uniform database column ->
0139     field structure mapping with just one group def + 1 RH_ASSIGN_GROUP per type.
0140 */
0141 
0142 /* Generically: We don't mess with types and expect the field types to
0143    exactly match the database types (sadly, CORAL is rather anal about
0144    such things). */
0145 template <typename TOutput, typename TGroup, typename TCType>
0146 struct GroupFieldHandler {
0147   typedef FieldHandler<TOutput, TCType, TCType> Type;
0148 };
0149 
0150 template <class TOutput>
0151 class RecordHelper {
0152 public:
0153   typedef coral::AttributeList AttributeList;
0154   /** A list of field handlers that determine how to handle a record. */
0155   typedef std::vector<FieldHandlerBase<TOutput>*> FieldVector;
0156 
0157   template <typename TField>
0158   void addField(const std::string& fieldName, void (TOutput::*setter)(const TField)) {
0159 #ifdef RECORDHELPER_DEBUG
0160     std::cout << "Adding field " << fieldName << ", type = " << typeid(TField).name() << std::endl;
0161 #endif
0162     this->fields_.push_back(
0163         new typename GroupFieldHandler<TOutput, typename Group<TOutput>::Type, TField>::Type(fieldName, setter));
0164   }
0165 
0166   /** Iterates over all known fields and extracts the fields of the record
0167       in source to the object in dest. */
0168   virtual void extractRecord(const AttributeList& source, TOutput& dest) {
0169     for (typename FieldVector::const_iterator it = fields_.begin(); it != fields_.end(); ++it) {
0170       (*it)->extractValue(source, dest);
0171     }
0172   }
0173 
0174   /** Returns a list of database column names for the added fields. */
0175   virtual std::vector<std::string> getColumnList() {
0176     std::vector<std::string> colList;
0177     for (typename FieldVector::const_iterator it = fields_.begin(); it != fields_.end(); ++it) {
0178       colList.push_back((*it)->getColumnName());
0179     }
0180 
0181     return colList;
0182   }
0183 
0184   /** Destructor: Wipe out all the field handlers. */
0185   virtual ~RecordHelper() {
0186     for (typename FieldVector::iterator it = fields_.begin(); it < fields_.end(); ++it) {
0187       delete *it;
0188     }
0189   }
0190 
0191 protected:
0192   /** List of known fields. TODO: Make private, add base type addField. */
0193   FieldVector fields_;
0194 };
0195 
0196 /** A helper macro to reduce the amount of typing, since
0197    the field name completely determines the setter. */
0198 #define ADD_FIELD(HELPER, OUTPUT_NAME, FIELD_NAME) HELPER.addField(#FIELD_NAME, &OUTPUT_NAME::set##FIELD_NAME);
0199 
0200 #endif