Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RFieldMeta.cxx
Go to the documentation of this file.
1/// \file RFieldMeta.cxx
2/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
3/// \date 2024-11-19
4
5// This file has concrete RField implementations that depend on ROOT Meta:
6// - RClassField
7// - RSoAField
8// - REnumField
9// - RPairField
10// - RProxiedCollectionField
11// - RMapField
12// - RSetField
13// - RStreamerField
14// - RField<TObject>
15// - RVariantField
16
17#include <ROOT/RField.hxx>
18#include <ROOT/RFieldBase.hxx>
19#include <ROOT/RFieldUtils.hxx>
21#include <ROOT/RNTupleUtils.hxx>
22#include <ROOT/RSpan.hxx>
23
24#include <TBaseClass.h>
25#include <TBufferFile.h>
26#include <TClass.h>
27#include <TClassEdit.h>
28#include <TDataMember.h>
29#include <TEnum.h>
30#include <TObject.h>
31#include <TObjArray.h>
32#include <TObjString.h>
33#include <TRealData.h>
34#include <TSchemaRule.h>
35#include <TSchemaRuleSet.h>
36#include <TStreamerElement.h>
37#include <TVirtualObject.h>
39
40#include <algorithm>
41#include <array>
42#include <cstddef> // std::size_t
43#include <cstdint> // std::uint32_t et al.
44#include <cstring> // for memset
45#include <memory>
46#include <mutex>
47#include <string>
48#include <string_view>
49#include <unordered_set>
50#include <utility>
51#include <variant>
52
54
55namespace {
56
57TClass *EnsureValidClass(std::string_view className)
58{
59 auto cl = TClass::GetClass(std::string(className).c_str());
60 if (cl == nullptr) {
61 throw ROOT::RException(R__FAIL("RField: no I/O support for type " + std::string(className)));
62 }
63 return cl;
64}
65
66/// Common checks used both by RClassField and RSoAField
67void EnsureValidUserClass(TClass *cl, const ROOT::RFieldBase &field, std::string_view fieldType)
68{
69 if (cl->GetState() < TClass::kInterpreted) {
70 throw ROOT::RException(R__FAIL(std::string(fieldType) + " " + cl->GetName() +
71 " cannot be constructed from a class that's not at least Interpreted"));
72 }
73 // Avoid accidentally supporting std types through TClass.
74 if (cl->Property() & kIsDefinedInStd) {
75 throw ROOT::RException(R__FAIL(field.GetTypeName() + " is not supported"));
76 }
77 if (field.GetTypeName() == "TObject") {
78 throw ROOT::RException(R__FAIL("TObject is only supported through RField<TObject>"));
79 }
80 if (cl->GetCollectionProxy()) {
81 throw ROOT::RException(R__FAIL(field.GetTypeName() + " has an associated collection proxy; "
82 "use RProxiedCollectionField instead"));
83 }
84 // Classes with, e.g., custom streamers are not supported through this field. Empty classes, however, are.
85 // Can be overwritten with the "rntuple.streamerMode=true" class attribute
86 if (!cl->CanSplit() && cl->Size() > 1 &&
88 throw ROOT::RException(R__FAIL(field.GetTypeName() + " cannot be stored natively in RNTuple"));
89 }
92 throw ROOT::RException(
93 R__FAIL(field.GetTypeName() + " has streamer mode enforced, not supported as native RNTuple class"));
94 }
95 // Detect custom streamers set on individual members at runtime via
96 // TClass::SetMemberStreamer() or TClass::AdoptMemberStreamer().
97 // CanSplit() only checks for custom streamers set at compile time (fHasCustomStreamerMember),
98 // but runtime streamers are stored in TRealData and must be checked here.
99 if (!cl->GetListOfRealData()) {
100 cl->BuildRealData();
101 }
102 for (auto realMember : ROOT::Detail::TRangeStaticCast<TRealData>(*cl->GetListOfRealData())) {
103 if (realMember->GetStreamer()) {
104 throw ROOT::RException(R__FAIL(std::string(field.GetTypeName()) + " has member " + realMember->GetName() +
105 " with a custom streamer; not supported natively in RNTuple"));
106 }
107 }
108}
109
110TEnum *EnsureValidEnum(std::string_view enumName)
111{
112 auto e = TEnum::GetEnum(std::string(enumName).c_str());
113 if (e == nullptr) {
114 throw ROOT::RException(R__FAIL("RField: no I/O support for enum type " + std::string(enumName)));
115 }
116 return e;
117}
118
119/// Create a comma-separated list of type names from the given fields. Uses either the real type names or the
120/// type aliases (if there are any, otherwise the actual type name). Used to construct template argument lists
121/// for templated types such as std::pair<...>, std::tuple<...>, std::variant<...>.
122std::string GetTypeList(std::span<std::unique_ptr<ROOT::RFieldBase>> itemFields, bool useTypeAliases)
123{
124 std::string result;
125 for (size_t i = 0; i < itemFields.size(); ++i) {
126 if (useTypeAliases && !itemFields[i]->GetTypeAlias().empty()) {
127 result += itemFields[i]->GetTypeAlias();
128 } else {
129 result += itemFields[i]->GetTypeName();
130 }
131 result.push_back(',');
132 }
133 if (result.empty()) {
134 throw ROOT::RException(R__FAIL("invalid empty type list provided as template argument"));
135 }
136 result.pop_back(); // remove trailing comma
137 return result;
138}
139
140std::string BuildSetTypeName(ROOT::RSetField::ESetType setType, const ROOT::RFieldBase &innerField, bool useTypeAlias)
141{
142 std::string typePrefix;
143 switch (setType) {
144 case ROOT::RSetField::ESetType::kSet: typePrefix = "std::set<"; break;
145 case ROOT::RSetField::ESetType::kUnorderedSet: typePrefix = "std::unordered_set<"; break;
146 case ROOT::RSetField::ESetType::kMultiSet: typePrefix = "std::multiset<"; break;
147 case ROOT::RSetField::ESetType::kUnorderedMultiSet: typePrefix = "std::unordered_multiset<"; break;
148 default: R__ASSERT(false);
149 }
150 return typePrefix +
151 ((useTypeAlias && !innerField.GetTypeAlias().empty()) ? innerField.GetTypeAlias()
152 : innerField.GetTypeName()) +
153 ">";
154}
155
156std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFieldBase *innerField, bool useTypeAliases)
157{
158 if (const auto pairField = dynamic_cast<const ROOT::RPairField *>(innerField)) {
159 std::string typePrefix;
160 switch (mapType) {
161 case ROOT::RMapField::EMapType::kMap: typePrefix = "std::map<"; break;
162 case ROOT::RMapField::EMapType::kUnorderedMap: typePrefix = "std::unordered_map<"; break;
163 case ROOT::RMapField::EMapType::kMultiMap: typePrefix = "std::multimap<"; break;
164 case ROOT::RMapField::EMapType::kUnorderedMultiMap: typePrefix = "std::unordered_multimap<"; break;
165 default: R__ASSERT(false);
166 }
167 const auto &items = pairField->GetConstSubfields();
168 std::string type = typePrefix;
169 for (int i : {0, 1}) {
170 if (useTypeAliases && !items[i]->GetTypeAlias().empty()) {
171 type += items[i]->GetTypeAlias();
172 } else {
173 type += items[i]->GetTypeName();
174 }
175 if (i == 0)
176 type.push_back(',');
177 }
178 return type + ">";
179 }
180
181 throw ROOT::RException(R__FAIL("RMapField inner field type must be of RPairField"));
183
184} // anonymous namespace
185
186ROOT::RClassField::RClassField(std::string_view fieldName, const RClassField &source)
187 : ROOT::RFieldBase(fieldName, source.GetTypeName(), ROOT::ENTupleStructure::kRecord, false /* isSimple */),
188 fClass(source.fClass),
191{
192 for (const auto &f : source.GetConstSubfields()) {
193 RFieldBase::Attach(f->Clone(f->GetFieldName()));
194 }
195 fTraits = source.GetTraits();
196}
197
198ROOT::RClassField::RClassField(std::string_view fieldName, std::string_view className)
199 : RClassField(fieldName, EnsureValidClass(className))
201}
202
203ROOT::RClassField::RClassField(std::string_view fieldName, TClass *classp)
204 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kRecord,
205 false /* isSimple */),
206 fClass(classp)
207{
208 EnsureValidUserClass(fClass, *this, "RClassField");
211 throw ROOT::RException(R__FAIL(GetTypeName() + " is a SoA field and connot be used through RClassField"));
214 if (!(fClass->ClassProperty() & kClassHasExplicitCtor))
216 if (!(fClass->ClassProperty() & kClassHasExplicitDtor))
218
219 std::string renormalizedAlias;
220 if (Internal::NeedsMetaNameAsAlias(classp->GetName(), renormalizedAlias))
221 fTypeAlias = renormalizedAlias;
223 int i = 0;
224 const auto *bases = fClass->GetListOfBases();
225 assert(bases);
226 for (auto baseClass : ROOT::Detail::TRangeStaticCast<TBaseClass>(*bases)) {
227 if (baseClass->GetDelta() < 0) {
228 throw RException(R__FAIL(std::string("virtual inheritance is not supported: ") + GetTypeName() +
229 " virtually inherits from " + baseClass->GetName()));
230 }
231 TClass *c = baseClass->GetClassPointer();
232 auto subField =
233 RFieldBase::Create(std::string(kPrefixInherited) + "_" + std::to_string(i), c->GetName()).Unwrap();
234 fTraits &= subField->GetTraits();
235 Attach(std::move(subField), RSubfieldInfo{kBaseClass, static_cast<std::size_t>(baseClass->GetDelta())});
236 i++;
237 }
239 // Skip, for instance, unscoped enum constants defined in the class
240 if (dataMember->Property() & kIsStatic)
241 continue;
242 // Skip members explicitly marked as transient by user comment
243 if (!dataMember->IsPersistent()) {
244 // TODO(jblomer): we could do better
246 continue;
247 }
248
249 // NOTE: we use the already-resolved type name for the fields, otherwise TClass::GetClass may fail to resolve
250 // context-dependent types (e.g. typedefs defined in the class itself - which will not be fully qualified in
251 // the string returned by dataMember->GetFullTypeName())
252 std::string typeName{dataMember->GetTrueTypeName()};
253
254 // For C-style arrays, complete the type name with the size for each dimension, e.g. `int[4][2]`
255 if (dataMember->Property() & kIsArray) {
256 for (int dim = 0, n = dataMember->GetArrayDim(); dim < n; ++dim) {
257 typeName += "[" + std::to_string(dataMember->GetMaxIndex(dim)) + "]";
258 }
259 }
260
261 auto subField = RFieldBase::Create(dataMember->GetName(), typeName).Unwrap();
262
263 fTraits &= subField->GetTraits();
264 Attach(std::move(subField), RSubfieldInfo{kDataMember, static_cast<std::size_t>(dataMember->GetOffset())});
265 }
267}
268
270{
271 if (fStagingArea) {
272 for (const auto &[_, si] : fStagingItems) {
273 if (!(si.fField->GetTraits() & kTraitTriviallyDestructible)) {
274 auto deleter = GetDeleterOf(*si.fField);
275 deleter->operator()(fStagingArea.get() + si.fOffset, true /* dtorOnly */);
276 }
277 }
278 }
279}
280
281void ROOT::RClassField::Attach(std::unique_ptr<RFieldBase> child, RSubfieldInfo info)
282{
283 fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
284 fSubfieldsInfo.push_back(info);
285 RFieldBase::Attach(std::move(child));
286}
287
288std::vector<const ROOT::TSchemaRule *> ROOT::RClassField::FindRules(const ROOT::RFieldDescriptor *fieldDesc)
289{
291 const auto ruleset = fClass->GetSchemaRules();
292 if (!ruleset)
293 return rules;
294
295 if (!fieldDesc) {
296 // If we have no on-disk information for the field, we still process the rules on the current in-memory version
297 // of the class
298 rules = ruleset->FindRules(fClass->GetName(), fClass->GetClassVersion(), fClass->GetCheckSum());
299 } else {
300 // We need to change (back) the name normalization from RNTuple to ROOT Meta
301 std::string normalizedName;
302 TClassEdit::GetNormalizedName(normalizedName, fieldDesc->GetTypeName());
303 // We do have an on-disk field that correspond to the current RClassField instance. Ask for rules matching the
304 // on-disk version of the field.
305 if (fieldDesc->GetTypeChecksum()) {
306 rules = ruleset->FindRules(normalizedName, fieldDesc->GetTypeVersion(), *fieldDesc->GetTypeChecksum());
307 } else {
308 rules = ruleset->FindRules(normalizedName, fieldDesc->GetTypeVersion());
309 }
310 }
311
312 // Cleanup and sort rules
313 // Check that any any given source member uses the same type in all rules
314 std::unordered_map<std::string, std::string> sourceNameAndType;
315 std::size_t nskip = 0; // skip whole-object-rules that were moved to the end of the rules vector
316 for (auto itr = rules.begin(); itr != rules.end() - nskip;) {
317 const auto rule = *itr;
318
319 // Erase unknown rule types
320 if (rule->GetRuleType() != ROOT::TSchemaRule::kReadRule) {
322 << "ignoring I/O customization rule with unsupported type: " << rule->GetRuleType();
323 itr = rules.erase(itr);
324 continue;
325 }
326
327 bool hasConflictingSourceMembers = false;
328 for (auto source : TRangeDynCast<TSchemaRule::TSources>(rule->GetSource())) {
329 auto memberType = source->GetTypeForDeclaration() + source->GetDimensions();
330 auto [itrSrc, isNew] = sourceNameAndType.emplace(source->GetName(), memberType);
331 if (!isNew && (itrSrc->second != memberType)) {
333 << "ignoring I/O customization rule due to conflicting source member type: " << itrSrc->second << " vs. "
334 << memberType << " for member " << source->GetName();
335 hasConflictingSourceMembers = true;
336 break;
337 }
338 }
339 if (hasConflictingSourceMembers) {
340 itr = rules.erase(itr);
341 continue;
342 }
343
344 // Rules targeting the entire object need to be executed at the end
345 if (rule->GetTarget() == nullptr) {
346 nskip++;
347 if (itr != rules.end() - nskip)
348 std::iter_swap(itr++, rules.end() - nskip);
349 continue;
350 }
351
352 ++itr;
353 }
354
355 return rules;
356}
357
358std::unique_ptr<ROOT::RFieldBase> ROOT::RClassField::CloneImpl(std::string_view newName) const
359{
360 return std::unique_ptr<RClassField>(new RClassField(newName, *this));
361}
362
363std::size_t ROOT::RClassField::AppendImpl(const void *from)
364{
365 std::size_t nbytes = 0;
366 for (unsigned i = 0; i < fSubfields.size(); i++) {
367 nbytes += CallAppendOn(*fSubfields[i], static_cast<const unsigned char *>(from) + fSubfieldsInfo[i].fOffset);
368 }
369 return nbytes;
370}
371
373{
374 for (const auto &[_, si] : fStagingItems) {
375 CallReadOn(*si.fField, globalIndex, fStagingArea.get() + si.fOffset);
376 }
377 for (unsigned i = 0; i < fSubfields.size(); i++) {
378 CallReadOn(*fSubfields[i], globalIndex, static_cast<unsigned char *>(to) + fSubfieldsInfo[i].fOffset);
379 }
380}
381
383{
384 for (const auto &[_, si] : fStagingItems) {
385 CallReadOn(*si.fField, localIndex, fStagingArea.get() + si.fOffset);
386 }
387 for (unsigned i = 0; i < fSubfields.size(); i++) {
388 CallReadOn(*fSubfields[i], localIndex, static_cast<unsigned char *>(to) + fSubfieldsInfo[i].fOffset);
389 }
390}
391
393 ROOT::DescriptorId_t classFieldId)
394{
395 auto idSourceMember = desc.FindFieldId(memberName, classFieldId);
396 if (idSourceMember != ROOT::kInvalidDescriptorId)
397 return idSourceMember;
398
399 for (const auto &subFieldDesc : desc.GetFieldIterable(classFieldId)) {
400 const auto subFieldName = subFieldDesc.GetFieldName();
401 if (subFieldName.length() > 2 && subFieldName[0] == ':' && subFieldName[1] == '_') {
402 idSourceMember = LookupMember(desc, memberName, subFieldDesc.GetId());
403 if (idSourceMember != ROOT::kInvalidDescriptorId)
404 return idSourceMember;
405 }
406 }
407
409}
410
411void ROOT::RClassField::SetStagingClass(const std::string &className, unsigned int classVersion)
412{
413 TClass::GetClass(className.c_str())->GetStreamerInfo(classVersion);
414 if (classVersion != GetTypeVersion() || className != GetTypeName()) {
415 fStagingClass = TClass::GetClass((className + std::string("@@") + std::to_string(classVersion)).c_str());
416 if (!fStagingClass) {
417 // For a rename rule, we may simply ask for the old class name
418 fStagingClass = TClass::GetClass(className.c_str());
419 }
420 } else {
422 }
424 R__ASSERT(static_cast<unsigned int>(fStagingClass->GetClassVersion()) == classVersion);
425}
426
427void ROOT::RClassField::PrepareStagingArea(const std::vector<const TSchemaRule *> &rules,
428 const ROOT::RNTupleDescriptor &desc,
429 const ROOT::RFieldDescriptor &classFieldDesc)
430{
431 std::size_t stagingAreaSize = 0;
432 for (const auto rule : rules) {
433 for (auto source : TRangeDynCast<TSchemaRule::TSources>(rule->GetSource())) {
434 auto [itr, isNew] = fStagingItems.emplace(source->GetName(), RStagingItem());
435 if (!isNew) {
436 // This source member has already been processed by another rule (and we only support one type per member)
437 continue;
438 }
439 RStagingItem &stagingItem = itr->second;
440
441 const auto memberFieldId = LookupMember(desc, source->GetName(), classFieldDesc.GetId());
442 if (memberFieldId == kInvalidDescriptorId) {
443 throw RException(R__FAIL(std::string("cannot find on disk rule source member ") + GetTypeName() + "." +
444 source->GetName()));
445 }
446
447 auto memberType = source->GetTypeForDeclaration() + source->GetDimensions();
448 auto memberField = Create("" /* we don't need a field name */, std::string(memberType)).Unwrap();
449 memberField->SetOnDiskId(memberFieldId);
450 auto fieldZero = std::make_unique<RFieldZero>();
451 Internal::SetAllowFieldSubstitutions(*fieldZero, true);
452 fieldZero->Attach(std::move(memberField));
453 stagingItem.fField = std::move(fieldZero);
454
455 stagingItem.fOffset = fStagingClass->GetDataMemberOffset(source->GetName());
456 // Since we successfully looked up the source member in the RNTuple on-disk metadata, we expect it
457 // to be present in the TClass instance, too.
459 stagingAreaSize = std::max(stagingAreaSize, stagingItem.fOffset + stagingItem.fField->begin()->GetValueSize());
460 }
461 }
462
463 if (stagingAreaSize) {
464 R__ASSERT(static_cast<Int_t>(stagingAreaSize) <= fStagingClass->Size()); // we may have removed rules
465 // We use std::make_unique instead of MakeUninitArray to zero-initialize the staging area.
466 fStagingArea = std::make_unique<unsigned char[]>(stagingAreaSize);
467
468 for (const auto &[_, si] : fStagingItems) {
469 const auto &memberField = *si.fField->cbegin();
470 if (!(memberField.GetTraits() & kTraitTriviallyConstructible)) {
471 CallConstructValueOn(memberField, fStagingArea.get() + si.fOffset);
472 }
473 }
474 }
475}
476
478{
479 auto func = rule->GetReadFunctionPointer();
480 if (func == nullptr) {
481 // Can happen for rename rules
482 return;
483 }
484 fReadCallbacks.emplace_back([func, stagingClass = fStagingClass, stagingArea = fStagingArea.get()](void *target) {
485 TVirtualObject onfileObj{nullptr};
486 onfileObj.fClass = stagingClass;
487 onfileObj.fObject = stagingArea;
488 func(static_cast<char *>(target), &onfileObj);
489 onfileObj.fObject = nullptr; // TVirtualObject does not own the value
490 });
491}
492
494{
495 std::vector<const TSchemaRule *> rules;
496 // On-disk members that are not targeted by an I/O rule; all other sub fields of the in-memory class
497 // will be marked as artificial (added member in a new class version or member set by rule).
498 std::unordered_set<std::string> regularSubfields;
499 // We generally don't support changing the number of base classes, with the exception of changing from/to zero
500 // base classes. The variable stores the number of on-disk base classes.
501 int nOnDiskBaseClasses = 0;
502
504 // This can happen for added base classes or added members of class type
505 rules = FindRules(nullptr);
506 if (!rules.empty())
508 } else {
509 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
510 const ROOT::RNTupleDescriptor &desc = descriptorGuard.GetRef();
511 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
512
513 if (fieldDesc.GetStructure() == ENTupleStructure::kStreamer) {
514 // Streamer field on disk but meanwhile the type can be represented as a class field; replace this field
515 // by a streamer field to read the data from disk.
516 auto substitute = std::make_unique<RStreamerField>(GetFieldName(), GetTypeName());
517 substitute->SetOnDiskId(GetOnDiskId());
518 return substitute;
519 }
520
521 for (auto linkId : fieldDesc.GetLinkIds()) {
522 const auto &subFieldDesc = desc.GetFieldDescriptor(linkId);
523 regularSubfields.insert(subFieldDesc.GetFieldName());
524 if (!subFieldDesc.GetFieldName().empty() && subFieldDesc.GetFieldName()[0] == ':')
525 nOnDiskBaseClasses++;
526 }
527
528 rules = FindRules(&fieldDesc);
529
530 // If we found a rule, we know it is valid to read on-disk data because we found the rule according to the on-disk
531 // (source) type name and version/checksum.
532 if (rules.empty()) {
533 // Otherwise we require compatible type names, after renormalization. GetTypeName() is already renormalized,
534 // but RNTuple data written with ROOT v6.34 might not have renormalized the field type name. Ask the
535 // RNTupleDescriptor, which knows about the spec version, for a fixed up type name.
536 std::string descTypeName = desc.GetTypeNameForComparison(fieldDesc);
537 if (GetTypeName() != descTypeName) {
538 throw RException(R__FAIL("incompatible type name for field " + GetFieldName() + ": " + GetTypeName() +
539 " vs. " + descTypeName));
540 }
541 }
542
543 const bool hasSources = std::any_of(rules.begin(), rules.end(), [](const auto &r) {
544 return r->GetSource() && (r->GetSource()->GetEntries() > 0);
545 });
546
547 // A staging class (conversion streamer info) only exists if there is at least one rule that has an
548 // on disk source member defined.
549 if (hasSources) {
550 SetStagingClass(fieldDesc.GetTypeName(), fieldDesc.GetTypeVersion());
551 PrepareStagingArea(rules, desc, fieldDesc);
552 for (auto &[_, si] : fStagingItems) {
553 Internal::CallConnectPageSourceOnField(*si.fField, pageSource);
554 si.fField = std::move(static_cast<RFieldZero *>(si.fField.get())->ReleaseSubfields()[0]);
555 }
556 }
557
558 // Remove target member of read rules from the list of regular members of the underlying on-disk field
559 for (const auto rule : rules) {
560 if (!rule->GetTarget())
561 continue;
562
563 for (const auto target : ROOT::Detail::TRangeStaticCast<const TObjString>(*rule->GetTarget())) {
564 regularSubfields.erase(std::string(target->GetString()));
565 }
566 }
567 }
568
569 for (const auto rule : rules) {
571 }
572
573 // Iterate over all sub fields in memory and mark those as missing that are not in the descriptor.
574 int nInMemoryBaseClasses = 0;
575 for (auto &field : fSubfields) {
576 const auto &fieldName = field->GetFieldName();
577 if (regularSubfields.count(fieldName) == 0) {
578 CallSetArtificialOn(*field);
579 }
580 if (!fieldName.empty() && fieldName[0] == ':')
581 nInMemoryBaseClasses++;
582 }
583
584 if (nInMemoryBaseClasses != 0 && nOnDiskBaseClasses != 0 && nInMemoryBaseClasses != nOnDiskBaseClasses) {
585 throw RException(R__FAIL(std::string("incompatible number of base classes for field ") + GetFieldName() + ": " +
586 GetTypeName() + ", " + std::to_string(nInMemoryBaseClasses) +
587 " base classes in memory "
588 " vs. " +
589 std::to_string(nOnDiskBaseClasses) + " base classes on-disk\n" +
591 }
592
593 return nullptr;
594}
595
600
602{
603 fClass->New(where);
604}
605
606void ROOT::RClassField::RClassDeleter::operator()(void *objPtr, bool dtorOnly)
607{
608 fClass->Destructor(objPtr, true /* dtorOnly */);
609 RDeleter::operator()(objPtr, dtorOnly);
610}
611
612std::vector<ROOT::RFieldBase::RValue> ROOT::RClassField::SplitValue(const RValue &value) const
613{
614 std::vector<RValue> result;
615 auto valuePtr = value.GetPtr<void>();
616 auto charPtr = static_cast<unsigned char *>(valuePtr.get());
617 result.reserve(fSubfields.size());
618 for (unsigned i = 0; i < fSubfields.size(); i++) {
619 result.emplace_back(
620 fSubfields[i]->BindValue(std::shared_ptr<void>(valuePtr, charPtr + fSubfieldsInfo[i].fOffset)));
621 }
622 return result;
623}
624
626{
627 return fClass->GetClassSize();
628}
629
631{
632 return fClass->GetClassVersion();
633}
634
636{
637 return fClass->GetCheckSum();
638}
639
640const std::type_info *ROOT::RClassField::GetPolymorphicTypeInfo() const
641{
642 bool polymorphic = fClass->ClassProperty() & kClassHasVirtual;
643 if (!polymorphic) {
644 return nullptr;
645 }
646 return fClass->GetTypeInfo();
647}
648
650{
651 visitor.VisitClassField(*this);
652}
653
654//------------------------------------------------------------------------------
655
656ROOT::Experimental::RSoAField::RSoAField(std::string_view fieldName, const RSoAField &source)
657 : ROOT::RFieldBase(fieldName, source.GetTypeName(), ROOT::ENTupleStructure::kCollection, false /* isSimple */),
658 fSoAClass(source.fSoAClass),
661{
662 fTraits = source.GetTraits();
663 Attach(source.fSubfields[0]->Clone(source.fSubfields[0]->GetFieldName()));
664 fRecordMemberFields = fSubfields[0]->GetMutableSubfields();
665}
666
667ROOT::Experimental::RSoAField::RSoAField(std::string_view fieldName, std::string_view className)
668 : RSoAField(fieldName, EnsureValidClass(className))
669{
670}
671
672ROOT::Experimental::RSoAField::RSoAField(std::string_view fieldName, TClass *clSoA)
673 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(clSoA->GetName()), ROOT::ENTupleStructure::kCollection,
674 false /* isSimple */),
675 fSoAClass(clSoA)
676{
677 static std::once_flag once;
678 std::call_once(once, []() {
679 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "The SoA field is experimental and still under development.";
680 });
681
682 EnsureValidUserClass(fSoAClass, *this, "RSoAField");
683 const auto recordTypeName = ROOT::Internal::GetRNTupleSoARecord(fSoAClass);
684 if (recordTypeName.empty()) {
685 throw ROOT::RException(R__FAIL(std::string("class ") + GetTypeName() +
686 " is not marked with the rntupleSoARecord "
687 "dictionary option; cannot create corresponding RSoAField."));
688 }
689 try {
690 Attach(std::make_unique<ROOT::RClassField>("_0", recordTypeName));
691 } catch (ROOT::RException &e) {
692 throw RException(R__FAIL("invalid record type of SoA field " + GetTypeName() + " [" + e.what() + "]"));
693 }
694 R__ASSERT(fSoAClass->GetClassVersion() >= 0);
695 if (static_cast<std::uint32_t>(fSoAClass->GetClassVersion()) != fSubfields[0]->GetTypeVersion()) {
696 throw RException(R__FAIL(std::string("version mismatch between SoA type and underlying record type: ") +
697 std::to_string(fSoAClass->GetClassVersion()) + " vs. " +
698 std::to_string(fSubfields[0]->GetTypeVersion())));
699 }
700 fRecordMemberFields = fSubfields[0]->GetMutableSubfields();
701
702 std::unordered_map<std::string, std::size_t> recordFieldNameToIdx;
703 for (std::size_t i = 0; i < fRecordMemberFields.size(); ++i) {
704 const RFieldBase *f = fRecordMemberFields[i];
705 assert(!f->GetFieldName().empty());
706 if (f->GetFieldName()[0] == ':') {
707 throw RException(R__FAIL("SoA fields with inheritance are currently unsupported"));
708 }
709 recordFieldNameToIdx[f->GetFieldName()] = i;
710 }
711
712 const auto *bases = fSoAClass->GetListOfBases();
713 assert(bases);
714 for (auto baseClass : ROOT::Detail::TRangeStaticCast<TBaseClass>(*bases)) {
715 if (baseClass->GetDelta() < 0) {
716 throw RException(R__FAIL(std::string("virtual inheritance is not supported: ") + GetTypeName() +
717 " virtually inherits from " + baseClass->GetName()));
718 }
719 // At a later point, we will support inheritance
720 throw RException(R__FAIL("SoA fields with inheritance are currently unsupported"));
721 }
722
724 unsigned int nMembers = 0;
725 for (auto dataMember : ROOT::Detail::TRangeStaticCast<TDataMember>(*fSoAClass->GetListOfDataMembers())) {
726 if ((dataMember->Property() & kIsStatic) || !dataMember->IsPersistent())
727 continue;
728
729 if (dataMember->Property() & kIsArray) {
730 throw RException(R__FAIL(std::string("unsupported array type in SoA class: ") + dataMember->GetName()));
731 }
732
733 const std::string typeName{dataMember->GetTrueTypeName()};
734 auto subField = RFieldBase::Create(dataMember->GetName(), typeName).Unwrap();
735 auto vecFieldPtr = dynamic_cast<RRVecField *>(subField.get());
736 if (!vecFieldPtr) {
737 throw RException(R__FAIL("invalid field type in SoA class: " + subField->GetTypeName()));
738 }
739 subField.release();
740 auto vecField = std::unique_ptr<RRVecField>(vecFieldPtr);
741
742 auto itr = recordFieldNameToIdx.find(vecField->GetFieldName());
743 if (itr == recordFieldNameToIdx.end()) {
744 throw RException(R__FAIL(std::string("unexpected SoA member: ") + vecField->GetFieldName()));
745 }
746 const RFieldBase *memberField = fRecordMemberFields[itr->second];
747 if (vecField->begin()->GetTypeName() != memberField->GetTypeName() ||
748 vecField->begin()->GetTypeAlias() != memberField->GetTypeAlias()) {
749 const std::string leftType =
750 vecField->begin()->GetTypeName() +
751 (vecField->begin()->GetTypeAlias().empty() ? "" : " [" + vecField->begin()->GetTypeAlias() + "]");
752 const std::string rightType =
753 memberField->GetTypeName() +
754 (memberField->GetTypeAlias().empty() ? "" : " [" + memberField->GetTypeAlias() + "]");
755 throw RException(R__FAIL(std::string("SoA member type mismatch: ") + vecField->GetFieldName() + " (" +
756 leftType + " vs. " + rightType + ")"));
757 }
758
759 fMaxAlignment = std::max(fMaxAlignment, vecField->GetAlignment());
760
761 assert(itr->second < fSoAMemberOffsets.size());
762 fSoAMemberOffsets[itr->second] = dataMember->GetOffset();
763 nMembers++;
764 }
765 if (recordFieldNameToIdx.size() != nMembers) {
766 throw RException(R__FAIL("missing SoA members"));
767 }
768
769 std::string renormalizedAlias;
770 if (ROOT::Internal::NeedsMetaNameAsAlias(fSoAClass->GetName(), renormalizedAlias))
771 fTypeAlias = renormalizedAlias;
772
774}
775
776std::unique_ptr<ROOT::RFieldBase> ROOT::Experimental::RSoAField::CloneImpl(std::string_view newName) const
777{
778 return std::unique_ptr<RSoAField>(new RSoAField(newName, *this));
779}
780
790
795
800
801std::size_t ROOT::Experimental::RSoAField::AppendImpl(const void *from)
802{
803 const std::size_t nSoAMembers = fSoAMemberOffsets.size();
804
805 std::size_t N = 0; // Set by first SoA member and verified for the rest
806 for (std::size_t i = 0; i < nSoAMembers; ++i) {
807 const void *rvecPtr = static_cast<const unsigned char *>(from) + fSoAMemberOffsets[i];
808 auto [beginPtr, sizePtr, _] = ROOT::Internal::GetRVecDataMembers(rvecPtr);
809 assert(*sizePtr >= 0);
810 if (i == 0) {
811 N = *sizePtr;
812 } else {
813 if (static_cast<std::size_t>(*sizePtr) != N) {
814 const auto f = fRecordMemberFields[i];
815 throw RException(R__FAIL("SoA length mismatch for " + f->GetFieldName() + ": " + std::to_string(*sizePtr) +
816 " vs. " + std::to_string(N) + " (expected)"));
817 }
818 }
819 }
820
821 std::size_t nbytes = 0;
822 if (N > 0) {
823 for (std::size_t i = 0; i < nSoAMembers; ++i) {
824 const void *rvecPtr = static_cast<const unsigned char *>(from) + fSoAMemberOffsets[i];
825 auto [beginPtr, _, __] = ROOT::Internal::GetRVecDataMembers(rvecPtr);
826 RFieldBase *memberField = fRecordMemberFields[i];
827 if (memberField->IsSimple()) {
828 GetPrincipalColumnOf(*memberField)->AppendV(*beginPtr, N);
829 nbytes += N * GetPrincipalColumnOf(*memberField)->GetElement()->GetPackedSize();
830 } else {
831 for (std::size_t j = 0; j < N; ++j) {
832 nbytes += CallAppendOn(*memberField, *beginPtr + j * memberField->GetValueSize());
833 }
834 }
835 }
836 }
837
838 fNWritten += N;
839 fPrincipalColumn->Append(&fNWritten);
840 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
841}
842
844{
845 throw RException(R__FAIL("not yet implemented"));
846}
847
849{
850 fSoAClass->New(where);
851}
852
854{
855 fSoAClass->Destructor(objPtr, true /* dtorOnly */);
856 RDeleter::operator()(objPtr, dtorOnly);
857}
858
859std::vector<ROOT::RFieldBase::RValue> ROOT::Experimental::RSoAField::SplitValue(const RValue & /* value */) const
860{
861 throw RException(R__FAIL("not yet implemented"));
862 return std::vector<RValue>();
863}
864
866{
867 return fSoAClass->GetClassSize();
868}
869
871{
872 return fSoAClass->GetClassVersion();
873}
874
876{
877 return fSoAClass->GetCheckSum();
878}
879
881{
882 // TODO(jblomer): factor out
883 bool polymorphic = fSoAClass->ClassProperty() & kClassHasVirtual;
884 if (!polymorphic) {
885 return nullptr;
886 }
887 return fSoAClass->GetTypeInfo();
888}
889
890//------------------------------------------------------------------------------
891
892ROOT::REnumField::REnumField(std::string_view fieldName, std::string_view enumName)
893 : REnumField(fieldName, EnsureValidEnum(enumName))
894{
895}
896
897ROOT::REnumField::REnumField(std::string_view fieldName, TEnum *enump)
898 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(enump->GetQualifiedName()), ROOT::ENTupleStructure::kPlain,
899 false /* isSimple */)
900{
901 // Avoid accidentally supporting std types through TEnum.
902 if (enump->Property() & kIsDefinedInStd) {
903 throw RException(R__FAIL(GetTypeName() + " is not supported"));
904 }
905
906 switch (enump->GetUnderlyingType()) {
907 case kBool_t: Attach(std::make_unique<RField<Bool_t>>("_0")); break;
908 case kChar_t: Attach(std::make_unique<RField<Char_t>>("_0")); break;
909 case kUChar_t: Attach(std::make_unique<RField<UChar_t>>("_0")); break;
910 case kShort_t: Attach(std::make_unique<RField<Short_t>>("_0")); break;
911 case kUShort_t: Attach(std::make_unique<RField<UShort_t>>("_0")); break;
912 case kInt_t: Attach(std::make_unique<RField<Int_t>>("_0")); break;
913 case kUInt_t: Attach(std::make_unique<RField<UInt_t>>("_0")); break;
914 case kLong_t: Attach(std::make_unique<RField<Long_t>>("_0")); break;
915 case kLong64_t: Attach(std::make_unique<RField<Long64_t>>("_0")); break;
916 case kULong_t: Attach(std::make_unique<RField<ULong_t>>("_0")); break;
917 case kULong64_t: Attach(std::make_unique<RField<ULong64_t>>("_0")); break;
918 default: throw RException(R__FAIL("Unsupported underlying integral type for enum type " + GetTypeName()));
919 }
920
922}
923
924ROOT::REnumField::REnumField(std::string_view fieldName, std::string_view enumName,
925 std::unique_ptr<RFieldBase> intField)
926 : ROOT::RFieldBase(fieldName, enumName, ROOT::ENTupleStructure::kPlain, false /* isSimple */)
927{
928 Attach(std::move(intField));
930}
931
932std::unique_ptr<ROOT::RFieldBase> ROOT::REnumField::CloneImpl(std::string_view newName) const
933{
934 auto newIntField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
935 return std::unique_ptr<REnumField>(new REnumField(newName, GetTypeName(), std::move(newIntField)));
936}
937
939{
940 // TODO(jblomer): allow enum to enum conversion only by rename rule
942}
943
944std::vector<ROOT::RFieldBase::RValue> ROOT::REnumField::SplitValue(const RValue &value) const
945{
946 std::vector<RValue> result;
947 result.emplace_back(fSubfields[0]->BindValue(value.GetPtr<void>()));
948 return result;
949}
950
952{
953 visitor.VisitEnumField(*this);
954}
955
956//------------------------------------------------------------------------------
957
958ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields)
959 : ROOT::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
960{
961 const std::string typeAlias = "std::pair<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
962 if (typeAlias != GetTypeName())
963 fTypeAlias = typeAlias;
964
965 AttachItemFields(std::move(itemFields));
966
967 // ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
968 auto *c = TClass::GetClass(GetTypeName().c_str());
969 if (!c)
970 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
971 fSize = c->Size();
972
973 auto firstElem = c->GetRealData("first");
974 if (!firstElem)
975 throw RException(R__FAIL("first: no such member"));
976 fOffsets.push_back(firstElem->GetThisOffset());
977
978 auto secondElem = c->GetRealData("second");
979 if (!secondElem)
980 throw RException(R__FAIL("second: no such member"));
981 fOffsets.push_back(secondElem->GetThisOffset());
982}
983
984std::unique_ptr<ROOT::RFieldBase> ROOT::RPairField::CloneImpl(std::string_view newName) const
985{
986 std::array<std::unique_ptr<RFieldBase>, 2> itemClones = {fSubfields[0]->Clone(fSubfields[0]->GetFieldName()),
987 fSubfields[1]->Clone(fSubfields[1]->GetFieldName())};
988 return std::unique_ptr<RPairField>(new RPairField(newName, std::move(itemClones)));
989}
990
992{
993 static const std::vector<std::string> prefixes = {"std::pair<", "std::tuple<"};
994
995 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
996 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
997
998 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
999 const auto nOnDiskSubfields = fieldDesc.GetLinkIds().size();
1000 if (nOnDiskSubfields != 2) {
1001 throw ROOT::RException(R__FAIL("invalid number of on-disk subfields for std::pair " +
1002 std::to_string(nOnDiskSubfields) + "\n" +
1003 Internal::GetTypeTraceReport(*this, desc)));
1004 }
1005}
1006
1007//------------------------------------------------------------------------------
1008
1011 bool readFromDisk)
1012{
1013 RIteratorFuncs ifuncs;
1014 ifuncs.fCreateIterators = proxy->GetFunctionCreateIterators(readFromDisk);
1015 ifuncs.fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(readFromDisk);
1016 ifuncs.fNext = proxy->GetFunctionNext(readFromDisk);
1017 R__ASSERT((ifuncs.fCreateIterators != nullptr) && (ifuncs.fDeleteTwoIterators != nullptr) &&
1018 (ifuncs.fNext != nullptr));
1019 return ifuncs;
1020}
1021
1023 : RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kCollection,
1024 false /* isSimple */),
1025 fNWritten(0)
1026{
1027 if (!classp->GetCollectionProxy())
1028 throw RException(R__FAIL(std::string(classp->GetName()) + " has no associated collection proxy"));
1029 if (classp->Property() & kIsDefinedInStd) {
1030 static const std::vector<std::string> supportedStdTypes = {
1031 "std::set<", "std::unordered_set<", "std::multiset<", "std::unordered_multiset<",
1032 "std::map<", "std::unordered_map<", "std::multimap<", "std::unordered_multimap<"};
1033 bool isSupported = false;
1034 for (const auto &tn : supportedStdTypes) {
1035 if (GetTypeName().rfind(tn, 0) == 0) {
1036 isSupported = true;
1037 break;
1038 }
1039 }
1040 if (!isSupported)
1041 throw RException(R__FAIL(std::string(GetTypeName()) + " is not supported"));
1042 }
1043
1044 std::string renormalizedAlias;
1045 if (Internal::NeedsMetaNameAsAlias(classp->GetName(), renormalizedAlias))
1046 fTypeAlias = renormalizedAlias;
1047
1048 fProxy.reset(classp->GetCollectionProxy()->Generate());
1049 fProperties = fProxy->GetProperties();
1050 fCollectionType = fProxy->GetCollectionType();
1051 if (fProxy->HasPointers())
1052 throw RException(R__FAIL("collection proxies whose value type is a pointer are not supported"));
1053
1054 fIFuncsRead = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), true /* readFromDisk */);
1055 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readFromDisk */);
1056}
1057
1058ROOT::RProxiedCollectionField::RProxiedCollectionField(std::string_view fieldName, std::string_view typeName)
1059 : RProxiedCollectionField(fieldName, EnsureValidClass(typeName))
1060{
1061 // NOTE (fdegeus): std::map is supported, custom associative might be supported in the future if the need arises.
1063 throw RException(R__FAIL("custom associative collection proxies not supported"));
1064
1065 std::unique_ptr<ROOT::RFieldBase> itemField;
1066
1067 if (auto valueClass = fProxy->GetValueClass()) {
1068 // Element type is a class
1069 itemField = RFieldBase::Create("_0", valueClass->GetName()).Unwrap();
1070 } else {
1071 switch (fProxy->GetType()) {
1072 case EDataType::kChar_t: itemField = std::make_unique<RField<Char_t>>("_0"); break;
1073 case EDataType::kUChar_t: itemField = std::make_unique<RField<UChar_t>>("_0"); break;
1074 case EDataType::kShort_t: itemField = std::make_unique<RField<Short_t>>("_0"); break;
1075 case EDataType::kUShort_t: itemField = std::make_unique<RField<UShort_t>>("_0"); break;
1076 case EDataType::kInt_t: itemField = std::make_unique<RField<Int_t>>("_0"); break;
1077 case EDataType::kUInt_t: itemField = std::make_unique<RField<UInt_t>>("_0"); break;
1078 case EDataType::kLong_t: itemField = std::make_unique<RField<Long_t>>("_0"); break;
1079 case EDataType::kLong64_t: itemField = std::make_unique<RField<Long64_t>>("_0"); break;
1080 case EDataType::kULong_t: itemField = std::make_unique<RField<ULong_t>>("_0"); break;
1081 case EDataType::kULong64_t: itemField = std::make_unique<RField<ULong64_t>>("_0"); break;
1082 case EDataType::kFloat_t: itemField = std::make_unique<RField<Float_t>>("_0"); break;
1083 case EDataType::kDouble_t: itemField = std::make_unique<RField<Double_t>>("_0"); break;
1084 case EDataType::kBool_t: itemField = std::make_unique<RField<Bool_t>>("_0"); break;
1085 default: throw RException(R__FAIL("unsupported value type: " + std::to_string(fProxy->GetType())));
1086 }
1087 }
1088
1089 fItemSize = itemField->GetValueSize();
1090 Attach(std::move(itemField));
1091}
1092
1093std::unique_ptr<ROOT::RFieldBase> ROOT::RProxiedCollectionField::CloneImpl(std::string_view newName) const
1094{
1095 auto clone =
1096 std::unique_ptr<RProxiedCollectionField>(new RProxiedCollectionField(newName, fProxy->GetCollectionClass()));
1097 clone->fItemSize = fItemSize;
1098 clone->Attach(fSubfields[0]->Clone(fSubfields[0]->GetFieldName()));
1099 return clone;
1100}
1101
1103{
1104 std::size_t nbytes = 0;
1105 unsigned count = 0;
1106 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), const_cast<void *>(from));
1107 for (auto ptr : RCollectionIterableOnce{const_cast<void *>(from), fIFuncsWrite, fProxy.get(),
1108 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
1109 nbytes += CallAppendOn(*fSubfields[0], ptr);
1110 count++;
1111 }
1112
1113 fNWritten += count;
1114 fPrincipalColumn->Append(&fNWritten);
1115 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
1116}
1117
1119{
1120 ROOT::NTupleSize_t nItems;
1121 RNTupleLocalIndex collectionStart;
1122 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1123
1125 void *obj =
1126 fProxy->Allocate(static_cast<std::uint32_t>(nItems), (fProperties & TVirtualCollectionProxy::kNeedDelete));
1127
1128 unsigned i = 0;
1129 for (auto elementPtr : RCollectionIterableOnce{obj, fIFuncsRead, fProxy.get(),
1130 (fCollectionType == kSTLvector || obj != to ? fItemSize : 0U)}) {
1131 CallReadOn(*fSubfields[0], collectionStart + (i++), elementPtr);
1132 }
1133 if (obj != to)
1134 fProxy->Commit(obj);
1135}
1136
1146
1151
1156
1161
1163{
1164 fProxy->New(where);
1165}
1166
1167std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RProxiedCollectionField::GetDeleter() const
1168{
1170 std::size_t itemSize = fCollectionType == kSTLvector ? fItemSize : 0U;
1171 return std::make_unique<RProxiedCollectionDeleter>(fProxy, GetDeleterOf(*fSubfields[0]), itemSize);
1172 }
1173 return std::make_unique<RProxiedCollectionDeleter>(fProxy);
1174}
1175
1177{
1178 if (fItemDeleter) {
1179 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), objPtr);
1180 for (auto ptr : RCollectionIterableOnce{objPtr, fIFuncsWrite, fProxy.get(), fItemSize}) {
1181 fItemDeleter->operator()(ptr, true /* dtorOnly */);
1182 }
1183 }
1184 fProxy->Destructor(objPtr, true /* dtorOnly */);
1185 RDeleter::operator()(objPtr, dtorOnly);
1186}
1187
1188std::vector<ROOT::RFieldBase::RValue> ROOT::RProxiedCollectionField::SplitValue(const RValue &value) const
1189{
1190 std::vector<RValue> result;
1191 auto valueRawPtr = value.GetPtr<void>().get();
1192 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), valueRawPtr);
1193 for (auto ptr : RCollectionIterableOnce{valueRawPtr, fIFuncsWrite, fProxy.get(),
1194 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
1195 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), ptr)));
1196 }
1197 return result;
1198}
1199
1204
1205//------------------------------------------------------------------------------
1206
1207ROOT::RMapField::RMapField(std::string_view fieldName, EMapType mapType, std::unique_ptr<RFieldBase> itemField)
1208 : RProxiedCollectionField(fieldName,
1209 EnsureValidClass(BuildMapTypeName(mapType, itemField.get(), false /* useTypeAliases */))),
1210 fMapType(mapType)
1211{
1212 if (!itemField->GetTypeAlias().empty())
1213 fTypeAlias = BuildMapTypeName(mapType, itemField.get(), true /* useTypeAliases */);
1214
1215 auto *itemClass = fProxy->GetValueClass();
1216 fItemSize = itemClass->GetClassSize();
1217
1218 Attach(std::move(itemField), "_0");
1219}
1220
1221std::unique_ptr<ROOT::RFieldBase> ROOT::RMapField::CloneImpl(std::string_view newName) const
1222{
1223 return std::make_unique<RMapField>(newName, fMapType, fSubfields[0]->Clone(fSubfields[0]->GetFieldName()));
1224}
1225
1227{
1228 static const std::vector<std::string> prefixesRegular = {"std::map<", "std::unordered_map<"};
1229
1230 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
1231
1232 switch (fMapType) {
1233 case EMapType::kMap:
1234 case EMapType::kUnorderedMap: EnsureMatchingTypePrefix(desc, prefixesRegular).ThrowOnError(); break;
1235 default:
1236 break;
1237 // no restrictions for multimaps
1238 }
1239}
1240
1241//------------------------------------------------------------------------------
1242
1243ROOT::RSetField::RSetField(std::string_view fieldName, ESetType setType, std::unique_ptr<RFieldBase> itemField)
1244 : ROOT::RProxiedCollectionField(fieldName,
1245 EnsureValidClass(BuildSetTypeName(setType, *itemField, false /* useTypeAlias */))),
1246 fSetType(setType)
1247{
1248 if (!itemField->GetTypeAlias().empty())
1249 fTypeAlias = BuildSetTypeName(setType, *itemField, true /* useTypeAlias */);
1250
1251 fItemSize = itemField->GetValueSize();
1252
1253 Attach(std::move(itemField), "_0");
1254}
1255
1256std::unique_ptr<ROOT::RFieldBase> ROOT::RSetField::CloneImpl(std::string_view newName) const
1257{
1258 return std::make_unique<RSetField>(newName, fSetType, fSubfields[0]->Clone(fSubfields[0]->GetFieldName()));
1259}
1260
1262{
1263 static const std::vector<std::string> prefixesRegular = {"std::set<", "std::unordered_set<", "std::map<",
1264 "std::unordered_map<"};
1265
1266 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
1267
1268 switch (fSetType) {
1269 case ESetType::kSet:
1270 case ESetType::kUnorderedSet: EnsureMatchingTypePrefix(desc, prefixesRegular).ThrowOnError(); break;
1271 default:
1272 break;
1273 // no restrictions for multisets
1274 }
1275}
1276
1277//------------------------------------------------------------------------------
1278
1279namespace {
1280
1281/// Used in RStreamerField::AppendImpl() in order to record the encountered streamer info records
1282class TBufferRecStreamer : public TBufferFile {
1283public:
1284 using RCallbackStreamerInfo = std::function<void(TVirtualStreamerInfo *)>;
1285
1286private:
1287 RCallbackStreamerInfo fCallbackStreamerInfo;
1288
1289public:
1290 TBufferRecStreamer(TBuffer::EMode mode, Int_t bufsize, RCallbackStreamerInfo callbackStreamerInfo)
1291 : TBufferFile(mode, bufsize), fCallbackStreamerInfo(callbackStreamerInfo)
1292 {
1293 }
1294 void TagStreamerInfo(TVirtualStreamerInfo *info) final { fCallbackStreamerInfo(info); }
1295};
1296
1297} // anonymous namespace
1298
1299ROOT::RStreamerField::RStreamerField(std::string_view fieldName, std::string_view className)
1300 : RStreamerField(fieldName, EnsureValidClass(className))
1301{
1302}
1303
1304ROOT::RStreamerField::RStreamerField(std::string_view fieldName, TClass *classp)
1305 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kStreamer,
1306 false /* isSimple */),
1307 fClass(classp),
1308 fIndex(0)
1309{
1310 std::string renormalizedAlias;
1311 if (Internal::NeedsMetaNameAsAlias(classp->GetName(), renormalizedAlias))
1312 fTypeAlias = renormalizedAlias;
1313
1315 // For RClassField, we only check for explicit constructors and destructors and then recursively combine traits from
1316 // all member subfields. For RStreamerField, we treat the class as a black box and additionally need to check for
1317 // implicit constructors and destructors.
1318 if (!(fClass->ClassProperty() & (kClassHasExplicitCtor | kClassHasImplicitCtor)))
1320 if (!(fClass->ClassProperty() & (kClassHasExplicitDtor | kClassHasImplicitDtor)))
1322}
1323
1324std::unique_ptr<ROOT::RFieldBase> ROOT::RStreamerField::CloneImpl(std::string_view newName) const
1325{
1326 return std::unique_ptr<RStreamerField>(new RStreamerField(newName, GetTypeName()));
1327}
1328
1329std::size_t ROOT::RStreamerField::AppendImpl(const void *from)
1330{
1331 TBufferRecStreamer buffer(TBuffer::kWrite, GetValueSize(),
1332 [this](TVirtualStreamerInfo *info) { fStreamerInfos[info->GetNumber()] = info; });
1333 fClass->Streamer(const_cast<void *>(from), buffer);
1334
1335 auto nbytes = buffer.Length();
1336 fAuxiliaryColumn->AppendV(buffer.Buffer(), buffer.Length());
1337 fIndex += nbytes;
1338 fPrincipalColumn->Append(&fIndex);
1339 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
1340}
1341
1343{
1344 RNTupleLocalIndex collectionStart;
1345 ROOT::NTupleSize_t nbytes;
1346 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nbytes);
1347
1348 TBufferFile buffer(TBuffer::kRead, nbytes);
1349 fAuxiliaryColumn->ReadV(collectionStart, nbytes, buffer.Buffer());
1350 fClass->Streamer(to, buffer);
1351}
1352
1362
1367
1372
1374{
1375 source.RegisterStreamerInfos();
1376 return nullptr;
1377}
1378
1383
1385{
1386 fClass->New(where);
1387}
1388
1390{
1391 fClass->Destructor(objPtr, true /* dtorOnly */);
1392 RDeleter::operator()(objPtr, dtorOnly);
1393}
1394
1404
1406{
1407 return std::min(alignof(std::max_align_t), GetValueSize()); // TODO(jblomer): fix me
1408}
1409
1411{
1412 return fClass->GetClassSize();
1413}
1414
1416{
1417 return fClass->GetClassVersion();
1418}
1419
1421{
1422 return fClass->GetCheckSum();
1423}
1424
1426{
1427 visitor.VisitStreamerField(*this);
1428}
1429
1430//------------------------------------------------------------------------------
1431
1433{
1434 if (auto dataMember = TObject::Class()->GetDataMember(name)) {
1435 return dataMember->GetOffset();
1436 }
1437 throw RException(R__FAIL('\'' + std::string(name) + '\'' + " is an invalid data member"));
1438}
1439
1440ROOT::RField<TObject>::RField(std::string_view fieldName, const RField<TObject> &source)
1441 : ROOT::RFieldBase(fieldName, "TObject", ROOT::ENTupleStructure::kRecord, false /* isSimple */)
1442{
1444 Attach(source.GetConstSubfields()[0]->Clone("fUniqueID"));
1445 Attach(source.GetConstSubfields()[1]->Clone("fBits"));
1446}
1447
1448ROOT::RField<TObject>::RField(std::string_view fieldName)
1449 : ROOT::RFieldBase(fieldName, "TObject", ROOT::ENTupleStructure::kRecord, false /* isSimple */)
1450{
1451 assert(TObject::Class()->GetClassVersion() == 1);
1452
1454 Attach(std::make_unique<RField<UInt_t>>("fUniqueID"));
1455 Attach(std::make_unique<RField<UInt_t>>("fBits"));
1456}
1457
1458std::unique_ptr<ROOT::RFieldBase> ROOT::RField<TObject>::CloneImpl(std::string_view newName) const
1459{
1460 return std::unique_ptr<RField<TObject>>(new RField<TObject>(newName, *this));
1461}
1462
1463std::size_t ROOT::RField<TObject>::AppendImpl(const void *from)
1464{
1465 // Cf. TObject::Streamer()
1466
1467 auto *obj = static_cast<const TObject *>(from);
1468 if (obj->TestBit(TObject::kIsReferenced)) {
1469 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
1470 }
1471
1472 std::size_t nbytes = 0;
1473 nbytes += CallAppendOn(*fSubfields[0], reinterpret_cast<const unsigned char *>(from) + GetOffsetUniqueID());
1474
1475 UInt_t bits = *reinterpret_cast<const UInt_t *>(reinterpret_cast<const unsigned char *>(from) + GetOffsetBits());
1476 bits &= (~TObject::kIsOnHeap & ~TObject::kNotDeleted);
1477 nbytes += CallAppendOn(*fSubfields[1], &bits);
1478
1479 return nbytes;
1480}
1481
1483{
1484 // Cf. TObject::Streamer()
1485
1486 auto *obj = static_cast<TObject *>(to);
1487 if (obj->TestBit(TObject::kIsReferenced)) {
1488 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
1489 }
1490
1491 *reinterpret_cast<UInt_t *>(reinterpret_cast<unsigned char *>(to) + GetOffsetUniqueID()) = uniqueID;
1492
1493 const UInt_t bitIsOnHeap = obj->TestBit(TObject::kIsOnHeap) ? TObject::kIsOnHeap : 0;
1494 bits |= bitIsOnHeap | TObject::kNotDeleted;
1495 *reinterpret_cast<UInt_t *>(reinterpret_cast<unsigned char *>(to) + GetOffsetBits()) = bits;
1496}
1497
1499{
1500 UInt_t uniqueID, bits;
1501 CallReadOn(*fSubfields[0], globalIndex, &uniqueID);
1502 CallReadOn(*fSubfields[1], globalIndex, &bits);
1503 ReadTObject(to, uniqueID, bits);
1504}
1505
1507{
1508 UInt_t uniqueID, bits;
1509 CallReadOn(*fSubfields[0], localIndex, &uniqueID);
1510 CallReadOn(*fSubfields[1], localIndex, &bits);
1511 ReadTObject(to, uniqueID, bits);
1512}
1513
1515{
1516 return TObject::Class()->GetClassVersion();
1517}
1518
1520{
1521 return TObject::Class()->GetCheckSum();
1522}
1523
1525{
1526 new (where) TObject();
1527}
1528
1529std::vector<ROOT::RFieldBase::RValue> ROOT::RField<TObject>::SplitValue(const RValue &value) const
1530{
1531 std::vector<RValue> result;
1532 // Use GetPtr<TObject> to type-check
1533 std::shared_ptr<void> ptr = value.GetPtr<TObject>();
1534 auto charPtr = static_cast<unsigned char *>(ptr.get());
1535 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(ptr, charPtr + GetOffsetUniqueID())));
1536 result.emplace_back(fSubfields[1]->BindValue(std::shared_ptr<void>(ptr, charPtr + GetOffsetBits())));
1537 return result;
1538}
1539
1541{
1542 return sizeof(TObject);
1543}
1544
1546{
1547 return alignof(TObject);
1548}
1549
1551{
1552 visitor.VisitTObjectField(*this);
1553}
1554
1555//------------------------------------------------------------------------------
1556
1557ROOT::RTupleField::RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
1558 : ROOT::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
1559{
1560 const std::string typeAlias = "std::tuple<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1561 if (typeAlias != GetTypeName())
1562 fTypeAlias = typeAlias;
1563
1564 AttachItemFields(std::move(itemFields));
1565
1566 auto *c = TClass::GetClass(GetTypeName().c_str());
1567 if (!c)
1568 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
1569 fSize = c->Size();
1570
1571 // ISO C++ does not guarantee neither specific layout nor member names for `std::tuple`. However, most
1572 // implementations including libstdc++ (gcc), libc++ (llvm), and MSVC name members as `_0`, `_1`, ..., `_N-1`,
1573 // following the order of the type list.
1574 // Use TClass to get their offsets; in case a particular `std::tuple` implementation does not define such
1575 // members, the assertion below will fail.
1576 for (unsigned i = 0; i < fSubfields.size(); ++i) {
1577 std::string memberName("_" + std::to_string(i));
1578 auto member = c->GetRealData(memberName.c_str());
1579 if (!member)
1580 throw RException(R__FAIL(memberName + ": no such member"));
1581 fOffsets.push_back(member->GetThisOffset());
1582 }
1583}
1584
1585std::unique_ptr<ROOT::RFieldBase> ROOT::RTupleField::CloneImpl(std::string_view newName) const
1586{
1587 std::vector<std::unique_ptr<RFieldBase>> itemClones;
1588 itemClones.reserve(fSubfields.size());
1589 for (const auto &f : fSubfields) {
1590 itemClones.emplace_back(f->Clone(f->GetFieldName()));
1591 }
1592 return std::unique_ptr<RTupleField>(new RTupleField(newName, std::move(itemClones)));
1593}
1594
1596{
1597 static const std::vector<std::string> prefixes = {"std::pair<", "std::tuple<"};
1598
1599 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
1600 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
1601
1602 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1603 const auto nOnDiskSubfields = fieldDesc.GetLinkIds().size();
1604 const auto nSubfields = fSubfields.size();
1605 if (nOnDiskSubfields != nSubfields) {
1606 throw ROOT::RException(R__FAIL("invalid number of on-disk subfields for std::tuple " +
1607 std::to_string(nOnDiskSubfields) + " vs. " + std::to_string(nSubfields) + "\n" +
1608 Internal::GetTypeTraceReport(*this, desc)));
1609 }
1610}
1611
1612//------------------------------------------------------------------------------
1613
1614namespace {
1615
1616// Depending on the compiler, the variant tag is stored either in a trailing char or in a trailing unsigned int
1617constexpr std::size_t GetVariantTagSize()
1618{
1619 // Should be all zeros except for the tag, which is 1
1620 std::variant<char> t;
1621 constexpr auto sizeOfT = sizeof(t);
1622
1623 static_assert(sizeOfT == 2 || sizeOfT == 8, "unsupported std::variant layout");
1624 return sizeOfT == 2 ? 1 : 4;
1625}
1626
1627template <std::size_t VariantSizeT>
1628struct RVariantTag {
1629 using ValueType_t = typename std::conditional_t<VariantSizeT == 1, std::uint8_t,
1630 typename std::conditional_t<VariantSizeT == 4, std::uint32_t, void>>;
1631};
1632
1633} // anonymous namespace
1634
1636 : ROOT::RFieldBase(name, source.GetTypeName(), ROOT::ENTupleStructure::kVariant, false /* isSimple */),
1637 fMaxItemSize(source.fMaxItemSize),
1639 fTagOffset(source.fTagOffset),
1641 fNWritten(source.fNWritten.size(), 0)
1642{
1643 for (const auto &f : source.GetConstSubfields())
1644 Attach(f->Clone(f->GetFieldName()));
1645 fTraits = source.fTraits;
1646}
1647
1648ROOT::RVariantField::RVariantField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
1649 : ROOT::RFieldBase(fieldName, "std::variant<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">",
1650 ROOT::ENTupleStructure::kVariant, false /* isSimple */)
1651{
1652 // The variant needs to initialize its own tag member
1654
1655 const std::string typeAlias = "std::variant<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1656 if (typeAlias != GetTypeName())
1657 fTypeAlias = typeAlias;
1658
1659 auto nFields = itemFields.size();
1660 if (nFields == 0 || nFields > kMaxVariants) {
1661 throw RException(R__FAIL("invalid number of variant fields (outside [1.." + std::to_string(kMaxVariants) + ")"));
1662 }
1663 fNWritten.resize(nFields, 0);
1664 for (unsigned int i = 0; i < nFields; ++i) {
1665 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
1666 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
1667 fTraits &= itemFields[i]->GetTraits();
1668 Attach(std::move(itemFields[i]), "_" + std::to_string(i));
1669 }
1670
1671 // With certain template parameters, the union of members of an std::variant starts at an offset > 0.
1672 // For instance, std::variant<std::optional<int>> on macOS.
1673 auto cl = TClass::GetClass(GetTypeName().c_str());
1674 assert(cl);
1675 auto dm = reinterpret_cast<TDataMember *>(cl->GetListOfDataMembers()->First());
1676 if (dm)
1677 fVariantOffset = dm->GetOffset();
1678
1679 const auto tagSize = GetVariantTagSize();
1680 const auto padding = tagSize - (fMaxItemSize % tagSize);
1681 fTagOffset = fVariantOffset + fMaxItemSize + ((padding == tagSize) ? 0 : padding);
1682}
1683
1684std::unique_ptr<ROOT::RFieldBase> ROOT::RVariantField::CloneImpl(std::string_view newName) const
1685{
1686 return std::unique_ptr<RVariantField>(new RVariantField(newName, *this));
1687}
1688
1689std::uint8_t ROOT::RVariantField::GetTag(const void *variantPtr, std::size_t tagOffset)
1690{
1691 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
1692 auto tag = *reinterpret_cast<const TagType_t *>(reinterpret_cast<const unsigned char *>(variantPtr) + tagOffset);
1693 return (tag == TagType_t(-1)) ? 0 : tag + 1;
1694}
1695
1696void ROOT::RVariantField::SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag)
1697{
1698 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
1699 auto tagPtr = reinterpret_cast<TagType_t *>(reinterpret_cast<unsigned char *>(variantPtr) + tagOffset);
1700 *tagPtr = (tag == 0) ? TagType_t(-1) : static_cast<TagType_t>(tag - 1);
1701}
1702
1703std::size_t ROOT::RVariantField::AppendImpl(const void *from)
1704{
1705 auto tag = GetTag(from, fTagOffset);
1706 std::size_t nbytes = 0;
1707 auto index = 0;
1708 if (tag > 0) {
1709 nbytes += CallAppendOn(*fSubfields[tag - 1], reinterpret_cast<const unsigned char *>(from) + fVariantOffset);
1710 index = fNWritten[tag - 1]++;
1711 }
1712 ROOT::Internal::RColumnSwitch varSwitch(index, tag);
1713 fPrincipalColumn->Append(&varSwitch);
1714 return nbytes + sizeof(ROOT::Internal::RColumnSwitch);
1715}
1716
1718{
1719 RNTupleLocalIndex variantIndex;
1720 std::uint32_t tag;
1721 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
1722 R__ASSERT(tag < 256);
1723
1724 // If `tag` equals 0, the variant is in the invalid state, i.e, it does not hold any of the valid alternatives in
1725 // the type list. This happens, e.g., if the field was late added; in this case, keep the invalid tag, which makes
1726 // any `std::holds_alternative<T>` check fail later.
1727 if (R__likely(tag > 0)) {
1728 void *varPtr = reinterpret_cast<unsigned char *>(to) + fVariantOffset;
1729 CallConstructValueOn(*fSubfields[tag - 1], varPtr);
1730 CallReadOn(*fSubfields[tag - 1], variantIndex, varPtr);
1731 }
1732 SetTag(to, fTagOffset, tag);
1733}
1734
1736{
1737 static RColumnRepresentations representations({{ENTupleColumnType::kSwitch}}, {});
1738 return representations;
1739}
1740
1745
1750
1752{
1753 static const std::vector<std::string> prefixes = {"std::variant<"};
1754
1755 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
1756 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
1757
1758 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1759 if (fSubfields.size() != fieldDesc.GetLinkIds().size()) {
1760 throw RException(R__FAIL("number of variants on-disk do not match for " + GetQualifiedFieldName() + "\n" +
1761 Internal::GetTypeTraceReport(*this, desc)));
1762 }
1763}
1764
1766{
1767 memset(where, 0, GetValueSize());
1768 CallConstructValueOn(*fSubfields[0], reinterpret_cast<unsigned char *>(where) + fVariantOffset);
1769 SetTag(where, fTagOffset, 1);
1770}
1771
1773{
1774 auto tag = GetTag(objPtr, fTagOffset);
1775 if (tag > 0) {
1776 fItemDeleters[tag - 1]->operator()(reinterpret_cast<unsigned char *>(objPtr) + fVariantOffset, true /*dtorOnly*/);
1777 }
1778 RDeleter::operator()(objPtr, dtorOnly);
1779}
1780
1781std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVariantField::GetDeleter() const
1782{
1783 std::vector<std::unique_ptr<RDeleter>> itemDeleters;
1784 itemDeleters.reserve(fSubfields.size());
1785 for (const auto &f : fSubfields) {
1786 itemDeleters.emplace_back(GetDeleterOf(*f));
1787 }
1788 return std::make_unique<RVariantDeleter>(fTagOffset, fVariantOffset, std::move(itemDeleters));
1789}
1790
1792{
1793 return std::max(fMaxAlignment, alignof(RVariantTag<GetVariantTagSize()>::ValueType_t));
1794}
1795
1797{
1798 const auto alignment = GetAlignment();
1799 const auto actualSize = fTagOffset + GetVariantTagSize();
1800 const auto padding = alignment - (actualSize % alignment);
1801 return actualSize + ((padding == alignment) ? 0 : padding);
1802}
1803
1805{
1806 std::fill(fNWritten.begin(), fNWritten.end(), 0);
1807}
ROOT::R::TRInterface & r
Definition Object.C:4
#define R__likely(expr)
Definition RConfig.hxx:587
#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:299
#define R__LOG_WARNING(...)
Definition RLogger.hxx:357
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Signed integer 4 bytes (int).
Definition RtypesCore.h:59
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int).
Definition RtypesCore.h:60
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
@ kClassHasExplicitCtor
@ kClassHasImplicitCtor
@ kClassHasVirtual
@ kClassHasExplicitDtor
@ kClassHasImplicitDtor
@ kIsArray
Definition TDictionary.h:79
@ kIsStatic
Definition TDictionary.h:80
@ kIsDefinedInStd
Definition TDictionary.h:98
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
#define N
char name[80]
Definition TGX11.cxx:148
@ kCollection
Definition TStructNode.h:21
TCanvas * alignment()
Definition alignment.C:1
#define _(A, B)
Definition cfortran.h:108
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitProxiedCollectionField(const ROOT::RProxiedCollectionField &field)
virtual void VisitTObjectField(const ROOT::RField< TObject > &field)
virtual void VisitStreamerField(const ROOT::RStreamerField &field)
virtual void VisitEnumField(const ROOT::REnumField &field)
virtual void VisitClassField(const ROOT::RClassField &field)
void operator()(void *objPtr, bool dtorOnly) final
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
std::vector< std::size_t > fSoAMemberOffsets
The offset of the RVec members in the SoA type in the order of subfields of the underlying record typ...
Definition RFieldSoA.hxx:68
const std::type_info * GetPolymorphicTypeInfo() const
For polymorphic classes (that declare or inherit at least one virtual method), return the expected dy...
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
std::vector< RFieldBase * > fRecordMemberFields
Direct access to the member fields of the underlying record.
Definition RFieldSoA.hxx:65
RSoAField(std::string_view fieldName, const RSoAField &source)
Used by CloneImpl.
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
std::uint32_t GetTypeChecksum() const final
Return the current TClass reported checksum of this class. Only valid if kTraitTypeChecksum is set.
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
ROOT::Internal::RColumnIndex fNWritten
Definition RFieldSoA.hxx:70
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Holds the index and the tag of a kSwitch column.
A helper class for piece-wise construction of an RExtraTypeInfoDescriptor.
RResult< RExtraTypeInfoDescriptor > MoveDescriptor()
RExtraTypeInfoDescriptorBuilder & ContentId(EExtraTypeInfoIds contentId)
RExtraTypeInfoDescriptorBuilder & TypeName(const std::string &typeName)
RExtraTypeInfoDescriptorBuilder & Content(const std::string &content)
RExtraTypeInfoDescriptorBuilder & TypeVersion(std::uint32_t typeVersion)
static std::string SerializeStreamerInfos(const StreamerInfoMap_t &infos)
const ROOT::RNTupleDescriptor & GetRef() const
Abstract interface to read data from an ntuple.
void RegisterStreamerInfos()
Builds the streamer info records from the descriptor's extra type info section.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
void operator()(void *objPtr, bool dtorOnly) final
std::unique_ptr< RFieldBase > BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final
Called by ConnectPageSource() before connecting; derived classes may override this as appropriate,...
void AddReadCallbacksFromIORule(const TSchemaRule *rule)
Register post-read callback corresponding to a ROOT I/O customization rules.
TClass * fStagingClass
The TClass instance that corresponds to the staging area.
Definition RField.hxx:176
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
std::size_t fMaxAlignment
Definition RField.hxx:167
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::vector< RSubfieldInfo > fSubfieldsInfo
Definition RField.hxx:166
void Attach(std::unique_ptr< RFieldBase > child, RSubfieldInfo info)
std::unique_ptr< unsigned char[]> fStagingArea
The staging area stores inputs to I/O rules according to the offsets given by the streamer info of "T...
Definition RField.hxx:171
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:223
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
std::vector< const TSchemaRule * > FindRules(const ROOT::RFieldDescriptor *fieldDesc)
Given the on-disk information from the page source, find all the I/O customization rules that apply t...
ROOT::DescriptorId_t LookupMember(const ROOT::RNTupleDescriptor &desc, std::string_view memberName, ROOT::DescriptorId_t classFieldId)
Returns the id of member 'name' in the class field given by 'fieldId', or kInvalidDescriptorId if no ...
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
RClassField(std::string_view fieldName, const RClassField &source)
Used by CloneImpl.
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
void PrepareStagingArea(const std::vector< const TSchemaRule * > &rules, const ROOT::RNTupleDescriptor &desc, const ROOT::RFieldDescriptor &classFieldId)
If there are rules with inputs (source members), create the staging area according to the TClass inst...
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
const std::type_info * GetPolymorphicTypeInfo() const
For polymorphic classes (that declare or inherit at least one virtual method), return the expected dy...
~RClassField() override
std::uint32_t GetTypeChecksum() const final
Return the current TClass reported checksum of this class. Only valid if kTraitTypeChecksum is set.
std::unordered_map< std::string, RStagingItem > fStagingItems
Lookup staging items by member name.
Definition RField.hxx:177
static constexpr const char * kPrefixInherited
Definition RField.hxx:153
void SetStagingClass(const std::string &className, unsigned int classVersion)
Sets fStagingClass according to the given name and version.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
REnumField(std::string_view fieldName, TEnum *enump)
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Field specific extra type information from the header / extenstion header.
The list of column representations a field can have.
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
std::shared_ptr< T > GetPtr() const
A field translates read and write calls from/to underlying columns to/from tree values.
virtual size_t GetValueSize() const =0
The number of bytes taken by a value of the appropriate type.
void Attach(std::unique_ptr< RFieldBase > child, std::string_view expectedChildName="")
Add a new subfield to the list of nested fields.
ROOT::Internal::RColumn * fPrincipalColumn
All fields that have columns have a distinct main column.
std::vector< std::unique_ptr< RFieldBase > > fSubfields
Collections and classes own subfields.
std::vector< const RFieldBase * > GetConstSubfields() const
@ kTraitSoACollection
The field represents a collection in SoA layout.
@ kTraitTypeChecksum
The TClass checksum is set and valid.
static std::unique_ptr< RDeleter > GetDeleterOf(const RFieldBase &other)
static ROOT::Internal::RColumn * GetPrincipalColumnOf(const RFieldBase &other)
Fields may need direct access to the principal column of their subfields, e.g. in RRVecField::ReadBul...
ROOT::Internal::RColumn * fAuxiliaryColumn
Some fields have a second column in its column representation.
RResult< void > EnsureMatchingOnDiskCollection(const RNTupleDescriptor &desc) const
Convenience wrapper for the common case of calling EnsureMatchinOnDiskField() for collections.
static void CallSetArtificialOn(RFieldBase &other)
Allow parents to mark their childs as artificial fields (used in class and record fields).
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots (grandparent.parent....
const std::string & GetFieldName() const
std::vector< ReadCallback_t > fReadCallbacks
List of functions to be called after reading a value.
RResult< void > EnsureMatchingOnDiskField(const RNTupleDescriptor &desc, std::uint32_t ignoreBits=0) const
Compares the field to the corresponding on-disk field information in the provided descriptor.
const std::string & GetTypeAlias() const
static std::size_t CallAppendOn(RFieldBase &other, const void *from)
Allow derived classes to call Append() and Read() on other (sub)fields.
RFieldBase(std::string_view name, std::string_view type, ROOT::ENTupleStructure structure, bool isSimple, std::size_t nRepetitions=0)
The constructor creates the underlying column objects and connects them to either a sink or a source.
friend class RFieldZero
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
Factory method to resurrect a field from the stored on-disk type information.
bool IsSimple() const
std::uint32_t GetTraits() const
const std::string & GetTypeName() const
void GenerateColumnsImpl(const ColumnRepresentation_t &representation, std::uint16_t representationIndex)
Helpers for generating columns.
RValue BindValue(std::shared_ptr< void > objPtr)
Creates a value from a memory location with an already constructed object.
static void CallReadOn(RFieldBase &other, RNTupleLocalIndex localIndex, void *to)
ROOT::DescriptorId_t GetOnDiskId() const
std::unique_ptr< RFieldBase > Clone(std::string_view newName) const
Copies the field and its subfields using a possibly new name and a new, unconnected set of columns.
static void CallConstructValueOn(const RFieldBase &other, void *where)
Allow derived classes to call ConstructValue(void *) and GetDeleter() on other (sub)fields.
RResult< void > EnsureMatchingTypePrefix(const RNTupleDescriptor &desc, const std::vector< std::string > &prefixes) const
Many fields accept a range of type prefixes for schema evolution, e.g.
@ kDiffTypeName
The in-memory field and the on-disk field have different type names.
@ kDiffTypeVersion
The in-memory field and the on-disk field differ in the type version.
Metadata stored for every field of an RNTuple.
ROOT::DescriptorId_t GetId() const
const std::vector< ROOT::DescriptorId_t > & GetLinkIds() const
std::optional< std::uint32_t > GetTypeChecksum() const
std::uint32_t GetTypeVersion() const
const std::string & GetTypeName() const
void ReadTObject(void *to, UInt_t uniqueID, UInt_t bits)
RField(std::string_view fieldName, const RField< TObject > &source)
Used by CloneImpl().
static std::size_t GetOffsetBits()
Definition RField.hxx:519
static std::size_t GetOffsetUniqueID()
Definition RField.hxx:518
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:320
RField(std::string_view name)
Definition RField.hxx:323
RMapField(std::string_view fieldName, EMapType mapType, std::unique_ptr< RFieldBase > itemField)
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
The on-storage metadata of an RNTuple.
RFieldDescriptorIterable GetFieldIterable(const RFieldDescriptor &fieldDesc) const
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
std::string GetTypeNameForComparison(const RFieldDescriptor &fieldDesc) const
Adjust the type name of the passed RFieldDescriptor for comparison with another renormalized type nam...
ROOT::DescriptorId_t FindFieldId(std::string_view fieldName, ROOT::DescriptorId_t parentId) const
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Template specializations for C++ std::pair.
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
RPairField(std::string_view fieldName, std::array< std::unique_ptr< RFieldBase >, 2 > itemFields)
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Allows for iterating over the elements of a proxied collection.
static RIteratorFuncs GetIteratorFuncs(TVirtualCollectionProxy *proxy, bool readFromDisk)
void operator()(void *objPtr, bool dtorOnly) final
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
RProxiedCollectionField(std::string_view fieldName, TClass *classp)
Constructor used when the value type of the collection is not known in advance, i....
RCollectionIterableOnce::RIteratorFuncs fIFuncsWrite
ROOT::Internal::RColumnIndex fNWritten
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
RCollectionIterableOnce::RIteratorFuncs fIFuncsRead
Two sets of functions to operate on iterators, to be used depending on the access type.
std::shared_ptr< TVirtualCollectionProxy > fProxy
The collection proxy is needed by the deleters and thus defined as a shared pointer.
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::unique_ptr< RDeleter > GetDeleter() const final
void ReconcileOnDiskField(const RNTupleDescriptor &desc) override
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Template specializations for ROOT's RVec.
RRecordField(std::string_view name, const RRecordField &source)
Definition RField.cxx:572
void AttachItemFields(ContainerT &&itemFields)
std::vector< std::size_t > fOffsets
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
RSetField(std::string_view fieldName, ESetType setType, std::unique_ptr< RFieldBase > itemField)
void operator()(void *objPtr, bool dtorOnly) final
ROOT::RExtraTypeInfoDescriptor GetExtraTypeInfo() const final
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
ROOT::Internal::RNTupleSerializer::StreamerInfoMap_t fStreamerInfos
streamer info records seen during writing
Definition RField.hxx:247
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
ROOT::Internal::RColumnIndex fIndex
number of bytes written in the current cluster
Definition RField.hxx:248
std::uint32_t GetTypeChecksum() const final
Return the current TClass reported checksum of this class. Only valid if kTraitTypeChecksum is set.
std::unique_ptr< RFieldBase > BeforeConnectPageSource(ROOT::Internal::RPageSource &source) final
Called by ConnectPageSource() before connecting; derived classes may override this as appropriate,...
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
RStreamerField(std::string_view fieldName, TClass *classp)
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
RTupleField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields)
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
std::vector< std::unique_ptr< RDeleter > > fItemDeleters
void operator()(void *objPtr, bool dtorOnly) final
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
static constexpr std::size_t kMaxVariants
std::vector< ROOT::Internal::RColumnIndex::ValueType > fNWritten
static std::uint8_t GetTag(const void *variantPtr, std::size_t tagOffset)
Extracts the index from an std::variant and transforms it into the 1-based index used for the switch ...
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
size_t fVariantOffset
In the std::variant memory layout, the actual union of types may start at an offset > 0.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
std::unique_ptr< RDeleter > GetDeleter() const final
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
size_t fTagOffset
In the std::variant memory layout, at which byte number is the index stored.
RVariantField(std::string_view name, const RVariantField &source)
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag)
void CommitClusterImpl() final
ReadFuncPtr_t GetReadFunctionPointer() const
Get the pointer to the function to be run for the rule (if it is a read rule).
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
char * Buffer() const
Definition TBuffer.h:96
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
UInt_t GetCheckSum(ECheckSum code=kCurrentCheckSum) const
Call GetCheckSum with validity check.
Definition TClass.cxx:6616
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2326
EState GetState() const
Definition TClass.h:504
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2038
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3828
TList * GetListOfRealData() const
Definition TClass.h:468
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5806
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition TClass.cxx:4657
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2918
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6191
@ kInterpreted
Definition TClass.h:129
Version_t GetClassVersion() const
Definition TClass.h:434
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:2994
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
The TEnum class implements the enum type.
Definition TEnum.h:33
EDataType GetUnderlyingType() const
Get the underlying integer type of the enum: enum E { kOne }; // ==> int enum F: long; // ==> long Re...
Definition TEnum.h:81
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Definition TEnum.cxx:141
static TEnum * GetEnum(const std::type_info &ti, ESearchAction sa=kALoadAndInterpLookup)
Definition TEnum.cxx:181
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Mother of all ROOT objects.
Definition TObject.h:42
@ kIsOnHeap
object is on heap
Definition TObject.h:90
@ kNotDeleted
object has not been deleted
Definition TObject.h:91
static TClass * Class()
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition TObject.h:74
RAII helper class that ensures that PushProxy() / PopProxy() are called when entering / leaving a C++...
Defines a common interface to inspect/change the contents of an object that represents a collection.
@ kNeedDelete
The collection contains directly or indirectly (via other collection) some pointers that need explici...
virtual Next_t GetFunctionNext(Bool_t read=kTRUE)=0
Return a pointer to a function that can advance an iterator (see Next_t).
virtual DeleteTwoIterators_t GetFunctionDeleteTwoIterators(Bool_t read=kTRUE)=0
virtual TVirtualCollectionProxy * Generate() const =0
Returns a clean object of the actual class that derives from TVirtualCollectionProxy.
virtual CreateIterators_t GetFunctionCreateIterators(Bool_t read=kTRUE)=0
Return a pointer to a function that can create an iterator pair, where each iterator points to the be...
Abstract Interface class describing Streamer information for one class.
virtual Int_t GetNumber() const =0
const Int_t n
Definition legend1.C:16
for(Int_t i=0;i< n;i++)
Definition legend1.C:18
TRangeCast< T, false > TRangeStaticCast
TRangeStaticCast is an adapter class that allows the typed iteration through a TCollection.
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:35
std::tuple< unsigned char **, std::int32_t *, std::int32_t * > GetRVecDataMembers(void *rvecPtr)
Retrieve the addresses of the data members of a generic RVec from a pointer to the beginning of the R...
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
if(pos!=-1) leafTypeName.Remove(pos)
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
std::string GetRNTupleSoARecord(const TClass *cl)
Checks if the "rntuple.SoARecord" class attribute is set in the dictionary.
bool NeedsMetaNameAsAlias(const std::string &metaNormalizedName, std::string &renormalizedAlias, bool isArgInTemplatedUserClass=false)
Checks if the meta normalized name is different from the RNTuple normalized name in a way that would ...
std::string GetTypeTraceReport(const RFieldBase &field, const RNTupleDescriptor &desc)
Prints the hierarchy of types with their field names and field IDs for the given in-memory field and ...
ERNTupleSerializationMode GetRNTupleSerializationMode(const TClass *cl)
std::string GetRenormalizedTypeName(const std::string &metaNormalizedName)
Given a type name normalized by ROOT meta, renormalize it for RNTuple. E.g., insert std::prefix.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
@ kSTLvector
Definition ESTLType.h:30
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
constexpr DescriptorId_t kInvalidDescriptorId
ENTupleStructure
The fields in the RNTuple data model tree can carry different structural information about the type s...
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.
std::size_t fOffset
offset in fStagingArea
Definition RField.hxx:150
std::unique_ptr< RFieldBase > fField
The field used to read the on-disk data.
Definition RField.hxx:149