Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldMeta.cxx
Go to the documentation of this file.
1/// \file RFieldMeta.cxx
2/// \ingroup NTuple
3/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
4/// \date 2024-11-19
5
6// This file has concrete RField implementations that depend on ROOT Meta:
7// - RClassField
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/RSpan.hxx>
22
23#include <TBaseClass.h>
24#include <TBufferFile.h>
25#include <TClass.h>
26#include <TClassEdit.h>
27#include <TDataMember.h>
28#include <TEnum.h>
29#include <TObject.h>
30#include <TObjArray.h>
31#include <TObjString.h>
32#include <TRealData.h>
33#include <TSchemaRule.h>
34#include <TSchemaRuleSet.h>
35#include <TStreamerElement.h>
36#include <TVirtualObject.h>
38
39#include <algorithm>
40#include <array>
41#include <cstddef> // std::size_t
42#include <cstdint> // std::uint32_t et al.
43#include <cstring> // for memset
44#include <memory>
45#include <string>
46#include <string_view>
47#include <unordered_set>
48#include <utility>
49#include <variant>
50
52
53namespace {
54
55TClass *EnsureValidClass(std::string_view className)
56{
57 auto cl = TClass::GetClass(std::string(className).c_str());
58 if (cl == nullptr) {
59 throw ROOT::RException(R__FAIL("RField: no I/O support for type " + std::string(className)));
60 }
61 return cl;
62}
63
64TEnum *EnsureValidEnum(std::string_view enumName)
65{
66 auto e = TEnum::GetEnum(std::string(enumName).c_str());
67 if (e == nullptr) {
68 throw ROOT::RException(R__FAIL("RField: no I/O support for enum type " + std::string(enumName)));
69 }
70 return e;
71}
72
73} // anonymous namespace
74
76 : ROOT::RFieldBase(fieldName, source.GetTypeName(), ROOT::ENTupleStructure::kRecord, false /* isSimple */),
78 fSubfieldsInfo(source.fSubfieldsInfo),
79 fMaxAlignment(source.fMaxAlignment)
80{
81 for (const auto &f : source.GetConstSubfields()) {
82 RFieldBase::Attach(f->Clone(f->GetFieldName()));
83 }
84 fTraits = source.GetTraits();
85}
86
87ROOT::RClassField::RClassField(std::string_view fieldName, std::string_view className)
89{
90}
91
93 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kRecord,
94 false /* isSimple */),
96{
98 throw RException(R__FAIL(std::string("RField: RClassField \"") + classp->GetName() +
99 " cannot be constructed from a class that's not at least Interpreted"));
100 }
101 // Avoid accidentally supporting std types through TClass.
103 throw RException(R__FAIL(std::string(GetTypeName()) + " is not supported"));
104 }
105 if (GetTypeName() == "TObject") {
106 throw RException(R__FAIL("TObject is only supported through RField<TObject>"));
107 }
108 if (fClass->GetCollectionProxy()) {
109 throw RException(R__FAIL(std::string(GetTypeName()) + " has an associated collection proxy; "
110 "use RProxiedCollectionField instead"));
111 }
112 // Classes with, e.g., custom streamers are not supported through this field. Empty classes, however, are.
113 // Can be overwritten with the "rntuple.streamerMode=true" class attribute
114 if (!fClass->CanSplit() && fClass->Size() > 1 &&
117 throw RException(R__FAIL(GetTypeName() + " cannot be stored natively in RNTuple"));
118 }
121 throw RException(R__FAIL(GetTypeName() + " has streamer mode enforced, not supported as native RNTuple class"));
122 }
123
128
129 int i = 0;
130 const auto *bases = fClass->GetListOfBases();
131 assert(bases);
133 if (baseClass->GetDelta() < 0) {
134 throw RException(R__FAIL(std::string("virtual inheritance is not supported: ") + GetTypeName() +
135 " virtually inherits from " + baseClass->GetName()));
136 }
137 TClass *c = baseClass->GetClassPointer();
138 auto subField =
139 RFieldBase::Create(std::string(kPrefixInherited) + "_" + std::to_string(i), c->GetName()).Unwrap();
140 fTraits &= subField->GetTraits();
141 Attach(std::move(subField), RSubFieldInfo{kBaseClass, static_cast<std::size_t>(baseClass->GetDelta())});
142 i++;
143 }
145 // Skip, for instance, unscoped enum constants defined in the class
146 if (dataMember->Property() & kIsStatic)
147 continue;
148 // Skip members explicitly marked as transient by user comment
149 if (!dataMember->IsPersistent()) {
150 // TODO(jblomer): we could do better
152 continue;
153 }
154
155 // NOTE: we use the already-resolved type name for the fields, otherwise TClass::GetClass may fail to resolve
156 // context-dependent types (e.g. typedefs defined in the class itself - which will not be fully qualified in
157 // the string returned by dataMember->GetFullTypeName())
158 std::string typeName{dataMember->GetTrueTypeName()};
159 // RFieldBase::Create() set subField->fTypeAlias based on the assumption that the user specified typeName, which
160 // already went through one round of type resolution.
161 std::string origTypeName{dataMember->GetFullTypeName()};
162
163 // For C-style arrays, complete the type name with the size for each dimension, e.g. `int[4][2]`
164 if (dataMember->Property() & kIsArray) {
165 for (int dim = 0, n = dataMember->GetArrayDim(); dim < n; ++dim) {
166 const auto addedStr = "[" + std::to_string(dataMember->GetMaxIndex(dim)) + "]";
167 typeName += addedStr;
169 }
170 }
171
172 auto subField = RFieldBase::Create(dataMember->GetName(), typeName).Unwrap();
173
175 if (normTypeName == subField->GetTypeName()) {
176 subField->fTypeAlias = "";
177 } else {
178 subField->fTypeAlias = normTypeName;
179 }
180
181 fTraits &= subField->GetTraits();
182 Attach(std::move(subField), RSubFieldInfo{kDataMember, static_cast<std::size_t>(dataMember->GetOffset())});
183 }
185}
186
188{
189 if (fStagingArea) {
190 for (const auto &[_, si] : fStagingItems) {
191 if (!(si.fField->GetTraits() & kTraitTriviallyDestructible)) {
192 auto deleter = si.fField->GetDeleter();
193 deleter->operator()(fStagingArea.get() + si.fOffset, true /* dtorOnly */);
194 }
195 }
196 }
197}
198
199void ROOT::RClassField::Attach(std::unique_ptr<RFieldBase> child, RSubFieldInfo info)
200{
201 fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
202 fSubfieldsInfo.push_back(info);
203 RFieldBase::Attach(std::move(child));
204}
205
206std::vector<const ROOT::TSchemaRule *> ROOT::RClassField::FindRules(const ROOT::RFieldDescriptor *fieldDesc)
207{
209 const auto ruleset = fClass->GetSchemaRules();
210 if (!ruleset)
211 return rules;
212
213 if (!fieldDesc) {
214 // If we have no on-disk information for the field, we still process the rules on the current in-memory version
215 // of the class
216 rules = ruleset->FindRules(fClass->GetName(), fClass->GetClassVersion(), fClass->GetCheckSum());
217 } else {
218 // We need to change (back) the name normalization from RNTuple to ROOT Meta
219 std::string normalizedName;
221 // We do have an on-disk field that correspond to the current RClassField instance. Ask for rules matching the
222 // on-disk version of the field.
223 if (fieldDesc->GetTypeChecksum()) {
224 rules = ruleset->FindRules(normalizedName, fieldDesc->GetTypeVersion(), *fieldDesc->GetTypeChecksum());
225 } else {
226 rules = ruleset->FindRules(normalizedName, fieldDesc->GetTypeVersion());
227 }
228 }
229
230 // Cleanup and sort rules
231 // Check that any any given source member uses the same type in all rules
232 std::unordered_map<std::string, std::string> sourceNameAndType;
233 std::size_t nskip = 0; // skip whole-object-rules that were moved to the end of the rules vector
234 for (auto itr = rules.begin(); itr != rules.end() - nskip;) {
235 const auto rule = *itr;
236
237 // Erase unknown rule types
238 if (rule->GetRuleType() != ROOT::TSchemaRule::kReadRule) {
240 << "ignoring I/O customization rule with unsupported type: " << rule->GetRuleType();
241 itr = rules.erase(itr);
242 continue;
243 }
244
245 bool hasConflictingSourceMembers = false;
246 for (auto source : TRangeDynCast<TSchemaRule::TSources>(rule->GetSource())) {
247 auto memberType = source->GetTypeForDeclaration() + source->GetDimensions();
248 auto [itrSrc, isNew] = sourceNameAndType.emplace(source->GetName(), memberType);
249 if (!isNew && (itrSrc->second != memberType)) {
251 << "ignoring I/O customization rule due to conflicting source member type: " << itrSrc->second << " vs. "
252 << memberType << " for member " << source->GetName();
254 break;
255 }
256 }
258 itr = rules.erase(itr);
259 continue;
260 }
261
262 // Rules targeting the entire object need to be executed at the end
263 if (rule->GetTarget() == nullptr) {
264 nskip++;
265 if (itr != rules.end() - nskip)
266 std::iter_swap(itr++, rules.end() - nskip);
267 continue;
268 }
269
270 ++itr;
271 }
272
273 return rules;
274}
275
276std::unique_ptr<ROOT::RFieldBase> ROOT::RClassField::CloneImpl(std::string_view newName) const
277{
278 return std::unique_ptr<RClassField>(new RClassField(newName, *this));
279}
280
281std::size_t ROOT::RClassField::AppendImpl(const void *from)
282{
283 std::size_t nbytes = 0;
284 for (unsigned i = 0; i < fSubfields.size(); i++) {
285 nbytes += CallAppendOn(*fSubfields[i], static_cast<const unsigned char *>(from) + fSubfieldsInfo[i].fOffset);
286 }
287 return nbytes;
288}
289
291{
292 for (const auto &[_, si] : fStagingItems) {
293 CallReadOn(*si.fField, globalIndex, fStagingArea.get() + si.fOffset);
294 }
295 for (unsigned i = 0; i < fSubfields.size(); i++) {
296 CallReadOn(*fSubfields[i], globalIndex, static_cast<unsigned char *>(to) + fSubfieldsInfo[i].fOffset);
297 }
298}
299
301{
302 for (const auto &[_, si] : fStagingItems) {
303 CallReadOn(*si.fField, localIndex, fStagingArea.get() + si.fOffset);
304 }
305 for (unsigned i = 0; i < fSubfields.size(); i++) {
306 CallReadOn(*fSubfields[i], localIndex, static_cast<unsigned char *>(to) + fSubfieldsInfo[i].fOffset);
307 }
308}
309
312{
315 return idSourceMember;
316
317 for (const auto &subFieldDesc : desc.GetFieldIterable(classFieldId)) {
318 const auto subFieldName = subFieldDesc.GetFieldName();
319 if (subFieldName.length() > 2 && subFieldName[0] == ':' && subFieldName[1] == '_') {
320 idSourceMember = LookupMember(desc, memberName, subFieldDesc.GetId());
322 return idSourceMember;
323 }
324 }
325
327}
328
329void ROOT::RClassField::SetStagingClass(const std::string &className, unsigned int classVersion)
330{
331 TClass::GetClass(className.c_str())->GetStreamerInfo(classVersion);
332 if (classVersion != GetTypeVersion()) {
333 fStagingClass = TClass::GetClass((className + std::string("@@") + std::to_string(classVersion)).c_str());
334 if (!fStagingClass) {
335 // For a rename rule, we may simply ask for the old class name
336 fStagingClass = TClass::GetClass(className.c_str());
337 }
338 } else {
339 fStagingClass = fClass;
340 }
341 R__ASSERT(fStagingClass);
342 R__ASSERT(static_cast<unsigned int>(fStagingClass->GetClassVersion()) == classVersion);
343}
344
345void ROOT::RClassField::PrepareStagingArea(const std::vector<const TSchemaRule *> &rules,
346 const ROOT::RNTupleDescriptor &desc,
348{
349 std::size_t stagingAreaSize = 0;
350 for (const auto rule : rules) {
351 for (auto source : TRangeDynCast<TSchemaRule::TSources>(rule->GetSource())) {
352 auto [itr, isNew] = fStagingItems.emplace(source->GetName(), RStagingItem());
353 if (!isNew) {
354 // This source member has already been processed by another rule (and we only support one type per member)
355 continue;
356 }
357 RStagingItem &stagingItem = itr->second;
358
359 const auto memberFieldId = LookupMember(desc, source->GetName(), classFieldDesc.GetId());
361 throw RException(R__FAIL(std::string("cannot find on disk rule source member ") + GetTypeName() + "." +
362 source->GetName()));
363 }
365
366 auto memberType = source->GetTypeForDeclaration() + source->GetDimensions();
367 stagingItem.fField = Create("" /* we don't need a field name */, std::string(memberType)).Unwrap();
368 stagingItem.fField->SetOnDiskId(memberFieldDesc.GetId());
369
370 stagingItem.fOffset = fStagingClass->GetDataMemberOffset(source->GetName());
371 // Since we successfully looked up the source member in the RNTuple on-disk metadata, we expect it
372 // to be present in the TClass instance, too.
374 stagingAreaSize = std::max(stagingAreaSize, stagingItem.fOffset + stagingItem.fField->GetValueSize());
375 }
376 }
377
378 if (stagingAreaSize) {
379 R__ASSERT(static_cast<Int_t>(stagingAreaSize) <= fStagingClass->Size()); // we may have removed rules
380 // We use std::make_unique instead of MakeUninitArray to zero-initialize the staging area.
381 fStagingArea = std::make_unique<unsigned char[]>(stagingAreaSize);
382
383 for (const auto &[_, si] : fStagingItems) {
384 if (!(si.fField->GetTraits() & kTraitTriviallyConstructible)) {
385 CallConstructValueOn(*si.fField, fStagingArea.get() + si.fOffset);
386 }
387 }
388 }
389}
390
392{
393 auto func = rule->GetReadFunctionPointer();
394 if (func == nullptr) {
395 // Can happen for rename rules
396 return;
397 }
398 fReadCallbacks.emplace_back([func, stagingClass = fStagingClass, stagingArea = fStagingArea.get()](void *target) {
399 TVirtualObject onfileObj{nullptr};
400 onfileObj.fClass = stagingClass;
401 onfileObj.fObject = stagingArea;
402 func(static_cast<char *>(target), &onfileObj);
403 onfileObj.fObject = nullptr; // TVirtualObject does not own the value
404 });
405}
406
408{
409 std::vector<const TSchemaRule *> rules;
410 // On-disk members that are not targeted by an I/O rule; all other sub fields of the in-memory class
411 // will be marked as artificial (added member in a new class version or member set by rule).
412 std::unordered_set<std::string> regularSubfields;
413
414 if (GetOnDiskId() == kInvalidDescriptorId) {
415 // This can happen for added base classes or added members of class type
416 rules = FindRules(nullptr);
417 if (!rules.empty())
418 SetStagingClass(GetTypeName(), GetTypeVersion());
419 } else {
420 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
421 const ROOT::RNTupleDescriptor &desc = descriptorGuard.GetRef();
422 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
423
424 for (auto linkId : fieldDesc.GetLinkIds()) {
425 const auto &subFieldDesc = desc.GetFieldDescriptor(linkId);
426 regularSubfields.insert(subFieldDesc.GetFieldName());
427 }
428
429 rules = FindRules(&fieldDesc);
430
431 // If the field's type name is not the on-disk name but we found a rule, we know it is valid to read
432 // on-disk data because we found the rule according to the on-disk (source) type name and version/checksum.
433 if ((GetTypeName() != fieldDesc.GetTypeName()) && rules.empty()) {
434 throw RException(R__FAIL("incompatible type name for field " + GetFieldName() + ": " + GetTypeName() +
435 " vs. " + fieldDesc.GetTypeName()));
436 }
437
438 if (!rules.empty()) {
439 SetStagingClass(fieldDesc.GetTypeName(), fieldDesc.GetTypeVersion());
440 PrepareStagingArea(rules, desc, fieldDesc);
441 for (auto &[_, si] : fStagingItems)
443
444 // Remove target member of read rules from the list of regular members of the underlying on-disk field
445 for (const auto rule : rules) {
446 if (!rule->GetTarget())
447 continue;
448
449 for (const auto target : ROOT::Detail::TRangeStaticCast<const TObjString>(*rule->GetTarget())) {
450 regularSubfields.erase(std::string(target->GetString()));
451 }
452 }
453 }
454 }
455
456 for (const auto rule : rules) {
457 AddReadCallbacksFromIORule(rule);
458 }
459
460 // Iterate over all sub fields in memory and mark those as missing that are not in the descriptor.
461 for (auto &field : fSubfields) {
462 if (regularSubfields.count(field->GetFieldName()) == 0) {
463 field->SetArtificial();
464 }
465 }
466}
467
469{
470 fClass->New(where);
471}
472
474{
475 fClass->Destructor(objPtr, true /* dtorOnly */);
476 RDeleter::operator()(objPtr, dtorOnly);
477}
478
479std::vector<ROOT::RFieldBase::RValue> ROOT::RClassField::SplitValue(const RValue &value) const
480{
481 std::vector<RValue> result;
482 auto basePtr = value.GetPtr<unsigned char>().get();
483 result.reserve(fSubfields.size());
484 for (unsigned i = 0; i < fSubfields.size(); i++) {
485 result.emplace_back(
486 fSubfields[i]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + fSubfieldsInfo[i].fOffset)));
487 }
488 return result;
489}
490
492{
493 return fClass->GetClassSize();
494}
495
497{
498 return fClass->GetClassVersion();
499}
500
502{
503 return fClass->GetCheckSum();
504}
505
507{
508 visitor.VisitClassField(*this);
509}
510
511//------------------------------------------------------------------------------
512
513ROOT::REnumField::REnumField(std::string_view fieldName, std::string_view enumName)
515{
516}
517
519 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(enump->GetQualifiedName()), ROOT::ENTupleStructure::kLeaf,
520 false /* isSimple */)
521{
522 // Avoid accidentally supporting std types through TEnum.
523 if (enump->Property() & kIsDefinedInStd) {
524 throw RException(R__FAIL(GetTypeName() + " is not supported"));
525 }
526
527 switch (enump->GetUnderlyingType()) {
528 case kChar_t: Attach(std::make_unique<RField<int8_t>>("_0")); break;
529 case kUChar_t: Attach(std::make_unique<RField<uint8_t>>("_0")); break;
530 case kShort_t: Attach(std::make_unique<RField<int16_t>>("_0")); break;
531 case kUShort_t: Attach(std::make_unique<RField<uint16_t>>("_0")); break;
532 case kInt_t: Attach(std::make_unique<RField<int32_t>>("_0")); break;
533 case kUInt_t: Attach(std::make_unique<RField<uint32_t>>("_0")); break;
534 case kLong_t:
535 case kLong64_t: Attach(std::make_unique<RField<int64_t>>("_0")); break;
536 case kULong_t:
537 case kULong64_t: Attach(std::make_unique<RField<uint64_t>>("_0")); break;
538 default: throw RException(R__FAIL("Unsupported underlying integral type for enum type " + GetTypeName()));
539 }
540
542}
543
544ROOT::REnumField::REnumField(std::string_view fieldName, std::string_view enumName,
545 std::unique_ptr<RFieldBase> intField)
547{
548 Attach(std::move(intField));
550}
551
552std::unique_ptr<ROOT::RFieldBase> ROOT::REnumField::CloneImpl(std::string_view newName) const
553{
554 auto newIntField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
555 return std::unique_ptr<REnumField>(new REnumField(newName, GetTypeName(), std::move(newIntField)));
556}
557
558std::vector<ROOT::RFieldBase::RValue> ROOT::REnumField::SplitValue(const RValue &value) const
559{
560 std::vector<RValue> result;
561 result.emplace_back(fSubfields[0]->BindValue(value.GetPtr<void>()));
562 return result;
563}
564
566{
567 visitor.VisitEnumField(*this);
568}
569
570//------------------------------------------------------------------------------
571
572std::string ROOT::RPairField::RPairField::GetTypeList(const std::array<std::unique_ptr<RFieldBase>, 2> &itemFields)
573{
574 return itemFields[0]->GetTypeName() + "," + itemFields[1]->GetTypeName();
575}
576
577ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields,
578 const std::array<std::size_t, 2> &offsets)
579 : ROOT::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields) + ">")
580{
581 AttachItemFields(std::move(itemFields));
582 fOffsets.push_back(offsets[0]);
583 fOffsets.push_back(offsets[1]);
584}
585
586ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields)
587 : ROOT::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields) + ">")
588{
589 AttachItemFields(std::move(itemFields));
590
591 // ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
592 auto *c = TClass::GetClass(GetTypeName().c_str());
593 if (!c)
594 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
595 fSize = c->Size();
596
597 auto firstElem = c->GetRealData("first");
598 if (!firstElem)
599 throw RException(R__FAIL("first: no such member"));
600 fOffsets.push_back(firstElem->GetThisOffset());
601
602 auto secondElem = c->GetRealData("second");
603 if (!secondElem)
604 throw RException(R__FAIL("second: no such member"));
605 fOffsets.push_back(secondElem->GetThisOffset());
606}
607
608//------------------------------------------------------------------------------
609
612 bool readFromDisk)
613{
615 ifuncs.fCreateIterators = proxy->GetFunctionCreateIterators(readFromDisk);
616 ifuncs.fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(readFromDisk);
617 ifuncs.fNext = proxy->GetFunctionNext(readFromDisk);
618 R__ASSERT((ifuncs.fCreateIterators != nullptr) && (ifuncs.fDeleteTwoIterators != nullptr) &&
619 (ifuncs.fNext != nullptr));
620 return ifuncs;
621}
622
624 : RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kCollection,
625 false /* isSimple */),
626 fNWritten(0)
627{
628 if (!classp->GetCollectionProxy())
629 throw RException(R__FAIL(std::string(GetTypeName()) + " has no associated collection proxy"));
630
631 fProxy.reset(classp->GetCollectionProxy()->Generate());
632 fProperties = fProxy->GetProperties();
633 fCollectionType = fProxy->GetCollectionType();
634 if (fProxy->HasPointers())
635 throw RException(R__FAIL("collection proxies whose value type is a pointer are not supported"));
636 if (!fProxy->GetCollectionClass()->HasDictionary()) {
637 throw RException(R__FAIL("dictionary not available for type " +
638 GetRenormalizedTypeName(fProxy->GetCollectionClass()->GetName())));
639 }
640
641 fIFuncsRead = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), true /* readFromDisk */);
642 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readFromDisk */);
643}
644
645ROOT::RProxiedCollectionField::RProxiedCollectionField(std::string_view fieldName, std::string_view typeName,
646 std::unique_ptr<RFieldBase> itemField)
648{
649 fItemSize = itemField->GetValueSize();
650 Attach(std::move(itemField));
651}
652
653ROOT::RProxiedCollectionField::RProxiedCollectionField(std::string_view fieldName, std::string_view typeName)
655{
656 // NOTE (fdegeus): std::map is supported, custom associative might be supported in the future if the need arises.
658 throw RException(R__FAIL("custom associative collection proxies not supported"));
659
660 std::unique_ptr<ROOT::RFieldBase> itemField;
661
662 if (auto valueClass = fProxy->GetValueClass()) {
663 // Element type is a class
664 itemField = RFieldBase::Create("_0", valueClass->GetName()).Unwrap();
665 } else {
666 switch (fProxy->GetType()) {
667 case EDataType::kChar_t: itemField = std::make_unique<RField<char>>("_0"); break;
668 case EDataType::kUChar_t: itemField = std::make_unique<RField<std::uint8_t>>("_0"); break;
669 case EDataType::kShort_t: itemField = std::make_unique<RField<std::int16_t>>("_0"); break;
670 case EDataType::kUShort_t: itemField = std::make_unique<RField<std::uint16_t>>("_0"); break;
671 case EDataType::kInt_t: itemField = std::make_unique<RField<std::int32_t>>("_0"); break;
672 case EDataType::kUInt_t: itemField = std::make_unique<RField<std::uint32_t>>("_0"); break;
674 case EDataType::kLong64_t: itemField = std::make_unique<RField<std::int64_t>>("_0"); break;
676 case EDataType::kULong64_t: itemField = std::make_unique<RField<std::uint64_t>>("_0"); break;
677 case EDataType::kFloat_t: itemField = std::make_unique<RField<float>>("_0"); break;
678 case EDataType::kDouble_t: itemField = std::make_unique<RField<double>>("_0"); break;
679 case EDataType::kBool_t: itemField = std::make_unique<RField<bool>>("_0"); break;
680 default: throw RException(R__FAIL("unsupported value type"));
681 }
682 }
683
684 fItemSize = itemField->GetValueSize();
685 Attach(std::move(itemField));
686}
687
688std::unique_ptr<ROOT::RFieldBase> ROOT::RProxiedCollectionField::CloneImpl(std::string_view newName) const
689{
690 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
691 return std::unique_ptr<RProxiedCollectionField>(
692 new RProxiedCollectionField(newName, GetTypeName(), std::move(newItemField)));
693}
694
695std::size_t ROOT::RProxiedCollectionField::AppendImpl(const void *from)
696{
697 std::size_t nbytes = 0;
698 unsigned count = 0;
699 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), const_cast<void *>(from));
700 for (auto ptr : RCollectionIterableOnce{const_cast<void *>(from), fIFuncsWrite, fProxy.get(),
701 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
702 nbytes += CallAppendOn(*fSubfields[0], ptr);
703 count++;
704 }
705
706 fNWritten += count;
707 fPrincipalColumn->Append(&fNWritten);
708 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
709}
710
712{
715 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
716
717 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), to);
718 void *obj =
719 fProxy->Allocate(static_cast<std::uint32_t>(nItems), (fProperties & TVirtualCollectionProxy::kNeedDelete));
720
721 unsigned i = 0;
722 for (auto elementPtr : RCollectionIterableOnce{obj, fIFuncsRead, fProxy.get(),
723 (fCollectionType == kSTLvector || obj != to ? fItemSize : 0U)}) {
724 CallReadOn(*fSubfields[0], collectionStart + (i++), elementPtr);
725 }
726 if (obj != to)
727 fProxy->Commit(obj);
728}
729
739
744
749
751{
752 fProxy->New(where);
753}
754
755std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RProxiedCollectionField::GetDeleter() const
756{
757 if (fProperties & TVirtualCollectionProxy::kNeedDelete) {
758 std::size_t itemSize = fCollectionType == kSTLvector ? fItemSize : 0U;
759 return std::make_unique<RProxiedCollectionDeleter>(fProxy, GetDeleterOf(*fSubfields[0]), itemSize);
760 }
761 return std::make_unique<RProxiedCollectionDeleter>(fProxy);
762}
763
765{
766 if (fItemDeleter) {
768 for (auto ptr : RCollectionIterableOnce{objPtr, fIFuncsWrite, fProxy.get(), fItemSize}) {
769 fItemDeleter->operator()(ptr, true /* dtorOnly */);
770 }
771 }
772 fProxy->Destructor(objPtr, true /* dtorOnly */);
773 RDeleter::operator()(objPtr, dtorOnly);
774}
775
776std::vector<ROOT::RFieldBase::RValue> ROOT::RProxiedCollectionField::SplitValue(const RValue &value) const
777{
778 std::vector<RValue> result;
779 auto valueRawPtr = value.GetPtr<void>().get();
781 for (auto ptr : RCollectionIterableOnce{valueRawPtr, fIFuncsWrite, fProxy.get(),
782 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
783 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), ptr)));
784 }
785 return result;
786}
787
789{
790 visitor.VisitProxiedCollectionField(*this);
791}
792
793//------------------------------------------------------------------------------
794
795ROOT::RMapField::RMapField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField)
797{
798 if (!dynamic_cast<RPairField *>(itemField.get()))
799 throw RException(R__FAIL("RMapField inner field type must be of RPairField"));
800
801 auto *itemClass = fProxy->GetValueClass();
802 fItemSize = itemClass->GetClassSize();
803
804 Attach(std::move(itemField));
805}
806
807//------------------------------------------------------------------------------
808
809ROOT::RSetField::RSetField(std::string_view fieldName, std::string_view typeName, std::unique_ptr<RFieldBase> itemField)
811{
812}
813
814//------------------------------------------------------------------------------
815
816namespace {
817
818/// Used in RStreamerField::AppendImpl() in order to record the encountered streamer info records
819class TBufferRecStreamer : public TBufferFile {
820public:
821 using RCallbackStreamerInfo = std::function<void(TVirtualStreamerInfo *)>;
822
823private:
824 RCallbackStreamerInfo fCallbackStreamerInfo;
825
826public:
827 TBufferRecStreamer(TBuffer::EMode mode, Int_t bufsiz, RCallbackStreamerInfo callbackStreamerInfo)
828 : TBufferFile(mode, bufsiz), fCallbackStreamerInfo(callbackStreamerInfo)
829 {
830 }
831 void TagStreamerInfo(TVirtualStreamerInfo *info) final { fCallbackStreamerInfo(info); }
832};
833
834} // anonymous namespace
835
836ROOT::RStreamerField::RStreamerField(std::string_view fieldName, std::string_view className, std::string_view typeAlias)
838{
840}
841
843 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kStreamer,
844 false /* isSimple */),
845 fClass(classp),
846 fIndex(0)
847{
849 // For RClassField, we only check for explicit constructors and destructors and then recursively combine traits from
850 // all member subfields. For RStreamerField, we treat the class as a black box and additionally need to check for
851 // implicit constructors and destructors.
856}
857
862
863std::unique_ptr<ROOT::RFieldBase> ROOT::RStreamerField::CloneImpl(std::string_view newName) const
864{
865 return std::unique_ptr<RStreamerField>(new RStreamerField(newName, GetTypeName(), GetTypeAlias()));
866}
867
868std::size_t ROOT::RStreamerField::AppendImpl(const void *from)
869{
870 TBufferRecStreamer buffer(TBuffer::kWrite, GetValueSize(),
871 [this](TVirtualStreamerInfo *info) { fStreamerInfos[info->GetNumber()] = info; });
872 fClass->Streamer(const_cast<void *>(from), buffer);
873
874 auto nbytes = buffer.Length();
875 fAuxiliaryColumn->AppendV(buffer.Buffer(), buffer.Length());
876 fIndex += nbytes;
877 fPrincipalColumn->Append(&fIndex);
878 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
879}
880
882{
885 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nbytes);
886
888 fAuxiliaryColumn->ReadV(collectionStart, nbytes, buffer.Buffer());
889 fClass->Streamer(to, buffer);
890}
891
901
906
911
913{
914 fClass->New(where);
915}
916
918{
919 fClass->Destructor(objPtr, true /* dtorOnly */);
920 RDeleter::operator()(objPtr, dtorOnly);
921}
922
932
934{
935 return std::min(alignof(std::max_align_t), GetValueSize()); // TODO(jblomer): fix me
936}
937
939{
940 return fClass->GetClassSize();
941}
942
944{
945 return fClass->GetClassVersion();
946}
947
949{
950 return fClass->GetCheckSum();
951}
952
954{
955 visitor.VisitStreamerField(*this);
956}
957
958//------------------------------------------------------------------------------
959
961{
962 if (auto dataMember = TObject::Class()->GetDataMember(name)) {
963 return dataMember->GetOffset();
964 }
965 throw RException(R__FAIL('\'' + std::string(name) + '\'' + " is an invalid data member"));
966}
967
969 : ROOT::RFieldBase(fieldName, "TObject", ROOT::ENTupleStructure::kRecord, false /* isSimple */)
970{
972 Attach(source.GetConstSubfields()[0]->Clone("fUniqueID"));
973 Attach(source.GetConstSubfields()[1]->Clone("fBits"));
974}
975
977 : ROOT::RFieldBase(fieldName, "TObject", ROOT::ENTupleStructure::kRecord, false /* isSimple */)
978{
979 assert(TObject::Class()->GetClassVersion() == 1);
980
982 Attach(std::make_unique<RField<UInt_t>>("fUniqueID"));
983 Attach(std::make_unique<RField<UInt_t>>("fBits"));
984}
985
986std::unique_ptr<ROOT::RFieldBase> ROOT::RField<TObject>::CloneImpl(std::string_view newName) const
987{
988 return std::unique_ptr<RField<TObject>>(new RField<TObject>(newName, *this));
989}
990
991std::size_t ROOT::RField<TObject>::AppendImpl(const void *from)
992{
993 // Cf. TObject::Streamer()
994
995 auto *obj = static_cast<const TObject *>(from);
996 if (obj->TestBit(TObject::kIsReferenced)) {
997 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
998 }
999
1000 std::size_t nbytes = 0;
1001 nbytes += CallAppendOn(*fSubfields[0], reinterpret_cast<const unsigned char *>(from) + GetOffsetUniqueID());
1002
1003 UInt_t bits = *reinterpret_cast<const UInt_t *>(reinterpret_cast<const unsigned char *>(from) + GetOffsetBits());
1004 bits &= (~TObject::kIsOnHeap & ~TObject::kNotDeleted);
1005 nbytes += CallAppendOn(*fSubfields[1], &bits);
1006
1007 return nbytes;
1008}
1009
1011{
1012 // Cf. TObject::Streamer()
1013
1014 auto *obj = static_cast<TObject *>(to);
1015 if (obj->TestBit(TObject::kIsReferenced)) {
1016 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
1017 }
1018
1019 *reinterpret_cast<UInt_t *>(reinterpret_cast<unsigned char *>(to) + GetOffsetUniqueID()) = uniqueID;
1020
1021 const UInt_t bitIsOnHeap = obj->TestBit(TObject::kIsOnHeap) ? TObject::kIsOnHeap : 0;
1023 *reinterpret_cast<UInt_t *>(reinterpret_cast<unsigned char *>(to) + GetOffsetBits()) = bits;
1024}
1025
1027{
1028 UInt_t uniqueID, bits;
1029 CallReadOn(*fSubfields[0], globalIndex, &uniqueID);
1030 CallReadOn(*fSubfields[1], globalIndex, &bits);
1031 ReadTObject(to, uniqueID, bits);
1032}
1033
1035{
1036 UInt_t uniqueID, bits;
1037 CallReadOn(*fSubfields[0], localIndex, &uniqueID);
1038 CallReadOn(*fSubfields[1], localIndex, &bits);
1039 ReadTObject(to, uniqueID, bits);
1040}
1041
1043{
1044 if (GetOnDiskTypeVersion() != 1) {
1045 throw RException(R__FAIL("unsupported on-disk version of TObject: " + std::to_string(GetTypeVersion())));
1046 }
1047}
1048
1050{
1051 return TObject::Class()->GetClassVersion();
1052}
1053
1055{
1056 return TObject::Class()->GetCheckSum();
1057}
1058
1060{
1061 new (where) TObject();
1062}
1063
1064std::vector<ROOT::RFieldBase::RValue> ROOT::RField<TObject>::SplitValue(const RValue &value) const
1065{
1066 std::vector<RValue> result;
1067 auto basePtr = value.GetPtr<unsigned char>().get();
1068 result.emplace_back(
1069 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + GetOffsetUniqueID())));
1070 result.emplace_back(
1071 fSubfields[1]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + GetOffsetBits())));
1072 return result;
1073}
1074
1076{
1077 return sizeof(TObject);
1078}
1079
1081{
1082 return alignof(TObject);
1083}
1084
1086{
1087 visitor.VisitTObjectField(*this);
1088}
1089
1090//------------------------------------------------------------------------------
1091
1092std::string ROOT::RTupleField::RTupleField::GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields)
1093{
1094 std::string result;
1095 if (itemFields.empty())
1096 throw RException(R__FAIL("the type list for std::tuple must have at least one element"));
1097 for (size_t i = 0; i < itemFields.size(); ++i) {
1098 result += itemFields[i]->GetTypeName() + ",";
1099 }
1100 result.pop_back(); // remove trailing comma
1101 return result;
1102}
1103
1104ROOT::RTupleField::RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
1105 const std::vector<std::size_t> &offsets)
1106 : ROOT::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields) + ">")
1107{
1108 AttachItemFields(std::move(itemFields));
1109 fOffsets = offsets;
1110}
1111
1112ROOT::RTupleField::RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
1113 : ROOT::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields) + ">")
1114{
1115 AttachItemFields(std::move(itemFields));
1116
1117 auto *c = TClass::GetClass(GetTypeName().c_str());
1118 if (!c)
1119 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
1120 fSize = c->Size();
1121
1122 // ISO C++ does not guarantee neither specific layout nor member names for `std::tuple`. However, most
1123 // implementations including libstdc++ (gcc), libc++ (llvm), and MSVC name members as `_0`, `_1`, ..., `_N-1`,
1124 // following the order of the type list.
1125 // Use TClass to get their offsets; in case a particular `std::tuple` implementation does not define such
1126 // members, the assertion below will fail.
1127 for (unsigned i = 0; i < fSubfields.size(); ++i) {
1128 std::string memberName("_" + std::to_string(i));
1129 auto member = c->GetRealData(memberName.c_str());
1130 if (!member)
1131 throw RException(R__FAIL(memberName + ": no such member"));
1132 fOffsets.push_back(member->GetThisOffset());
1133 }
1134}
1135
1136//------------------------------------------------------------------------------
1137
1138namespace {
1139
1140// Depending on the compiler, the variant tag is stored either in a trailing char or in a trailing unsigned int
1141constexpr std::size_t GetVariantTagSize()
1142{
1143 // Should be all zeros except for the tag, which is 1
1144 std::variant<char> t;
1145 constexpr auto sizeOfT = sizeof(t);
1146
1147 static_assert(sizeOfT == 2 || sizeOfT == 8, "unsupported std::variant layout");
1148 return sizeOfT == 2 ? 1 : 4;
1149}
1150
1151template <std::size_t VariantSizeT>
1152struct RVariantTag {
1153 using ValueType_t = typename std::conditional_t<VariantSizeT == 1, std::uint8_t,
1154 typename std::conditional_t<VariantSizeT == 4, std::uint32_t, void>>;
1155};
1156
1157} // anonymous namespace
1158
1159std::string ROOT::RVariantField::GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields)
1160{
1161 std::string result;
1162 for (size_t i = 0; i < itemFields.size(); ++i) {
1163 result += itemFields[i]->GetTypeName() + ",";
1164 }
1165 R__ASSERT(!result.empty()); // there is always at least one variant
1166 result.pop_back(); // remove trailing comma
1167 return result;
1168}
1169
1171 : ROOT::RFieldBase(name, source.GetTypeName(), ROOT::ENTupleStructure::kVariant, false /* isSimple */),
1172 fMaxItemSize(source.fMaxItemSize),
1173 fMaxAlignment(source.fMaxAlignment),
1174 fTagOffset(source.fTagOffset),
1175 fVariantOffset(source.fVariantOffset),
1176 fNWritten(source.fNWritten.size(), 0)
1177{
1178 for (const auto &f : source.GetConstSubfields())
1179 Attach(f->Clone(f->GetFieldName()));
1180 fTraits = source.fTraits;
1181}
1182
1183ROOT::RVariantField::RVariantField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
1184 : ROOT::RFieldBase(fieldName, "std::variant<" + GetTypeList(itemFields) + ">", ROOT::ENTupleStructure::kVariant,
1185 false /* isSimple */)
1186{
1187 // The variant needs to initialize its own tag member
1189
1190 auto nFields = itemFields.size();
1191 if (nFields == 0 || nFields > kMaxVariants) {
1192 throw RException(R__FAIL("invalid number of variant fields (outside [1.." + std::to_string(kMaxVariants) + ")"));
1193 }
1194 fNWritten.resize(nFields, 0);
1195 for (unsigned int i = 0; i < nFields; ++i) {
1198 fTraits &= itemFields[i]->GetTraits();
1199 Attach(std::move(itemFields[i]));
1200 }
1201
1202 // With certain template parameters, the union of members of an std::variant starts at an offset > 0.
1203 // For instance, std::variant<std::optional<int>> on macOS.
1204 auto cl = TClass::GetClass(GetTypeName().c_str());
1205 assert(cl);
1206 auto dm = reinterpret_cast<TDataMember *>(cl->GetListOfDataMembers()->First());
1207 if (dm)
1208 fVariantOffset = dm->GetOffset();
1209
1210 const auto tagSize = GetVariantTagSize();
1211 const auto padding = tagSize - (fMaxItemSize % tagSize);
1213}
1214
1215std::unique_ptr<ROOT::RFieldBase> ROOT::RVariantField::CloneImpl(std::string_view newName) const
1216{
1217 return std::unique_ptr<RVariantField>(new RVariantField(newName, *this));
1218}
1219
1220std::uint8_t ROOT::RVariantField::GetTag(const void *variantPtr, std::size_t tagOffset)
1221{
1222 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
1223 auto tag = *reinterpret_cast<const TagType_t *>(reinterpret_cast<const unsigned char *>(variantPtr) + tagOffset);
1224 return (tag == TagType_t(-1)) ? 0 : tag + 1;
1225}
1226
1227void ROOT::RVariantField::SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag)
1228{
1229 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
1230 auto tagPtr = reinterpret_cast<TagType_t *>(reinterpret_cast<unsigned char *>(variantPtr) + tagOffset);
1231 *tagPtr = (tag == 0) ? TagType_t(-1) : static_cast<TagType_t>(tag - 1);
1232}
1233
1234std::size_t ROOT::RVariantField::AppendImpl(const void *from)
1235{
1236 auto tag = GetTag(from, fTagOffset);
1237 std::size_t nbytes = 0;
1238 auto index = 0;
1239 if (tag > 0) {
1240 nbytes += CallAppendOn(*fSubfields[tag - 1], reinterpret_cast<const unsigned char *>(from) + fVariantOffset);
1241 index = fNWritten[tag - 1]++;
1242 }
1244 fPrincipalColumn->Append(&varSwitch);
1245 return nbytes + sizeof(ROOT::Internal::RColumnSwitch);
1246}
1247
1249{
1251 std::uint32_t tag;
1252 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
1253 R__ASSERT(tag < 256);
1254
1255 // If `tag` equals 0, the variant is in the invalid state, i.e, it does not hold any of the valid alternatives in
1256 // the type list. This happens, e.g., if the field was late added; in this case, keep the invalid tag, which makes
1257 // any `std::holds_alternative<T>` check fail later.
1258 if (R__likely(tag > 0)) {
1259 void *varPtr = reinterpret_cast<unsigned char *>(to) + fVariantOffset;
1260 CallConstructValueOn(*fSubfields[tag - 1], varPtr);
1261 CallReadOn(*fSubfields[tag - 1], variantIndex, varPtr);
1262 }
1263 SetTag(to, fTagOffset, tag);
1264}
1265
1271
1276
1281
1283{
1284 memset(where, 0, GetValueSize());
1285 CallConstructValueOn(*fSubfields[0], reinterpret_cast<unsigned char *>(where) + fVariantOffset);
1286 SetTag(where, fTagOffset, 1);
1287}
1288
1290{
1291 auto tag = GetTag(objPtr, fTagOffset);
1292 if (tag > 0) {
1293 fItemDeleters[tag - 1]->operator()(reinterpret_cast<unsigned char *>(objPtr) + fVariantOffset, true /*dtorOnly*/);
1294 }
1295 RDeleter::operator()(objPtr, dtorOnly);
1296}
1297
1298std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVariantField::GetDeleter() const
1299{
1300 std::vector<std::unique_ptr<RDeleter>> itemDeleters;
1301 itemDeleters.reserve(fSubfields.size());
1302 for (const auto &f : fSubfields) {
1303 itemDeleters.emplace_back(GetDeleterOf(*f));
1304 }
1305 return std::make_unique<RVariantDeleter>(fTagOffset, fVariantOffset, std::move(itemDeleters));
1306}
1307
1309{
1310 return std::max(fMaxAlignment, alignof(RVariantTag<GetVariantTagSize()>::ValueType_t));
1311}
1312
1314{
1315 const auto alignment = GetAlignment();
1316 const auto actualSize = fTagOffset + GetVariantTagSize();
1317 const auto padding = alignment - (actualSize % alignment);
1318 return actualSize + ((padding == alignment) ? 0 : padding);
1319}
1320
1322{
1323 std::fill(fNWritten.begin(), fNWritten.end(), 0);
1324}
Cppyy::TCppType_t fClass
#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:358
#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
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kLong_t
Definition TDataType.h:30
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kUInt_t
Definition TDataType.h:30
@ kClassHasExplicitCtor
@ kClassHasImplicitCtor
@ 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
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
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 char Point_t Rectangle_t WindowAttributes_t index
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 Int_t Int_t Window_t child
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 mode
char name[80]
Definition TGX11.cxx:110
TCanvas * alignment()
Definition alignment.C:1
#define _(A, B)
Definition cfortran.h:108
Abstract base class for classes implementing the visitor design pattern.
Holds the index and the tag of a kSwitch column.
A helper class for piece-wise construction of an RExtraTypeInfoDescriptor.
static std::string SerializeStreamerInfos(const StreamerInfoMap_t &infos)
Abstract interface to read data from an ntuple.
void operator()(void *objPtr, bool dtorOnly) final
The field for a class with dictionary.
Definition RField.hxx:111
void AddReadCallbacksFromIORule(const TSchemaRule *rule)
Register post-read callback corresponding to a ROOT I/O customization rules.
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.
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:197
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
void Attach(std::unique_ptr< RFieldBase > child, RSubFieldInfo info)
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
TClass * fClass
Definition RField.hxx:140
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
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.
~RClassField() override
std::uint32_t GetTypeChecksum() const final
Return the current TClass reported checksum of this class. Only valid if kTraitTypeChecksum is set.
static constexpr const char * kPrefixInherited
Prefix used in the subfield names generated for base classes.
Definition RField.hxx:129
void SetStagingClass(const std::string &className, unsigned int classVersion)
Sets fStagingClass according to the given name and version.
void BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final
Called by ConnectPageSource() before connecting; derived classes may override this as appropriate.
The field for an unscoped or scoped enum with dictionary.
Definition RField.hxx:257
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)
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
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.
A field translates read and write calls from/to underlying columns to/from tree values.
void Attach(std::unique_ptr< RFieldBase > child)
Add a new subfield to the list of nested fields.
std::vector< std::unique_ptr< RFieldBase > > fSubfields
Collections and classes own subfields.
virtual void AfterConnectPageSource()
Called by ConnectPageSource() once connected; derived classes may override this as appropriate.
@ kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
@ kTraitTriviallyConstructible
No constructor needs to be called, i.e.
@ kTraitTypeChecksum
The TClass checksum is set and valid.
friend class ROOT::RClassField
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
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.
std::string fTypeAlias
A typedef or using name that was used when creating the field.
const std::string & GetTypeName() const
Metadata stored for every field of an RNTuple.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:285
RField(std::string_view name)
Definition RField.hxx:288
RMapField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
The on-storage metadata of an RNTuple.
RFieldDescriptorIterable GetFieldIterable(const RFieldDescriptor &fieldDesc) const
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
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.
RPairField(std::string_view fieldName, std::array< std::unique_ptr< RFieldBase >, 2 > itemFields, const std::array< std::size_t, 2 > &offsets)
Allows for iterating over the elements of a proxied collection.
static RIteratorFuncs GetIteratorFuncs(TVirtualCollectionProxy *proxy, bool readFromDisk)
void operator()(void *objPtr, bool dtorOnly) final
The field for a class representing a collection of elements via TVirtualCollectionProxy.
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 final
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
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
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
const_iterator begin() const
const_iterator end() const
The field for an untyped record.
void AttachItemFields(std::vector< std::unique_ptr< RFieldBase > > itemFields)
Definition RField.cxx:498
std::vector< std::size_t > fOffsets
RSetField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
void operator()(void *objPtr, bool dtorOnly) final
The field for a class using ROOT standard streaming.
Definition RField.hxx:204
ROOT::RExtraTypeInfoDescriptor GetExtraTypeInfo() const final
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
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...
void BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final
Called by ConnectPageSource() before connecting; derived classes may override this as appropriate.
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 > 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.
RTupleField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields, const std::vector< std::size_t > &offsets)
void operator()(void *objPtr, bool dtorOnly) final
Template specializations for C++ std::variant.
static std::string GetTypeList(const std::vector< std::unique_ptr< RFieldBase > > &itemFields)
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
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
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
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2425
EState GetState() const
Definition TClass.h:495
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3898
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5844
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3764
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:3003
Long_t ClassProperty() const
Return the C++ property of this class, eg.
Definition TClass.cxx:2502
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6229
@ kInterpreted
Definition TClass.h:129
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:3074
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
static TEnum * GetEnum(const std::type_info &ti, ESearchAction sa=kALoadAndInterpLookup)
Definition TEnum.cxx:182
Mother of all ROOT objects.
Definition TObject.h:41
@ kIsOnHeap
object is on heap
Definition TObject.h:87
@ kNotDeleted
object has not been deleted
Definition TObject.h:88
static TClass * Class()
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition TObject.h:71
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...
Abstract Interface class describing Streamer information for one class.
const Int_t n
Definition legend1.C:16
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
ERNTupleSerializationMode GetRNTupleSerializationMode(TClass *cl)
std::string GetNormalizedUnresolvedTypeName(const std::string &origName)
Applies all RNTuple type normalization rules except typedef resolution.
std::string GetRenormalizedTypeName(const std::string &metaNormalizedName)
Given a type name normalized by ROOT meta, renormalize it for RNTuple. E.g., insert std::prefix.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
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 ntuple model tree can carry different structural information about the type system.
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.