Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:11:38

0001 // -*- C++ -*-
0002 //
0003 // Package:     Core
0004 // Class  :     FWExpressionValidator
0005 //
0006 // Implementation:
0007 //     <Notes on implementation>
0008 //
0009 // Original Author:  Chris Jones
0010 //         Created:  Fri Aug 22 20:42:51 EDT 2008
0011 //
0012 
0013 // system include files
0014 #include <cctype>
0015 #include <algorithm>
0016 
0017 #include "FWCore/Reflection/interface/BaseWithDict.h"
0018 #include "FWCore/Reflection/interface/FunctionWithDict.h"
0019 #include <cstring>
0020 
0021 // user include files
0022 #include "Fireworks/Core/src/FWExpressionValidator.h"
0023 #include "CommonTools/Utils/interface/returnType.h"
0024 
0025 //
0026 // constants, enums and typedefs
0027 //
0028 typedef std::vector<std::shared_ptr<fireworks::OptionNode> > Options;
0029 
0030 namespace fireworks {
0031   template <class T>
0032   struct OptionNodePtrCompare {
0033     bool operator()(const T& iLHS, const T& iRHS) const { return *iLHS < *iRHS; }
0034   };
0035 
0036   template <class T>
0037   struct OptionNodePtrEqual {
0038     bool operator()(const T& iLHS, const T& iRHS) const { return iLHS->description() == iRHS->description(); }
0039   };
0040 
0041   class OptionNode {
0042   public:
0043     OptionNode(const edm::FunctionWithDict&);
0044     OptionNode(const std::string& iDescription, unsigned long iSubstitutionEnd, const edm::TypeWithDict& iType);
0045 
0046     const std::string& description() const { return m_description; }
0047     unsigned long substitutionEnd() const { return m_endOfName; }
0048     const std::vector<std::shared_ptr<OptionNode> >& options() const {
0049       if (m_hasSubOptions && m_subOptions.empty()) {
0050         fillOptionForType(m_type, m_subOptions);
0051         std::sort(
0052             m_subOptions.begin(), m_subOptions.end(), fireworks::OptionNodePtrCompare<std::shared_ptr<OptionNode> >());
0053         std::vector<std::shared_ptr<OptionNode> >::iterator it = std::unique(
0054             m_subOptions.begin(), m_subOptions.end(), fireworks::OptionNodePtrEqual<std::shared_ptr<OptionNode> >());
0055         m_subOptions.erase(it, m_subOptions.end());
0056 
0057         m_hasSubOptions = !m_subOptions.empty();
0058       }
0059       return m_subOptions;
0060     }
0061 
0062     bool operator<(const OptionNode& iRHS) const {
0063       return m_description.substr(0, m_endOfName) < iRHS.m_description.substr(0, iRHS.m_endOfName);
0064     }
0065 
0066     static void fillOptionForType(const edm::TypeWithDict&, std::vector<std::shared_ptr<OptionNode> >&);
0067 
0068   private:
0069     edm::TypeWithDict m_type;
0070     mutable std::string m_description;
0071     mutable std::string::size_type m_endOfName;
0072     mutable std::vector<std::shared_ptr<OptionNode> > m_subOptions;
0073     mutable bool m_hasSubOptions;
0074     static bool typeHasOptions(const edm::TypeWithDict& iType);
0075   };
0076 
0077   OptionNode::OptionNode(const std::string& iDescription,
0078                          unsigned long iSubstitutionEnd,
0079                          const edm::TypeWithDict& iType)
0080       : m_type(iType),
0081         m_description(iDescription),
0082         m_endOfName(iSubstitutionEnd),
0083         m_hasSubOptions(typeHasOptions(iType)) {}
0084 
0085   namespace {
0086     std::string descriptionFromMember(const edm::FunctionWithDict& iMember) {
0087       std::string typeString = iMember.typeName();
0088       std::string::size_type index = typeString.find_first_of('(');
0089       if (index == std::string::npos) {
0090         return iMember.name() + ":" + typeString;
0091       } else {
0092         return iMember.name() + typeString.substr(index, std::string::npos) + ":" + typeString.substr(0, index);
0093       }
0094     }
0095   }  // namespace
0096 
0097   OptionNode::OptionNode(const edm::FunctionWithDict& iMember)
0098       : m_type(reco::returnType(iMember)),
0099         m_description(descriptionFromMember(iMember)),
0100         m_endOfName(iMember.name().size()),
0101         m_hasSubOptions(typeHasOptions(m_type)) {}
0102 
0103   void OptionNode::fillOptionForType(const edm::TypeWithDict& iType,
0104                                      std::vector<std::shared_ptr<OptionNode> >& oOptions) {
0105     edm::TypeWithDict type = iType;
0106     if (type.isPointer()) {
0107       type = type.toType();  // for Pointers, I get the real type this way
0108     }
0109     // first look in base scope
0110     edm::TypeFunctionMembers functions(type);
0111     oOptions.reserve(oOptions.size() + functions.size());
0112     for (auto const& function : functions) {
0113       edm::FunctionWithDict m(function);
0114       if (!m.isConst() || m.isConstructor() || m.isDestructor() || m.isOperator() || !m.isPublic() ||
0115           m.name().substr(0, 2) == "__") {
0116         continue;
0117       }
0118       oOptions.push_back(std::make_shared<OptionNode>(m));
0119     }
0120 
0121     edm::TypeBases bases(type);
0122     for (auto const& base : bases) {
0123       fillOptionForType(edm::BaseWithDict(base).typeOf(), oOptions);
0124     }
0125   }
0126 
0127   bool OptionNode::typeHasOptions(const edm::TypeWithDict& iType) { return iType.isClass(); }
0128 
0129 }  // namespace fireworks
0130 
0131 //
0132 // static data member definitions
0133 //
0134 
0135 //
0136 // constructors and destructor
0137 //
0138 #define FUN1(_fun_) \
0139   m_builtins.push_back(std::make_shared<OptionNode>(#_fun_ "(float):float", strlen(#_fun_) + 1, s_float))
0140 
0141 #define FUN2(_fun_) \
0142   m_builtins.push_back(std::make_shared<OptionNode>(#_fun_ "(float,float):float", strlen(#_fun_) + 1, s_float))
0143 
0144 FWExpressionValidator::FWExpressionValidator() {
0145   using fireworks::OptionNode;
0146   static const edm::TypeWithDict s_float(typeid(float));
0147   FUN1(abs);
0148   FUN1(acos);
0149   FUN1(asin);
0150   FUN1(atan);
0151   FUN1(cos);
0152   FUN1(cosh);
0153   FUN1(exp);
0154   FUN1(log);
0155   FUN1(log10);
0156   FUN1(sin);
0157   FUN1(sinh);
0158   FUN1(sqrt);
0159   FUN1(tan);
0160   FUN1(tanh);
0161   FUN2(atan2);
0162   FUN2(chi2prob);
0163   FUN2(pow);
0164   FUN2(min);
0165   FUN2(max);
0166   std::sort(m_builtins.begin(), m_builtins.end(), fireworks::OptionNodePtrCompare<std::shared_ptr<OptionNode> >());
0167 }
0168 
0169 // FWExpressionValidator::FWExpressionValidator(const FWExpressionValidator& rhs)
0170 // {
0171 //    // do actual copying here;
0172 // }
0173 
0174 FWExpressionValidator::~FWExpressionValidator() {}
0175 
0176 //
0177 // assignment operators
0178 //
0179 // const FWExpressionValidator& FWExpressionValidator::operator=(const FWExpressionValidator& rhs)
0180 // {
0181 //   //An exception safe implementation is
0182 //   FWExpressionValidator temp(rhs);
0183 //   swap(rhs);
0184 //
0185 //   return *this;
0186 // }
0187 
0188 //
0189 // member functions
0190 //
0191 void FWExpressionValidator::setType(const edm::TypeWithDict& iType) {
0192   using fireworks::OptionNode;
0193   m_type = iType;
0194   m_options.clear();
0195   m_options = m_builtins;
0196   OptionNode::fillOptionForType(iType, m_options);
0197   std::sort(m_options.begin(), m_options.end(), fireworks::OptionNodePtrCompare<std::shared_ptr<OptionNode> >());
0198   std::vector<std::shared_ptr<OptionNode> >::iterator it =
0199       std::unique(m_options.begin(), m_options.end(), fireworks::OptionNodePtrEqual<std::shared_ptr<OptionNode> >());
0200   m_options.erase(it, m_options.end());
0201 }
0202 
0203 //
0204 // const member functions
0205 //
0206 namespace {
0207   void dummyDelete(void*) {}
0208 
0209   void findTypeDelimiters(const char*& ioBegin, const char* iEnd, std::vector<const char*>& oDelimeters) {
0210     oDelimeters.clear();
0211     if (ioBegin == iEnd) {
0212       return;
0213     }
0214     const char* it = iEnd - 1;
0215     const char* itEnd = ioBegin - 1;
0216     for (; it != itEnd; --it) {
0217       if (isalnum(*it)) {
0218         continue;
0219       }
0220       bool shouldStop = false;
0221       switch (*it) {
0222         case '_':
0223           break;
0224         case '.':
0225           oDelimeters.push_back(it);
0226           break;
0227         default:
0228           shouldStop = true;
0229       }
0230       if (shouldStop) {
0231         break;
0232       }
0233     }
0234     ioBegin = it + 1;
0235     std::reverse(oDelimeters.begin(), oDelimeters.end());
0236   }
0237 }  // namespace
0238 
0239 void FWExpressionValidator::fillOptions(
0240     const char* iBegin,
0241     const char* iEnd,
0242     std::vector<std::pair<std::shared_ptr<std::string>, std::string> >& oOptions) const {
0243   using fireworks::OptionNode;
0244   oOptions.clear();
0245   std::vector<const char*> delimeters;
0246   findTypeDelimiters(iBegin, iEnd, delimeters);
0247   //must find correct OptionNode
0248   const Options* nodes = &m_options;
0249   const char* begin = iBegin;
0250   for (std::vector<const char*>::iterator it = delimeters.begin(), itEnd = delimeters.end(); it != itEnd; ++it) {
0251     OptionNode temp(std::string(begin, *it), *it - begin, edm::TypeWithDict());
0252 
0253     std::shared_ptr<OptionNode> comp(&temp, dummyDelete);
0254     Options::const_iterator itFind = std::lower_bound(
0255         nodes->begin(), nodes->end(), comp, fireworks::OptionNodePtrCompare<std::shared_ptr<OptionNode> >());
0256 
0257     if (itFind == nodes->end() || *comp < *(*itFind)) {
0258       //no match so we have an error
0259       return;
0260     }
0261     nodes = &((*itFind)->options());
0262     begin = (*it) + 1;
0263   }
0264 
0265   //only use add items which begin with the part of the member we are trying to match
0266   std::string part(begin, iEnd);
0267   unsigned int part_size = part.size();
0268   for (Options::const_iterator it = nodes->begin(), itEnd = nodes->end(); it != itEnd; ++it) {
0269     if (part == (*it)->description().substr(0, part_size)) {
0270       oOptions.push_back(
0271           std::make_pair(std::shared_ptr<std::string>(const_cast<std::string*>(&((*it)->description())), dummyDelete),
0272                          (*it)->description().substr(part_size, (*it)->substitutionEnd() - part_size)));
0273     }
0274   }
0275 }
0276 
0277 //
0278 // static member functions
0279 //