35 {
"Double_t",
"double"},
36 {
"string",
"std::string"},
38 {
"byte",
"std::byte"},
40 {
"int8_t",
"std::int8_t"},
41 {
"UChar_t",
"unsigned char"},
42 {
"uint8_t",
"std::uint8_t"},
45 {
"int16_t",
"std::int16_t"},
46 {
"UShort_t",
"unsigned short"},
47 {
"uint16_t",
"std::uint16_t"},
50 {
"int32_t",
"std::int32_t"},
51 {
"UInt_t",
"unsigned int"},
52 {
"unsigned",
"unsigned int"},
53 {
"uint32_t",
"std::uint32_t"},
58 {
"ULong_t",
"unsigned long"},
60 {
"Long64_t",
"long long"},
61 {
"int64_t",
"std::int64_t"},
62 {
"ULong64_t",
"unsigned long long"},
63 {
"uint64_t",
"std::uint64_t"}};
69bool IsUserClass(
const std::string &typeName)
71 return typeName.rfind(
"std::", 0) != 0 && typeName.rfind(
"ROOT::VecOps::RVec<", 0) != 0;
79std::tuple<std::string, std::vector<std::size_t>> ParseArrayType(
const std::string &typeName)
81 std::vector<std::size_t> sizeVec;
84 std::string prefix{typeName};
85 while (prefix.back() ==
']') {
86 auto posRBrace = prefix.size() - 1;
87 auto posLBrace = prefix.rfind(
'[', posRBrace);
88 if (posLBrace == std::string_view::npos) {
91 if (posRBrace - posLBrace <= 1) {
95 const std::size_t
size =
101 sizeVec.insert(sizeVec.begin(),
size);
102 prefix.resize(posLBrace);
104 return std::make_tuple(prefix, sizeVec);
109std::string GetStandardArrayType(
const std::string &baseType,
const std::vector<std::size_t> &dimensions)
111 std::string typeName = baseType;
113 typeName =
"std::array<" + typeName +
"," + std::to_string(*i) +
">";
120std::string GetNormalizedTemplateArg(
const std::string &arg,
bool keepQualifier,
F fnTypeNormalizer)
124 if (std::isdigit(arg[0]) || arg[0] ==
'-') {
130 return fnTypeNormalizer(arg);
132 std::string qualifier;
137 const auto [base,
_] = ParseArrayType(arg);
138 if (base.rfind(
"const ", 0) == 0 || base.rfind(
"volatile const ", 0) == 0 ||
139 base.find(
" const", base.length() - 6) != std::string::npos ||
140 base.find(
" const volatile", base.length() - 15) != std::string::npos) {
141 qualifier +=
"const ";
143 if (base.rfind(
"volatile ", 0) == 0 || base.rfind(
"const volatile ", 0) == 0 ||
144 base.find(
" volatile", base.length() - 9) != std::string::npos) {
145 qualifier +=
"volatile ";
147 return qualifier + fnTypeNormalizer(arg);
150using AnglePos = std::pair<std::string::size_type, std::string::size_type>;
151std::vector<AnglePos> FindTemplateAngleBrackets(
const std::string &typeName)
153 std::vector<AnglePos> result;
154 std::string::size_type currentPos = 0;
155 while (currentPos < typeName.size()) {
156 const auto posOpen = typeName.find(
'<', currentPos);
157 if (posOpen == std::string::npos) {
162 auto posClose = posOpen + 1;
164 while (posClose < typeName.size()) {
165 const auto c = typeName[posClose];
168 }
else if (
c ==
'>') {
178 result.emplace_back(posOpen, posClose);
181 if (posClose < typeName.size() - 1) {
182 R__ASSERT(typeName.substr(posClose + 1, 2) ==
"::");
184 currentPos = posClose + 1;
193void RemoveSpaceBefore(std::string &typeName,
char beforeChar)
195 auto dst = typeName.begin();
196 auto end = typeName.end();
197 for (
auto src = dst; src != end; ++src) {
200 if (next != end && *next == beforeChar) {
207 typeName.erase(dst, end);
211void RemoveSpaceAfter(std::string &typeName,
char afterChar)
213 auto dst = typeName.begin();
214 auto end = typeName.end();
215 for (
auto src = dst; src != end; ++src) {
217 if (*src == afterChar) {
219 if (next != end && *next ==
' ') {
225 typeName.erase(dst, end);
229void RemoveLeadingKeyword(std::string &typeName)
231 if (typeName.rfind(
"class ", 0) == 0) {
232 typeName.erase(0, 6);
233 }
else if (typeName.rfind(
"struct ", 0) == 0) {
234 typeName.erase(0, 7);
235 }
else if (typeName.rfind(
"enum ", 0) == 0) {
236 typeName.erase(0, 5);
241void RemoveCVQualifiers(std::string &typeName)
243 if (typeName.rfind(
"const ", 0) == 0)
244 typeName.erase(0, 6);
245 if (typeName.rfind(
"volatile ", 0) == 0)
246 typeName.erase(0, 9);
247 if (typeName.find(
" volatile", typeName.length() - 9) != std::string::npos)
248 typeName.erase(typeName.length() - 9);
249 if (typeName.find(
" const", typeName.length() - 6) != std::string::npos)
250 typeName.erase(typeName.length() - 6);
254void MapIntegerType(std::string &typeName)
256 if (typeName ==
"signed char") {
258 }
else if (typeName ==
"unsigned char") {
260 }
else if (typeName ==
"short" || typeName ==
"short int" || typeName ==
"signed short" ||
261 typeName ==
"signed short int") {
263 }
else if (typeName ==
"unsigned short" || typeName ==
"unsigned short int") {
265 }
else if (typeName ==
"int" || typeName ==
"signed" || typeName ==
"signed int") {
267 }
else if (typeName ==
"unsigned" || typeName ==
"unsigned int") {
269 }
else if (typeName ==
"long" || typeName ==
"long int" || typeName ==
"signed long" ||
270 typeName ==
"signed long int") {
272 }
else if (typeName ==
"unsigned long" || typeName ==
"unsigned long int") {
274 }
else if (typeName ==
"long long" || typeName ==
"long long int" || typeName ==
"signed long long" ||
275 typeName ==
"signed long long int") {
277 }
else if (typeName ==
"unsigned long long" || typeName ==
"unsigned long long int") {
282 if (typeName ==
"__int64") {
283 typeName =
"std::int64_t";
284 }
else if (typeName ==
"unsigned __int64") {
285 typeName =
"std::uint64_t";
291std::string GetRawDemangledTypeName(
const std::type_info &ti)
296 std::string result{str};
303void RenormalizeStdString(std::string &normalizedTypeName)
305 static const std::string gStringName =
306 GetRenormalizedDemangledTypeName(GetRawDemangledTypeName(
typeid(std::string)),
false );
311 if (normalizedTypeName == gStringName) {
312 normalizedTypeName =
"std::string";
317void RenormalizeStdlibType(std::string &normalizedTypeName)
319 static std::vector<std::pair<std::string, std::string>> gDistortedStdlibNames = []() {
322 static const std::vector<std::pair<const std::type_info &, std::string>> gCandidates =
323 {{
typeid(std::vector<char>),
"std::vector<"},
324 {
typeid(std::array<char, 1>),
"std::array<"},
325 {
typeid(std::variant<char>),
"std::variant<"},
326 {
typeid(std::pair<char, char>),
"std::pair<"},
327 {
typeid(std::tuple<char>),
"std::tuple<"},
328 {
typeid(std::bitset<1>),
"std::bitset<"},
329 {
typeid(std::unique_ptr<char>),
"std::unique_ptr<"},
330 {
typeid(std::optional<char>),
"std::optional<"},
331 {
typeid(std::set<char>),
"std::set<"},
332 {
typeid(std::unordered_set<char>),
"std::unordered_set<"},
333 {
typeid(std::multiset<char>),
"std::multiset<"},
334 {
typeid(std::unordered_multiset<char>),
"std::unordered_multiset<"},
335 {
typeid(std::map<char, char>),
"std::map<"},
336 {
typeid(std::unordered_map<char, char>),
"std::unordered_map<"},
337 {
typeid(std::multimap<char, char>),
"std::multimap<"},
338 {
typeid(std::unordered_multimap<char, char>),
"std::unordered_multimap<"},
339 {
typeid(std::atomic<char>),
"std::atomic<"}};
342 std::vector<std::pair<std::string, std::string>> result;
343 for (
const auto &[ti, prefix] : gCandidates) {
344 const auto dm = GetRawDemangledTypeName(ti);
345 if (dm.rfind(prefix, 0) == std::string::npos)
346 result.push_back(std::make_pair(dm.substr(0, dm.find(
'<') + 1), prefix));
352 for (
const auto &[seenPrefix, canonicalPrefix] : gDistortedStdlibNames) {
353 if (normalizedTypeName.rfind(seenPrefix, 0) == 0) {
354 normalizedTypeName = canonicalPrefix + normalizedTypeName.substr(seenPrefix.length());
361void NormalizeTemplateArguments(std::string &templatedTypeName,
int maxTemplateArgs,
F fnTypeNormalizer)
363 const auto angleBrackets = FindTemplateAngleBrackets(templatedTypeName);
366 std::string normName;
367 std::string::size_type currentPos = 0;
368 for (std::size_t i = 0; i < angleBrackets.size(); i++) {
369 const auto [posOpen, posClose] = angleBrackets[i];
371 normName += templatedTypeName.substr(currentPos, posOpen + 1 - currentPos);
373 const auto argList = templatedTypeName.substr(posOpen + 1, posClose - posOpen - 1);
377 const bool isUserClass = IsUserClass(templatedTypeName);
378 for (
const auto &
a : templateArgs) {
379 normName += GetNormalizedTemplateArg(
a, isUserClass, fnTypeNormalizer) +
",";
382 normName[normName.size() - 1] =
'>';
383 currentPos = posClose + 1;
387 const auto lastClosePos = angleBrackets.back().second;
388 normName += templatedTypeName.substr(lastClosePos + 1);
390 templatedTypeName = normName;
394std::string GetRenormalizedMetaTypeName(
const std::string &metaNormalizedName)
399 if (canonicalTypePrefix ==
"Double32_t")
402 if (canonicalTypePrefix.find(
'<') == std::string::npos) {
404 return canonicalTypePrefix;
407 std::string normName{canonicalTypePrefix};
408 NormalizeTemplateArguments(normName, 0 , GetRenormalizedMetaTypeName);
415std::string GetRenormalizedDemangledTypeName(
const std::string &demangledName,
bool renormalizeStdString)
417 std::string tn{demangledName};
418 RemoveSpaceBefore(tn,
'[');
419 auto [canonicalTypePrefix,
dimensions] = ParseArrayType(tn);
420 RemoveCVQualifiers(canonicalTypePrefix);
421 RemoveLeadingKeyword(canonicalTypePrefix);
422 MapIntegerType(canonicalTypePrefix);
424 if (canonicalTypePrefix.find(
'<') == std::string::npos) {
426 return GetStandardArrayType(canonicalTypePrefix, dimensions);
428 RemoveSpaceBefore(canonicalTypePrefix,
'>');
429 RemoveSpaceAfter(canonicalTypePrefix,
',');
430 RemoveSpaceBefore(canonicalTypePrefix,
',');
431 RenormalizeStdlibType(canonicalTypePrefix);
434 int maxTemplateArgs = 0;
435 if (canonicalTypePrefix.rfind(
"std::vector<", 0) == 0 || canonicalTypePrefix.rfind(
"std::set<", 0) == 0 ||
436 canonicalTypePrefix.rfind(
"std::unordered_set<", 0) == 0 ||
437 canonicalTypePrefix.rfind(
"std::multiset<", 0) == 0 ||
438 canonicalTypePrefix.rfind(
"std::unordered_multiset<", 0) == 0 ||
439 canonicalTypePrefix.rfind(
"std::unique_ptr<", 0) == 0) {
441 }
else if (canonicalTypePrefix.rfind(
"std::map<", 0) == 0 ||
442 canonicalTypePrefix.rfind(
"std::unordered_map<", 0) == 0 ||
443 canonicalTypePrefix.rfind(
"std::multimap<", 0) == 0 ||
444 canonicalTypePrefix.rfind(
"std::unordered_multimap<", 0) == 0) {
448 std::string normName{canonicalTypePrefix};
449 NormalizeTemplateArguments(normName, maxTemplateArgs, [renormalizeStdString](
const std::string &
n) {
450 return GetRenormalizedDemangledTypeName(
n, renormalizeStdString);
454 if (renormalizeStdString) {
455 RenormalizeStdString(normName);
458 return GetStandardArrayType(normName, dimensions);
469 if (cleanedType.empty())
472 auto [canonicalType,
dimensions] = ParseArrayType(cleanedType);
474 RemoveLeadingKeyword(canonicalType);
475 if (canonicalType.substr(0, 2) ==
"::") {
476 canonicalType.erase(0, 2);
479 RemoveSpaceBefore(canonicalType,
'>');
481 if (canonicalType.substr(0, 6) ==
"array<") {
482 canonicalType =
"std::" + canonicalType;
483 }
else if (canonicalType.substr(0, 7) ==
"atomic<") {
484 canonicalType =
"std::" + canonicalType;
485 }
else if (canonicalType.substr(0, 7) ==
"bitset<") {
486 canonicalType =
"std::" + canonicalType;
487 }
else if (canonicalType.substr(0, 4) ==
"map<") {
488 canonicalType =
"std::" + canonicalType;
489 }
else if (canonicalType.substr(0, 9) ==
"multimap<") {
490 canonicalType =
"std::" + canonicalType;
491 }
else if (canonicalType.substr(0, 9) ==
"multiset<") {
492 canonicalType =
"std::" + canonicalType;
494 if (canonicalType.substr(0, 5) ==
"pair<") {
495 canonicalType =
"std::" + canonicalType;
496 }
else if (canonicalType.substr(0, 4) ==
"set<") {
497 canonicalType =
"std::" + canonicalType;
498 }
else if (canonicalType.substr(0, 6) ==
"tuple<") {
499 canonicalType =
"std::" + canonicalType;
500 }
else if (canonicalType.substr(0, 11) ==
"unique_ptr<") {
501 canonicalType =
"std::" + canonicalType;
502 }
else if (canonicalType.substr(0, 14) ==
"unordered_map<") {
503 canonicalType =
"std::" + canonicalType;
504 }
else if (canonicalType.substr(0, 19) ==
"unordered_multimap<") {
505 canonicalType =
"std::" + canonicalType;
506 }
else if (canonicalType.substr(0, 19) ==
"unordered_multiset<") {
507 canonicalType =
"std::" + canonicalType;
508 }
else if (canonicalType.substr(0, 14) ==
"unordered_set<") {
509 canonicalType =
"std::" + canonicalType;
510 }
else if (canonicalType.substr(0, 8) ==
"variant<") {
511 canonicalType =
"std::" + canonicalType;
512 }
else if (canonicalType.substr(0, 7) ==
"vector<") {
513 canonicalType =
"std::" + canonicalType;
514 }
else if (canonicalType.substr(0, 11) ==
"ROOT::RVec<") {
515 canonicalType =
"ROOT::VecOps::RVec<" + canonicalType.substr(11);
518 if (
auto it = typeTranslationMap.find(canonicalType); it != typeTranslationMap.end()) {
519 canonicalType = it->second;
522 MapIntegerType(canonicalType);
524 return GetStandardArrayType(canonicalType,
dimensions);
529 return GetRenormalizedDemangledTypeName(GetRawDemangledTypeName(ti),
true );
534 return GetRenormalizedMetaTypeName(metaNormalizedName);
574 std::string shortType;
578 if (canonicalTypePrefix.find(
'<') == std::string::npos) {
580 return canonicalTypePrefix;
583 const auto angleBrackets = FindTemplateAngleBrackets(canonicalTypePrefix);
587 const bool isUserClass = IsUserClass(canonicalTypePrefix);
589 std::string normName;
590 std::string::size_type currentPos = 0;
591 for (std::size_t i = 0; i < angleBrackets.size(); i++) {
592 const auto [posOpen, posClose] = angleBrackets[i];
594 normName += canonicalTypePrefix.substr(currentPos, posOpen + 1 - currentPos);
596 const auto argList = canonicalTypePrefix.substr(posOpen + 1, posClose - posOpen - 1);
600 for (
const auto &
a : templateArgs) {
606 const auto cl =
TClass::GetClass(canonicalTypePrefix.substr(0, posClose + 1).c_str());
608 const std::string expandedName = cl->GetName();
609 const auto expandedAngleBrackets = FindTemplateAngleBrackets(expandedName);
611 R__ASSERT(!expandedAngleBrackets.empty());
613 const auto [expandedPosOpen, expandedPosClose] = expandedAngleBrackets.back();
614 const auto expandedArgList =
615 expandedName.substr(expandedPosOpen + 1, expandedPosClose - expandedPosOpen - 1);
621 for (std::size_t j = templateArgs.size(); j < expandedTemplateArgs.size(); ++j) {
628 normName[normName.size() - 1] =
'>';
629 currentPos = posClose + 1;
633 const auto lastClosePos = angleBrackets.back().second;
634 normName += canonicalTypePrefix.substr(lastClosePos + 1);
775 std::string fFieldName;
776 std::string fTypeName;
778 std::uint32_t fTypeVersion = 0;
779 std::optional<std::uint32_t> fTypeChecksum;
782 std::vector<const RFieldBase *> inMemoryStack;
783 std::vector<const RFieldDescriptor *> onDiskStack;
785 auto fnGetLine = [](
const RFieldInfo &fieldInfo,
int level) -> std::string {
786 std::string
line = std::string(2 * level,
' ') + fieldInfo.fFieldName +
" [" + fieldInfo.fTypeName;
787 if (fieldInfo.fTypeVersion > 0)
788 line +=
", type version: " + std::to_string(fieldInfo.fTypeVersion);
789 if (fieldInfo.fTypeChecksum)
790 line +=
", type checksum: " + std::to_string(*fieldInfo.fTypeChecksum);
791 line +=
"] (id: " + std::to_string(fieldInfo.fFieldId) +
")\n";
797 inMemoryStack.push_back(fieldPtr);
804 onDiskStack.push_back(&fieldDesc);
805 fieldId = fieldDesc.GetParentId();
808 std::string report =
"In-memory field/type hierarchy:\n";
810 for (
auto itr = inMemoryStack.rbegin(); itr != inMemoryStack.rend(); ++itr, ++indentLevel) {
811 RFieldInfo fieldInfo;
812 fieldInfo.fFieldName = (*itr)->GetFieldName();
813 fieldInfo.fTypeName = (*itr)->GetTypeName();
814 fieldInfo.fFieldId = (*itr)->GetOnDiskId();
815 fieldInfo.fTypeVersion = (*itr)->GetTypeVersion();
817 fieldInfo.fTypeChecksum = (*itr)->GetTypeChecksum();
819 report += fnGetLine(fieldInfo, indentLevel);
822 report +=
"On-disk field/type hierarchy:\n";
824 for (
auto itr = onDiskStack.rbegin(); itr != onDiskStack.rend(); ++itr, ++indentLevel) {
825 RFieldInfo fieldInfo;
826 fieldInfo.fFieldName = (*itr)->GetFieldName();
827 fieldInfo.fTypeName = (*itr)->GetTypeName();
828 fieldInfo.fFieldId = (*itr)->GetId();
829 fieldInfo.fTypeVersion = (*itr)->GetTypeVersion();
830 fieldInfo.fTypeChecksum = (*itr)->GetTypeChecksum();
832 report += fnGetLine(fieldInfo, indentLevel);