36 {
"Double_t",
"double"},
37 {
"string",
"std::string"},
39 {
"byte",
"std::byte"},
41 {
"int8_t",
"std::int8_t"},
42 {
"UChar_t",
"unsigned char"},
43 {
"uint8_t",
"std::uint8_t"},
46 {
"int16_t",
"std::int16_t"},
47 {
"UShort_t",
"unsigned short"},
48 {
"uint16_t",
"std::uint16_t"},
51 {
"int32_t",
"std::int32_t"},
52 {
"UInt_t",
"unsigned int"},
53 {
"unsigned",
"unsigned int"},
54 {
"uint32_t",
"std::uint32_t"},
59 {
"ULong_t",
"unsigned long"},
61 {
"Long64_t",
"long long"},
62 {
"int64_t",
"std::int64_t"},
63 {
"ULong64_t",
"unsigned long long"},
64 {
"uint64_t",
"std::uint64_t"}};
70bool IsUserClass(
const std::string &typeName)
72 return typeName.rfind(
"std::", 0) != 0 && typeName.rfind(
"ROOT::VecOps::RVec<", 0) != 0;
80std::tuple<std::string, std::vector<std::size_t>> ParseArrayType(
const std::string &typeName)
82 std::vector<std::size_t> sizeVec;
85 std::string prefix{typeName};
86 while (prefix.back() ==
']') {
87 auto posRBrace = prefix.size() - 1;
88 auto posLBrace = prefix.rfind(
'[', posRBrace);
89 if (posLBrace == std::string_view::npos) {
92 if (posRBrace - posLBrace <= 1) {
96 const std::size_t
size =
102 sizeVec.insert(sizeVec.begin(),
size);
103 prefix.resize(posLBrace);
105 return std::make_tuple(prefix, sizeVec);
110std::string GetStandardArrayType(
const std::string &baseType,
const std::vector<std::size_t> &dimensions)
112 std::string typeName = baseType;
113 for (
auto i = dimensions.rbegin(), iEnd = dimensions.rend(); i != iEnd; ++i) {
114 typeName =
"std::array<" + typeName +
"," + std::to_string(*i) +
">";
121std::string GetNormalizedTemplateArg(
const std::string &arg,
bool keepQualifier,
F fnTypeNormalizer)
125 if (std::isdigit(arg[0]) || arg[0] ==
'-') {
131 return fnTypeNormalizer(arg);
133 std::string qualifier;
138 const auto [base,
_] = ParseArrayType(arg);
139 if (base.rfind(
"const ", 0) == 0 || base.rfind(
"volatile const ", 0) == 0 ||
140 base.find(
" const", base.length() - 6) != std::string::npos ||
141 base.find(
" const volatile", base.length() - 15) != std::string::npos) {
142 qualifier +=
"const ";
144 if (base.rfind(
"volatile ", 0) == 0 || base.rfind(
"const volatile ", 0) == 0 ||
145 base.find(
" volatile", base.length() - 9) != std::string::npos) {
146 qualifier +=
"volatile ";
148 return qualifier + fnTypeNormalizer(arg);
151using AnglePos = std::pair<std::string::size_type, std::string::size_type>;
152std::vector<AnglePos> FindTemplateAngleBrackets(
const std::string &typeName)
154 std::vector<AnglePos>
result;
155 std::string::size_type currentPos = 0;
156 while (currentPos < typeName.size()) {
157 const auto posOpen = typeName.find(
'<', currentPos);
158 if (posOpen == std::string::npos) {
163 auto posClose = posOpen + 1;
165 while (posClose < typeName.size()) {
166 const auto c = typeName[posClose];
169 }
else if (
c ==
'>') {
179 result.emplace_back(posOpen, posClose);
182 if (posClose < typeName.size() - 1) {
183 R__ASSERT(typeName.substr(posClose + 1, 2) ==
"::");
185 currentPos = posClose + 1;
194void RemoveSpaceBefore(std::string &typeName,
char beforeChar)
196 auto dst = typeName.begin();
197 auto end = typeName.end();
198 for (
auto src = dst;
src != end; ++
src) {
201 if (next != end && *next == beforeChar) {
208 typeName.erase(dst, end);
212void RemoveSpaceAfter(std::string &typeName,
char afterChar)
214 auto dst = typeName.begin();
215 auto end = typeName.end();
216 for (
auto src = dst;
src != end; ++
src) {
218 if (*
src == afterChar) {
220 if (next != end && *next ==
' ') {
226 typeName.erase(dst, end);
230void RemoveLeadingKeyword(std::string &typeName)
232 if (typeName.rfind(
"class ", 0) == 0) {
233 typeName.erase(0, 6);
234 }
else if (typeName.rfind(
"struct ", 0) == 0) {
235 typeName.erase(0, 7);
236 }
else if (typeName.rfind(
"enum ", 0) == 0) {
237 typeName.erase(0, 5);
242void RemoveCVQualifiers(std::string &typeName)
244 if (typeName.rfind(
"const ", 0) == 0)
245 typeName.erase(0, 6);
246 if (typeName.rfind(
"volatile ", 0) == 0)
247 typeName.erase(0, 9);
248 if (typeName.find(
" volatile", typeName.length() - 9) != std::string::npos)
249 typeName.erase(typeName.length() - 9);
250 if (typeName.find(
" const", typeName.length() - 6) != std::string::npos)
251 typeName.erase(typeName.length() - 6);
255void MapIntegerType(std::string &typeName)
257 if (typeName ==
"signed char") {
259 }
else if (typeName ==
"unsigned char") {
261 }
else if (typeName ==
"short" || typeName ==
"short int" || typeName ==
"signed short" ||
262 typeName ==
"signed short int") {
264 }
else if (typeName ==
"unsigned short" || typeName ==
"unsigned short int") {
266 }
else if (typeName ==
"int" || typeName ==
"signed" || typeName ==
"signed int") {
268 }
else if (typeName ==
"unsigned" || typeName ==
"unsigned int") {
270 }
else if (typeName ==
"long" || typeName ==
"long int" || typeName ==
"signed long" ||
271 typeName ==
"signed long int") {
273 }
else if (typeName ==
"unsigned long" || typeName ==
"unsigned long int") {
275 }
else if (typeName ==
"long long" || typeName ==
"long long int" || typeName ==
"signed long long" ||
276 typeName ==
"signed long long int") {
278 }
else if (typeName ==
"unsigned long long" || typeName ==
"unsigned long long int") {
283 if (typeName ==
"__int64") {
284 typeName =
"std::int64_t";
285 }
else if (typeName ==
"unsigned __int64") {
286 typeName =
"std::uint64_t";
292std::string GetRawDemangledTypeName(
const std::type_info &ti)
304void RenormalizeStdString(std::string &normalizedTypeName)
306 static const std::string gStringName =
307 GetRenormalizedDemangledTypeName(GetRawDemangledTypeName(
typeid(std::string)),
false );
312 if (normalizedTypeName == gStringName) {
313 normalizedTypeName =
"std::string";
318void RenormalizeStdlibType(std::string &normalizedTypeName)
320 static std::vector<std::pair<std::string, std::string>> gDistortedStdlibNames = []() {
323 static const std::vector<std::pair<const std::type_info &, std::string>> gCandidates =
324 {{
typeid(std::vector<char>),
"std::vector<"},
325 {
typeid(std::array<char, 1>),
"std::array<"},
326 {
typeid(std::variant<char>),
"std::variant<"},
327 {
typeid(std::pair<char, char>),
"std::pair<"},
328 {
typeid(std::tuple<char>),
"std::tuple<"},
329 {
typeid(std::bitset<1>),
"std::bitset<"},
330 {
typeid(std::unique_ptr<char>),
"std::unique_ptr<"},
331 {
typeid(std::optional<char>),
"std::optional<"},
332 {
typeid(std::set<char>),
"std::set<"},
333 {
typeid(std::unordered_set<char>),
"std::unordered_set<"},
334 {
typeid(std::multiset<char>),
"std::multiset<"},
335 {
typeid(std::unordered_multiset<char>),
"std::unordered_multiset<"},
336 {
typeid(std::map<char, char>),
"std::map<"},
337 {
typeid(std::unordered_map<char, char>),
"std::unordered_map<"},
338 {
typeid(std::multimap<char, char>),
"std::multimap<"},
339 {
typeid(std::unordered_multimap<char, char>),
"std::unordered_multimap<"},
340 {
typeid(std::atomic<char>),
"std::atomic<"}};
343 std::vector<std::pair<std::string, std::string>>
result;
344 for (
const auto &[ti, prefix] : gCandidates) {
345 const auto dm = GetRawDemangledTypeName(ti);
346 if (dm.rfind(prefix, 0) == std::string::npos)
347 result.push_back(std::make_pair(dm.substr(0, dm.find(
'<') + 1), prefix));
353 for (
const auto &[seenPrefix, canonicalPrefix] : gDistortedStdlibNames) {
354 if (normalizedTypeName.rfind(seenPrefix, 0) == 0) {
355 normalizedTypeName = canonicalPrefix + normalizedTypeName.substr(seenPrefix.length());
362void NormalizeTemplateArguments(std::string &templatedTypeName,
int maxTemplateArgs,
F fnTypeNormalizer)
364 const auto angleBrackets = FindTemplateAngleBrackets(templatedTypeName);
367 std::string normName;
368 std::string::size_type currentPos = 0;
369 for (std::size_t i = 0; i < angleBrackets.size(); i++) {
370 const auto [posOpen, posClose] = angleBrackets[i];
372 normName += templatedTypeName.substr(currentPos, posOpen + 1 - currentPos);
374 const auto argList = templatedTypeName.substr(posOpen + 1, posClose - posOpen - 1);
378 const bool isUserClass = IsUserClass(templatedTypeName);
379 for (
const auto &
a : templateArgs) {
380 normName += GetNormalizedTemplateArg(
a, isUserClass, fnTypeNormalizer) +
",";
383 normName[normName.size() - 1] =
'>';
384 currentPos = posClose + 1;
388 const auto lastClosePos = angleBrackets.back().second;
389 normName += templatedTypeName.substr(lastClosePos + 1);
391 templatedTypeName = normName;
395std::string GetRenormalizedMetaTypeName(
const std::string &metaNormalizedName)
400 if (canonicalTypePrefix ==
"Double32_t")
403 if (canonicalTypePrefix.find(
'<') == std::string::npos) {
405 return canonicalTypePrefix;
408 std::string normName{canonicalTypePrefix};
409 NormalizeTemplateArguments(normName, 0 , GetRenormalizedMetaTypeName);
416std::string GetRenormalizedDemangledTypeName(
const std::string &demangledName,
bool renormalizeStdString)
418 std::string tn{demangledName};
419 RemoveSpaceBefore(tn,
'[');
420 auto [canonicalTypePrefix, dimensions] = ParseArrayType(tn);
421 RemoveCVQualifiers(canonicalTypePrefix);
422 RemoveLeadingKeyword(canonicalTypePrefix);
423 MapIntegerType(canonicalTypePrefix);
425 if (canonicalTypePrefix.find(
'<') == std::string::npos) {
427 return GetStandardArrayType(canonicalTypePrefix, dimensions);
429 RemoveSpaceBefore(canonicalTypePrefix,
'>');
430 RemoveSpaceAfter(canonicalTypePrefix,
',');
431 RemoveSpaceBefore(canonicalTypePrefix,
',');
432 RenormalizeStdlibType(canonicalTypePrefix);
435 int maxTemplateArgs = 0;
436 if (canonicalTypePrefix.rfind(
"std::vector<", 0) == 0 || canonicalTypePrefix.rfind(
"std::set<", 0) == 0 ||
437 canonicalTypePrefix.rfind(
"std::unordered_set<", 0) == 0 ||
438 canonicalTypePrefix.rfind(
"std::multiset<", 0) == 0 ||
439 canonicalTypePrefix.rfind(
"std::unordered_multiset<", 0) == 0 ||
440 canonicalTypePrefix.rfind(
"std::unique_ptr<", 0) == 0) {
442 }
else if (canonicalTypePrefix.rfind(
"std::map<", 0) == 0 ||
443 canonicalTypePrefix.rfind(
"std::unordered_map<", 0) == 0 ||
444 canonicalTypePrefix.rfind(
"std::multimap<", 0) == 0 ||
445 canonicalTypePrefix.rfind(
"std::unordered_multimap<", 0) == 0) {
449 std::string normName{canonicalTypePrefix};
450 NormalizeTemplateArguments(normName, maxTemplateArgs, [renormalizeStdString](
const std::string &
n) {
451 return GetRenormalizedDemangledTypeName(
n, renormalizeStdString);
455 if (renormalizeStdString) {
456 RenormalizeStdString(normName);
459 return GetStandardArrayType(normName, dimensions);
470 if (cleanedType.empty())
473 auto [canonicalType, dimensions] = ParseArrayType(cleanedType);
475 RemoveLeadingKeyword(canonicalType);
476 if (canonicalType.substr(0, 2) ==
"::") {
477 canonicalType.erase(0, 2);
480 RemoveSpaceBefore(canonicalType,
'>');
482 if (canonicalType.substr(0, 6) ==
"array<") {
483 canonicalType =
"std::" + canonicalType;
484 }
else if (canonicalType.substr(0, 7) ==
"atomic<") {
485 canonicalType =
"std::" + canonicalType;
486 }
else if (canonicalType.substr(0, 7) ==
"bitset<") {
487 canonicalType =
"std::" + canonicalType;
488 }
else if (canonicalType.substr(0, 4) ==
"map<") {
489 canonicalType =
"std::" + canonicalType;
490 }
else if (canonicalType.substr(0, 9) ==
"multimap<") {
491 canonicalType =
"std::" + canonicalType;
492 }
else if (canonicalType.substr(0, 9) ==
"multiset<") {
493 canonicalType =
"std::" + canonicalType;
495 if (canonicalType.substr(0, 5) ==
"pair<") {
496 canonicalType =
"std::" + canonicalType;
497 }
else if (canonicalType.substr(0, 4) ==
"set<") {
498 canonicalType =
"std::" + canonicalType;
499 }
else if (canonicalType.substr(0, 6) ==
"tuple<") {
500 canonicalType =
"std::" + canonicalType;
501 }
else if (canonicalType.substr(0, 11) ==
"unique_ptr<") {
502 canonicalType =
"std::" + canonicalType;
503 }
else if (canonicalType.substr(0, 14) ==
"unordered_map<") {
504 canonicalType =
"std::" + canonicalType;
505 }
else if (canonicalType.substr(0, 19) ==
"unordered_multimap<") {
506 canonicalType =
"std::" + canonicalType;
507 }
else if (canonicalType.substr(0, 19) ==
"unordered_multiset<") {
508 canonicalType =
"std::" + canonicalType;
509 }
else if (canonicalType.substr(0, 14) ==
"unordered_set<") {
510 canonicalType =
"std::" + canonicalType;
511 }
else if (canonicalType.substr(0, 8) ==
"variant<") {
512 canonicalType =
"std::" + canonicalType;
513 }
else if (canonicalType.substr(0, 7) ==
"vector<") {
514 canonicalType =
"std::" + canonicalType;
515 }
else if (canonicalType.substr(0, 11) ==
"ROOT::RVec<") {
516 canonicalType =
"ROOT::VecOps::RVec<" + canonicalType.substr(11);
519 if (
auto it = typeTranslationMap.find(canonicalType); it != typeTranslationMap.end()) {
520 canonicalType = it->second;
523 MapIntegerType(canonicalType);
525 return GetStandardArrayType(canonicalType, dimensions);
530 return GetRenormalizedDemangledTypeName(GetRawDemangledTypeName(ti),
true );
535 return GetRenormalizedMetaTypeName(metaNormalizedName);
575 std::string shortType;
579 if (canonicalTypePrefix.find(
'<') == std::string::npos) {
581 return canonicalTypePrefix;
584 const auto angleBrackets = FindTemplateAngleBrackets(canonicalTypePrefix);
588 const bool isUserClass = IsUserClass(canonicalTypePrefix);
590 std::string normName;
591 std::string::size_type currentPos = 0;
592 for (std::size_t i = 0; i < angleBrackets.size(); i++) {
593 const auto [posOpen, posClose] = angleBrackets[i];
595 normName += canonicalTypePrefix.substr(currentPos, posOpen + 1 - currentPos);
597 const auto argList = canonicalTypePrefix.substr(posOpen + 1, posClose - posOpen - 1);
601 for (
const auto &
a : templateArgs) {
607 const auto cl =
TClass::GetClass(canonicalTypePrefix.substr(0, posClose + 1).c_str());
609 const std::string expandedName = cl->GetName();
610 const auto expandedAngleBrackets = FindTemplateAngleBrackets(expandedName);
612 R__ASSERT(!expandedAngleBrackets.empty());
614 const auto [expandedPosOpen, expandedPosClose] = expandedAngleBrackets.back();
615 const auto expandedArgList =
616 expandedName.substr(expandedPosOpen + 1, expandedPosClose - expandedPosOpen - 1);
622 for (std::size_t j = templateArgs.size(); j < expandedTemplateArgs.size(); ++j) {
629 normName[normName.size() - 1] =
'>';
630 currentPos = posClose + 1;
634 const auto lastClosePos = angleBrackets.back().second;
635 normName += canonicalTypePrefix.substr(lastClosePos + 1);
776 std::string fFieldName;
777 std::string fTypeName;
779 std::uint32_t fTypeVersion = 0;
780 std::optional<std::uint32_t> fTypeChecksum;
783 std::vector<const RFieldBase *> inMemoryStack;
784 std::vector<const RFieldDescriptor *> onDiskStack;
786 auto fnGetLine = [](
const RFieldInfo &fieldInfo,
int level) -> std::string {
787 std::string
line = std::string(2 * level,
' ') + fieldInfo.fFieldName +
" [" + fieldInfo.fTypeName;
788 if (fieldInfo.fTypeVersion > 0)
789 line +=
", type version: " + std::to_string(fieldInfo.fTypeVersion);
790 if (fieldInfo.fTypeChecksum)
791 line +=
", type checksum: " + std::to_string(*fieldInfo.fTypeChecksum);
792 line +=
"] (id: " + std::to_string(fieldInfo.fFieldId) +
")\n";
798 inMemoryStack.push_back(fieldPtr);
805 onDiskStack.push_back(&fieldDesc);
806 fieldId = fieldDesc.GetParentId();
809 std::string report =
"In-memory field/type hierarchy:\n";
811 for (
auto itr = inMemoryStack.rbegin(); itr != inMemoryStack.rend(); ++itr, ++indentLevel) {
812 RFieldInfo fieldInfo;
813 fieldInfo.fFieldName = (*itr)->GetFieldName();
814 fieldInfo.fTypeName = (*itr)->GetTypeName();
815 fieldInfo.fFieldId = (*itr)->GetOnDiskId();
816 fieldInfo.fTypeVersion = (*itr)->GetTypeVersion();
818 fieldInfo.fTypeChecksum = (*itr)->GetTypeChecksum();
820 report += fnGetLine(fieldInfo, indentLevel);
823 report +=
"On-disk field/type hierarchy:\n";
825 for (
auto itr = onDiskStack.rbegin(); itr != onDiskStack.rend(); ++itr, ++indentLevel) {
826 RFieldInfo fieldInfo;
827 fieldInfo.fFieldName = (*itr)->GetFieldName();
828 fieldInfo.fTypeName = (*itr)->GetTypeName();
829 fieldInfo.fFieldId = (*itr)->GetId();
830 fieldInfo.fTypeVersion = (*itr)->GetTypeVersion();
831 fieldInfo.fTypeChecksum = (*itr)->GetTypeChecksum();
833 report += fnGetLine(fieldInfo, indentLevel);