Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:03:36

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