Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldUtils.cxx
Go to the documentation of this file.
1/// \file RFieldUtils.cxx
2/// \ingroup NTuple
3/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
4/// \date 2024-11-19
5
7
8#include <ROOT/RField.hxx>
9#include <ROOT/RLogger.hxx>
10#include <ROOT/RNTupleTypes.hxx>
11#include <ROOT/RNTupleUtils.hxx>
12
13#include <TClass.h>
14#include <TClassEdit.h>
15#include <TDictAttributeMap.h>
16
17#include <algorithm>
18#include <charconv>
19#include <limits>
20#include <string>
21#include <string_view>
22#include <system_error>
23#include <unordered_map>
24#include <utility>
25#include <vector>
26
27namespace {
28
29std::string GetRenormalizedDemangledTypeName(const std::string &demangledName, bool renormalizeStdString);
30
31const std::unordered_map<std::string_view, std::string_view> typeTranslationMap{
32 {"Bool_t", "bool"},
33 {"Float_t", "float"},
34 {"Double_t", "double"},
35 {"string", "std::string"},
36
37 {"byte", "std::byte"},
38 {"Char_t", "char"},
39 {"int8_t", "std::int8_t"},
40 {"UChar_t", "unsigned char"},
41 {"uint8_t", "std::uint8_t"},
42
43 {"Short_t", "short"},
44 {"int16_t", "std::int16_t"},
45 {"UShort_t", "unsigned short"},
46 {"uint16_t", "std::uint16_t"},
47
48 {"Int_t", "int"},
49 {"int32_t", "std::int32_t"},
50 {"UInt_t", "unsigned int"},
51 {"unsigned", "unsigned int"},
52 {"uint32_t", "std::uint32_t"},
53
54 // Long_t and ULong_t follow the platform's size of long and unsigned long: They are 64 bit on 64-bit Linux and
55 // macOS, but 32 bit on 32-bit platforms and Windows (regardless of pointer size).
56 {"Long_t", "long"},
57 {"ULong_t", "unsigned long"},
58
59 {"Long64_t", "long long"},
60 {"int64_t", "std::int64_t"},
61 {"ULong64_t", "unsigned long long"},
62 {"uint64_t", "std::uint64_t"}};
63
64// Natively supported types drop the default template arguments and the CV qualifiers in template arguments.
65bool IsUserClass(const std::string &typeName)
66{
67 return typeName.rfind("std::", 0) != 0 && typeName.rfind("ROOT::VecOps::RVec<", 0) != 0;
68}
69
70/// Parse a type name of the form `T[n][m]...` and return the base type `T` and a vector that contains,
71/// in order, the declared size for each dimension, e.g. for `unsigned char[1][2][3]` it returns the tuple
72/// `{"unsigned char", {1, 2, 3}}`. Extra whitespace in `typeName` should be removed before calling this function.
73///
74/// If `typeName` is not an array type, it returns a tuple `{T, {}}`. On error, it returns a default-constructed tuple.
75std::tuple<std::string, std::vector<std::size_t>> ParseArrayType(const std::string &typeName)
76{
77 std::vector<std::size_t> sizeVec;
78
79 // Only parse outer array definition, i.e. the right `]` should be at the end of the type name
80 std::string prefix{typeName};
81 while (prefix.back() == ']') {
82 auto posRBrace = prefix.size() - 1;
83 auto posLBrace = prefix.rfind('[', posRBrace);
84 if (posLBrace == std::string_view::npos) {
85 throw ROOT::RException(R__FAIL(std::string("invalid array type: ") + typeName));
86 }
87 if (posRBrace - posLBrace <= 1) {
88 throw ROOT::RException(R__FAIL(std::string("invalid array type: ") + typeName));
89 }
90
91 const std::size_t size =
93 if (size == 0) {
94 throw ROOT::RException(R__FAIL(std::string("invalid array size: ") + typeName));
95 }
96
97 sizeVec.insert(sizeVec.begin(), size);
98 prefix.resize(posLBrace);
99 }
100 return std::make_tuple(prefix, sizeVec);
101}
102
103/// Assembles a (nested) std::array<> based type based on the dimensions retrieved from ParseArrayType(). Returns
104/// baseType if there are no dimensions.
105std::string GetStandardArrayType(const std::string &baseType, const std::vector<std::size_t> &dimensions)
106{
107 std::string typeName = baseType;
108 for (auto i = dimensions.rbegin(), iEnd = dimensions.rend(); i != iEnd; ++i) {
109 typeName = "std::array<" + typeName + "," + std::to_string(*i) + ">";
110 }
111 return typeName;
112}
113
114// Recursively normalizes a template argument using the regular type name normalizer F as a helper.
115template <typename F>
116std::string GetNormalizedTemplateArg(const std::string &arg, bool keepQualifier, F fnTypeNormalizer)
117{
118 R__ASSERT(!arg.empty());
119
120 if (std::isdigit(arg[0]) || arg[0] == '-') {
121 // Integer template argument
123 }
124
125 if (!keepQualifier)
126 return fnTypeNormalizer(arg);
127
128 std::string qualifier;
129 // Type name template argument; template arguments must keep their CV qualifier. We assume that fnTypeNormalizer
130 // strips the qualifier.
131 // Demangled names may have the CV qualifiers suffixed and not prefixed (but const always before volatile).
132 // Note that in the latter case, we may have the CV qualifiers before array brackets, e.g. `int const[2]`.
133 const auto [base, _] = ParseArrayType(arg);
134 if (base.rfind("const ", 0) == 0 || base.rfind("volatile const ", 0) == 0 ||
135 base.find(" const", base.length() - 6) != std::string::npos ||
136 base.find(" const volatile", base.length() - 15) != std::string::npos) {
137 qualifier += "const ";
138 }
139 if (base.rfind("volatile ", 0) == 0 || base.rfind("const volatile ", 0) == 0 ||
140 base.find(" volatile", base.length() - 9) != std::string::npos) {
141 qualifier += "volatile ";
142 }
143 return qualifier + fnTypeNormalizer(arg);
144}
145
146using AnglePos = std::pair<std::string::size_type, std::string::size_type>;
147std::vector<AnglePos> FindTemplateAngleBrackets(const std::string &typeName)
148{
149 std::vector<AnglePos> result;
150 std::string::size_type currentPos = 0;
151 while (currentPos < typeName.size()) {
152 const auto posOpen = typeName.find('<', currentPos);
153 if (posOpen == std::string::npos) {
154 // If there are no more templates, the function is done.
155 break;
156 }
157
158 auto posClose = posOpen + 1;
159 int level = 1;
160 while (posClose < typeName.size()) {
161 const auto c = typeName[posClose];
162 if (c == '<') {
163 level++;
164 } else if (c == '>') {
165 if (level == 1) {
166 break;
167 }
168 level--;
169 }
170 posClose++;
171 }
172 // We should have found a closing angle bracket at the right level.
173 R__ASSERT(posClose < typeName.size());
174 result.emplace_back(posOpen, posClose);
175
176 // If we are not at the end yet, the following two characeters should be :: for nested types.
177 if (posClose < typeName.size() - 1) {
178 R__ASSERT(typeName.substr(posClose + 1, 2) == "::");
179 }
180 currentPos = posClose + 1;
181 }
182
183 return result;
184}
185
186// TClassEdit::CleanType and the name demangling insert blanks between closing angle brackets,
187// as they were required before C++11. Name demangling introduces a blank before array dimensions,
188// which should also be removed.
189void RemoveSpaceBefore(std::string &typeName, char beforeChar)
190{
191 auto dst = typeName.begin();
192 auto end = typeName.end();
193 for (auto src = dst; src != end; ++src) {
194 if (*src == ' ') {
195 auto next = src + 1;
196 if (next != end && *next == beforeChar) {
197 // Skip this space before a closing angle bracket.
198 continue;
199 }
200 }
201 *(dst++) = *src;
202 }
203 typeName.erase(dst, end);
204}
205
206// The demangled name adds spaces after commas
207void RemoveSpaceAfter(std::string &typeName, char afterChar)
208{
209 auto dst = typeName.begin();
210 auto end = typeName.end();
211 for (auto src = dst; src != end; ++src) {
212 *(dst++) = *src;
213 if (*src == afterChar) {
214 auto next = src + 1;
215 if (next != end && *next == ' ') {
216 // Skip this space before a closing angle bracket.
217 ++src;
218 }
219 }
220 }
221 typeName.erase(dst, end);
222}
223
224// We normalize typenames to omit any `class`, `struct`, `enum` prefix
225void RemoveLeadingKeyword(std::string &typeName)
226{
227 if (typeName.rfind("class ", 0) == 0) {
228 typeName.erase(0, 6);
229 } else if (typeName.rfind("struct ", 0) == 0) {
230 typeName.erase(0, 7);
231 } else if (typeName.rfind("enum ", 0) == 0) {
232 typeName.erase(0, 5);
233 }
234}
235
236// Needed for template arguments in demangled names
237void RemoveCVQualifiers(std::string &typeName)
238{
239 if (typeName.rfind("const ", 0) == 0)
240 typeName.erase(0, 6);
241 if (typeName.rfind("volatile ", 0) == 0)
242 typeName.erase(0, 9);
243 if (typeName.find(" volatile", typeName.length() - 9) != std::string::npos)
244 typeName.erase(typeName.length() - 9);
245 if (typeName.find(" const", typeName.length() - 6) != std::string::npos)
246 typeName.erase(typeName.length() - 6);
247}
248
249// Map fundamental integer types to stdint integer types (e.g. int --> std::int32_t)
250void MapIntegerType(std::string &typeName)
251{
252 if (typeName == "signed char") {
254 } else if (typeName == "unsigned char") {
256 } else if (typeName == "short" || typeName == "short int" || typeName == "signed short" ||
257 typeName == "signed short int") {
259 } else if (typeName == "unsigned short" || typeName == "unsigned short int") {
261 } else if (typeName == "int" || typeName == "signed" || typeName == "signed int") {
262 typeName = ROOT::RField<int>::TypeName();
263 } else if (typeName == "unsigned" || typeName == "unsigned int") {
265 } else if (typeName == "long" || typeName == "long int" || typeName == "signed long" ||
266 typeName == "signed long int") {
268 } else if (typeName == "unsigned long" || typeName == "unsigned long int") {
270 } else if (typeName == "long long" || typeName == "long long int" || typeName == "signed long long" ||
271 typeName == "signed long long int") {
273 } else if (typeName == "unsigned long long" || typeName == "unsigned long long int") {
275 } else {
276 // The following two types are 64-bit integers on Windows that we can encounter during renormalization of
277 // demangled std::type_info names.
278 if (typeName == "__int64") {
279 typeName = "std::int64_t";
280 } else if (typeName == "unsigned __int64") {
281 typeName = "std::uint64_t";
282 }
283 }
284}
285
286// Note that ROOT Meta already defines GetDemangledTypeName(), which does both demangling and normalizing.
287std::string GetRawDemangledTypeName(const std::type_info &ti)
288{
289 int e;
290 char *str = TClassEdit::DemangleName(ti.name(), e);
291 R__ASSERT(str && e == 0);
292 std::string result{str};
293 free(str);
294
295 return result;
296}
297
298// Reverse std::string --> std::basic_string<char> from the demangling
300{
301 static const std::string gStringName =
302 GetRenormalizedDemangledTypeName(GetRawDemangledTypeName(typeid(std::string)), false /* renormalizeStdString */);
303
304 // For real nested types of std::string (not typedefs like std::string::size_type), we would need to also check
305 // something like (normalizedTypeName + "::" == gStringName + "::") and replace only the prefix. However, since
306 // such a nested type is not standardized, it currently does not seem necessary to add the logic.
308 normalizedTypeName = "std::string";
309 }
310}
311
312// Reverse "internal" namespace prefix found in demangled names, such as std::vector<T> --> std::__1::vector<T>
314{
315 static std::vector<std::pair<std::string, std::string>> gDistortedStdlibNames = []() {
316 // clang-format off
317 // Listed in order of appearance in the BinaryFormatSpecification.md
318 static const std::vector<std::pair<const std::type_info &, std::string>> gCandidates =
319 {{typeid(std::vector<char>), "std::vector<"},
320 {typeid(std::array<char, 1>), "std::array<"},
321 {typeid(std::variant<char>), "std::variant<"},
322 {typeid(std::pair<char, char>), "std::pair<"},
323 {typeid(std::tuple<char>), "std::tuple<"},
324 {typeid(std::bitset<1>), "std::bitset<"},
325 {typeid(std::unique_ptr<char>), "std::unique_ptr<"},
326 {typeid(std::optional<char>), "std::optional<"},
327 {typeid(std::set<char>), "std::set<"},
328 {typeid(std::unordered_set<char>), "std::unordered_set<"},
329 {typeid(std::multiset<char>), "std::multiset<"},
330 {typeid(std::unordered_multiset<char>), "std::unordered_multiset<"},
331 {typeid(std::map<char, char>), "std::map<"},
332 {typeid(std::unordered_map<char, char>), "std::unordered_map<"},
333 {typeid(std::multimap<char, char>), "std::multimap<"},
334 {typeid(std::unordered_multimap<char, char>), "std::unordered_multimap<"},
335 {typeid(std::atomic<char>), "std::atomic<"}};
336 // clang-format on
337
338 std::vector<std::pair<std::string, std::string>> result;
339 for (const auto &[ti, prefix] : gCandidates) {
340 const auto dm = GetRawDemangledTypeName(ti);
341 if (dm.rfind(prefix, 0) == std::string::npos)
342 result.push_back(std::make_pair(dm.substr(0, dm.find('<') + 1), prefix));
343 }
344
345 return result;
346 }();
347
348 for (const auto &[seenPrefix, canonicalPrefix] : gDistortedStdlibNames) {
349 if (normalizedTypeName.rfind(seenPrefix, 0) == 0) {
351 break;
352 }
353 }
354}
355
356template <typename F>
358{
360 R__ASSERT(!angleBrackets.empty());
361
362 std::string normName;
363 std::string::size_type currentPos = 0;
364 for (std::size_t i = 0; i < angleBrackets.size(); i++) {
365 const auto [posOpen, posClose] = angleBrackets[i];
366 // Append the type prefix until the open angle bracket.
368
369 const auto argList = templatedTypeName.substr(posOpen + 1, posClose - posOpen - 1);
371 R__ASSERT(!templateArgs.empty());
372
374 for (const auto &a : templateArgs) {
376 }
377
378 normName[normName.size() - 1] = '>';
379 currentPos = posClose + 1;
380 }
381
382 // Append the rest of the type from the last closing angle bracket.
383 const auto lastClosePos = angleBrackets.back().second;
385
387}
388
389// Given a type name normalized by ROOT Meta, return the type name normalized according to the RNTuple rules.
390std::string GetRenormalizedMetaTypeName(const std::string &metaNormalizedName)
391{
393 // RNTuple resolves Double32_t for the normalized type name but keeps Double32_t for the type alias
394 // (also in template parameters)
395 if (canonicalTypePrefix == "Double32_t")
396 return "double";
397
398 if (canonicalTypePrefix.find('<') == std::string::npos) {
399 // If there are no templates, the function is done.
400 return canonicalTypePrefix;
401 }
402
403 std::string normName{canonicalTypePrefix};
405
406 return normName;
407}
408
409// Given a demangled name ("normalized by the compiler"), return the type name normalized according to the
410// RNTuple rules.
411std::string GetRenormalizedDemangledTypeName(const std::string &demangledName, bool renormalizeStdString)
412{
413 std::string tn{demangledName};
414 RemoveSpaceBefore(tn, '[');
419
420 if (canonicalTypePrefix.find('<') == std::string::npos) {
421 // If there are no templates, the function is done.
423 }
426 RemoveSpaceBefore(canonicalTypePrefix, ','); // MSVC fancies spaces before commas in the demangled name
428
429 // Remove optional stdlib template arguments
430 int maxTemplateArgs = 0;
431 if (canonicalTypePrefix.rfind("std::vector<", 0) == 0 || canonicalTypePrefix.rfind("std::set<", 0) == 0 ||
432 canonicalTypePrefix.rfind("std::unordered_set<", 0) == 0 ||
433 canonicalTypePrefix.rfind("std::multiset<", 0) == 0 ||
434 canonicalTypePrefix.rfind("std::unordered_multiset<", 0) == 0 ||
435 canonicalTypePrefix.rfind("std::unique_ptr<", 0) == 0) {
436 maxTemplateArgs = 1;
437 } else if (canonicalTypePrefix.rfind("std::map<", 0) == 0 ||
438 canonicalTypePrefix.rfind("std::unordered_map<", 0) == 0 ||
439 canonicalTypePrefix.rfind("std::multimap<", 0) == 0 ||
440 canonicalTypePrefix.rfind("std::unordered_multimap<", 0) == 0) {
441 maxTemplateArgs = 2;
442 }
443
444 std::string normName{canonicalTypePrefix};
447 });
448 // In RenormalizeStdString(), we normalize the demangled type name of `std::string`,
449 // so we need to prevent an endless recursion.
452 }
453
455}
456
457} // namespace
458
459std::string ROOT::Internal::GetCanonicalTypePrefix(const std::string &typeName)
460{
461 // Remove outer cv qualifiers and extra white spaces
462 const std::string cleanedType = TClassEdit::CleanType(typeName.c_str(), /*mode=*/1);
463
464 // Can happen when called from RFieldBase::Create() and is caught there
465 if (cleanedType.empty())
466 return "";
467
469
471 if (canonicalType.substr(0, 2) == "::") {
472 canonicalType.erase(0, 2);
473 }
474
476
477 if (canonicalType.substr(0, 6) == "array<") {
478 canonicalType = "std::" + canonicalType;
479 } else if (canonicalType.substr(0, 7) == "atomic<") {
480 canonicalType = "std::" + canonicalType;
481 } else if (canonicalType.substr(0, 7) == "bitset<") {
482 canonicalType = "std::" + canonicalType;
483 } else if (canonicalType.substr(0, 4) == "map<") {
484 canonicalType = "std::" + canonicalType;
485 } else if (canonicalType.substr(0, 9) == "multimap<") {
486 canonicalType = "std::" + canonicalType;
487 } else if (canonicalType.substr(0, 9) == "multiset<") {
488 canonicalType = "std::" + canonicalType;
489 }
490 if (canonicalType.substr(0, 5) == "pair<") {
491 canonicalType = "std::" + canonicalType;
492 } else if (canonicalType.substr(0, 4) == "set<") {
493 canonicalType = "std::" + canonicalType;
494 } else if (canonicalType.substr(0, 6) == "tuple<") {
495 canonicalType = "std::" + canonicalType;
496 } else if (canonicalType.substr(0, 11) == "unique_ptr<") {
497 canonicalType = "std::" + canonicalType;
498 } else if (canonicalType.substr(0, 14) == "unordered_map<") {
499 canonicalType = "std::" + canonicalType;
500 } else if (canonicalType.substr(0, 19) == "unordered_multimap<") {
501 canonicalType = "std::" + canonicalType;
502 } else if (canonicalType.substr(0, 19) == "unordered_multiset<") {
503 canonicalType = "std::" + canonicalType;
504 } else if (canonicalType.substr(0, 14) == "unordered_set<") {
505 canonicalType = "std::" + canonicalType;
506 } else if (canonicalType.substr(0, 8) == "variant<") {
507 canonicalType = "std::" + canonicalType;
508 } else if (canonicalType.substr(0, 7) == "vector<") {
509 canonicalType = "std::" + canonicalType;
510 } else if (canonicalType.substr(0, 11) == "ROOT::RVec<") {
511 canonicalType = "ROOT::VecOps::RVec<" + canonicalType.substr(11);
512 }
513
514 if (auto it = typeTranslationMap.find(canonicalType); it != typeTranslationMap.end()) {
515 canonicalType = it->second;
516 }
517
519
521}
522
523std::string ROOT::Internal::GetRenormalizedTypeName(const std::type_info &ti)
524{
525 return GetRenormalizedDemangledTypeName(GetRawDemangledTypeName(ti), true /* renormalizeStdString */);
526}
527
532
534{
538 std::string shortType;
539 splitname.ShortType(shortType, modType);
541
542 if (canonicalTypePrefix.find('<') == std::string::npos) {
543 // If there are no templates, the function is done.
544 return canonicalTypePrefix;
545 }
546
548 R__ASSERT(!angleBrackets.empty());
549
550 // For user-defined class types, we will need to get the default-initialized template arguments.
552
553 std::string normName;
554 std::string::size_type currentPos = 0;
555 for (std::size_t i = 0; i < angleBrackets.size(); i++) {
556 const auto [posOpen, posClose] = angleBrackets[i];
557 // Append the type prefix until the open angle bracket.
559
560 const auto argList = canonicalTypePrefix.substr(posOpen + 1, posClose - posOpen - 1);
561 const auto templateArgs = TokenizeTypeList(argList);
562 R__ASSERT(!templateArgs.empty());
563
564 for (const auto &a : templateArgs) {
566 }
567
568 // For user-defined classes, append default-initialized template arguments.
569 if (isUserClass) {
570 const auto cl = TClass::GetClass(canonicalTypePrefix.substr(0, posClose + 1).c_str());
571 if (cl) {
572 const std::string expandedName = cl->GetName();
574 // We can have fewer pairs than angleBrackets, for example in case of type aliases.
576
578 const auto expandedArgList =
581 // Note that we may be in a sitation where expandedTemplateArgs.size() is _smaller_ than
582 // templateArgs.size(), which is when the input type name has the optional template arguments explicitly
583 // spelled out but ROOT Meta is told to ignore some template arguments.
584
585 for (std::size_t j = templateArgs.size(); j < expandedTemplateArgs.size(); ++j) {
586 normName +=
588 }
589 }
590 }
591
592 normName[normName.size() - 1] = '>';
593 currentPos = posClose + 1;
594 }
595
596 // Append the rest of the type from the last closing angle bracket.
597 const auto lastClosePos = angleBrackets.back().second;
599
600 return normName;
601}
602
603std::string ROOT::Internal::GetNormalizedInteger(long long val)
604{
605 return std::to_string(val);
606}
607
608std::string ROOT::Internal::GetNormalizedInteger(unsigned long long val)
609{
610 if (val > std::numeric_limits<std::int64_t>::max())
611 return std::to_string(val) + "u";
612 return std::to_string(val);
613}
614
622
623long long ROOT::Internal::ParseIntTypeToken(const std::string &intToken)
624{
625 std::size_t nChars = 0;
626 long long res = std::stoll(intToken, &nChars);
627 if (nChars == intToken.size())
628 return res;
629
630 assert(nChars < intToken.size());
631 if (nChars == 0) {
632 throw RException(R__FAIL("invalid integer type token: " + intToken));
633 }
634
635 auto suffix = intToken.substr(nChars);
636 std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::toupper);
637 if (suffix == "L" || suffix == "LL")
638 return res;
639 if (res >= 0 && (suffix == "U" || suffix == "UL" || suffix == "ULL"))
640 return res;
641
642 throw RException(R__FAIL("invalid integer type token: " + intToken));
643}
644
645unsigned long long ROOT::Internal::ParseUIntTypeToken(const std::string &uintToken)
646{
647 std::size_t nChars = 0;
648 unsigned long long res = std::stoull(uintToken, &nChars);
649 if (nChars == uintToken.size())
650 return res;
651
652 assert(nChars < uintToken.size());
653 if (nChars == 0) {
654 throw RException(R__FAIL("invalid integer type token: " + uintToken));
655 }
656
657 auto suffix = uintToken.substr(nChars);
658 std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::toupper);
659 if (suffix == "U" || suffix == "L" || suffix == "LL" || suffix == "UL" || suffix == "ULL")
660 return res;
661
662 throw RException(R__FAIL("invalid integer type token: " + uintToken));
663}
664
666{
667 auto am = cl->GetAttributeMap();
668 if (!am || !am->HasKey("rntuple.streamerMode"))
669 return ERNTupleSerializationMode::kUnset;
670
671 std::string value = am->GetPropertyAsString("rntuple.streamerMode");
672 std::transform(value.begin(), value.end(), value.begin(), ::toupper);
673 if (value == "TRUE") {
674 return ERNTupleSerializationMode::kForceStreamerMode;
675 } else if (value == "FALSE") {
676 return ERNTupleSerializationMode::kForceNativeMode;
677 } else {
678 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "invalid setting for 'rntuple.streamerMode' class attribute: "
679 << am->GetPropertyAsString("rntuple.streamerMode");
680 return ERNTupleSerializationMode::kUnset;
681 }
682}
683
684std::vector<std::string> ROOT::Internal::TokenizeTypeList(std::string_view templateType, std::size_t maxArgs)
685{
686 std::vector<std::string> result;
687 if (templateType.empty())
688 return result;
689
690 const char *eol = templateType.data() + templateType.length();
691 const char *typeBegin = templateType.data();
692 const char *typeCursor = templateType.data();
693 unsigned int nestingLevel = 0;
694 while (typeCursor != eol) {
695 switch (*typeCursor) {
696 case '<': ++nestingLevel; break;
697 case '>': --nestingLevel; break;
698 case ',':
699 if (nestingLevel == 0) {
700 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
701 if (maxArgs && result.size() == maxArgs)
702 return result;
703 typeBegin = typeCursor + 1;
704 }
705 break;
706 }
707 typeCursor++;
708 }
709 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
710 return result;
711}
712
714 const std::type_info &ti)
715{
716 // Fast path: the caller provided the expected type name (from RField<T>::TypeName())
718 return true;
719
720 // The type name may be equal to the alternative, short type name issued by Meta. This is a rare case used, e.g.,
721 // by the ATLAS DataVector class to hide a default template parameter from the on-disk type name.
722 // Thus, we check again using first ROOT Meta normalization followed by RNTuple re-normalization.
724}
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:300
#define R__LOG_WARNING(...)
Definition RLogger.hxx:358
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
#define _(A, B)
Definition cfortran.h:108
#define free
Definition civetweb.c:1578
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
static std::string TypeName()
Definition RField.hxx:289
const_iterator begin() const
const_iterator end() const
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2974
TDictAttributeMap * GetAttributeMap() const
const Int_t n
Definition legend1.C:16
ERNTupleSerializationMode
Possible settings for the "rntuple.streamerMode" class attribute in the dictionary.
std::vector< std::string > TokenizeTypeList(std::string_view templateType, std::size_t maxArgs=0)
Used in RFieldBase::Create() in order to get the comma-separated list of template types E....
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
unsigned long long ParseUIntTypeToken(const std::string &uintToken)
std::string GetNormalizedInteger(const std::string &intTemplateArg)
Appends 'll' or 'ull' to the where necessary and strips the suffix if not needed.
ERNTupleSerializationMode GetRNTupleSerializationMode(TClass *cl)
std::string GetCanonicalTypePrefix(const std::string &typeName)
Applies RNTuple specific type name normalization rules (see specs) that help the string parsing in RF...
std::string GetNormalizedUnresolvedTypeName(const std::string &origName)
Applies all RNTuple type normalization rules except typedef resolution.
bool IsMatchingFieldType(const std::string &actualTypeName)
Helper to check if a given type name is the one expected of Field<T>.
Definition RField.hxx:511
std::string GetRenormalizedTypeName(const std::string &metaNormalizedName)
Given a type name normalized by ROOT meta, renormalize it for RNTuple. E.g., insert std::prefix.
long long ParseIntTypeToken(const std::string &intToken)
std::string GetDemangledTypeName(const std::type_info &t)
std::string CleanType(const char *typeDesc, int mode=0, const char **tail=nullptr)
Cleanup type description, redundant blanks removed and redundant tail ignored return *tail = pointer ...
char * DemangleName(const char *mangled_name, int &errorCode)
Definition TClassEdit.h:255
@ kDropComparator
Definition TClassEdit.h:84
@ kDropStlDefault
Definition TClassEdit.h:83