Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #include "FWCore/Reflection/interface/TypeWithDict.h"
0002 
0003 #include "FWCore/Utilities/interface/EDMException.h"
0004 #include "FWCore/Utilities/interface/Exception.h"
0005 #include "FWCore/Utilities/interface/FriendlyName.h"
0006 #include "FWCore/Reflection/interface/FunctionWithDict.h"
0007 #include "FWCore/Reflection/interface/MemberWithDict.h"
0008 #include "FWCore/Reflection/interface/ObjectWithDict.h"
0009 #include "FWCore/Utilities/interface/TypeDemangler.h"
0010 #include "FWCore/Utilities/interface/TypeID.h"
0011 
0012 #include "TClass.h"
0013 #include "TClassTable.h"
0014 #include "TDataType.h"
0015 #include "TEnum.h"
0016 #include "TEnumConstant.h"
0017 #include "TMethodArg.h"
0018 #include "TRealData.h"
0019 #include "TROOT.h"
0020 
0021 #include "oneapi/tbb/concurrent_unordered_map.h"
0022 
0023 #include <cassert>
0024 #include <cstdio>
0025 #include <cstdlib>
0026 #include <ostream>
0027 #include <typeinfo>
0028 #include <typeindex>
0029 
0030 #include <cxxabi.h>
0031 
0032 //#include <iostream>
0033 namespace edm {
0034 
0035   namespace {
0036     using Map = oneapi::tbb::concurrent_unordered_map<std::string, TypeWithDict>;
0037     Map typeMap;
0038     using FunctionMap = oneapi::tbb::concurrent_unordered_map<std::string, FunctionWithDict>;
0039     FunctionMap functionMap;
0040 
0041     struct TypeIndexHash {
0042       std::size_t operator()(std::type_index ti) const { return ti.hash_code(); }
0043     };
0044 
0045     using TypeIndexMap = oneapi::tbb::concurrent_unordered_map<std::type_index, TypeWithDict, TypeIndexHash>;
0046     TypeIndexMap typeIndexMap;
0047   }  // namespace
0048   static void throwTypeException(std::string const& function, std::string const& typeName) {
0049     throw Exception(errors::DictionaryNotFound) << "Function " << function << ",\n"
0050                                                 << "no data dictionary found for type:\n\n"
0051                                                 << typeName << "\nMost likely the dictionary was never generated,\n"
0052                                                 << "but it may be that it was generated in the wrong package.\n"
0053                                                 << "Please add (or move) the specification\n"
0054                                                 << "<class name=\"whatever\"/>\n"
0055                                                 << "to the appropriate classes_def.xml file.\n"
0056                                                 << "If the class is a template instance, you may need\n"
0057                                                 << "to define a dummy variable of this type in classes.h.\n"
0058                                                 << "Also, if this class has any transient members,\n"
0059                                                 << "you need to specify them in classes_def.xml.";
0060   }
0061 
0062   TypeWithDict TypeWithDict::byTypeInfo(std::type_info const& ti) {
0063     // This is a public static function.
0064     auto index = std::type_index(ti);
0065     auto const& item = typeIndexMap.find(index);
0066     if (item != typeIndexMap.end()) {
0067       return item->second;
0068     }
0069     TypeWithDict theType(ti, 0L);
0070     typeIndexMap.insert(std::make_pair(index, theType));
0071     return theType;
0072   }
0073 
0074   TypeWithDict TypeWithDict::byName(std::string const& name) {
0075     // This is a public static function.
0076     auto const& item = typeMap.find(name);
0077     if (item != typeMap.end()) {
0078       return item->second;
0079     }
0080     TypeWithDict theType = TypeWithDict::byName(name, 0L);
0081     typeMap.insert(std::make_pair(name, theType));
0082     return theType;
0083   }
0084 
0085   TypeWithDict TypeWithDict::byName(std::string const& name, long property) {
0086     // This is a private static function.
0087 
0088     static std::string const constPrefix("const ");
0089     static std::string const constSuffix(" const");
0090     static size_t const constPrefixSize(constPrefix.size());
0091     static size_t const constSuffixSize(constSuffix.size());
0092 
0093     // Handle references
0094     if (name.back() == '&') {
0095       assert(property == 0L);
0096       property |= kIsReference;
0097       return byName(name.substr(0, name.size() - 1), property);
0098     }
0099 
0100     // Handle const qualifier
0101     if (name.size() > constSuffixSize && name.back() != '*') {
0102       if (name.substr(0, constPrefixSize) == constPrefix) {
0103         property |= kIsConstant;
0104         return byName(name.substr(constPrefixSize), property);
0105       }
0106       if (name.substr(name.size() - constSuffixSize) == constSuffix) {
0107         property |= kIsConstant;
0108         return byName(name.substr(0, name.size() - constSuffixSize), property);
0109       }
0110     }
0111 
0112     // Handle pointers
0113     if (name.back() == '*') {
0114       // pointer to pointer not supported
0115       assert(!(property & (long)kIsPointer));
0116       // C-style array of pointers is not supported
0117       assert(!(property & (long)kIsArray));
0118       property |= kIsPointer;
0119       if (property & (long)kIsConstant) {
0120         property &= ~((long)kIsConstant);
0121         property |= kIsConstPointer;
0122       }
0123       return byName(name.substr(0, name.size() - 1), property);
0124     }
0125 
0126     // Handle C-style arrays
0127     if (name.back() == ']') {
0128       // pointer to array not supported
0129       assert(!(property & (long)kIsPointer));
0130       // Protect against the remote possibility of '[' nested in a class type
0131       size_t begin = name.find_last_of("<>:,()");
0132       if (begin == std::string::npos) {
0133         begin = 0;
0134       } else {
0135         ++begin;
0136       }
0137       size_t first = name.find('[', begin);
0138       assert(first != std::string::npos);
0139       assert(first != 0);
0140       TypeWithDict ret = TypeWithDict::byName(name.substr(0, first), property);
0141       ret.property_ |= kIsArray;
0142       ret.arrayDimensions_ = value_ptr<std::vector<size_t> >(new std::vector<size_t>);
0143       std::string const dimensions = name.substr(first);
0144       char const* s = dimensions.c_str();
0145       while (true) {
0146         size_t x = 0;
0147         int count = sscanf(s, "[%lu]", &x);
0148         assert(count == 1);
0149         ret.arrayDimensions_->push_back(x);
0150         ++s;
0151         while (*s != '\0' && *s != '[') {
0152           ++s;
0153         }
0154         if (*s == '\0') {
0155           break;
0156         }
0157       }
0158       return ret;
0159     }
0160 
0161     // Handle classes
0162     TClass* theClass = nullptr;
0163     try {
0164       theClass = TClass::GetClass(name.c_str());
0165     } catch (cms::Exception& e) {
0166       e.addContext("Calling edm::TypeWithDict::byName()");
0167       e.addAdditionalInfo("Getting TClass for " + name);
0168       throw;
0169     }
0170     if (theClass != nullptr) {
0171       return TypeWithDict(theClass, property);
0172     }
0173 
0174     // Handle enums
0175     TEnum* theEnum = TEnum::GetEnum(name.c_str(), TEnum::kAutoload);
0176     if (theEnum) {
0177       return TypeWithDict(theEnum, property);
0178     }
0179 
0180     // Handle built-ins
0181     TDataType* theDataType = gROOT->GetType(name.c_str());
0182     if (theDataType) {
0183       switch (theDataType->GetType()) {
0184         case kUInt_t:
0185           return TypeWithDict(typeid(unsigned int), property);
0186         case kInt_t:
0187           return TypeWithDict(typeid(int), property);
0188         case kULong_t:
0189           return TypeWithDict(typeid(unsigned long), property);
0190         case kLong_t:
0191           return TypeWithDict(typeid(long), property);
0192         case kULong64_t:
0193           return TypeWithDict(typeid(unsigned long long), property);
0194         case kLong64_t:
0195           return TypeWithDict(typeid(long long), property);
0196         case kUShort_t:
0197           return TypeWithDict(typeid(unsigned short), property);
0198         case kShort_t:
0199           return TypeWithDict(typeid(short), property);
0200         case kUChar_t:
0201           return TypeWithDict(typeid(unsigned char), property);
0202         case kChar_t:
0203           return TypeWithDict(typeid(char), property);
0204         case kBool_t:
0205           return TypeWithDict(typeid(bool), property);
0206         case kFloat_t:
0207           return TypeWithDict(typeid(float), property);
0208         case kFloat16_t:
0209           return TypeWithDict(typeid(Float16_t), property);
0210         case kDouble_t:
0211           return TypeWithDict(typeid(double), property);
0212         case kDouble32_t:
0213           return TypeWithDict(typeid(Double32_t), property);
0214         case kCharStar:
0215           return TypeWithDict(typeid(char*), property);
0216         case kDataTypeAliasSignedChar_t:
0217           return TypeWithDict(typeid(signed char), property);
0218       }
0219     }
0220 
0221     if (name == "void") {
0222       return TypeWithDict(typeid(void), property);
0223     }
0224 
0225     // For a reason not understood, TClass::GetClass sometimes cannot find std::type_info
0226     // by name.  This simple workaround bypasses the problem.
0227     // The problem really should be debugged.  (testORA12)
0228     if (name == "std::type_info") {
0229       return TypeWithDict(typeid(std::type_info), property);
0230     }
0231 
0232     // For a reason not understood, TClass::GetClass sometimes cannot find std::vector<T>::value_type
0233     // when T is a nested class.
0234     if (stripNamespace(name) == "value_type") {
0235       size_t begin = name.find('<');
0236       size_t end = name.rfind('>');
0237       if (begin != std::string::npos && end != std::string::npos && end > ++begin) {
0238         return TypeWithDict::byName(name.substr(begin, end - begin), property);
0239       }
0240     }
0241     //std::cerr << "DEBUG BY NAME: " << name << std::endl;
0242     return TypeWithDict();
0243   }
0244 
0245   TypeWithDict::TypeWithDict()
0246       : ti_(&typeid(TypeWithDict::invalidType)),
0247         class_(nullptr),
0248         enum_(nullptr),
0249         dataType_(nullptr),
0250         arrayDimensions_(nullptr),
0251         property_(0L) {}
0252 
0253   TypeWithDict::TypeWithDict(TypeWithDict const& rhs)
0254       : ti_(rhs.ti_),
0255         class_(rhs.class_),
0256         enum_(rhs.enum_),
0257         dataType_(rhs.dataType_),
0258         arrayDimensions_(rhs.arrayDimensions_),
0259         property_(rhs.property_) {}
0260 
0261   TypeWithDict& TypeWithDict::stripConstRef() {
0262     if (isPointer()) {
0263       property_ &= ~((long)kIsReference | (long)kIsConstPointer);
0264     } else {
0265       property_ &= ~((long)kIsConstant | (long)kIsReference);
0266     }
0267     return *this;
0268   }
0269 
0270   TypeWithDict& TypeWithDict::operator=(TypeWithDict const& rhs) {
0271     if (this != &rhs) {
0272       ti_ = rhs.ti_;
0273       class_ = rhs.class_;
0274       enum_ = rhs.enum_;
0275       dataType_ = rhs.dataType_;
0276       arrayDimensions_ = rhs.arrayDimensions_;
0277       property_ = rhs.property_;
0278     }
0279     return *this;
0280   }
0281 
0282   TypeWithDict::TypeWithDict(std::type_info const& ti) : TypeWithDict(ti, 0L) {}
0283 
0284   TypeWithDict::TypeWithDict(std::type_info const& ti, long property /*= 0L*/)
0285       : ti_(&ti),
0286         class_(TClass::GetClass(ti)),
0287         enum_(nullptr),
0288         dataType_(TDataType::GetDataType(TDataType::GetType(ti))),
0289         arrayDimensions_(nullptr),
0290         property_(property) {
0291     if (class_ != nullptr) {
0292       return;
0293     }
0294 
0295     // Handle pointers and arrays
0296     // Must be done before dataType_ is checked, because dataType_ will be filled for char*
0297     char lastChar = TypeID(*ti_).className().back();
0298     if (lastChar == '*' || lastChar == ']') {
0299       *this = TypeWithDict::byName(TypeID(*ti_).className());
0300       return;
0301     }
0302 
0303     if (dataType_ != nullptr) {
0304       return;
0305     }
0306 
0307     enum_ = TEnum::GetEnum(ti, TEnum::kAutoload);
0308     if (enum_ != nullptr) {
0309       return;
0310     }
0311 
0312     if (ti == typeid(void)) {
0313       // For some reason, "void" has a data type if accessed by name, but not by type_info.
0314       dataType_ = gROOT->GetType("void");
0315       return;
0316     }
0317 
0318     // std::cerr << "DEBUG BY TI: " << name() << std::endl;
0319 
0320     throwTypeException("TypeWithDict): ", name());
0321   }
0322 
0323   TypeWithDict::TypeWithDict(TClass* cl) : TypeWithDict(cl, 0L) {}
0324 
0325   TypeWithDict::TypeWithDict(TClass* cl, long property)
0326       : ti_(cl->GetTypeInfo()),
0327         class_(cl),
0328         enum_(nullptr),
0329         dataType_(nullptr),
0330         arrayDimensions_(nullptr),
0331         property_(property) {
0332     if (ti_ == nullptr) {
0333       ti_ = &typeid(TypeWithDict::dummyType);
0334     }
0335   }
0336 
0337   TypeWithDict::TypeWithDict(TEnum* enm) : TypeWithDict(enm, 0L) {}
0338 
0339   TypeWithDict::TypeWithDict(TEnum* enm, long property)
0340       : ti_(&typeid(TypeWithDict::dummyType)),
0341         class_(nullptr),
0342         enum_(enm),
0343         dataType_(nullptr),
0344         arrayDimensions_(nullptr),
0345         property_(property) {}
0346 
0347   TypeWithDict::TypeWithDict(TMethodArg* arg) : TypeWithDict(arg, 0L) {}
0348 
0349   TypeWithDict::TypeWithDict(TMethodArg* arg, long property)
0350       : TypeWithDict(byName(arg->GetTypeName(), arg->Property() | property)) {}
0351 
0352   TypeWithDict::operator bool() const {
0353     if (*ti_ == typeid(invalidType)) {
0354       return false;
0355     }
0356     if (class_ != nullptr || dataType_ != nullptr || enum_ != nullptr) {
0357       return true;
0358     }
0359     return false;
0360   }
0361 
0362   bool TypeWithDict::invalidTypeInfo() const { return *ti_ == typeid(dummyType) || isPointer() || isArray(); }
0363 
0364   std::type_info const& TypeWithDict::typeInfo() const {
0365     if (*ti_ == typeid(dummyType) || isPointer() || isArray()) {
0366       // No accurate type_info
0367       if (qualifiedName().c_str() != nullptr) {
0368         std::string category("unknown");
0369         if (isPointer()) {
0370           category = "a pointer";
0371         } else if (isArray()) {
0372           category = "an array";
0373         } else if (isEnum()) {
0374           category = "an enum";
0375         } else if (isClass()) {
0376           throw Exception(errors::DictionaryNotFound) << "No Dictionary for class: '" << name() << "'" << std::endl;
0377         }
0378         throw Exception(errors::LogicError)
0379             << "Function TypeWithDict::typeInfo: Type\n"
0380             << qualifiedName() << "\ndoes not have valid type_info information in ROOT\n"
0381             << "because it is " << category << ".\n";
0382       }
0383     }
0384     return *ti_;
0385   }
0386 
0387   TClass* TypeWithDict::getClass() const {
0388     if (isPointer() || isArray()) {
0389       return nullptr;
0390     }
0391     return class_;
0392   }
0393 
0394   TEnum* TypeWithDict::getEnum() const {
0395     if (isPointer() || isArray()) {
0396       return nullptr;
0397     }
0398     return enum_;
0399   }
0400 
0401   TDataType* TypeWithDict::getDataType() const {
0402     if (isPointer() || isArray()) {
0403       return nullptr;
0404     }
0405     return dataType_;
0406   }
0407 
0408   long TypeWithDict::getProperty() const { return property_; }
0409 
0410   bool TypeWithDict::isClass() const {
0411     // Note: This really means is class, struct, or union.
0412     return class_ != nullptr && !isPointer() && !isArray();
0413   }
0414 
0415   bool TypeWithDict::isConst() const { return (property_ & (long)kIsConstant); }
0416 
0417   bool TypeWithDict::isArray() const { return (property_ & (long)kIsArray); }
0418 
0419   bool TypeWithDict::isEnum() const { return enum_ != nullptr && !isPointer() && !isArray(); }
0420 
0421   bool TypeWithDict::isFundamental() const { return dataType_ != nullptr && !isPointer() && !isArray(); }
0422 
0423   bool TypeWithDict::isPointer() const { return (property_ & (long)kIsPointer); }
0424 
0425   bool TypeWithDict::isReference() const { return (property_ & (long)kIsReference); }
0426 
0427   bool TypeWithDict::isTemplateInstance() const { return (isClass() && name().back() == '>'); }
0428 
0429   bool TypeWithDict::isTypedef() const {
0430     if (class_ != nullptr || dataType_ != nullptr || enum_ != nullptr || *ti_ == typeid(invalidType)) {
0431       return false;
0432     }
0433     return true;
0434   }
0435 
0436   bool TypeWithDict::isVirtual() const { return isClass() && (class_->ClassProperty() & (long)kClassHasVirtual); }
0437 
0438   void TypeWithDict::print(std::ostream& os) const { os << name(); }
0439 
0440   std::string TypeWithDict::cppName() const {
0441     std::string cName = qualifiedName();
0442     // Get rid of silly ROOT typedefs
0443     replaceString(cName, "ULong64_t", "unsigned long long");
0444     replaceString(cName, "Long64_t", "long long");
0445     return cName;
0446   }
0447 
0448   std::string TypeWithDict::qualifiedName() const {
0449     std::string qname(name());
0450     if (isConst() && !isPointer()) {
0451       qname = "const " + qname;
0452     } else if (property_ & kIsConstPointer) {
0453       qname += " const";
0454     }
0455     if (isReference()) {
0456       qname += '&';
0457     }
0458     return qname;
0459   }
0460 
0461   std::string TypeWithDict::unscopedName() const { return stripNamespace(name()); }
0462 
0463   std::string TypeWithDict::name() const {
0464     if (*ti_ == typeid(invalidType)) {
0465       return std::string();
0466     }
0467     std::ostringstream out;
0468     if (isPointer() && isConst()) {
0469       out << "const ";
0470     }
0471     if (enum_ != nullptr) {
0472       if (enum_->GetClass()) {
0473         out << std::string(enum_->GetClass()->GetName());
0474         out << "::";
0475       }
0476       out << enum_->GetName();
0477     } else if (*ti_ == typeid(dummyType) && isClass()) {
0478       out << class_->GetName();
0479     } else {
0480       out << TypeID(*ti_).className();
0481     }
0482     if (isPointer()) {
0483       out << '*';
0484     }
0485     if (isArray()) {
0486       for (size_t i = 0; i < arrayDimension(); ++i) {
0487         out << '[';
0488         out << std::dec << maximumIndex(i);
0489         out << ']';
0490       }
0491     }
0492     return out.str();
0493   }
0494 
0495   std::string TypeWithDict::userClassName() const { return name(); }
0496 
0497   std::string TypeWithDict::friendlyClassName() const { return friendlyname::friendlyName(name()); }
0498 
0499   size_t TypeWithDict::size() const {
0500     size_t nBytes = 0;
0501     if (isPointer()) {
0502       nBytes = sizeof(void*);
0503     } else if (class_ != nullptr) {
0504       nBytes = class_->GetClassSize();
0505     } else if (dataType_ != nullptr) {
0506       nBytes = dataType_->Size();
0507     } else if (enum_ != nullptr) {
0508       nBytes = sizeof(int);
0509     }
0510     if (isArray()) {
0511       nBytes *= arrayLength();
0512     }
0513     return nBytes;
0514   }
0515 
0516   size_t TypeWithDict::arrayLength() const {
0517     assert(isArray());
0518     size_t theLength = 1;
0519     for (size_t i = 0; i < arrayDimension(); ++i) {
0520       theLength *= maximumIndex(i);
0521     }
0522     return theLength;
0523   }
0524 
0525   size_t TypeWithDict::arrayDimension() const {
0526     assert(isArray());
0527     return arrayDimensions_->size();
0528   }
0529 
0530   size_t TypeWithDict::maximumIndex(size_t dim) const {
0531     assert(isArray());
0532     return (*arrayDimensions_)[dim];
0533   }
0534 
0535   size_t TypeWithDict::dataMemberSize() const {
0536     if (isClass()) {
0537       return class_->GetListOfDataMembers()->GetSize();
0538     }
0539     if (isEnum()) {
0540       return enum_->GetConstants()->GetSize();
0541     }
0542     return 0;
0543   }
0544 
0545   size_t TypeWithDict::functionMemberSize() const {
0546     if (isClass()) {
0547       return class_->GetListOfMethods()->GetSize();
0548     }
0549     return 0;
0550   }
0551 
0552   void const* TypeWithDict::pointerToBaseType(void const* ptr, TypeWithDict const& derivedType) const {
0553     if (!isClass()) {
0554       return ptr;
0555     }
0556     if (this->ti_ == derivedType.ti_ || *this->ti_ == *derivedType.ti_) {
0557       return ptr;
0558     }
0559     int offset = derivedType.getBaseClassOffset(*this);
0560     if (offset < 0) {
0561       return nullptr;
0562     }
0563     return static_cast<char const*>(ptr) + offset;
0564   }
0565 
0566   void const* TypeWithDict::pointerToContainedType(void const* ptr, TypeWithDict const& derivedType) const {
0567     if (!isClass()) {
0568       return ptr;
0569     }
0570     return pointerToBaseType(ptr, derivedType);
0571   }
0572 
0573   TypeWithDict TypeWithDict::nestedType(char const* nestedName) const { return byName(name() + "::" + nestedName); }
0574 
0575   TypeWithDict TypeWithDict::nestedType(std::string const& nestedName) const {
0576     return byName(name() + "::" + nestedName);
0577   }
0578 
0579   MemberWithDict TypeWithDict::dataMemberByName(std::string const& member) const {
0580     if (isClass()) {
0581       TDataMember* dataMember = class_->GetDataMember(member.c_str());
0582       if (dataMember == nullptr) {
0583         // Look for indirect data members
0584         TRealData* realDataMember = class_->GetRealData(member.c_str());
0585         if (realDataMember != nullptr) {
0586           dataMember = realDataMember->GetDataMember();
0587         }
0588       }
0589       return MemberWithDict(dataMember);
0590     }
0591     if (isEnum()) {
0592       TClass* cl = enum_->GetClass();
0593       return MemberWithDict(cl->GetDataMember(member.c_str()));
0594     }
0595     return MemberWithDict();
0596   }
0597 
0598   FunctionWithDict TypeWithDict::functionMemberByName(std::string const& member) const {
0599     if (!isClass()) {
0600       return FunctionWithDict();
0601     }
0602     TMethod* meth = reinterpret_cast<TMethod*>(class_->GetListOfMethods()->FindObject(member.c_str()));
0603     if (meth == nullptr) {
0604       return FunctionWithDict();
0605     }
0606     return FunctionWithDict(meth);
0607   }
0608 
0609   FunctionWithDict TypeWithDict::functionMemberByName(std::string const& functionName,
0610                                                       std::string const& proto,
0611                                                       bool isConst) const {
0612     if (!isClass()) {
0613       return FunctionWithDict();
0614     }
0615     std::string const& key = name() + '#' + functionName + '#' + proto;
0616     auto const& item = functionMap.find(key);
0617     if (item != functionMap.end()) {
0618       return item->second;
0619     }
0620     TMethod* meth = class_->GetMethodWithPrototype(
0621         functionName.c_str(), proto.c_str(), /*objectIsConst=*/isConst, /*mode=*/ROOT::kConversionMatch);
0622     if (meth == nullptr) {
0623       return FunctionWithDict();
0624     }
0625     FunctionWithDict theFunction = FunctionWithDict(meth);
0626     functionMap.insert(std::make_pair(key, theFunction));
0627     return theFunction;
0628   }
0629 
0630   TypeWithDict TypeWithDict::finalType() const {
0631     if (*ti_ == typeid(invalidType)) {
0632       return TypeWithDict();
0633     }
0634     if (!isClass() && !isFundamental()) {
0635       return *this;
0636     }
0637     return TypeWithDict(*ti_);
0638   }
0639 
0640   TypeWithDict TypeWithDict::toType() const {
0641     if (*ti_ == typeid(invalidType)) {
0642       return TypeWithDict();
0643     }
0644     if (isReference()) {
0645       TypeWithDict newType = *this;
0646       newType.property_ &= ~((long)kIsReference);
0647       return newType;
0648     }
0649     if (isPointer()) {
0650       TypeWithDict newType = *this;
0651       newType.property_ &= ~((long)kIsPointer | (long)kIsConstPointer);
0652       return newType;
0653     }
0654     if (isArray()) {
0655       TypeWithDict newType = *this;
0656       size_t size = newType.arrayDimensions_->size();
0657       if (size == 1) {
0658         newType.property_ &= ~((long)kIsArray);
0659         value_ptr<std::vector<size_t> > emptyVec;
0660         newType.arrayDimensions_ = emptyVec;
0661       } else {
0662         std::vector<size_t>& dims = *newType.arrayDimensions_;
0663         for (size_t i = 0; i != size; ++i) {
0664           dims[i] = dims[i + 1];
0665         }
0666         newType.arrayDimensions_->resize(size - 1);
0667       }
0668       return newType;
0669     }
0670     return *this;
0671   }
0672 
0673   std::string TypeWithDict::templateName() const {
0674     if (!isTemplateInstance()) {
0675       return "";
0676     }
0677     if (name() == "std::string") {
0678       return std::string("std::basic_string");
0679     }
0680     std::string templateName(name());
0681     auto begin = templateName.find('<');
0682     assert(begin != std::string::npos);
0683     auto end = templateName.rfind('<');
0684     assert(end != std::string::npos);
0685     assert(begin <= end);
0686     if (begin < end) {
0687       int depth = 1;
0688       for (auto idx = begin + 1; idx <= end; ++idx) {
0689         char c = templateName[idx];
0690         if (c == '<') {
0691           if (depth == 0) {
0692             begin = idx;
0693           }
0694           ++depth;
0695         } else if (c == '>') {
0696           --depth;
0697           assert(depth >= 0);
0698         }
0699       }
0700     }
0701     return templateName.substr(0, begin);
0702   }
0703 
0704   TypeWithDict TypeWithDict::templateArgumentAt(size_t index) const {
0705     if (!isClass()) {
0706       return TypeWithDict();
0707     }
0708     std::string className(unscopedName());
0709     auto begin = className.find('<');
0710     if (begin == std::string::npos) {
0711       return TypeWithDict();
0712     }
0713     ++begin;
0714     auto end = className.rfind('>');
0715     assert(end != std::string::npos);
0716     assert(begin < end);
0717     int depth = 0;
0718     size_t argCount = 0;
0719     for (auto idx = begin; idx < end; ++idx) {
0720       char c = className[idx];
0721       if (c == '<') {
0722         ++depth;
0723       } else if (c == '>') {
0724         --depth;
0725         assert(depth >= 0);
0726       } else if ((depth == 0) && (c == ',')) {
0727         if (argCount < index) {
0728           begin = idx + 1;
0729           ++argCount;
0730         } else {
0731           end = idx;
0732           break;
0733         }
0734       }
0735     }
0736     assert(depth == 0);
0737     if (argCount < index) {
0738       return TypeWithDict();
0739     }
0740     return byName(className.substr(begin, end - begin));
0741   }
0742 
0743   bool TypeWithDict::hasBase(std::string const& basename) const {
0744     if (!isClass()) {
0745       return false;
0746     }
0747     TClass* cl = class_->GetBaseClass(basename.c_str());
0748     if (cl != nullptr) {
0749       return true;
0750     }
0751     return false;
0752   }
0753 
0754   bool TypeWithDict::hasBase(TypeWithDict const& basety) const {
0755     if (!isClass()) {
0756       return false;
0757     }
0758     if (basety.class_ == nullptr) {
0759       return false;
0760     }
0761     TClass* cl = class_->GetBaseClass(basety.name().c_str());
0762     if (cl != nullptr) {
0763       return true;
0764     }
0765     return false;
0766   }
0767 
0768   int TypeWithDict::getBaseClassOffset(TypeWithDict const& baseClass) const {
0769     if (!isClass()) {
0770       throw Exception(errors::LogicError) << "Function TypeWithDict::getBaseClassOffset(), type\n"
0771                                           << name() << "\nis not a class\n";
0772     }
0773     if (baseClass.class_ == nullptr) {
0774       throw Exception(errors::LogicError) << "Function TypeWithDict::getBaseClassOffset(), base type\n"
0775                                           << name() << "\nis not a class\n";
0776     }
0777     int offset = class_->GetBaseClassOffset(baseClass.class_);
0778     return offset;
0779   }
0780 
0781   int TypeWithDict::stringToEnumValue(std::string const& name) const {
0782     if (!isEnum()) {
0783       throw Exception(errors::LogicError) << "Function TypeWithDict::stringToEnumValue(), type\n"
0784                                           << name << "\nis not an enum\n";
0785     }
0786     TEnumConstant const* ec = enum_->GetConstant(name.c_str());
0787     if (!ec) {
0788       throw Exception(errors::LogicError) << "Function TypeWithDict::stringToEnumValue(), type\n"
0789                                           << name << "\nis not an enum constant\n";
0790     }
0791     return static_cast<int>(ec->GetValue());
0792   }
0793 
0794   void* TypeWithDict::allocate() const { return new char[size()]; }
0795 
0796   void TypeWithDict::deallocate(void* address) const { delete[] reinterpret_cast<char*>(address); }
0797 
0798   ObjectWithDict TypeWithDict::construct() const {
0799     if (isClass()) {
0800       return ObjectWithDict(*this, class_->New());
0801     }
0802     return ObjectWithDict(*this, new char[size()]);
0803   }
0804 
0805   void TypeWithDict::destruct(void* address, bool dealloc) const {
0806     if (isClass()) {
0807       class_->Destructor(address, !dealloc);
0808       return;
0809     }
0810     if (dealloc) {
0811       delete[] reinterpret_cast<char*>(address);
0812     }
0813   }
0814 
0815   // A related free function
0816   bool hasDictionary(std::type_info const& ti) {
0817     if (ti.name()[1] == '\0') {
0818       // returns true for built in types (single character mangled names)
0819       return true;
0820     }
0821     return (TClassTable::GetDict(ti) != nullptr);
0822   }
0823 
0824   bool operator==(TypeWithDict const& a, TypeWithDict const& b) { return a.name() == b.name(); }
0825 
0826   bool operator==(TypeWithDict const& a, std::type_info const& b) {
0827     if (*a.ti_ == typeid(TypeWithDict::dummyType) || a.isPointer() || a.isArray()) {
0828       // No accurate type_info
0829       return a.name() == TypeID(b).className();
0830     }
0831     return *a.ti_ == b;
0832   }
0833 
0834   std::ostream& operator<<(std::ostream& os, TypeWithDict const& ty) {
0835     ty.print(os);
0836     return os;
0837   }
0838 
0839   //-------------------------------------------------------------
0840   //
0841   //
0842 
0843   TypeBases::TypeBases(TypeWithDict const& type) : class_(type.getClass()) {}
0844 
0845   IterWithDict<TBaseClass> TypeBases::begin() const {
0846     if (class_ == nullptr) {
0847       return IterWithDict<TBaseClass>();
0848     }
0849     return IterWithDict<TBaseClass>(class_->GetListOfBases());
0850   }
0851 
0852   IterWithDict<TBaseClass> TypeBases::end() const { return IterWithDict<TBaseClass>(); }
0853 
0854   size_t TypeBases::size() const {
0855     if (class_ == nullptr) {
0856       return 0;
0857     }
0858     return class_->GetListOfBases()->GetSize();
0859   }
0860 
0861   //-------------------------------------------------------------
0862   //
0863   //
0864 
0865   TypeDataMembers::TypeDataMembers(TypeWithDict const& type) : class_(type.getClass()) {}
0866 
0867   IterWithDict<TDataMember> TypeDataMembers::begin() const {
0868     if (class_ == nullptr) {
0869       return IterWithDict<TDataMember>();
0870     }
0871     return IterWithDict<TDataMember>(class_->GetListOfDataMembers());
0872   }
0873 
0874   IterWithDict<TDataMember> TypeDataMembers::end() const { return IterWithDict<TDataMember>(); }
0875 
0876   size_t TypeDataMembers::size() const {
0877     if (class_ == nullptr) {
0878       return 0;
0879     }
0880     return class_->GetListOfDataMembers()->GetSize();
0881   }
0882 
0883   //-------------------------------------------------------------
0884   //
0885   //
0886 
0887   TypeFunctionMembers::TypeFunctionMembers(TypeWithDict const& type) : class_(type.getClass()) {}
0888 
0889   IterWithDict<TMethod> TypeFunctionMembers::begin() const {
0890     if (class_ == nullptr) {
0891       return IterWithDict<TMethod>();
0892     }
0893     return IterWithDict<TMethod>(class_->GetListOfMethods());
0894   }
0895 
0896   IterWithDict<TMethod> TypeFunctionMembers::end() const { return IterWithDict<TMethod>(); }
0897 
0898   size_t TypeFunctionMembers::size() const {
0899     if (class_ == nullptr) {
0900       return 0;
0901     }
0902     return class_->GetListOfMethods(kFALSE)->GetSize();
0903   }
0904 
0905 }  // namespace edm