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// - RSoAField
9// - REnumField
10// - RPairField
11// - RProxiedCollectionField
12// - RMapField
13// - RSetField
14// - RStreamerField
15// - RField<TObject>
16// - RVariantField
17
18#include <ROOT/RField.hxx>
19#include <ROOT/RFieldBase.hxx>
20#include <ROOT/RFieldUtils.hxx>
22#include <ROOT/RNTupleUtils.hxx>
23#include <ROOT/RSpan.hxx>
24
25#include <TBaseClass.h>
26#include <TBufferFile.h>
27#include <TClass.h>
28#include <TClassEdit.h>
29#include <TDataMember.h>
30#include <TEnum.h>
31#include <TObject.h>
32#include <TObjArray.h>
33#include <TObjString.h>
34#include <TRealData.h>
35#include <TSchemaRule.h>
36#include <TSchemaRuleSet.h>
37#include <TStreamerElement.h>
38#include <TVirtualObject.h>
40
41#include <algorithm>
42#include <array>
43#include <cstddef> // std::size_t
44#include <cstdint> // std::uint32_t et al.
45#include <cstring> // for memset
46#include <memory>
47#include <mutex>
48#include <string>
49#include <string_view>
50#include <unordered_set>
51#include <utility>
52#include <variant>
53
55
56namespace {
57
58TClass *EnsureValidClass(std::string_view className)
59{
60 auto cl = TClass::GetClass(std::string(className).c_str());
61 if (cl == nullptr) {
62 throw ROOT::RException(R__FAIL("RField: no I/O support for type " + std::string(className)));
63 }
64 return cl;
65}
66
67/// Common checks used both by RClassField and RSoAField
68void EnsureValidUserClass(TClass *cl, const ROOT::RFieldBase &field, std::string_view fieldType)
69{
70 if (cl->GetState() < TClass::kInterpreted) {
71 throw ROOT::RException(R__FAIL(std::string(fieldType) + " " + cl->GetName() +
72 " cannot be constructed from a class that's not at least Interpreted"));
73 }
74 // Avoid accidentally supporting std types through TClass.
75 if (cl->Property() & kIsDefinedInStd) {
76 throw ROOT::RException(R__FAIL(field.GetTypeName() + " is not supported"));
77 }
78 if (field.GetTypeName() == "TObject") {
79 throw ROOT::RException(R__FAIL("TObject is only supported through RField<TObject>"));
80 }
81 if (cl->GetCollectionProxy()) {
82 throw ROOT::RException(R__FAIL(field.GetTypeName() + " has an associated collection proxy; "
83 "use RProxiedCollectionField instead"));
84 }
85 // Classes with, e.g., custom streamers are not supported through this field. Empty classes, however, are.
86 // Can be overwritten with the "rntuple.streamerMode=true" class attribute
87 if (!cl->CanSplit() && cl->Size() > 1 &&
89 throw ROOT::RException(R__FAIL(field.GetTypeName() + " cannot be stored natively in RNTuple"));
90 }
93 throw ROOT::RException(
94 R__FAIL(field.GetTypeName() + " has streamer mode enforced, not supported as native RNTuple class"));
95 }
96 // Detect custom streamers set on individual members at runtime via
97 // TClass::SetMemberStreamer() or TClass::AdoptMemberStreamer().
98 // CanSplit() only checks for custom streamers set at compile time (fHasCustomStreamerMember),
99 // but runtime streamers are stored in TRealData and must be checked here.
100 if (!cl->GetListOfRealData()) {
101 cl->BuildRealData();
102 }
103 for (auto realMember : ROOT::Detail::TRangeStaticCast<TRealData>(*cl->GetListOfRealData())) {
104 if (realMember->GetStreamer()) {
105 throw ROOT::RException(R__FAIL(std::string(field.GetTypeName()) + " has member " + realMember->GetName() +
106 " with a custom streamer; not supported natively in RNTuple"));
107 }
108 }
109}
110
111TEnum *EnsureValidEnum(std::string_view enumName)
112{
113 auto e = TEnum::GetEnum(std::string(enumName).c_str());
114 if (e == nullptr) {
115 throw ROOT::RException(R__FAIL("RField: no I/O support for enum type " + std::string(enumName)));
116 }
117 return e;
118}
119
120/// Create a comma-separated list of type names from the given fields. Uses either the real type names or the
121/// type aliases (if there are any, otherwise the actual type name). Used to construct template argument lists
122/// for templated types such as std::pair<...>, std::tuple<...>, std::variant<...>.
123std::string GetTypeList(std::span<std::unique_ptr<ROOT::RFieldBase>> itemFields, bool useTypeAliases)
124{
125 std::string result;
126 for (size_t i = 0; i < itemFields.size(); ++i) {
127 if (useTypeAliases && !itemFields[i]->GetTypeAlias().empty()) {
128 result += itemFields[i]->GetTypeAlias();
129 } else {
130 result += itemFields[i]->GetTypeName();
131 }
132 result.push_back(',');
133 }
134 if (result.empty()) {
135 throw ROOT::RException(R__FAIL("invalid empty type list provided as template argument"));
136 }
137 result.pop_back(); // remove trailing comma
138 return result;
139}
140
141std::string BuildSetTypeName(ROOT::RSetField::ESetType setType, const ROOT::RFieldBase &innerField, bool useTypeAlias)
142{
143 std::string typePrefix;
144 switch (setType) {
145 case ROOT::RSetField::ESetType::kSet: typePrefix = "std::set<"; break;
146 case ROOT::RSetField::ESetType::kUnorderedSet: typePrefix = "std::unordered_set<"; break;
147 case ROOT::RSetField::ESetType::kMultiSet: typePrefix = "std::multiset<"; break;
148 case ROOT::RSetField::ESetType::kUnorderedMultiSet: typePrefix = "std::unordered_multiset<"; break;
149 default: R__ASSERT(false);
150 }
151 return typePrefix +
152 ((useTypeAlias && !innerField.GetTypeAlias().empty()) ? innerField.GetTypeAlias()
153 : innerField.GetTypeName()) +
154 ">";
155}
156
157std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFieldBase *innerField, bool useTypeAliases)
158{
159 if (const auto pairField = dynamic_cast<const ROOT::RPairField *>(innerField)) {
160 std::string typePrefix;
161 switch (mapType) {
162 case ROOT::RMapField::EMapType::kMap: typePrefix = "std::map<"; break;
163 case ROOT::RMapField::EMapType::kUnorderedMap: typePrefix = "std::unordered_map<"; break;
164 case ROOT::RMapField::EMapType::kMultiMap: typePrefix = "std::multimap<"; break;
165 case ROOT::RMapField::EMapType::kUnorderedMultiMap: typePrefix = "std::unordered_multimap<"; break;
166 default: R__ASSERT(false);
167 }
168 const auto &items = pairField->GetConstSubfields();
169 std::string type = typePrefix;
170 for (int i : {0, 1}) {
171 if (useTypeAliases && !items[i]->GetTypeAlias().empty()) {
172 type += items[i]->GetTypeAlias();
173 } else {
174 type += items[i]->GetTypeName();
175 }
176 if (i == 0)
177 type.push_back(',');
178 }
179 return type + ">";
180 }
181
182 throw ROOT::RException(R__FAIL("RMapField inner field type must be of RPairField"));
183}
184
185} // anonymous namespace
186
187ROOT::RClassField::RClassField(std::string_view fieldName, const RClassField &source)
188 : ROOT::RFieldBase(fieldName, source.GetTypeName(), ROOT::ENTupleStructure::kRecord, false /* isSimple */),
189 fClass(source.fClass),
192{
193 for (const auto &f : source.GetConstSubfields()) {
194 RFieldBase::Attach(f->Clone(f->GetFieldName()));
195 }
196 fTraits = source.GetTraits();
197}
198
199ROOT::RClassField::RClassField(std::string_view fieldName, std::string_view className)
200 : RClassField(fieldName, EnsureValidClass(className))
201{
202}
203
204ROOT::RClassField::RClassField(std::string_view fieldName, TClass *classp)
205 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kRecord,
206 false /* isSimple */),
207 fClass(classp)
208{
209 EnsureValidUserClass(fClass, *this, "RClassField");
210
212 throw ROOT::RException(R__FAIL(GetTypeName() + " is a SoA field and connot be used through RClassField"));
213 }
214
215 if (!(fClass->ClassProperty() & kClassHasExplicitCtor))
217 if (!(fClass->ClassProperty() & kClassHasExplicitDtor))
219
220 std::string renormalizedAlias;
221 if (Internal::NeedsMetaNameAsAlias(classp->GetName(), renormalizedAlias))
222 fTypeAlias = renormalizedAlias;
223
224 int i = 0;
225 const auto *bases = fClass->GetListOfBases();
226 assert(bases);
227 for (auto baseClass : ROOT::Detail::TRangeStaticCast<TBaseClass>(*bases)) {
228 if (baseClass->GetDelta() < 0) {
229 throw RException(R__FAIL(std::string("virtual inheritance is not supported: ") + GetTypeName() +
230 " virtually inherits from " + baseClass->GetName()));
231 }
232 TClass *c = baseClass->GetClassPointer();
233 auto subField =
234 RFieldBase::Create(std::string(kPrefixInherited) + "_" + std::to_string(i), c->GetName()).Unwrap();
235 fTraits &= subField->GetTraits();
236 Attach(std::move(subField), RSubfieldInfo{kBaseClass, static_cast<std::size_t>(baseClass->GetDelta())});
237 i++;
238 }
239 for (auto dataMember : ROOT::Detail::TRangeStaticCast<TDataMember>(*fClass->GetListOfDataMembers())) {
240 // Skip, for instance, unscoped enum constants defined in the class
241 if (dataMember->Property() & kIsStatic)
242 continue;
243 // Skip members explicitly marked as transient by user comment
244 if (!dataMember->IsPersistent()) {
245 // TODO(jblomer): we could do better
247 continue;
248 }
249
250 // NOTE: we use the already-resolved type name for the fields, otherwise TClass::GetClass may fail to resolve
251 // context-dependent types (e.g. typedefs defined in the class itself - which will not be fully qualified in
252 // the string returned by dataMember->GetFullTypeName())
253 std::string typeName{dataMember->GetTrueTypeName()};
254
255 // For C-style arrays, complete the type name with the size for each dimension, e.g. `int[4][2]`
256 if (dataMember->Property() & kIsArray) {
257 for (int dim = 0, n = dataMember->GetArrayDim(); dim < n; ++dim) {
258 typeName += "[" + std::to_string(dataMember->GetMaxIndex(dim)) + "]";
259 }
260 }
261
262 auto subField = RFieldBase::Create(dataMember->GetName(), typeName).Unwrap();
263
264 fTraits &= subField->GetTraits();
265 Attach(std::move(subField), RSubfieldInfo{kDataMember, static_cast<std::size_t>(dataMember->GetOffset())});
266 }
268}
269
271{
272 if (fStagingArea) {
273 for (const auto &[_, si] : fStagingItems) {
274 if (!(si.fField->GetTraits() & kTraitTriviallyDestructible)) {
275 auto deleter = GetDeleterOf(*si.fField);
276 deleter->operator()(fStagingArea.get() + si.fOffset, true /* dtorOnly */);
277 }
278 }
279 }
280}
281
282void ROOT::RClassField::Attach(std::unique_ptr<RFieldBase> child, RSubfieldInfo info)
283{
284 fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
285 fSubfieldsInfo.push_back(info);
286 RFieldBase::Attach(std::move(child));
287}
288
289std::vector<const ROOT::TSchemaRule *> ROOT::RClassField::FindRules(const ROOT::RFieldDescriptor *fieldDesc)
290{
292 const auto ruleset = fClass->GetSchemaRules();
293 if (!ruleset)
294 return rules;
295
296 if (!fieldDesc) {
297 // If we have no on-disk information for the field, we still process the rules on the current in-memory version
298 // of the class
299 rules = ruleset->FindRules(fClass->GetName(), fClass->GetClassVersion(), fClass->GetCheckSum());
300 } else {
301 // We need to change (back) the name normalization from RNTuple to ROOT Meta
302 std::string normalizedName;
303 TClassEdit::GetNormalizedName(normalizedName, fieldDesc->GetTypeName());
304 // We do have an on-disk field that correspond to the current RClassField instance. Ask for rules matching the
305 // on-disk version of the field.
306 if (fieldDesc->GetTypeChecksum()) {
307 rules = ruleset->FindRules(normalizedName, fieldDesc->GetTypeVersion(), *fieldDesc->GetTypeChecksum());
308 } else {
309 rules = ruleset->FindRules(normalizedName, fieldDesc->GetTypeVersion());
310 }
311 }
312
313 // Cleanup and sort rules
314 // Check that any any given source member uses the same type in all rules
315 std::unordered_map<std::string, std::string> sourceNameAndType;
316 std::size_t nskip = 0; // skip whole-object-rules that were moved to the end of the rules vector
317 for (auto itr = rules.begin(); itr != rules.end() - nskip;) {
318 const auto rule = *itr;
319
320 // Erase unknown rule types
321 if (rule->GetRuleType() != ROOT::TSchemaRule::kReadRule) {
323 << "ignoring I/O customization rule with unsupported type: " << rule->GetRuleType();
324 itr = rules.erase(itr);
325 continue;
326 }
327
328 bool hasConflictingSourceMembers = false;
329 for (auto source : TRangeDynCast<TSchemaRule::TSources>(rule->GetSource())) {
330 auto memberType = source->GetTypeForDeclaration() + source->GetDimensions();
331 auto [itrSrc, isNew] = sourceNameAndType.emplace(source->GetName(), memberType);
332 if (!isNew && (itrSrc->second != memberType)) {
334 << "ignoring I/O customization rule due to conflicting source member type: " << itrSrc->second << " vs. "
335 << memberType << " for member " << source->GetName();
336 hasConflictingSourceMembers = true;
337 break;
338 }
339 }
340 if (hasConflictingSourceMembers) {
341 itr = rules.erase(itr);
342 continue;
343 }
344
345 // Rules targeting the entire object need to be executed at the end
346 if (rule->GetTarget() == nullptr) {
347 nskip++;
348 if (itr != rules.end() - nskip)
349 std::iter_swap(itr++, rules.end() - nskip);
350 continue;
351 }
352
353 ++itr;
354 }
355
356 return rules;
357}
358
359std::unique_ptr<ROOT::RFieldBase> ROOT::RClassField::CloneImpl(std::string_view newName) const
360{
361 return std::unique_ptr<RClassField>(new RClassField(newName, *this));
362}
363
364std::size_t ROOT::RClassField::AppendImpl(const void *from)
365{
366 std::size_t nbytes = 0;
367 for (unsigned i = 0; i < fSubfields.size(); i++) {
368 nbytes += CallAppendOn(*fSubfields[i], static_cast<const unsigned char *>(from) + fSubfieldsInfo[i].fOffset);
369 }
370 return nbytes;
371}
372
374{
375 for (const auto &[_, si] : fStagingItems) {
376 CallReadOn(*si.fField, globalIndex, fStagingArea.get() + si.fOffset);
377 }
378 for (unsigned i = 0; i < fSubfields.size(); i++) {
379 CallReadOn(*fSubfields[i], globalIndex, static_cast<unsigned char *>(to) + fSubfieldsInfo[i].fOffset);
380 }
381}
382
384{
385 for (const auto &[_, si] : fStagingItems) {
386 CallReadOn(*si.fField, localIndex, fStagingArea.get() + si.fOffset);
387 }
388 for (unsigned i = 0; i < fSubfields.size(); i++) {
389 CallReadOn(*fSubfields[i], localIndex, static_cast<unsigned char *>(to) + fSubfieldsInfo[i].fOffset);
390 }
391}
392
394 ROOT::DescriptorId_t classFieldId)
395{
396 auto idSourceMember = desc.FindFieldId(memberName, classFieldId);
397 if (idSourceMember != ROOT::kInvalidDescriptorId)
398 return idSourceMember;
399
400 for (const auto &subFieldDesc : desc.GetFieldIterable(classFieldId)) {
401 const auto subFieldName = subFieldDesc.GetFieldName();
402 if (subFieldName.length() > 2 && subFieldName[0] == ':' && subFieldName[1] == '_') {
403 idSourceMember = LookupMember(desc, memberName, subFieldDesc.GetId());
404 if (idSourceMember != ROOT::kInvalidDescriptorId)
405 return idSourceMember;
406 }
407 }
408
410}
411
412void ROOT::RClassField::SetStagingClass(const std::string &className, unsigned int classVersion)
413{
414 TClass::GetClass(className.c_str())->GetStreamerInfo(classVersion);
415 if (classVersion != GetTypeVersion() || className != GetTypeName()) {
416 fStagingClass = TClass::GetClass((className + std::string("@@") + std::to_string(classVersion)).c_str());
417 if (!fStagingClass) {
418 // For a rename rule, we may simply ask for the old class name
419 fStagingClass = TClass::GetClass(className.c_str());
420 }
421 } else {
423 }
425 R__ASSERT(static_cast<unsigned int>(fStagingClass->GetClassVersion()) == classVersion);
426}
427
428void ROOT::RClassField::PrepareStagingArea(const std::vector<const TSchemaRule *> &rules,
429 const ROOT::RNTupleDescriptor &desc,
430 const ROOT::RFieldDescriptor &classFieldDesc)
431{
432 std::size_t stagingAreaSize = 0;
433 for (const auto rule : rules) {
434 for (auto source : TRangeDynCast<TSchemaRule::TSources>(rule->GetSource())) {
435 auto [itr, isNew] = fStagingItems.emplace(source->GetName(), RStagingItem());
436 if (!isNew) {
437 // This source member has already been processed by another rule (and we only support one type per member)
438 continue;
439 }
440 RStagingItem &stagingItem = itr->second;
441
442 const auto memberFieldId = LookupMember(desc, source->GetName(), classFieldDesc.GetId());
443 if (memberFieldId == kInvalidDescriptorId) {
444 throw RException(R__FAIL(std::string("cannot find on disk rule source member ") + GetTypeName() + "." +
445 source->GetName()));
446 }
447
448 auto memberType = source->GetTypeForDeclaration() + source->GetDimensions();
449 auto memberField = Create("" /* we don't need a field name */, std::string(memberType)).Unwrap();
450 memberField->SetOnDiskId(memberFieldId);
451 auto fieldZero = std::make_unique<RFieldZero>();
452 Internal::SetAllowFieldSubstitutions(*fieldZero, true);
453 fieldZero->Attach(std::move(memberField));
454 stagingItem.fField = std::move(fieldZero);
455
456 stagingItem.fOffset = fStagingClass->GetDataMemberOffset(source->GetName());
457 // Since we successfully looked up the source member in the RNTuple on-disk metadata, we expect it
458 // to be present in the TClass instance, too.
460 stagingAreaSize = std::max(stagingAreaSize, stagingItem.fOffset + stagingItem.fField->begin()->GetValueSize());
461 }
462 }
463
464 if (stagingAreaSize) {
465 R__ASSERT(static_cast<Int_t>(stagingAreaSize) <= fStagingClass->Size()); // we may have removed rules
466 // We use std::make_unique instead of MakeUninitArray to zero-initialize the staging area.
467 fStagingArea = std::make_unique<unsigned char[]>(stagingAreaSize);
468
469 for (const auto &[_, si] : fStagingItems) {
470 const auto &memberField = *si.fField->cbegin();
471 if (!(memberField.GetTraits() & kTraitTriviallyConstructible)) {
472 CallConstructValueOn(memberField, fStagingArea.get() + si.fOffset);
473 }
474 }
475 }
476}
477
479{
480 auto func = rule->GetReadFunctionPointer();
481 if (func == nullptr) {
482 // Can happen for rename rules
483 return;
484 }
485 fReadCallbacks.emplace_back([func, stagingClass = fStagingClass, stagingArea = fStagingArea.get()](void *target) {
486 TVirtualObject onfileObj{nullptr};
487 onfileObj.fClass = stagingClass;
488 onfileObj.fObject = stagingArea;
489 func(static_cast<char *>(target), &onfileObj);
490 onfileObj.fObject = nullptr; // TVirtualObject does not own the value
491 });
492}
493
495{
496 std::vector<const TSchemaRule *> rules;
497 // On-disk members that are not targeted by an I/O rule; all other sub fields of the in-memory class
498 // will be marked as artificial (added member in a new class version or member set by rule).
499 std::unordered_set<std::string> regularSubfields;
500 // We generally don't support changing the number of base classes, with the exception of changing from/to zero
501 // base classes. The variable stores the number of on-disk base classes.
502 int nOnDiskBaseClasses = 0;
503
505 // This can happen for added base classes or added members of class type
506 rules = FindRules(nullptr);
507 if (!rules.empty())
509 } else {
510 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
511 const ROOT::RNTupleDescriptor &desc = descriptorGuard.GetRef();
512 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
513
514 if (fieldDesc.GetStructure() == ENTupleStructure::kStreamer) {
515 // Streamer field on disk but meanwhile the type can be represented as a class field; replace this field
516 // by a streamer field to read the data from disk.
517 auto substitute = std::make_unique<RStreamerField>(GetFieldName(), GetTypeName());
518 substitute->SetOnDiskId(GetOnDiskId());
519 return substitute;
520 }
521
522 for (auto linkId : fieldDesc.GetLinkIds()) {
523 const auto &subFieldDesc = desc.GetFieldDescriptor(linkId);
524 regularSubfields.insert(subFieldDesc.GetFieldName());
525 if (!subFieldDesc.GetFieldName().empty() && subFieldDesc.GetFieldName()[0] == ':')
526 nOnDiskBaseClasses++;
527 }
528
529 rules = FindRules(&fieldDesc);
530
531 // 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
532 // (source) type name and version/checksum.
533 if (rules.empty()) {
534 // Otherwise we require compatible type names, after renormalization. GetTypeName() is already renormalized,
535 // but RNTuple data written with ROOT v6.34 might not have renormalized the field type name. Ask the
536 // RNTupleDescriptor, which knows about the spec version, for a fixed up type name.
537 std::string descTypeName = desc.GetTypeNameForComparison(fieldDesc);
538 if (GetTypeName() != descTypeName) {
539 throw RException(R__FAIL("incompatible type name for field " + GetFieldName() + ": " + GetTypeName() +
540 " vs. " + descTypeName));
541 }
542 }
543
544 const bool hasSources = std::any_of(rules.begin(), rules.end(), [](const auto &r) {
545 return r->GetSource() && (r->GetSource()->GetEntries() > 0);
546 });
547
548 // A staging class (conversion streamer info) only exists if there is at least one rule that has an
549 // on disk source member defined.
550 if (hasSources) {
551 SetStagingClass(fieldDesc.GetTypeName(), fieldDesc.GetTypeVersion());
552 PrepareStagingArea(rules, desc, fieldDesc);
553 for (auto &[_, si] : fStagingItems) {
554 Internal::CallConnectPageSourceOnField(*si.fField, pageSource);
555 si.fField = std::move(static_cast<RFieldZero *>(si.fField.get())->ReleaseSubfields()[0]);
556 }
557 }
558
559 // Remove target member of read rules from the list of regular members of the underlying on-disk field
560 for (const auto rule : rules) {
561 if (!rule->GetTarget())
562 continue;
563
564 for (const auto target : ROOT::Detail::TRangeStaticCast<const TObjString>(*rule->GetTarget())) {
565 regularSubfields.erase(std::string(target->GetString()));
566 }
567 }
568 }
569
570 for (const auto rule : rules) {
572 }
573
574 // Iterate over all sub fields in memory and mark those as missing that are not in the descriptor.
575 int nInMemoryBaseClasses = 0;
576 for (auto &field : fSubfields) {
577 const auto &fieldName = field->GetFieldName();
578 if (regularSubfields.count(fieldName) == 0) {
579 CallSetArtificialOn(*field);
580 }
581 if (!fieldName.empty() && fieldName[0] == ':')
582 nInMemoryBaseClasses++;
583 }
584
585 if (nInMemoryBaseClasses != 0 && nOnDiskBaseClasses != 0 && nInMemoryBaseClasses != nOnDiskBaseClasses) {
586 throw RException(R__FAIL(std::string("incompatible number of base classes for field ") + GetFieldName() + ": " +
587 GetTypeName() + ", " + std::to_string(nInMemoryBaseClasses) +
588 " base classes in memory "
589 " vs. " +
590 std::to_string(nOnDiskBaseClasses) + " base classes on-disk\n" +
592 }
593
594 return nullptr;
595}
596
601
603{
604 fClass->New(where);
605}
606
607void ROOT::RClassField::RClassDeleter::operator()(void *objPtr, bool dtorOnly)
608{
609 fClass->Destructor(objPtr, true /* dtorOnly */);
610 RDeleter::operator()(objPtr, dtorOnly);
611}
612
613std::vector<ROOT::RFieldBase::RValue> ROOT::RClassField::SplitValue(const RValue &value) const
614{
615 std::vector<RValue> result;
616 auto valuePtr = value.GetPtr<void>();
617 auto charPtr = static_cast<unsigned char *>(valuePtr.get());
618 result.reserve(fSubfields.size());
619 for (unsigned i = 0; i < fSubfields.size(); i++) {
620 result.emplace_back(
621 fSubfields[i]->BindValue(std::shared_ptr<void>(valuePtr, charPtr + fSubfieldsInfo[i].fOffset)));
622 }
623 return result;
624}
625
627{
628 return fClass->GetClassSize();
629}
630
632{
633 return fClass->GetClassVersion();
634}
635
637{
638 return fClass->GetCheckSum();
639}
640
641const std::type_info *ROOT::RClassField::GetPolymorphicTypeInfo() const
642{
643 bool polymorphic = fClass->ClassProperty() & kClassHasVirtual;
644 if (!polymorphic) {
645 return nullptr;
646 }
647 return fClass->GetTypeInfo();
648}
649
651{
652 visitor.VisitClassField(*this);
653}
654
655//------------------------------------------------------------------------------
656
657ROOT::Experimental::RSoAField::RSoAField(std::string_view fieldName, const RSoAField &source)
658 : ROOT::RFieldBase(fieldName, source.GetTypeName(), ROOT::ENTupleStructure::kCollection, false /* isSimple */),
659 fSoAClass(source.fSoAClass),
662{
663 fTraits = source.GetTraits();
664 Attach(source.fSubfields[0]->Clone(source.fSubfields[0]->GetFieldName()));
665 fRecordMemberFields = fSubfields[0]->GetMutableSubfields();
666}
667
668ROOT::Experimental::RSoAField::RSoAField(std::string_view fieldName, std::string_view className)
669 : RSoAField(fieldName, EnsureValidClass(className))
670{
671}
672
673ROOT::Experimental::RSoAField::RSoAField(std::string_view fieldName, TClass *clSoA)
674 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(clSoA->GetName()), ROOT::ENTupleStructure::kCollection,
675 false /* isSimple */),
676 fSoAClass(clSoA)
677{
678 static std::once_flag once;
679 std::call_once(once, []() {
680 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "The SoA field is experimental and still under development.";
681 });
682
683 EnsureValidUserClass(fSoAClass, *this, "RSoAField");
684 const auto recordTypeName = ROOT::Internal::GetRNTupleSoARecord(fSoAClass);
685 if (recordTypeName.empty()) {
686 throw ROOT::RException(R__FAIL(std::string("class ") + GetTypeName() +
687 " is not marked with the rntupleSoARecord "
688 "dictionary option; cannot create corresponding RSoAField."));
689 }
690 try {
691 Attach(std::make_unique<ROOT::RClassField>("_0", recordTypeName));
692 } catch (ROOT::RException &e) {
693 throw RException(R__FAIL("invalid record type of SoA field " + GetTypeName() + " [" + e.what() + "]"));
694 }
695 R__ASSERT(fSoAClass->GetClassVersion() >= 0);
696 if (static_cast<std::uint32_t>(fSoAClass->GetClassVersion()) != fSubfields[0]->GetTypeVersion()) {
697 throw RException(R__FAIL(std::string("version mismatch between SoA type and underlying record type: ") +
698 std::to_string(fSoAClass->GetClassVersion()) + " vs. " +
699 std::to_string(fSubfields[0]->GetTypeVersion())));
700 }
701 fRecordMemberFields = fSubfields[0]->GetMutableSubfields();
702
703 std::unordered_map<std::string, std::size_t> recordFieldNameToIdx;
704 for (std::size_t i = 0; i < fRecordMemberFields.size(); ++i) {
705 const RFieldBase *f = fRecordMemberFields[i];
706 assert(!f->GetFieldName().empty());
707 if (f->GetFieldName()[0] == ':') {
708 throw RException(R__FAIL("SoA fields with inheritance are currently unsupported"));
709 }
710 recordFieldNameToIdx[f->GetFieldName()] = i;
711 }
712
713 const auto *bases = fSoAClass->GetListOfBases();
714 assert(bases);
715 for (auto baseClass : ROOT::Detail::TRangeStaticCast<TBaseClass>(*bases)) {
716 if (baseClass->GetDelta() < 0) {
717 throw RException(R__FAIL(std::string("virtual inheritance is not supported: ") + GetTypeName() +
718 " virtually inherits from " + baseClass->GetName()));
719 }
720 // At a later point, we will support inheritance
721 throw RException(R__FAIL("SoA fields with inheritance are currently unsupported"));
722 }
723
725 unsigned int nMembers = 0;
726 for (auto dataMember : ROOT::Detail::TRangeStaticCast<TDataMember>(*fSoAClass->GetListOfDataMembers())) {
727 if ((dataMember->Property() & kIsStatic) || !dataMember->IsPersistent())
728 continue;
729
730 if (dataMember->Property() & kIsArray) {
731 throw RException(R__FAIL(std::string("unsupported array type in SoA class: ") + dataMember->GetName()));
732 }
733
734 const std::string typeName{dataMember->GetTrueTypeName()};
735 auto subField = RFieldBase::Create(dataMember->GetName(), typeName).Unwrap();
736 auto vecFieldPtr = dynamic_cast<RRVecField *>(subField.get());
737 if (!vecFieldPtr) {
738 throw RException(R__FAIL("invalid field type in SoA class: " + subField->GetTypeName()));
739 }
740 subField.release();
741 auto vecField = std::unique_ptr<RRVecField>(vecFieldPtr);
742
743 auto itr = recordFieldNameToIdx.find(vecField->GetFieldName());
744 if (itr == recordFieldNameToIdx.end()) {
745 throw RException(R__FAIL(std::string("unexpected SoA member: ") + vecField->GetFieldName()));
746 }
747 const RFieldBase *memberField = fRecordMemberFields[itr->second];
748 if (vecField->begin()->GetTypeName() != memberField->GetTypeName() ||
749 vecField->begin()->GetTypeAlias() != memberField->GetTypeAlias()) {
750 const std::string leftType =
751 vecField->begin()->GetTypeName() +
752 (vecField->begin()->GetTypeAlias().empty() ? "" : " [" + vecField->begin()->GetTypeAlias() + "]");
753 const std::string rightType =
754 memberField->GetTypeName() +
755 (memberField->GetTypeAlias().empty() ? "" : " [" + memberField->GetTypeAlias() + "]");
756 throw RException(R__FAIL(std::string("SoA member type mismatch: ") + vecField->GetFieldName() + " (" +
757 leftType + " vs. " + rightType + ")"));
758 }
759
760 fMaxAlignment = std::max(fMaxAlignment, vecField->GetAlignment());
761
762 assert(itr->second < fSoAMemberOffsets.size());
763 fSoAMemberOffsets[itr->second] = dataMember->GetOffset();
764 nMembers++;
765 }
766 if (recordFieldNameToIdx.size() != nMembers) {
767 throw RException(R__FAIL("missing SoA members"));
768 }
769
770 std::string renormalizedAlias;
771 if (ROOT::Internal::NeedsMetaNameAsAlias(fSoAClass->GetName(), renormalizedAlias))
772 fTypeAlias = renormalizedAlias;
773
775}
776
777std::unique_ptr<ROOT::RFieldBase> ROOT::Experimental::RSoAField::CloneImpl(std::string_view newName) const
778{
779 return std::unique_ptr<RSoAField>(new RSoAField(newName, *this));
780}
781
791
796
801
802std::size_t ROOT::Experimental::RSoAField::AppendImpl(const void *from)
803{
804 const std::size_t nSoAMembers = fSoAMemberOffsets.size();
805
806 std::size_t N = 0; // Set by first SoA member and verified for the rest
807 for (std::size_t i = 0; i < nSoAMembers; ++i) {
808 const void *rvecPtr = static_cast<const unsigned char *>(from) + fSoAMemberOffsets[i];
809 auto [beginPtr, sizePtr, _] = ROOT::Internal::GetRVecDataMembers(rvecPtr);
810 assert(*sizePtr >= 0);
811 if (i == 0) {
812 N = *sizePtr;
813 } else {
814 if (static_cast<std::size_t>(*sizePtr) != N) {
815 const auto f = fRecordMemberFields[i];
816 throw RException(R__FAIL("SoA length mismatch for " + f->GetFieldName() + ": " + std::to_string(*sizePtr) +
817 " vs. " + std::to_string(N) + " (expected)"));
818 }
819 }
820 }
821
822 std::size_t nbytes = 0;
823 if (N > 0) {
824 for (std::size_t i = 0; i < nSoAMembers; ++i) {
825 const void *rvecPtr = static_cast<const unsigned char *>(from) + fSoAMemberOffsets[i];
826 auto [beginPtr, _, __] = ROOT::Internal::GetRVecDataMembers(rvecPtr);
827 RFieldBase *memberField = fRecordMemberFields[i];
828 if (memberField->IsSimple()) {
829 GetPrincipalColumnOf(*memberField)->AppendV(*beginPtr, N);
830 nbytes += N * GetPrincipalColumnOf(*memberField)->GetElement()->GetPackedSize();
831 } else {
832 for (std::size_t j = 0; j < N; ++j) {
833 nbytes += CallAppendOn(*memberField, *beginPtr + j * memberField->GetValueSize());
834 }
835 }
836 }
837 }
838
839 fNWritten += N;
840 fPrincipalColumn->Append(&fNWritten);
841 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
842}
843
845{
846 throw RException(R__FAIL("not yet implemented"));
847}
848
850{
851 fSoAClass->New(where);
852}
853
855{
856 fSoAClass->Destructor(objPtr, true /* dtorOnly */);
857 RDeleter::operator()(objPtr, dtorOnly);
858}
859
860std::vector<ROOT::RFieldBase::RValue> ROOT::Experimental::RSoAField::SplitValue(const RValue & /* value */) const
861{
862 throw RException(R__FAIL("not yet implemented"));
863 return std::vector<RValue>();
864}
865
867{
868 return fSoAClass->GetClassSize();
869}
870
872{
873 return fSoAClass->GetClassVersion();
874}
875
877{
878 return fSoAClass->GetCheckSum();
879}
880
882{
883 // TODO(jblomer): factor out
884 bool polymorphic = fSoAClass->ClassProperty() & kClassHasVirtual;
885 if (!polymorphic) {
886 return nullptr;
887 }
888 return fSoAClass->GetTypeInfo();
889}
890
891//------------------------------------------------------------------------------
892
893ROOT::REnumField::REnumField(std::string_view fieldName, std::string_view enumName)
894 : REnumField(fieldName, EnsureValidEnum(enumName))
895{
896}
897
898ROOT::REnumField::REnumField(std::string_view fieldName, TEnum *enump)
899 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(enump->GetQualifiedName()), ROOT::ENTupleStructure::kPlain,
900 false /* isSimple */)
901{
902 // Avoid accidentally supporting std types through TEnum.
903 if (enump->Property() & kIsDefinedInStd) {
904 throw RException(R__FAIL(GetTypeName() + " is not supported"));
905 }
906
907 switch (enump->GetUnderlyingType()) {
908 case kBool_t: Attach(std::make_unique<RField<Bool_t>>("_0")); break;
909 case kChar_t: Attach(std::make_unique<RField<Char_t>>("_0")); break;
910 case kUChar_t: Attach(std::make_unique<RField<UChar_t>>("_0")); break;
911 case kShort_t: Attach(std::make_unique<RField<Short_t>>("_0")); break;
912 case kUShort_t: Attach(std::make_unique<RField<UShort_t>>("_0")); break;
913 case kInt_t: Attach(std::make_unique<RField<Int_t>>("_0")); break;
914 case kUInt_t: Attach(std::make_unique<RField<UInt_t>>("_0")); break;
915 case kLong_t: Attach(std::make_unique<RField<Long_t>>("_0")); break;
916 case kLong64_t: Attach(std::make_unique<RField<Long64_t>>("_0")); break;
917 case kULong_t: Attach(std::make_unique<RField<ULong_t>>("_0")); break;
918 case kULong64_t: Attach(std::make_unique<RField<ULong64_t>>("_0")); break;
919 default: throw RException(R__FAIL("Unsupported underlying integral type for enum type " + GetTypeName()));
920 }
921
923}
924
925ROOT::REnumField::REnumField(std::string_view fieldName, std::string_view enumName,
926 std::unique_ptr<RFieldBase> intField)
927 : ROOT::RFieldBase(fieldName, enumName, ROOT::ENTupleStructure::kPlain, false /* isSimple */)
928{
929 Attach(std::move(intField));
931}
932
933std::unique_ptr<ROOT::RFieldBase> ROOT::REnumField::CloneImpl(std::string_view newName) const
934{
935 auto newIntField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
936 return std::unique_ptr<REnumField>(new REnumField(newName, GetTypeName(), std::move(newIntField)));
937}
938
940{
941 // TODO(jblomer): allow enum to enum conversion only by rename rule
943}
944
945std::vector<ROOT::RFieldBase::RValue> ROOT::REnumField::SplitValue(const RValue &value) const
946{
947 std::vector<RValue> result;
948 result.emplace_back(fSubfields[0]->BindValue(value.GetPtr<void>()));
949 return result;
950}
951
953{
954 visitor.VisitEnumField(*this);
955}
956
957//------------------------------------------------------------------------------
958
959ROOT::RPairField::RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields)
960 : ROOT::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
961{
962 const std::string typeAlias = "std::pair<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
963 if (typeAlias != GetTypeName())
964 fTypeAlias = typeAlias;
965
966 AttachItemFields(std::move(itemFields));
967
968 // ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
969 auto *c = TClass::GetClass(GetTypeName().c_str());
970 if (!c)
971 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
972 fSize = c->Size();
973
974 auto firstElem = c->GetRealData("first");
975 if (!firstElem)
976 throw RException(R__FAIL("first: no such member"));
977 fOffsets.push_back(firstElem->GetThisOffset());
978
979 auto secondElem = c->GetRealData("second");
980 if (!secondElem)
981 throw RException(R__FAIL("second: no such member"));
982 fOffsets.push_back(secondElem->GetThisOffset());
983}
984
985std::unique_ptr<ROOT::RFieldBase> ROOT::RPairField::CloneImpl(std::string_view newName) const
986{
987 std::array<std::unique_ptr<RFieldBase>, 2> itemClones = {fSubfields[0]->Clone(fSubfields[0]->GetFieldName()),
988 fSubfields[1]->Clone(fSubfields[1]->GetFieldName())};
989 return std::unique_ptr<RPairField>(new RPairField(newName, std::move(itemClones)));
990}
991
993{
994 static const std::vector<std::string> prefixes = {"std::pair<", "std::tuple<"};
995
996 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
997 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
998
999 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1000 const auto nOnDiskSubfields = fieldDesc.GetLinkIds().size();
1001 if (nOnDiskSubfields != 2) {
1002 throw ROOT::RException(R__FAIL("invalid number of on-disk subfields for std::pair " +
1003 std::to_string(nOnDiskSubfields) + "\n" +
1004 Internal::GetTypeTraceReport(*this, desc)));
1005 }
1006}
1007
1008//------------------------------------------------------------------------------
1009
1012 bool readFromDisk)
1013{
1014 RIteratorFuncs ifuncs;
1015 ifuncs.fCreateIterators = proxy->GetFunctionCreateIterators(readFromDisk);
1016 ifuncs.fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(readFromDisk);
1017 ifuncs.fNext = proxy->GetFunctionNext(readFromDisk);
1018 R__ASSERT((ifuncs.fCreateIterators != nullptr) && (ifuncs.fDeleteTwoIterators != nullptr) &&
1019 (ifuncs.fNext != nullptr));
1020 return ifuncs;
1021}
1022
1024 : RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kCollection,
1025 false /* isSimple */),
1026 fNWritten(0)
1027{
1028 if (!classp->GetCollectionProxy())
1029 throw RException(R__FAIL(std::string(classp->GetName()) + " has no associated collection proxy"));
1030 if (classp->Property() & kIsDefinedInStd) {
1031 static const std::vector<std::string> supportedStdTypes = {
1032 "std::set<", "std::unordered_set<", "std::multiset<", "std::unordered_multiset<",
1033 "std::map<", "std::unordered_map<", "std::multimap<", "std::unordered_multimap<"};
1034 bool isSupported = false;
1035 for (const auto &tn : supportedStdTypes) {
1036 if (GetTypeName().rfind(tn, 0) == 0) {
1037 isSupported = true;
1038 break;
1039 }
1040 }
1041 if (!isSupported)
1042 throw RException(R__FAIL(std::string(GetTypeName()) + " is not supported"));
1043 }
1044
1045 std::string renormalizedAlias;
1046 if (Internal::NeedsMetaNameAsAlias(classp->GetName(), renormalizedAlias))
1047 fTypeAlias = renormalizedAlias;
1048
1049 fProxy.reset(classp->GetCollectionProxy()->Generate());
1050 fProperties = fProxy->GetProperties();
1051 fCollectionType = fProxy->GetCollectionType();
1052 if (fProxy->HasPointers())
1053 throw RException(R__FAIL("collection proxies whose value type is a pointer are not supported"));
1054
1055 fIFuncsRead = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), true /* readFromDisk */);
1056 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readFromDisk */);
1057}
1058
1059ROOT::RProxiedCollectionField::RProxiedCollectionField(std::string_view fieldName, std::string_view typeName)
1060 : RProxiedCollectionField(fieldName, EnsureValidClass(typeName))
1061{
1062 // NOTE (fdegeus): std::map is supported, custom associative might be supported in the future if the need arises.
1064 throw RException(R__FAIL("custom associative collection proxies not supported"));
1065
1066 std::unique_ptr<ROOT::RFieldBase> itemField;
1067
1068 if (auto valueClass = fProxy->GetValueClass()) {
1069 // Element type is a class
1070 itemField = RFieldBase::Create("_0", valueClass->GetName()).Unwrap();
1071 } else {
1072 switch (fProxy->GetType()) {
1073 case EDataType::kChar_t: itemField = std::make_unique<RField<Char_t>>("_0"); break;
1074 case EDataType::kUChar_t: itemField = std::make_unique<RField<UChar_t>>("_0"); break;
1075 case EDataType::kShort_t: itemField = std::make_unique<RField<Short_t>>("_0"); break;
1076 case EDataType::kUShort_t: itemField = std::make_unique<RField<UShort_t>>("_0"); break;
1077 case EDataType::kInt_t: itemField = std::make_unique<RField<Int_t>>("_0"); break;
1078 case EDataType::kUInt_t: itemField = std::make_unique<RField<UInt_t>>("_0"); break;
1079 case EDataType::kLong_t: itemField = std::make_unique<RField<Long_t>>("_0"); break;
1080 case EDataType::kLong64_t: itemField = std::make_unique<RField<Long64_t>>("_0"); break;
1081 case EDataType::kULong_t: itemField = std::make_unique<RField<ULong_t>>("_0"); break;
1082 case EDataType::kULong64_t: itemField = std::make_unique<RField<ULong64_t>>("_0"); break;
1083 case EDataType::kFloat_t: itemField = std::make_unique<RField<Float_t>>("_0"); break;
1084 case EDataType::kDouble_t: itemField = std::make_unique<RField<Double_t>>("_0"); break;
1085 case EDataType::kBool_t: itemField = std::make_unique<RField<Bool_t>>("_0"); break;
1086 default: throw RException(R__FAIL("unsupported value type: " + std::to_string(fProxy->GetType())));
1087 }
1088 }
1089
1090 fItemSize = itemField->GetValueSize();
1091 Attach(std::move(itemField));
1092}
1093
1094std::unique_ptr<ROOT::RFieldBase> ROOT::RProxiedCollectionField::CloneImpl(std::string_view newName) const
1095{
1096 auto clone =
1097 std::unique_ptr<RProxiedCollectionField>(new RProxiedCollectionField(newName, fProxy->GetCollectionClass()));
1098 clone->fItemSize = fItemSize;
1099 clone->Attach(fSubfields[0]->Clone(fSubfields[0]->GetFieldName()));
1100 return clone;
1101}
1102
1104{
1105 std::size_t nbytes = 0;
1106 unsigned count = 0;
1107 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), const_cast<void *>(from));
1108 for (auto ptr : RCollectionIterableOnce{const_cast<void *>(from), fIFuncsWrite, fProxy.get(),
1109 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
1110 nbytes += CallAppendOn(*fSubfields[0], ptr);
1111 count++;
1112 }
1113
1114 fNWritten += count;
1115 fPrincipalColumn->Append(&fNWritten);
1116 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
1117}
1118
1120{
1121 ROOT::NTupleSize_t nItems;
1122 RNTupleLocalIndex collectionStart;
1123 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1124
1126 void *obj =
1127 fProxy->Allocate(static_cast<std::uint32_t>(nItems), (fProperties & TVirtualCollectionProxy::kNeedDelete));
1128
1129 unsigned i = 0;
1130 for (auto elementPtr : RCollectionIterableOnce{obj, fIFuncsRead, fProxy.get(),
1131 (fCollectionType == kSTLvector || obj != to ? fItemSize : 0U)}) {
1132 CallReadOn(*fSubfields[0], collectionStart + (i++), elementPtr);
1133 }
1134 if (obj != to)
1135 fProxy->Commit(obj);
1136}
1137
1147
1152
1157
1162
1164{
1165 fProxy->New(where);
1166}
1167
1168std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RProxiedCollectionField::GetDeleter() const
1169{
1171 std::size_t itemSize = fCollectionType == kSTLvector ? fItemSize : 0U;
1172 return std::make_unique<RProxiedCollectionDeleter>(fProxy, GetDeleterOf(*fSubfields[0]), itemSize);
1173 }
1174 return std::make_unique<RProxiedCollectionDeleter>(fProxy);
1175}
1176
1178{
1179 if (fItemDeleter) {
1180 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), objPtr);
1181 for (auto ptr : RCollectionIterableOnce{objPtr, fIFuncsWrite, fProxy.get(), fItemSize}) {
1182 fItemDeleter->operator()(ptr, true /* dtorOnly */);
1183 }
1184 }
1185 fProxy->Destructor(objPtr, true /* dtorOnly */);
1186 RDeleter::operator()(objPtr, dtorOnly);
1187}
1188
1189std::vector<ROOT::RFieldBase::RValue> ROOT::RProxiedCollectionField::SplitValue(const RValue &value) const
1190{
1191 std::vector<RValue> result;
1192 auto valueRawPtr = value.GetPtr<void>().get();
1193 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), valueRawPtr);
1194 for (auto ptr : RCollectionIterableOnce{valueRawPtr, fIFuncsWrite, fProxy.get(),
1195 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
1196 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), ptr)));
1197 }
1198 return result;
1199}
1200
1205
1206//------------------------------------------------------------------------------
1207
1208ROOT::RMapField::RMapField(std::string_view fieldName, EMapType mapType, std::unique_ptr<RFieldBase> itemField)
1209 : RProxiedCollectionField(fieldName,
1210 EnsureValidClass(BuildMapTypeName(mapType, itemField.get(), false /* useTypeAliases */))),
1211 fMapType(mapType)
1212{
1213 if (!itemField->GetTypeAlias().empty())
1214 fTypeAlias = BuildMapTypeName(mapType, itemField.get(), true /* useTypeAliases */);
1215
1216 auto *itemClass = fProxy->GetValueClass();
1217 fItemSize = itemClass->GetClassSize();
1218
1219 Attach(std::move(itemField), "_0");
1220}
1221
1222std::unique_ptr<ROOT::RFieldBase> ROOT::RMapField::CloneImpl(std::string_view newName) const
1223{
1224 return std::make_unique<RMapField>(newName, fMapType, fSubfields[0]->Clone(fSubfields[0]->GetFieldName()));
1225}
1226
1228{
1229 static const std::vector<std::string> prefixesRegular = {"std::map<", "std::unordered_map<"};
1230
1231 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
1232
1233 switch (fMapType) {
1234 case EMapType::kMap:
1235 case EMapType::kUnorderedMap: EnsureMatchingTypePrefix(desc, prefixesRegular).ThrowOnError(); break;
1236 default:
1237 break;
1238 // no restrictions for multimaps
1239 }
1240}
1241
1242//------------------------------------------------------------------------------
1243
1244ROOT::RSetField::RSetField(std::string_view fieldName, ESetType setType, std::unique_ptr<RFieldBase> itemField)
1245 : ROOT::RProxiedCollectionField(fieldName,
1246 EnsureValidClass(BuildSetTypeName(setType, *itemField, false /* useTypeAlias */))),
1247 fSetType(setType)
1248{
1249 if (!itemField->GetTypeAlias().empty())
1250 fTypeAlias = BuildSetTypeName(setType, *itemField, true /* useTypeAlias */);
1251
1252 fItemSize = itemField->GetValueSize();
1253
1254 Attach(std::move(itemField), "_0");
1255}
1256
1257std::unique_ptr<ROOT::RFieldBase> ROOT::RSetField::CloneImpl(std::string_view newName) const
1258{
1259 return std::make_unique<RSetField>(newName, fSetType, fSubfields[0]->Clone(fSubfields[0]->GetFieldName()));
1260}
1261
1263{
1264 static const std::vector<std::string> prefixesRegular = {"std::set<", "std::unordered_set<", "std::map<",
1265 "std::unordered_map<"};
1266
1267 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
1268
1269 switch (fSetType) {
1270 case ESetType::kSet:
1271 case ESetType::kUnorderedSet: EnsureMatchingTypePrefix(desc, prefixesRegular).ThrowOnError(); break;
1272 default:
1273 break;
1274 // no restrictions for multisets
1275 }
1276}
1277
1278//------------------------------------------------------------------------------
1279
1280namespace {
1281
1282/// Used in RStreamerField::AppendImpl() in order to record the encountered streamer info records
1283class TBufferRecStreamer : public TBufferFile {
1284public:
1285 using RCallbackStreamerInfo = std::function<void(TVirtualStreamerInfo *)>;
1286
1287private:
1288 RCallbackStreamerInfo fCallbackStreamerInfo;
1289
1290public:
1291 TBufferRecStreamer(TBuffer::EMode mode, Int_t bufsize, RCallbackStreamerInfo callbackStreamerInfo)
1292 : TBufferFile(mode, bufsize), fCallbackStreamerInfo(callbackStreamerInfo)
1293 {
1294 }
1295 void TagStreamerInfo(TVirtualStreamerInfo *info) final { fCallbackStreamerInfo(info); }
1296};
1297
1298} // anonymous namespace
1299
1300ROOT::RStreamerField::RStreamerField(std::string_view fieldName, std::string_view className)
1301 : RStreamerField(fieldName, EnsureValidClass(className))
1302{
1303}
1304
1305ROOT::RStreamerField::RStreamerField(std::string_view fieldName, TClass *classp)
1306 : ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(classp->GetName()), ROOT::ENTupleStructure::kStreamer,
1307 false /* isSimple */),
1308 fClass(classp),
1309 fIndex(0)
1310{
1311 std::string renormalizedAlias;
1312 if (Internal::NeedsMetaNameAsAlias(classp->GetName(), renormalizedAlias))
1313 fTypeAlias = renormalizedAlias;
1314
1316 // For RClassField, we only check for explicit constructors and destructors and then recursively combine traits from
1317 // all member subfields. For RStreamerField, we treat the class as a black box and additionally need to check for
1318 // implicit constructors and destructors.
1319 if (!(fClass->ClassProperty() & (kClassHasExplicitCtor | kClassHasImplicitCtor)))
1321 if (!(fClass->ClassProperty() & (kClassHasExplicitDtor | kClassHasImplicitDtor)))
1323}
1324
1325std::unique_ptr<ROOT::RFieldBase> ROOT::RStreamerField::CloneImpl(std::string_view newName) const
1326{
1327 return std::unique_ptr<RStreamerField>(new RStreamerField(newName, GetTypeName()));
1328}
1329
1330std::size_t ROOT::RStreamerField::AppendImpl(const void *from)
1331{
1332 TBufferRecStreamer buffer(TBuffer::kWrite, GetValueSize(),
1333 [this](TVirtualStreamerInfo *info) { fStreamerInfos[info->GetNumber()] = info; });
1334 fClass->Streamer(const_cast<void *>(from), buffer);
1335
1336 auto nbytes = buffer.Length();
1337 fAuxiliaryColumn->AppendV(buffer.Buffer(), buffer.Length());
1338 fIndex += nbytes;
1339 fPrincipalColumn->Append(&fIndex);
1340 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
1341}
1342
1344{
1345 RNTupleLocalIndex collectionStart;
1346 ROOT::NTupleSize_t nbytes;
1347 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nbytes);
1348
1349 TBufferFile buffer(TBuffer::kRead, nbytes);
1350 fAuxiliaryColumn->ReadV(collectionStart, nbytes, buffer.Buffer());
1351 fClass->Streamer(to, buffer);
1352}
1353
1363
1368
1373
1375{
1376 source.RegisterStreamerInfos();
1377 return nullptr;
1378}
1379
1384
1386{
1387 fClass->New(where);
1388}
1389
1391{
1392 fClass->Destructor(objPtr, true /* dtorOnly */);
1393 RDeleter::operator()(objPtr, dtorOnly);
1394}
1395
1405
1407{
1408 return std::min(alignof(std::max_align_t), GetValueSize()); // TODO(jblomer): fix me
1409}
1410
1412{
1413 return fClass->GetClassSize();
1414}
1415
1417{
1418 return fClass->GetClassVersion();
1419}
1420
1422{
1423 return fClass->GetCheckSum();
1424}
1425
1427{
1428 visitor.VisitStreamerField(*this);
1429}
1430
1431//------------------------------------------------------------------------------
1432
1434{
1435 if (auto dataMember = TObject::Class()->GetDataMember(name)) {
1436 return dataMember->GetOffset();
1437 }
1438 throw RException(R__FAIL('\'' + std::string(name) + '\'' + " is an invalid data member"));
1439}
1440
1441ROOT::RField<TObject>::RField(std::string_view fieldName, const RField<TObject> &source)
1442 : ROOT::RFieldBase(fieldName, "TObject", ROOT::ENTupleStructure::kRecord, false /* isSimple */)
1443{
1445 Attach(source.GetConstSubfields()[0]->Clone("fUniqueID"));
1446 Attach(source.GetConstSubfields()[1]->Clone("fBits"));
1447}
1448
1449ROOT::RField<TObject>::RField(std::string_view fieldName)
1450 : ROOT::RFieldBase(fieldName, "TObject", ROOT::ENTupleStructure::kRecord, false /* isSimple */)
1451{
1452 assert(TObject::Class()->GetClassVersion() == 1);
1453
1455 Attach(std::make_unique<RField<UInt_t>>("fUniqueID"));
1456 Attach(std::make_unique<RField<UInt_t>>("fBits"));
1457}
1458
1459std::unique_ptr<ROOT::RFieldBase> ROOT::RField<TObject>::CloneImpl(std::string_view newName) const
1460{
1461 return std::unique_ptr<RField<TObject>>(new RField<TObject>(newName, *this));
1462}
1463
1464std::size_t ROOT::RField<TObject>::AppendImpl(const void *from)
1465{
1466 // Cf. TObject::Streamer()
1467
1468 auto *obj = static_cast<const TObject *>(from);
1469 if (obj->TestBit(TObject::kIsReferenced)) {
1470 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
1471 }
1472
1473 std::size_t nbytes = 0;
1474 nbytes += CallAppendOn(*fSubfields[0], reinterpret_cast<const unsigned char *>(from) + GetOffsetUniqueID());
1475
1476 UInt_t bits = *reinterpret_cast<const UInt_t *>(reinterpret_cast<const unsigned char *>(from) + GetOffsetBits());
1477 bits &= (~TObject::kIsOnHeap & ~TObject::kNotDeleted);
1478 nbytes += CallAppendOn(*fSubfields[1], &bits);
1479
1480 return nbytes;
1481}
1482
1484{
1485 // Cf. TObject::Streamer()
1486
1487 auto *obj = static_cast<TObject *>(to);
1488 if (obj->TestBit(TObject::kIsReferenced)) {
1489 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
1490 }
1491
1492 *reinterpret_cast<UInt_t *>(reinterpret_cast<unsigned char *>(to) + GetOffsetUniqueID()) = uniqueID;
1493
1494 const UInt_t bitIsOnHeap = obj->TestBit(TObject::kIsOnHeap) ? TObject::kIsOnHeap : 0;
1495 bits |= bitIsOnHeap | TObject::kNotDeleted;
1496 *reinterpret_cast<UInt_t *>(reinterpret_cast<unsigned char *>(to) + GetOffsetBits()) = bits;
1497}
1498
1500{
1501 UInt_t uniqueID, bits;
1502 CallReadOn(*fSubfields[0], globalIndex, &uniqueID);
1503 CallReadOn(*fSubfields[1], globalIndex, &bits);
1504 ReadTObject(to, uniqueID, bits);
1505}
1506
1508{
1509 UInt_t uniqueID, bits;
1510 CallReadOn(*fSubfields[0], localIndex, &uniqueID);
1511 CallReadOn(*fSubfields[1], localIndex, &bits);
1512 ReadTObject(to, uniqueID, bits);
1513}
1514
1516{
1517 return TObject::Class()->GetClassVersion();
1518}
1519
1521{
1522 return TObject::Class()->GetCheckSum();
1523}
1524
1526{
1527 new (where) TObject();
1528}
1529
1530std::vector<ROOT::RFieldBase::RValue> ROOT::RField<TObject>::SplitValue(const RValue &value) const
1531{
1532 std::vector<RValue> result;
1533 // Use GetPtr<TObject> to type-check
1534 std::shared_ptr<void> ptr = value.GetPtr<TObject>();
1535 auto charPtr = static_cast<unsigned char *>(ptr.get());
1536 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(ptr, charPtr + GetOffsetUniqueID())));
1537 result.emplace_back(fSubfields[1]->BindValue(std::shared_ptr<void>(ptr, charPtr + GetOffsetBits())));
1538 return result;
1539}
1540
1542{
1543 return sizeof(TObject);
1544}
1545
1547{
1548 return alignof(TObject);
1549}
1550
1552{
1553 visitor.VisitTObjectField(*this);
1554}
1555
1556//------------------------------------------------------------------------------
1557
1558ROOT::RTupleField::RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
1559 : ROOT::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">")
1560{
1561 const std::string typeAlias = "std::tuple<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1562 if (typeAlias != GetTypeName())
1563 fTypeAlias = typeAlias;
1564
1565 AttachItemFields(std::move(itemFields));
1566
1567 auto *c = TClass::GetClass(GetTypeName().c_str());
1568 if (!c)
1569 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
1570 fSize = c->Size();
1571
1572 // ISO C++ does not guarantee neither specific layout nor member names for `std::tuple`. However, most
1573 // implementations including libstdc++ (gcc), libc++ (llvm), and MSVC name members as `_0`, `_1`, ..., `_N-1`,
1574 // following the order of the type list.
1575 // Use TClass to get their offsets; in case a particular `std::tuple` implementation does not define such
1576 // members, the assertion below will fail.
1577 for (unsigned i = 0; i < fSubfields.size(); ++i) {
1578 std::string memberName("_" + std::to_string(i));
1579 auto member = c->GetRealData(memberName.c_str());
1580 if (!member)
1581 throw RException(R__FAIL(memberName + ": no such member"));
1582 fOffsets.push_back(member->GetThisOffset());
1583 }
1584}
1585
1586std::unique_ptr<ROOT::RFieldBase> ROOT::RTupleField::CloneImpl(std::string_view newName) const
1587{
1588 std::vector<std::unique_ptr<RFieldBase>> itemClones;
1589 itemClones.reserve(fSubfields.size());
1590 for (const auto &f : fSubfields) {
1591 itemClones.emplace_back(f->Clone(f->GetFieldName()));
1592 }
1593 return std::unique_ptr<RTupleField>(new RTupleField(newName, std::move(itemClones)));
1594}
1595
1597{
1598 static const std::vector<std::string> prefixes = {"std::pair<", "std::tuple<"};
1599
1600 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
1601 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
1602
1603 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1604 const auto nOnDiskSubfields = fieldDesc.GetLinkIds().size();
1605 const auto nSubfields = fSubfields.size();
1606 if (nOnDiskSubfields != nSubfields) {
1607 throw ROOT::RException(R__FAIL("invalid number of on-disk subfields for std::tuple " +
1608 std::to_string(nOnDiskSubfields) + " vs. " + std::to_string(nSubfields) + "\n" +
1609 Internal::GetTypeTraceReport(*this, desc)));
1610 }
1611}
1612
1613//------------------------------------------------------------------------------
1614
1615namespace {
1616
1617// Depending on the compiler, the variant tag is stored either in a trailing char or in a trailing unsigned int
1618constexpr std::size_t GetVariantTagSize()
1619{
1620 // Should be all zeros except for the tag, which is 1
1621 std::variant<char> t;
1622 constexpr auto sizeOfT = sizeof(t);
1623
1624 static_assert(sizeOfT == 2 || sizeOfT == 8, "unsupported std::variant layout");
1625 return sizeOfT == 2 ? 1 : 4;
1626}
1627
1628template <std::size_t VariantSizeT>
1629struct RVariantTag {
1630 using ValueType_t = typename std::conditional_t<VariantSizeT == 1, std::uint8_t,
1631 typename std::conditional_t<VariantSizeT == 4, std::uint32_t, void>>;
1632};
1633
1634} // anonymous namespace
1635
1637 : ROOT::RFieldBase(name, source.GetTypeName(), ROOT::ENTupleStructure::kVariant, false /* isSimple */),
1638 fMaxItemSize(source.fMaxItemSize),
1640 fTagOffset(source.fTagOffset),
1642 fNWritten(source.fNWritten.size(), 0)
1643{
1644 for (const auto &f : source.GetConstSubfields())
1645 Attach(f->Clone(f->GetFieldName()));
1646 fTraits = source.fTraits;
1647}
1648
1649ROOT::RVariantField::RVariantField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
1650 : ROOT::RFieldBase(fieldName, "std::variant<" + GetTypeList(itemFields, false /* useTypeAliases */) + ">",
1651 ROOT::ENTupleStructure::kVariant, false /* isSimple */)
1652{
1653 // The variant needs to initialize its own tag member
1655
1656 const std::string typeAlias = "std::variant<" + GetTypeList(itemFields, true /* useTypeAliases */) + ">";
1657 if (typeAlias != GetTypeName())
1658 fTypeAlias = typeAlias;
1659
1660 auto nFields = itemFields.size();
1661 if (nFields == 0 || nFields > kMaxVariants) {
1662 throw RException(R__FAIL("invalid number of variant fields (outside [1.." + std::to_string(kMaxVariants) + ")"));
1663 }
1664 fNWritten.resize(nFields, 0);
1665 for (unsigned int i = 0; i < nFields; ++i) {
1666 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
1667 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
1668 fTraits &= itemFields[i]->GetTraits();
1669 Attach(std::move(itemFields[i]), "_" + std::to_string(i));
1670 }
1671
1672 // With certain template parameters, the union of members of an std::variant starts at an offset > 0.
1673 // For instance, std::variant<std::optional<int>> on macOS.
1674 auto cl = TClass::GetClass(GetTypeName().c_str());
1675 assert(cl);
1676 auto dm = reinterpret_cast<TDataMember *>(cl->GetListOfDataMembers()->First());
1677 if (dm)
1678 fVariantOffset = dm->GetOffset();
1679
1680 const auto tagSize = GetVariantTagSize();
1681 const auto padding = tagSize - (fMaxItemSize % tagSize);
1682 fTagOffset = fVariantOffset + fMaxItemSize + ((padding == tagSize) ? 0 : padding);
1683}
1684
1685std::unique_ptr<ROOT::RFieldBase> ROOT::RVariantField::CloneImpl(std::string_view newName) const
1686{
1687 return std::unique_ptr<RVariantField>(new RVariantField(newName, *this));
1688}
1689
1690std::uint8_t ROOT::RVariantField::GetTag(const void *variantPtr, std::size_t tagOffset)
1691{
1692 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
1693 auto tag = *reinterpret_cast<const TagType_t *>(reinterpret_cast<const unsigned char *>(variantPtr) + tagOffset);
1694 return (tag == TagType_t(-1)) ? 0 : tag + 1;
1695}
1696
1697void ROOT::RVariantField::SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag)
1698{
1699 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
1700 auto tagPtr = reinterpret_cast<TagType_t *>(reinterpret_cast<unsigned char *>(variantPtr) + tagOffset);
1701 *tagPtr = (tag == 0) ? TagType_t(-1) : static_cast<TagType_t>(tag - 1);
1702}
1703
1704std::size_t ROOT::RVariantField::AppendImpl(const void *from)
1705{
1706 auto tag = GetTag(from, fTagOffset);
1707 std::size_t nbytes = 0;
1708 auto index = 0;
1709 if (tag > 0) {
1710 nbytes += CallAppendOn(*fSubfields[tag - 1], reinterpret_cast<const unsigned char *>(from) + fVariantOffset);
1711 index = fNWritten[tag - 1]++;
1712 }
1713 ROOT::Internal::RColumnSwitch varSwitch(index, tag);
1714 fPrincipalColumn->Append(&varSwitch);
1715 return nbytes + sizeof(ROOT::Internal::RColumnSwitch);
1716}
1717
1719{
1720 RNTupleLocalIndex variantIndex;
1721 std::uint32_t tag;
1722 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
1723 R__ASSERT(tag < 256);
1724
1725 // If `tag` equals 0, the variant is in the invalid state, i.e, it does not hold any of the valid alternatives in
1726 // the type list. This happens, e.g., if the field was late added; in this case, keep the invalid tag, which makes
1727 // any `std::holds_alternative<T>` check fail later.
1728 if (R__likely(tag > 0)) {
1729 void *varPtr = reinterpret_cast<unsigned char *>(to) + fVariantOffset;
1730 CallConstructValueOn(*fSubfields[tag - 1], varPtr);
1731 CallReadOn(*fSubfields[tag - 1], variantIndex, varPtr);
1732 }
1733 SetTag(to, fTagOffset, tag);
1734}
1735
1737{
1738 static RColumnRepresentations representations({{ENTupleColumnType::kSwitch}}, {});
1739 return representations;
1740}
1741
1746
1751
1753{
1754 static const std::vector<std::string> prefixes = {"std::variant<"};
1755
1756 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
1757 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
1758
1759 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1760 if (fSubfields.size() != fieldDesc.GetLinkIds().size()) {
1761 throw RException(R__FAIL("number of variants on-disk do not match for " + GetQualifiedFieldName() + "\n" +
1762 Internal::GetTypeTraceReport(*this, desc)));
1763 }
1764}
1765
1767{
1768 memset(where, 0, GetValueSize());
1769 CallConstructValueOn(*fSubfields[0], reinterpret_cast<unsigned char *>(where) + fVariantOffset);
1770 SetTag(where, fTagOffset, 1);
1771}
1772
1774{
1775 auto tag = GetTag(objPtr, fTagOffset);
1776 if (tag > 0) {
1777 fItemDeleters[tag - 1]->operator()(reinterpret_cast<unsigned char *>(objPtr) + fVariantOffset, true /*dtorOnly*/);
1778 }
1779 RDeleter::operator()(objPtr, dtorOnly);
1780}
1781
1782std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVariantField::GetDeleter() const
1783{
1784 std::vector<std::unique_ptr<RDeleter>> itemDeleters;
1785 itemDeleters.reserve(fSubfields.size());
1786 for (const auto &f : fSubfields) {
1787 itemDeleters.emplace_back(GetDeleterOf(*f));
1788 }
1789 return std::make_unique<RVariantDeleter>(fTagOffset, fVariantOffset, std::move(itemDeleters));
1790}
1791
1793{
1794 return std::max(fMaxAlignment, alignof(RVariantTag<GetVariantTagSize()>::ValueType_t));
1795}
1796
1798{
1799 const auto alignment = GetAlignment();
1800 const auto actualSize = fTagOffset + GetVariantTagSize();
1801 const auto padding = alignment - (actualSize % alignment);
1802 return actualSize + ((padding == alignment) ? 0 : padding);
1803}
1804
1806{
1807 std::fill(fNWritten.begin(), fNWritten.end(), 0);
1808}
#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:300
#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
if(isa< VarDecl >(D)||isa< FieldDecl >(D)||isa< EnumConstantDecl >(D))
Definition TCling.cxx:7039
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
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 r
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
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 Atom_t Time_t type
char name[80]
Definition TGX11.cxx:148
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:69
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:66
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:71
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. This is necessary whe...
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor. Multiple threads can take the lock concurrently....
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:177
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:168
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
Additional information kept for each entry in fSubfields
Definition RField.hxx:167
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:172
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:224
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
TClass * fClass
Definition RField.hxx:165
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:178
static constexpr const char * kPrefixInherited
Prefix used in the subfield names generated for base classes.
Definition RField.hxx:154
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: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.
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
@ 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.
@ 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.
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
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.
std::string fTypeAlias
A typedef or using name that was used when creating the field.
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:520
static std::size_t GetOffsetUniqueID()
Definition RField.hxx:519
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:321
RField(std::string_view name)
Definition RField.hxx:324
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
const std::string & GetName() 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:573
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:248
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:249
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 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:36
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.
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:151
std::unique_ptr< RFieldBase > fField
The field used to read the on-disk data.
Definition RField.hxx:150