File indexing completed on 2024-04-06 12:11:38
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
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
0022 #include "Fireworks/Core/src/FWExpressionValidator.h"
0023 #include "CommonTools/Utils/interface/returnType.h"
0024
0025
0026
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 }
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();
0108 }
0109
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 }
0130
0131
0132
0133
0134
0135
0136
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
0170
0171
0172
0173
0174 FWExpressionValidator::~FWExpressionValidator() {}
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
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
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 }
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
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
0259 return;
0260 }
0261 nodes = &((*itFind)->options());
0262 begin = (*it) + 1;
0263 }
0264
0265
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
0279