Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldMeta.cxx
Go to the documentation of this file.
1/// \file RFieldMeta.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
4/// \date 2024-11-19
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8// This file has concrete RField implementations that depend on ROOT Meta:
9// - RClassField
10// - REnumField
11// - RPairField
12// - RProxiedCollectionField
13// - RMapField
14// - RSetField
15// - RStreamerField
16// - RPairField
17// - RField<TObject>
18// - RVariantField
19
20#include <ROOT/RField.hxx>
21#include <ROOT/RFieldBase.hxx>
22#include "RFieldUtils.hxx"
24#include <ROOT/RSpan.hxx>
25
26#include <TBaseClass.h>
27#include <TBufferFile.h>
28#include <TClass.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 <TVirtualObject.h>
39
40#include <algorithm>
41#include <array>
42#include <cstddef> // std::size_t
43#include <cstdint> // std::uint32_t et al.
44#include <cstring> // for memset
45#include <memory>
46#include <string>
47#include <string_view>
48#include <utility>
49#include <variant>
50
51ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, const RClassField &source)
52 : ROOT::Experimental::RFieldBase(fieldName, source.GetTypeName(), ENTupleStructure::kRecord, false /* isSimple */),
53 fClass(source.fClass),
54 fSubFieldsInfo(source.fSubFieldsInfo),
55 fMaxAlignment(source.fMaxAlignment)
56{
57 for (const auto &f : source.GetSubFields()) {
58 RFieldBase::Attach(f->Clone(f->GetFieldName()));
59 }
60 fTraits = source.GetTraits();
61}
62
63ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className)
64 : RClassField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
65{
66}
67
68ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
69 : ROOT::Experimental::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */),
70 fClass(classp)
71{
72 if (fClass == nullptr) {
73 throw RException(R__FAIL("RField: no I/O support for type " + std::string(className)));
74 }
75 // Avoid accidentally supporting std types through TClass.
77 throw RException(R__FAIL(std::string(className) + " is not supported"));
78 }
79 if (className == "TObject") {
80 throw RException(R__FAIL("TObject is only supported through RField<TObject>"));
81 }
83 throw RException(
84 R__FAIL(std::string(className) + " has an associated collection proxy; use RProxiedCollectionField instead"));
85 }
86 // Classes with, e.g., custom streamers are not supported through this field. Empty classes, however, are.
87 // Can be overwritten with the "rntuple.streamerMode=true" class attribute
88 if (!fClass->CanSplit() && fClass->Size() > 1 &&
90 throw RException(R__FAIL(std::string(className) + " cannot be stored natively in RNTuple"));
91 }
93 throw RException(
94 R__FAIL(std::string(className) + " has streamer mode enforced, not supported as native RNTuple class"));
95 }
96
101
102 int i = 0;
104 if (baseClass->GetDelta() < 0) {
105 throw RException(R__FAIL(std::string("virtual inheritance is not supported: ") + std::string(className) +
106 " virtually inherits from " + baseClass->GetName()));
107 }
108 TClass *c = baseClass->GetClassPointer();
109 auto subField =
110 RFieldBase::Create(std::string(kPrefixInherited) + "_" + std::to_string(i), c->GetName()).Unwrap();
111 fTraits &= subField->GetTraits();
112 Attach(std::move(subField), RSubFieldInfo{kBaseClass, static_cast<std::size_t>(baseClass->GetDelta())});
113 i++;
114 }
116 // Skip, for instance, unscoped enum constants defined in the class
117 if (dataMember->Property() & kIsStatic)
118 continue;
119 // Skip members explicitly marked as transient by user comment
120 if (!dataMember->IsPersistent()) {
121 // TODO(jblomer): we could do better
123 continue;
124 }
125
126 std::string typeName{Internal::GetNormalizedTypeName(dataMember->GetTrueTypeName())};
127 std::string typeAlias{Internal::GetNormalizedTypeName(dataMember->GetFullTypeName())};
128
129 // For C-style arrays, complete the type name with the size for each dimension, e.g. `int[4][2]`
130 if (dataMember->Property() & kIsArray) {
131 for (int dim = 0, n = dataMember->GetArrayDim(); dim < n; ++dim)
132 typeName += "[" + std::to_string(dataMember->GetMaxIndex(dim)) + "]";
133 }
134
135 std::unique_ptr<RFieldBase> subField;
136
137 subField = RFieldBase::Create(dataMember->GetName(), typeName, typeAlias).Unwrap();
138 fTraits &= subField->GetTraits();
139 Attach(std::move(subField), RSubFieldInfo{kDataMember, static_cast<std::size_t>(dataMember->GetOffset())});
140 }
142}
143
144void ROOT::Experimental::RClassField::Attach(std::unique_ptr<RFieldBase> child, RSubFieldInfo info)
145{
146 fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
147 fSubFieldsInfo.push_back(info);
148 RFieldBase::Attach(std::move(child));
149}
150
151void ROOT::Experimental::RClassField::AddReadCallbacksFromIORules(const std::span<const ROOT::TSchemaRule *> rules,
152 TClass *classp)
153{
154 for (const auto rule : rules) {
155 if (rule->GetRuleType() != ROOT::TSchemaRule::kReadRule) {
156 R__LOG_WARNING(NTupleLog()) << "ignoring I/O customization rule with unsupported type";
157 continue;
158 }
159 auto func = rule->GetReadFunctionPointer();
160 R__ASSERT(func != nullptr);
161 fReadCallbacks.emplace_back([func, classp](void *target) {
162 TVirtualObject oldObj{nullptr};
163 oldObj.fClass = classp;
164 oldObj.fObject = target;
165 func(static_cast<char *>(target), &oldObj);
166 oldObj.fClass = nullptr; // TVirtualObject does not own the value
167 });
168 }
169}
170
171std::unique_ptr<ROOT::Experimental::RFieldBase>
172ROOT::Experimental::RClassField::CloneImpl(std::string_view newName) const
173{
174 return std::unique_ptr<RClassField>(new RClassField(newName, *this));
175}
176
178{
179 std::size_t nbytes = 0;
180 for (unsigned i = 0; i < fSubFields.size(); i++) {
181 nbytes += CallAppendOn(*fSubFields[i], static_cast<const unsigned char *>(from) + fSubFieldsInfo[i].fOffset);
182 }
183 return nbytes;
184}
185
187{
188 for (unsigned i = 0; i < fSubFields.size(); i++) {
189 CallReadOn(*fSubFields[i], globalIndex, static_cast<unsigned char *>(to) + fSubFieldsInfo[i].fOffset);
190 }
191}
192
194{
195 for (unsigned i = 0; i < fSubFields.size(); i++) {
196 CallReadOn(*fSubFields[i], clusterIndex, static_cast<unsigned char *>(to) + fSubFieldsInfo[i].fOffset);
197 }
198}
199
201{
202 // Add post-read callbacks for I/O customization rules; only rules that target transient members are allowed for now
203 // TODO(jalopezg): revise after supporting schema evolution
204 const auto ruleset = fClass->GetSchemaRules();
205 if (!ruleset)
206 return;
207 auto referencesNonTransientMembers = [klass = fClass](const ROOT::TSchemaRule *rule) {
208 if (rule->GetTarget() == nullptr)
209 return false;
210 for (auto target : ROOT::Detail::TRangeStaticCast<TObjString>(*rule->GetTarget())) {
211 const auto dataMember = klass->GetDataMember(target->GetString());
212 if (!dataMember || dataMember->IsPersistent()) {
213 R__LOG_WARNING(NTupleLog()) << "ignoring I/O customization rule with non-transient member: "
214 << dataMember->GetName();
215 return true;
216 }
217 }
218 return false;
219 };
220
221 auto rules = ruleset->FindRules(fClass->GetName(), static_cast<Int_t>(GetOnDiskTypeVersion()),
222 static_cast<UInt_t>(GetOnDiskTypeChecksum()));
223 rules.erase(std::remove_if(rules.begin(), rules.end(), referencesNonTransientMembers), rules.end());
224 AddReadCallbacksFromIORules(rules, fClass);
225}
226
228{
229 fClass->New(where);
230}
231
233{
234 fClass->Destructor(objPtr, true /* dtorOnly */);
235 RDeleter::operator()(objPtr, dtorOnly);
236}
237
238std::vector<ROOT::Experimental::RFieldBase::RValue>
240{
241 std::vector<RValue> result;
242 auto basePtr = value.GetPtr<unsigned char>().get();
243 result.reserve(fSubFields.size());
244 for (unsigned i = 0; i < fSubFields.size(); i++) {
245 result.emplace_back(
246 fSubFields[i]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + fSubFieldsInfo[i].fOffset)));
247 }
248 return result;
249}
250
252{
253 return fClass->GetClassSize();
254}
255
257{
258 return fClass->GetClassVersion();
259}
260
262{
263 return fClass->GetCheckSum();
264}
265
267{
268 visitor.VisitClassField(*this);
269}
270
271//------------------------------------------------------------------------------
272
273ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName)
274 : REnumField(fieldName, enumName, TEnum::GetEnum(std::string(enumName).c_str()))
275{
276}
277
278ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName, TEnum *enump)
279 : ROOT::Experimental::RFieldBase(fieldName, enumName, ENTupleStructure::kLeaf, false /* isSimple */)
280{
281 if (enump == nullptr) {
282 throw RException(R__FAIL("RField: no I/O support for enum type " + std::string(enumName)));
283 }
284 // Avoid accidentally supporting std types through TEnum.
285 if (enump->Property() & kIsDefinedInStd) {
286 throw RException(R__FAIL(std::string(enumName) + " is not supported"));
287 }
288
289 switch (enump->GetUnderlyingType()) {
290 case kChar_t: Attach(std::make_unique<RField<int8_t>>("_0")); break;
291 case kUChar_t: Attach(std::make_unique<RField<uint8_t>>("_0")); break;
292 case kShort_t: Attach(std::make_unique<RField<int16_t>>("_0")); break;
293 case kUShort_t: Attach(std::make_unique<RField<uint16_t>>("_0")); break;
294 case kInt_t: Attach(std::make_unique<RField<int32_t>>("_0")); break;
295 case kUInt_t: Attach(std::make_unique<RField<uint32_t>>("_0")); break;
296 case kLong_t:
297 case kLong64_t: Attach(std::make_unique<RField<int64_t>>("_0")); break;
298 case kULong_t:
299 case kULong64_t: Attach(std::make_unique<RField<uint64_t>>("_0")); break;
300 default: throw RException(R__FAIL("Unsupported underlying integral type for enum type " + std::string(enumName)));
301 }
302
304}
305
306ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName,
307 std::unique_ptr<RFieldBase> intField)
308 : ROOT::Experimental::RFieldBase(fieldName, enumName, ENTupleStructure::kLeaf, false /* isSimple */)
309{
310 Attach(std::move(intField));
312}
313
314std::unique_ptr<ROOT::Experimental::RFieldBase>
315ROOT::Experimental::REnumField::CloneImpl(std::string_view newName) const
316{
317 auto newIntField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
318 return std::unique_ptr<REnumField>(new REnumField(newName, GetTypeName(), std::move(newIntField)));
319}
320
321std::vector<ROOT::Experimental::RFieldBase::RValue>
323{
324 std::vector<RValue> result;
325 result.emplace_back(fSubFields[0]->BindValue(value.GetPtr<void>()));
326 return result;
327}
328
330{
331 visitor.VisitEnumField(*this);
332}
333
334//------------------------------------------------------------------------------
335
336std::string
337ROOT::Experimental::RPairField::RPairField::GetTypeList(const std::array<std::unique_ptr<RFieldBase>, 2> &itemFields)
338{
339 return itemFields[0]->GetTypeName() + "," + itemFields[1]->GetTypeName();
340}
341
343 std::array<std::unique_ptr<RFieldBase>, 2> itemFields,
344 const std::array<std::size_t, 2> &offsets)
345 : ROOT::Experimental::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields) + ">")
346{
347 AttachItemFields(std::move(itemFields));
348 fOffsets.push_back(offsets[0]);
349 fOffsets.push_back(offsets[1]);
350}
351
353 std::array<std::unique_ptr<RFieldBase>, 2> itemFields)
354 : ROOT::Experimental::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields) + ">")
355{
356 AttachItemFields(std::move(itemFields));
357
358 // ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
359 auto *c = TClass::GetClass(GetTypeName().c_str());
360 if (!c)
361 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
362 fSize = c->Size();
363
364 auto firstElem = c->GetRealData("first");
365 if (!firstElem)
366 throw RException(R__FAIL("first: no such member"));
367 fOffsets.push_back(firstElem->GetThisOffset());
368
369 auto secondElem = c->GetRealData("second");
370 if (!secondElem)
371 throw RException(R__FAIL("second: no such member"));
372 fOffsets.push_back(secondElem->GetThisOffset());
373}
374
375//------------------------------------------------------------------------------
376
379 bool readFromDisk)
380{
381 RIteratorFuncs ifuncs;
382 ifuncs.fCreateIterators = proxy->GetFunctionCreateIterators(readFromDisk);
383 ifuncs.fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(readFromDisk);
384 ifuncs.fNext = proxy->GetFunctionNext(readFromDisk);
385 R__ASSERT((ifuncs.fCreateIterators != nullptr) && (ifuncs.fDeleteTwoIterators != nullptr) &&
386 (ifuncs.fNext != nullptr));
387 return ifuncs;
388}
389
391 std::string_view typeName, TClass *classp)
392 : RFieldBase(fieldName, typeName, ENTupleStructure::kCollection, false /* isSimple */), fNWritten(0)
393{
394 if (classp == nullptr)
395 throw RException(R__FAIL("RField: no I/O support for collection proxy type " + std::string(typeName)));
396 if (!classp->GetCollectionProxy())
397 throw RException(R__FAIL(std::string(typeName) + " has no associated collection proxy"));
398
399 fProxy.reset(classp->GetCollectionProxy()->Generate());
400 fProperties = fProxy->GetProperties();
401 fCollectionType = fProxy->GetCollectionType();
402 if (fProxy->HasPointers())
403 throw RException(R__FAIL("collection proxies whose value type is a pointer are not supported"));
404 if (!fProxy->GetCollectionClass()->HasDictionary()) {
405 throw RException(R__FAIL("dictionary not available for type " +
406 Internal::GetNormalizedTypeName(fProxy->GetCollectionClass()->GetName())));
407 }
408
409 fIFuncsRead = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), true /* readFromDisk */);
410 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readFromDisk */);
411}
412
414 std::string_view typeName,
415 std::unique_ptr<RFieldBase> itemField)
416 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
417{
418 fItemSize = itemField->GetValueSize();
419 Attach(std::move(itemField));
420}
421
423 std::string_view typeName)
424 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
425{
426 // NOTE (fdegeus): std::map is supported, custom associative might be supported in the future if the need arises.
428 throw RException(R__FAIL("custom associative collection proxies not supported"));
429
430 std::unique_ptr<ROOT::Experimental::RFieldBase> itemField;
431
432 if (auto valueClass = fProxy->GetValueClass()) {
433 // Element type is a class
434 itemField = RFieldBase::Create("_0", valueClass->GetName()).Unwrap();
435 } else {
436 switch (fProxy->GetType()) {
437 case EDataType::kChar_t: itemField = std::make_unique<RField<char>>("_0"); break;
438 case EDataType::kUChar_t: itemField = std::make_unique<RField<std::uint8_t>>("_0"); break;
439 case EDataType::kShort_t: itemField = std::make_unique<RField<std::int16_t>>("_0"); break;
440 case EDataType::kUShort_t: itemField = std::make_unique<RField<std::uint16_t>>("_0"); break;
441 case EDataType::kInt_t: itemField = std::make_unique<RField<std::int32_t>>("_0"); break;
442 case EDataType::kUInt_t: itemField = std::make_unique<RField<std::uint32_t>>("_0"); break;
444 case EDataType::kLong64_t: itemField = std::make_unique<RField<std::int64_t>>("_0"); break;
446 case EDataType::kULong64_t: itemField = std::make_unique<RField<std::uint64_t>>("_0"); break;
447 case EDataType::kFloat_t: itemField = std::make_unique<RField<float>>("_0"); break;
448 case EDataType::kDouble_t: itemField = std::make_unique<RField<double>>("_0"); break;
449 case EDataType::kBool_t: itemField = std::make_unique<RField<bool>>("_0"); break;
450 default: throw RException(R__FAIL("unsupported value type"));
451 }
452 }
453
454 fItemSize = itemField->GetValueSize();
455 Attach(std::move(itemField));
456}
457
458std::unique_ptr<ROOT::Experimental::RFieldBase>
460{
461 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
462 return std::unique_ptr<RProxiedCollectionField>(
463 new RProxiedCollectionField(newName, GetTypeName(), std::move(newItemField)));
464}
465
467{
468 std::size_t nbytes = 0;
469 unsigned count = 0;
470 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), const_cast<void *>(from));
471 for (auto ptr : RCollectionIterableOnce{const_cast<void *>(from), fIFuncsWrite, fProxy.get(),
472 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
473 nbytes += CallAppendOn(*fSubFields[0], ptr);
474 count++;
475 }
476
477 fNWritten += count;
478 fPrincipalColumn->Append(&fNWritten);
479 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
480}
481
483{
484 ClusterSize_t nItems;
485 RClusterIndex collectionStart;
486 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
487
488 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), to);
489 void *obj =
490 fProxy->Allocate(static_cast<std::uint32_t>(nItems), (fProperties & TVirtualCollectionProxy::kNeedDelete));
491
492 unsigned i = 0;
493 for (auto elementPtr : RCollectionIterableOnce{obj, fIFuncsRead, fProxy.get(),
494 (fCollectionType == kSTLvector || obj != to ? fItemSize : 0U)}) {
495 CallReadOn(*fSubFields[0], collectionStart + (i++), elementPtr);
496 }
497 if (obj != to)
498 fProxy->Commit(obj);
499}
500
503{
504 static RColumnRepresentations representations(
506 {});
507 return representations;
508}
509
511{
512 GenerateColumnsImpl<ClusterSize_t>();
513}
514
516{
517 GenerateColumnsImpl<ClusterSize_t>(desc);
518}
519
521{
522 fProxy->New(where);
523}
524
525std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter>
527{
528 if (fProperties & TVirtualCollectionProxy::kNeedDelete) {
529 std::size_t itemSize = fCollectionType == kSTLvector ? fItemSize : 0U;
530 return std::make_unique<RProxiedCollectionDeleter>(fProxy, GetDeleterOf(*fSubFields[0]), itemSize);
531 }
532 return std::make_unique<RProxiedCollectionDeleter>(fProxy);
533}
534
536{
537 if (fItemDeleter) {
538 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), objPtr);
539 for (auto ptr : RCollectionIterableOnce{objPtr, fIFuncsWrite, fProxy.get(), fItemSize}) {
540 fItemDeleter->operator()(ptr, true /* dtorOnly */);
541 }
542 }
543 fProxy->Destructor(objPtr, true /* dtorOnly */);
544 RDeleter::operator()(objPtr, dtorOnly);
545}
546
547std::vector<ROOT::Experimental::RFieldBase::RValue>
549{
550 std::vector<RValue> result;
551 auto valueRawPtr = value.GetPtr<void>().get();
552 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), valueRawPtr);
553 for (auto ptr : RCollectionIterableOnce{valueRawPtr, fIFuncsWrite, fProxy.get(),
554 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
555 result.emplace_back(fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), ptr)));
556 }
557 return result;
558}
559
561{
562 visitor.VisitProxiedCollectionField(*this);
563}
564
565//------------------------------------------------------------------------------
566
567ROOT::Experimental::RMapField::RMapField(std::string_view fieldName, std::string_view typeName,
568 std::unique_ptr<RFieldBase> itemField)
569 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
570{
571 if (!dynamic_cast<RPairField *>(itemField.get()))
572 throw RException(R__FAIL("RMapField inner field type must be of RPairField"));
573
574 auto *itemClass = fProxy->GetValueClass();
575 fItemSize = itemClass->GetClassSize();
576
577 Attach(std::move(itemField));
578}
579
580//------------------------------------------------------------------------------
581
582ROOT::Experimental::RSetField::RSetField(std::string_view fieldName, std::string_view typeName,
583 std::unique_ptr<RFieldBase> itemField)
584 : ROOT::Experimental::RProxiedCollectionField(fieldName, typeName, std::move(itemField))
585{
586}
587
588//------------------------------------------------------------------------------
589
590namespace {
591
592/// Used in RStreamerField::AppendImpl() in order to record the encountered streamer info records
593class TBufferRecStreamer : public TBufferFile {
594public:
595 using RCallbackStreamerInfo = std::function<void(TVirtualStreamerInfo *)>;
596
597private:
598 RCallbackStreamerInfo fCallbackStreamerInfo;
599
600public:
601 TBufferRecStreamer(TBuffer::EMode mode, Int_t bufsiz, RCallbackStreamerInfo callbackStreamerInfo)
602 : TBufferFile(mode, bufsiz), fCallbackStreamerInfo(callbackStreamerInfo)
603 {
604 }
605 void TagStreamerInfo(TVirtualStreamerInfo *info) final { fCallbackStreamerInfo(info); }
606};
607
608} // anonymous namespace
609
610ROOT::Experimental::RStreamerField::RStreamerField(std::string_view fieldName, std::string_view className,
611 std::string_view typeAlias)
612 : RStreamerField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
613{
614 fTypeAlias = typeAlias;
615}
616
617ROOT::Experimental::RStreamerField::RStreamerField(std::string_view fieldName, std::string_view className,
618 TClass *classp)
619 : ROOT::Experimental::RFieldBase(fieldName, className, ENTupleStructure::kStreamer, false /* isSimple */),
620 fClass(classp),
621 fIndex(0)
622{
623 if (fClass == nullptr) {
624 throw RException(R__FAIL("RStreamerField: no I/O support for type " + std::string(className)));
625 }
626
632}
633
634std::unique_ptr<ROOT::Experimental::RFieldBase>
636{
637 return std::unique_ptr<RStreamerField>(new RStreamerField(newName, GetTypeName(), GetTypeAlias()));
638}
639
641{
642 TBufferRecStreamer buffer(TBuffer::kWrite, GetValueSize(),
643 [this](TVirtualStreamerInfo *info) { fStreamerInfos[info->GetNumber()] = info; });
644 fClass->Streamer(const_cast<void *>(from), buffer);
645
646 auto nbytes = buffer.Length();
647 fAuxiliaryColumn->AppendV(buffer.Buffer(), buffer.Length());
648 fIndex += nbytes;
649 fPrincipalColumn->Append(&fIndex);
650 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
651}
652
654{
655 RClusterIndex collectionStart;
656 ClusterSize_t nbytes;
657 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nbytes);
658
659 TBufferFile buffer(TBuffer::kRead, nbytes);
660 fAuxiliaryColumn->ReadV(collectionStart, nbytes, buffer.Buffer());
661 fClass->Streamer(to, buffer);
662}
663
666{
671 {});
672 return representations;
673}
674
676{
677 GenerateColumnsImpl<ClusterSize_t, std::byte>();
678}
679
681{
682 GenerateColumnsImpl<ClusterSize_t, std::byte>(desc);
683}
684
686{
687 fClass->New(where);
688}
689
691{
692 fClass->Destructor(objPtr, true /* dtorOnly */);
693 RDeleter::operator()(objPtr, dtorOnly);
694}
695
697{
699 extraTypeInfoBuilder.ContentId(EExtraTypeInfoIds::kStreamerInfo)
700 .TypeVersion(GetTypeVersion())
701 .TypeName(GetTypeName())
703 return extraTypeInfoBuilder.MoveDescriptor().Unwrap();
704}
705
707{
708 return std::min(alignof(std::max_align_t), GetValueSize()); // TODO(jblomer): fix me
709}
710
712{
713 return fClass->GetClassSize();
714}
715
717{
718 return fClass->GetClassVersion();
719}
720
722{
723 return fClass->GetCheckSum();
724}
725
727{
728 visitor.VisitStreamerField(*this);
729}
730
731//------------------------------------------------------------------------------
732
734{
735 if (auto dataMember = TObject::Class()->GetDataMember(name)) {
736 return dataMember->GetOffset();
737 }
738 throw RException(R__FAIL('\'' + std::string(name) + '\'' + " is an invalid data member"));
739}
740
741ROOT::Experimental::RField<TObject>::RField(std::string_view fieldName, const RField<TObject> &source)
742 : ROOT::Experimental::RFieldBase(fieldName, "TObject", ENTupleStructure::kRecord, false /* isSimple */)
743{
745 Attach(source.GetSubFields()[0]->Clone("fUniqueID"));
746 Attach(source.GetSubFields()[1]->Clone("fBits"));
747}
748
750 : ROOT::Experimental::RFieldBase(fieldName, "TObject", ENTupleStructure::kRecord, false /* isSimple */)
751{
752 assert(TObject::Class()->GetClassVersion() == 1);
753
755 Attach(std::make_unique<RField<UInt_t>>("fUniqueID"));
756 Attach(std::make_unique<RField<UInt_t>>("fBits"));
757}
758
759std::unique_ptr<ROOT::Experimental::RFieldBase>
761{
762 return std::unique_ptr<RField<TObject>>(new RField<TObject>(newName, *this));
763}
764
766{
767 // Cf. TObject::Streamer()
768
769 auto *obj = static_cast<const TObject *>(from);
770 if (obj->TestBit(TObject::kIsReferenced)) {
771 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
772 }
773
774 std::size_t nbytes = 0;
775 nbytes += CallAppendOn(*fSubFields[0], reinterpret_cast<const unsigned char *>(from) + GetOffsetUniqueID());
776
777 UInt_t bits = *reinterpret_cast<const UInt_t *>(reinterpret_cast<const unsigned char *>(from) + GetOffsetBits());
778 bits &= (~TObject::kIsOnHeap & ~TObject::kNotDeleted);
779 nbytes += CallAppendOn(*fSubFields[1], &bits);
780
781 return nbytes;
782}
783
785{
786 // Cf. TObject::Streamer()
787
788 auto *obj = static_cast<TObject *>(to);
789 if (obj->TestBit(TObject::kIsReferenced)) {
790 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
791 }
792
793 CallReadOn(*fSubFields[0], globalIndex, static_cast<unsigned char *>(to) + GetOffsetUniqueID());
794
795 const UInt_t bitIsOnHeap = obj->TestBit(TObject::kIsOnHeap) ? TObject::kIsOnHeap : 0;
796 UInt_t bits;
797 CallReadOn(*fSubFields[1], globalIndex, &bits);
798 bits |= bitIsOnHeap | TObject::kNotDeleted;
799 *reinterpret_cast<UInt_t *>(reinterpret_cast<unsigned char *>(to) + GetOffsetBits()) = bits;
800}
801
803{
804 if (GetTypeVersion() != 1) {
805 throw RException(R__FAIL("unsupported on-disk version of TObject: " + std::to_string(GetTypeVersion())));
806 }
807}
808
810{
812}
813
815{
816 return TObject::Class()->GetCheckSum();
817}
818
820{
821 new (where) TObject();
822}
823
824std::vector<ROOT::Experimental::RFieldBase::RValue>
826{
827 std::vector<RValue> result;
828 auto basePtr = value.GetPtr<unsigned char>().get();
829 result.emplace_back(
830 fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + GetOffsetUniqueID())));
831 result.emplace_back(
832 fSubFields[1]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + GetOffsetBits())));
833 return result;
834}
835
837{
838 return sizeof(TObject);
839}
840
842{
843 return alignof(TObject);
844}
845
847{
848 visitor.VisitTObjectField(*this);
849}
850
851//------------------------------------------------------------------------------
852
853std::string
854ROOT::Experimental::RTupleField::RTupleField::GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields)
855{
856 std::string result;
857 if (itemFields.empty())
858 throw RException(R__FAIL("the type list for std::tuple must have at least one element"));
859 for (size_t i = 0; i < itemFields.size(); ++i) {
860 result += itemFields[i]->GetTypeName() + ",";
861 }
862 result.pop_back(); // remove trailing comma
863 return result;
864}
865
867 std::vector<std::unique_ptr<RFieldBase>> itemFields,
868 const std::vector<std::size_t> &offsets)
869 : ROOT::Experimental::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields) + ">")
870{
871 AttachItemFields(std::move(itemFields));
872 fOffsets = offsets;
873}
874
876 std::vector<std::unique_ptr<RFieldBase>> itemFields)
877 : ROOT::Experimental::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields) + ">")
878{
879 AttachItemFields(std::move(itemFields));
880
881 auto *c = TClass::GetClass(GetTypeName().c_str());
882 if (!c)
883 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
884 fSize = c->Size();
885
886 // ISO C++ does not guarantee neither specific layout nor member names for `std::tuple`. However, most
887 // implementations including libstdc++ (gcc), libc++ (llvm), and MSVC name members as `_0`, `_1`, ..., `_N-1`,
888 // following the order of the type list.
889 // Use TClass to get their offsets; in case a particular `std::tuple` implementation does not define such
890 // members, the assertion below will fail.
891 for (unsigned i = 0; i < fSubFields.size(); ++i) {
892 std::string memberName("_" + std::to_string(i));
893 auto member = c->GetRealData(memberName.c_str());
894 if (!member)
895 throw RException(R__FAIL(memberName + ": no such member"));
896 fOffsets.push_back(member->GetThisOffset());
897 }
898}
899
900//------------------------------------------------------------------------------
901
902namespace {
903
904// Depending on the compiler, the variant tag is stored either in a trailing char or in a trailing unsigned int
905constexpr std::size_t GetVariantTagSize()
906{
907 // Should be all zeros except for the tag, which is 1
908 std::variant<char> t;
909 constexpr auto sizeOfT = sizeof(t);
910
911 static_assert(sizeOfT == 2 || sizeOfT == 8, "unsupported std::variant layout");
912 return sizeOfT == 2 ? 1 : 4;
913}
914
915template <std::size_t VariantSizeT>
916struct RVariantTag {
917 using ValueType_t = typename std::conditional_t<VariantSizeT == 1, std::uint8_t,
918 typename std::conditional_t<VariantSizeT == 4, std::uint32_t, void>>;
919};
920
921} // anonymous namespace
922
923std::string ROOT::Experimental::RVariantField::GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields)
924{
925 std::string result;
926 for (size_t i = 0; i < itemFields.size(); ++i) {
927 result += itemFields[i]->GetTypeName() + ",";
928 }
929 R__ASSERT(!result.empty()); // there is always at least one variant
930 result.pop_back(); // remove trailing comma
931 return result;
932}
933
935 : ROOT::Experimental::RFieldBase(name, source.GetTypeName(), ENTupleStructure::kVariant, false /* isSimple */),
936 fMaxItemSize(source.fMaxItemSize),
937 fMaxAlignment(source.fMaxAlignment),
938 fTagOffset(source.fTagOffset),
939 fVariantOffset(source.fVariantOffset),
940 fNWritten(source.fNWritten.size(), 0)
941{
942 for (const auto &f : source.GetSubFields())
943 Attach(f->Clone(f->GetFieldName()));
944 fTraits = source.fTraits;
945}
946
948 std::vector<std::unique_ptr<RFieldBase>> itemFields)
949 : ROOT::Experimental::RFieldBase(fieldName, "std::variant<" + GetTypeList(itemFields) + ">",
950 ENTupleStructure::kVariant, false /* isSimple */)
951{
952 // The variant needs to initialize its own tag member
953 fTraits |= kTraitTriviallyDestructible & ~kTraitTriviallyConstructible;
954
955 auto nFields = itemFields.size();
956 if (nFields == 0 || nFields > kMaxVariants) {
957 throw RException(R__FAIL("invalid number of variant fields (outside [1.." + std::to_string(kMaxVariants) + ")"));
958 }
959 fNWritten.resize(nFields, 0);
960 for (unsigned int i = 0; i < nFields; ++i) {
961 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
962 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
963 fTraits &= itemFields[i]->GetTraits();
964 Attach(std::move(itemFields[i]));
965 }
966
967 // With certain template parameters, the union of members of an std::variant starts at an offset > 0.
968 // For instance, std::variant<std::optional<int>> on macOS.
969 auto cl = TClass::GetClass(GetTypeName().c_str());
970 assert(cl);
971 auto dm = reinterpret_cast<TDataMember *>(cl->GetListOfDataMembers()->First());
972 if (dm)
974
975 const auto tagSize = GetVariantTagSize();
976 const auto padding = tagSize - (fMaxItemSize % tagSize);
977 fTagOffset = fVariantOffset + fMaxItemSize + ((padding == tagSize) ? 0 : padding);
978}
979
980std::unique_ptr<ROOT::Experimental::RFieldBase>
981ROOT::Experimental::RVariantField::CloneImpl(std::string_view newName) const
982{
983 return std::unique_ptr<RVariantField>(new RVariantField(newName, *this));
984}
985
986std::uint8_t ROOT::Experimental::RVariantField::GetTag(const void *variantPtr, std::size_t tagOffset)
987{
988 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
989 auto tag = *reinterpret_cast<const TagType_t *>(reinterpret_cast<const unsigned char *>(variantPtr) + tagOffset);
990 return (tag == TagType_t(-1)) ? 0 : tag + 1;
991}
992
993void ROOT::Experimental::RVariantField::SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag)
994{
995 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
996 auto tagPtr = reinterpret_cast<TagType_t *>(reinterpret_cast<unsigned char *>(variantPtr) + tagOffset);
997 *tagPtr = (tag == 0) ? TagType_t(-1) : static_cast<TagType_t>(tag - 1);
998}
999
1001{
1002 auto tag = GetTag(from, fTagOffset);
1003 std::size_t nbytes = 0;
1004 auto index = 0;
1005 if (tag > 0) {
1006 nbytes += CallAppendOn(*fSubFields[tag - 1], reinterpret_cast<const unsigned char *>(from) + fVariantOffset);
1007 index = fNWritten[tag - 1]++;
1008 }
1009 RColumnSwitch varSwitch(ClusterSize_t(index), tag);
1010 fPrincipalColumn->Append(&varSwitch);
1011 return nbytes + sizeof(RColumnSwitch);
1012}
1013
1015{
1016 RClusterIndex variantIndex;
1017 std::uint32_t tag;
1018 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
1019 R__ASSERT(tag < 256);
1020
1021 // If `tag` equals 0, the variant is in the invalid state, i.e, it does not hold any of the valid alternatives in
1022 // the type list. This happens, e.g., if the field was late added; in this case, keep the invalid tag, which makes
1023 // any `std::holds_alternative<T>` check fail later.
1024 if (R__likely(tag > 0)) {
1025 void *varPtr = reinterpret_cast<unsigned char *>(to) + fVariantOffset;
1026 CallConstructValueOn(*fSubFields[tag - 1], varPtr);
1027 CallReadOn(*fSubFields[tag - 1], variantIndex, varPtr);
1028 }
1029 SetTag(to, fTagOffset, tag);
1030}
1031
1034{
1035 static RColumnRepresentations representations({{EColumnType::kSwitch}}, {});
1036 return representations;
1037}
1038
1040{
1041 GenerateColumnsImpl<RColumnSwitch>();
1042}
1043
1045{
1046 GenerateColumnsImpl<RColumnSwitch>(desc);
1047}
1048
1050{
1051 memset(where, 0, GetValueSize());
1052 CallConstructValueOn(*fSubFields[0], reinterpret_cast<unsigned char *>(where) + fVariantOffset);
1053 SetTag(where, fTagOffset, 1);
1054}
1055
1057{
1058 auto tag = GetTag(objPtr, fTagOffset);
1059 if (tag > 0) {
1060 fItemDeleters[tag - 1]->operator()(reinterpret_cast<unsigned char *>(objPtr) + fVariantOffset, true /*dtorOnly*/);
1061 }
1062 RDeleter::operator()(objPtr, dtorOnly);
1063}
1064
1065std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RVariantField::GetDeleter() const
1066{
1067 std::vector<std::unique_ptr<RDeleter>> itemDeleters;
1068 itemDeleters.reserve(fSubFields.size());
1069 for (const auto &f : fSubFields) {
1070 itemDeleters.emplace_back(GetDeleterOf(*f));
1071 }
1072 return std::make_unique<RVariantDeleter>(fTagOffset, fVariantOffset, std::move(itemDeleters));
1073}
1074
1076{
1077 return std::max(fMaxAlignment, alignof(RVariantTag<GetVariantTagSize()>::ValueType_t));
1078}
1079
1081{
1082 const auto alignment = GetAlignment();
1083 const auto actualSize = fTagOffset + GetVariantTagSize();
1084 const auto padding = alignment - (actualSize % alignment);
1085 return actualSize + ((padding == alignment) ? 0 : padding);
1086}
1087
1089{
1090 std::fill(fNWritten.begin(), fNWritten.end(), 0);
1091}
Cppyy::TCppType_t fClass
#define R__likely(expr)
Definition RConfig.hxx:595
#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:290
#define R__LOG_WARNING(...)
Definition RLogger.hxx:363
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kLong_t
Definition TDataType.h:30
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kUInt_t
Definition TDataType.h:30
@ kClassHasExplicitCtor
@ kClassHasExplicitDtor
@ kIsArray
Definition TDictionary.h:79
@ kIsStatic
Definition TDictionary.h:80
@ kIsDefinedInStd
Definition TDictionary.h:98
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t child
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char mode
char name[80]
Definition TGX11.cxx:110
TCanvas * alignment()
Definition alignment.C:1
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitProxiedCollectionField(const RProxiedCollectionField &field)
virtual void VisitStreamerField(const RStreamerField &field)
virtual void VisitTObjectField(const RField< TObject > &field)
virtual void VisitEnumField(const REnumField &field)
virtual void VisitClassField(const RClassField &field)
A helper class for piece-wise construction of an RExtraTypeInfoDescriptor.
RExtraTypeInfoDescriptorBuilder & Content(const std::string &content)
RExtraTypeInfoDescriptorBuilder & TypeVersion(std::uint32_t typeVersion)
RExtraTypeInfoDescriptorBuilder & TypeName(const std::string &typeName)
RExtraTypeInfoDescriptorBuilder & ContentId(EExtraTypeInfoIds contentId)
static std::string SerializeStreamerInfos(const StreamerInfoMap_t &infos)
void operator()(void *objPtr, bool dtorOnly) final
The field for a class with dictionary.
Definition RField.hxx:99
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
static constexpr const char * kPrefixInherited
Prefix used in the subfield names generated for base classes.
Definition RField.hxx:110
void Attach(std::unique_ptr< RFieldBase > child, RSubFieldInfo info)
void OnConnectPageSource() final
Called by ConnectPageSource() once connected; derived classes may override this as appropriate.
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
std::uint32_t GetTypeChecksum() const final
Return the current TClass reported checksum of this class. Only valid if kTraitTypeChecksum is set.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
void AddReadCallbacksFromIORules(const std::span< const TSchemaRule * > rules, TClass *classp=nullptr)
Register post-read callbacks corresponding to a list of ROOT I/O customization rules.
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 GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:153
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.
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Holds the index and the tag of a kSwitch column.
The field for an unscoped or scoped enum with dictionary.
Definition RField.hxx:213
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
REnumField(std::string_view fieldName, std::string_view enumName, TEnum *enump)
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Field specific extra type information from the header / extenstion header.
Some fields have multiple possible column representations, e.g.
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.
static constexpr int kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
void Attach(std::unique_ptr< RFieldBase > child)
Add a new subfield to the list of nested fields.
std::vector< RFieldBase * > GetSubFields()
static constexpr int kTraitTriviallyConstructible
No constructor needs to be called, i.e.
std::string fTypeAlias
A typedef or using name that was used when creating the field.
const std::string & GetTypeName() const
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &canonicalType, const std::string &typeAlias, bool continueOnError=false)
Factory method to resurrect a field from the stored on-disk type information.
int fTraits
Properties of the type that allow for optimizations of collections of that type.
static constexpr int kTraitTypeChecksum
The TClass checksum is set and valid.
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:241
RField(std::string_view name)
Definition RField.hxx:244
RMapField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
The on-storage meta-data of an ntuple.
Template specializations for C++ std::pair.
RPairField(std::string_view fieldName, std::array< std::unique_ptr< RFieldBase >, 2 > itemFields, const std::array< std::size_t, 2 > &offsets)
Allows for iterating over the elements of a proxied collection.
static RIteratorFuncs GetIteratorFuncs(TVirtualCollectionProxy *proxy, bool readFromDisk)
The field for a class representing a collection of elements via TVirtualCollectionProxy.
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::shared_ptr< TVirtualCollectionProxy > fProxy
The collection proxy is needed by the deleters and thus defined as a shared pointer.
RCollectionIterableOnce::RIteratorFuncs fIFuncsRead
Two sets of functions to operate on iterators, to be used depending on the access type.
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
RProxiedCollectionField(std::string_view fieldName, std::string_view typeName, TClass *classp)
Constructor used when the value type of the collection is not known in advance, i....
std::unique_ptr< RDeleter > GetDeleter() const final
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
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 corresponsing to the field type ...
RCollectionIterableOnce::RIteratorFuncs fIFuncsWrite
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
The field for an untyped record.
std::vector< std::size_t > fOffsets
void AttachItemFields(std::vector< std::unique_ptr< RFieldBase > > itemFields)
RSetField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
void operator()(void *objPtr, bool dtorOnly) final
The field for a class using ROOT standard streaming.
Definition RField.hxx:160
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(NTupleSize_t globalIndex, void *to) final
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::uint32_t GetTypeChecksum() const final
Return the current TClass reported checksum of this class. Only valid if kTraitTypeChecksum is set.
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponsing to the field type ...
RStreamerField(std::string_view fieldName, std::string_view className, TClass *classp)
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
RExtraTypeInfoDescriptor GetExtraTypeInfo() const final
RTupleField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields, const std::vector< std::size_t > &offsets)
void operator()(void *objPtr, bool dtorOnly) final
Template specializations for C++ std::variant.
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag)
static std::string GetTypeList(const std::vector< std::unique_ptr< RFieldBase > > &itemFields)
std::vector< ClusterSize_t::ValueType > fNWritten
size_t fTagOffset
In the std::variant memory layout, at which byte number is the index stored.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
static constexpr std::size_t kMaxVariants
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
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 ...
RVariantField(std::string_view name, const RVariantField &source)
size_t fVariantOffset
In the std::variant memory layout, the actual union of types may start at an offset > 0.
std::unique_ptr< RDeleter > GetDeleter() const 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.
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponsing to the field type ...
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:81
UInt_t GetCheckSum(ECheckSum code=kCurrentCheckSum) const
Call GetCheckSum with validity check.
Definition TClass.cxx:6586
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2388
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3839
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5785
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3705
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2966
Long_t ClassProperty() const
Return the C++ property of this class, eg.
Definition TClass.cxx:2465
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6167
Version_t GetClassVersion() const
Definition TClass.h:421
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:3037
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Longptr_t GetOffset() const
Get offset from "this".
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:71
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Definition TEnum.cxx:139
Mother of all ROOT objects.
Definition TObject.h:41
@ kIsOnHeap
object is on heap
Definition TObject.h:81
@ kNotDeleted
object has not been deleted
Definition TObject.h:82
static TClass * Class()
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition TObject.h:65
RAII helper class that ensures that PushProxy() / PopProxy() are called when entering / leaving a C++...
Defines a common interface to inspect/change the contents of an object that represents a collection.
@ kNeedDelete
The collection contains directly or indirectly (via other collection) some pointers that need explici...
virtual Next_t GetFunctionNext(Bool_t read=kTRUE)=0
Return a pointer to a function that can advance an iterator (see Next_t).
virtual DeleteTwoIterators_t GetFunctionDeleteTwoIterators(Bool_t read=kTRUE)=0
virtual TVirtualCollectionProxy * Generate() const =0
Returns a clean object of the actual class that derives from TVirtualCollectionProxy.
virtual CreateIterators_t GetFunctionCreateIterators(Bool_t read=kTRUE)=0
Return a pointer to a function that can create an iterator pair, where each iterator points to the be...
Wrapper around an object and giving indirect access to its content even if the object is not of a cla...
Abstract Interface class describing Streamer information for one class.
virtual Int_t GetNumber() const =0
const Int_t n
Definition legend1.C:16
std::string GetNormalizedTypeName(const std::string &typeName)
Applies type name normalization rules that lead to the final name used to create a RField,...
ERNTupleSerializationMode GetRNTupleSerializationMode(TClass *cl)
RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
RClusterSize ClusterSize_t
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
TClass * GetClass(T *)
Definition TClass.h:664
@ kSTLvector
Definition ESTLType.h:30
Wrap the integer in a struct in order to avoid template specialization clash with std::uint64_t.