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 <unordered_set>
49#include <utility>
50#include <variant>
51
52ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, const RClassField &source)
53 : ROOT::Experimental::RFieldBase(fieldName, source.GetTypeName(), ENTupleStructure::kRecord, false /* isSimple */),
54 fClass(source.fClass),
55 fSubFieldsInfo(source.fSubFieldsInfo),
56 fMaxAlignment(source.fMaxAlignment)
57{
58 for (const auto &f : source.GetSubFields()) {
59 RFieldBase::Attach(f->Clone(f->GetFieldName()));
60 }
61 fTraits = source.GetTraits();
62}
63
64ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className)
65 : RClassField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
66{
67}
68
69ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
70 : ROOT::Experimental::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */),
71 fClass(classp)
72{
73 if (fClass == nullptr) {
74 throw RException(R__FAIL("RField: no I/O support for type " + std::string(className)));
75 }
76 // Avoid accidentally supporting std types through TClass.
78 throw RException(R__FAIL(std::string(className) + " is not supported"));
79 }
80 if (className == "TObject") {
81 throw RException(R__FAIL("TObject is only supported through RField<TObject>"));
82 }
84 throw RException(
85 R__FAIL(std::string(className) + " has an associated collection proxy; use RProxiedCollectionField instead"));
86 }
87 // Classes with, e.g., custom streamers are not supported through this field. Empty classes, however, are.
88 // Can be overwritten with the "rntuple.streamerMode=true" class attribute
89 if (!fClass->CanSplit() && fClass->Size() > 1 &&
91 throw RException(R__FAIL(std::string(className) + " cannot be stored natively in RNTuple"));
92 }
94 throw RException(
95 R__FAIL(std::string(className) + " has streamer mode enforced, not supported as native RNTuple class"));
96 }
97
102
103 int i = 0;
105 if (baseClass->GetDelta() < 0) {
106 throw RException(R__FAIL(std::string("virtual inheritance is not supported: ") + std::string(className) +
107 " virtually inherits from " + baseClass->GetName()));
108 }
109 TClass *c = baseClass->GetClassPointer();
110 auto subField =
111 RFieldBase::Create(std::string(kPrefixInherited) + "_" + std::to_string(i), c->GetName()).Unwrap();
112 fTraits &= subField->GetTraits();
113 Attach(std::move(subField), RSubFieldInfo{kBaseClass, static_cast<std::size_t>(baseClass->GetDelta())});
114 i++;
115 }
117 // Skip, for instance, unscoped enum constants defined in the class
118 if (dataMember->Property() & kIsStatic)
119 continue;
120 // Skip members explicitly marked as transient by user comment
121 if (!dataMember->IsPersistent()) {
122 // TODO(jblomer): we could do better
124 continue;
125 }
126
127 std::string typeName{Internal::GetNormalizedTypeName(dataMember->GetTrueTypeName())};
128 std::string typeAlias{Internal::GetNormalizedTypeName(dataMember->GetFullTypeName())};
129
130 // For C-style arrays, complete the type name with the size for each dimension, e.g. `int[4][2]`
131 if (dataMember->Property() & kIsArray) {
132 for (int dim = 0, n = dataMember->GetArrayDim(); dim < n; ++dim)
133 typeName += "[" + std::to_string(dataMember->GetMaxIndex(dim)) + "]";
134 }
135
136 std::unique_ptr<RFieldBase> subField;
137
138 subField = RFieldBase::Create(dataMember->GetName(), typeName, typeAlias).Unwrap();
139 fTraits &= subField->GetTraits();
140 Attach(std::move(subField), RSubFieldInfo{kDataMember, static_cast<std::size_t>(dataMember->GetOffset())});
141 }
143}
144
145void ROOT::Experimental::RClassField::Attach(std::unique_ptr<RFieldBase> child, RSubFieldInfo info)
146{
147 fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
148 fSubFieldsInfo.push_back(info);
149 RFieldBase::Attach(std::move(child));
150}
151
152void ROOT::Experimental::RClassField::AddReadCallbacksFromIORules(const std::span<const ROOT::TSchemaRule *> rules,
153 TClass *classp)
154{
155 for (const auto rule : rules) {
156 if (rule->GetRuleType() != ROOT::TSchemaRule::kReadRule) {
157 R__LOG_WARNING(NTupleLog()) << "ignoring I/O customization rule with unsupported type";
158 continue;
159 }
160 auto func = rule->GetReadFunctionPointer();
161 R__ASSERT(func != nullptr);
162 fReadCallbacks.emplace_back([func, classp](void *target) {
163 TVirtualObject oldObj{nullptr};
164 oldObj.fClass = classp;
165 oldObj.fObject = target;
166 func(static_cast<char *>(target), &oldObj);
167 oldObj.fClass = nullptr; // TVirtualObject does not own the value
168 });
169 }
170}
171
172std::unique_ptr<ROOT::Experimental::RFieldBase>
173ROOT::Experimental::RClassField::CloneImpl(std::string_view newName) const
174{
175 return std::unique_ptr<RClassField>(new RClassField(newName, *this));
176}
177
179{
180 std::size_t nbytes = 0;
181 for (unsigned i = 0; i < fSubFields.size(); i++) {
182 nbytes += CallAppendOn(*fSubFields[i], static_cast<const unsigned char *>(from) + fSubFieldsInfo[i].fOffset);
183 }
184 return nbytes;
185}
186
188{
189 for (unsigned i = 0; i < fSubFields.size(); i++) {
190 CallReadOn(*fSubFields[i], globalIndex, static_cast<unsigned char *>(to) + fSubFieldsInfo[i].fOffset);
191 }
192}
193
195{
196 for (unsigned i = 0; i < fSubFields.size(); i++) {
197 CallReadOn(*fSubFields[i], clusterIndex, static_cast<unsigned char *>(to) + fSubFieldsInfo[i].fOffset);
198 }
199}
200
202{
203 // This can happen for added base classes or non-simple members.
204 if (GetOnDiskId() == kInvalidDescriptorId) {
205 return;
206 }
207 // Gather all known sub fields in the descriptor.
208 std::unordered_set<std::string> knownSubFields;
209 {
210 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
211 const RNTupleDescriptor &desc = descriptorGuard.GetRef();
212 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
213 // Check that we have the same type.
214 if (GetTypeName() != fieldDesc.GetTypeName())
215 throw RException(R__FAIL("incompatible type name for field " + GetFieldName() + ": " + GetTypeName() +
216 " vs. " + fieldDesc.GetTypeName()));
217
218 for (auto linkId : fieldDesc.GetLinkIds()) {
219 const auto &subFieldDesc = desc.GetFieldDescriptor(linkId);
220 knownSubFields.insert(subFieldDesc.GetFieldName());
221 }
222 }
223
224 // Iterate over all sub fields in memory and mark those as missing that are not in the descriptor.
225 for (auto &field : fSubFields) {
226 if (knownSubFields.count(field->GetFieldName()) == 0) {
227 field->SetArtificial();
228 }
229 }
230}
231
233{
234 // Add post-read callbacks for I/O customization rules; only rules that target transient members are allowed for now
235 // TODO(jalopezg): revise after supporting schema evolution
236 const auto ruleset = fClass->GetSchemaRules();
237 if (!ruleset)
238 return;
239 auto referencesNonTransientMembers = [klass = fClass](const ROOT::TSchemaRule *rule) {
240 if (rule->GetTarget() == nullptr)
241 return false;
242 for (auto target : ROOT::Detail::TRangeStaticCast<TObjString>(*rule->GetTarget())) {
243 const auto dataMember = klass->GetDataMember(target->GetString());
244 if (!dataMember || dataMember->IsPersistent()) {
245 R__LOG_WARNING(NTupleLog()) << "ignoring I/O customization rule with non-transient member: "
246 << dataMember->GetName();
247 return true;
248 }
249 }
250 return false;
251 };
252
253 auto rules = ruleset->FindRules(fClass->GetName(), static_cast<Int_t>(GetOnDiskTypeVersion()),
254 static_cast<UInt_t>(GetOnDiskTypeChecksum()));
255 rules.erase(std::remove_if(rules.begin(), rules.end(), referencesNonTransientMembers), rules.end());
256 AddReadCallbacksFromIORules(rules, fClass);
257}
258
260{
261 fClass->New(where);
262}
263
265{
266 fClass->Destructor(objPtr, true /* dtorOnly */);
267 RDeleter::operator()(objPtr, dtorOnly);
268}
269
270std::vector<ROOT::Experimental::RFieldBase::RValue>
272{
273 std::vector<RValue> result;
274 auto basePtr = value.GetPtr<unsigned char>().get();
275 result.reserve(fSubFields.size());
276 for (unsigned i = 0; i < fSubFields.size(); i++) {
277 result.emplace_back(
278 fSubFields[i]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + fSubFieldsInfo[i].fOffset)));
279 }
280 return result;
281}
282
284{
285 return fClass->GetClassSize();
286}
287
289{
290 return fClass->GetClassVersion();
291}
292
294{
295 return fClass->GetCheckSum();
296}
297
299{
300 visitor.VisitClassField(*this);
301}
302
303//------------------------------------------------------------------------------
304
305ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName)
306 : REnumField(fieldName, enumName, TEnum::GetEnum(std::string(enumName).c_str()))
307{
308}
309
310ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName, TEnum *enump)
311 : ROOT::Experimental::RFieldBase(fieldName, enumName, ENTupleStructure::kLeaf, false /* isSimple */)
312{
313 if (enump == nullptr) {
314 throw RException(R__FAIL("RField: no I/O support for enum type " + std::string(enumName)));
315 }
316 // Avoid accidentally supporting std types through TEnum.
317 if (enump->Property() & kIsDefinedInStd) {
318 throw RException(R__FAIL(std::string(enumName) + " is not supported"));
319 }
320
321 switch (enump->GetUnderlyingType()) {
322 case kChar_t: Attach(std::make_unique<RField<int8_t>>("_0")); break;
323 case kUChar_t: Attach(std::make_unique<RField<uint8_t>>("_0")); break;
324 case kShort_t: Attach(std::make_unique<RField<int16_t>>("_0")); break;
325 case kUShort_t: Attach(std::make_unique<RField<uint16_t>>("_0")); break;
326 case kInt_t: Attach(std::make_unique<RField<int32_t>>("_0")); break;
327 case kUInt_t: Attach(std::make_unique<RField<uint32_t>>("_0")); break;
328 case kLong_t:
329 case kLong64_t: Attach(std::make_unique<RField<int64_t>>("_0")); break;
330 case kULong_t:
331 case kULong64_t: Attach(std::make_unique<RField<uint64_t>>("_0")); break;
332 default: throw RException(R__FAIL("Unsupported underlying integral type for enum type " + std::string(enumName)));
333 }
334
336}
337
338ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName,
339 std::unique_ptr<RFieldBase> intField)
340 : ROOT::Experimental::RFieldBase(fieldName, enumName, ENTupleStructure::kLeaf, false /* isSimple */)
341{
342 Attach(std::move(intField));
344}
345
346std::unique_ptr<ROOT::Experimental::RFieldBase>
347ROOT::Experimental::REnumField::CloneImpl(std::string_view newName) const
348{
349 auto newIntField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
350 return std::unique_ptr<REnumField>(new REnumField(newName, GetTypeName(), std::move(newIntField)));
351}
352
353std::vector<ROOT::Experimental::RFieldBase::RValue>
355{
356 std::vector<RValue> result;
357 result.emplace_back(fSubFields[0]->BindValue(value.GetPtr<void>()));
358 return result;
359}
360
362{
363 visitor.VisitEnumField(*this);
364}
365
366//------------------------------------------------------------------------------
367
368std::string
369ROOT::Experimental::RPairField::RPairField::GetTypeList(const std::array<std::unique_ptr<RFieldBase>, 2> &itemFields)
370{
371 return itemFields[0]->GetTypeName() + "," + itemFields[1]->GetTypeName();
372}
373
375 std::array<std::unique_ptr<RFieldBase>, 2> itemFields,
376 const std::array<std::size_t, 2> &offsets)
377 : ROOT::Experimental::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields) + ">")
378{
379 AttachItemFields(std::move(itemFields));
380 fOffsets.push_back(offsets[0]);
381 fOffsets.push_back(offsets[1]);
382}
383
385 std::array<std::unique_ptr<RFieldBase>, 2> itemFields)
386 : ROOT::Experimental::RRecordField(fieldName, "std::pair<" + GetTypeList(itemFields) + ">")
387{
388 AttachItemFields(std::move(itemFields));
389
390 // ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
391 auto *c = TClass::GetClass(GetTypeName().c_str());
392 if (!c)
393 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
394 fSize = c->Size();
395
396 auto firstElem = c->GetRealData("first");
397 if (!firstElem)
398 throw RException(R__FAIL("first: no such member"));
399 fOffsets.push_back(firstElem->GetThisOffset());
400
401 auto secondElem = c->GetRealData("second");
402 if (!secondElem)
403 throw RException(R__FAIL("second: no such member"));
404 fOffsets.push_back(secondElem->GetThisOffset());
405}
406
407//------------------------------------------------------------------------------
408
411 bool readFromDisk)
412{
413 RIteratorFuncs ifuncs;
414 ifuncs.fCreateIterators = proxy->GetFunctionCreateIterators(readFromDisk);
415 ifuncs.fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(readFromDisk);
416 ifuncs.fNext = proxy->GetFunctionNext(readFromDisk);
417 R__ASSERT((ifuncs.fCreateIterators != nullptr) && (ifuncs.fDeleteTwoIterators != nullptr) &&
418 (ifuncs.fNext != nullptr));
419 return ifuncs;
420}
421
423 std::string_view typeName, TClass *classp)
424 : RFieldBase(fieldName, typeName, ENTupleStructure::kCollection, false /* isSimple */), fNWritten(0)
425{
426 if (classp == nullptr)
427 throw RException(R__FAIL("RField: no I/O support for collection proxy type " + std::string(typeName)));
428 if (!classp->GetCollectionProxy())
429 throw RException(R__FAIL(std::string(typeName) + " has no associated collection proxy"));
430
431 fProxy.reset(classp->GetCollectionProxy()->Generate());
432 fProperties = fProxy->GetProperties();
433 fCollectionType = fProxy->GetCollectionType();
434 if (fProxy->HasPointers())
435 throw RException(R__FAIL("collection proxies whose value type is a pointer are not supported"));
436 if (!fProxy->GetCollectionClass()->HasDictionary()) {
437 throw RException(R__FAIL("dictionary not available for type " +
438 Internal::GetNormalizedTypeName(fProxy->GetCollectionClass()->GetName())));
439 }
440
441 fIFuncsRead = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), true /* readFromDisk */);
442 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readFromDisk */);
443}
444
446 std::string_view typeName,
447 std::unique_ptr<RFieldBase> itemField)
448 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
449{
450 fItemSize = itemField->GetValueSize();
451 Attach(std::move(itemField));
452}
453
455 std::string_view typeName)
456 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
457{
458 // NOTE (fdegeus): std::map is supported, custom associative might be supported in the future if the need arises.
460 throw RException(R__FAIL("custom associative collection proxies not supported"));
461
462 std::unique_ptr<ROOT::Experimental::RFieldBase> itemField;
463
464 if (auto valueClass = fProxy->GetValueClass()) {
465 // Element type is a class
466 itemField = RFieldBase::Create("_0", valueClass->GetName()).Unwrap();
467 } else {
468 switch (fProxy->GetType()) {
469 case EDataType::kChar_t: itemField = std::make_unique<RField<char>>("_0"); break;
470 case EDataType::kUChar_t: itemField = std::make_unique<RField<std::uint8_t>>("_0"); break;
471 case EDataType::kShort_t: itemField = std::make_unique<RField<std::int16_t>>("_0"); break;
472 case EDataType::kUShort_t: itemField = std::make_unique<RField<std::uint16_t>>("_0"); break;
473 case EDataType::kInt_t: itemField = std::make_unique<RField<std::int32_t>>("_0"); break;
474 case EDataType::kUInt_t: itemField = std::make_unique<RField<std::uint32_t>>("_0"); break;
476 case EDataType::kLong64_t: itemField = std::make_unique<RField<std::int64_t>>("_0"); break;
478 case EDataType::kULong64_t: itemField = std::make_unique<RField<std::uint64_t>>("_0"); break;
479 case EDataType::kFloat_t: itemField = std::make_unique<RField<float>>("_0"); break;
480 case EDataType::kDouble_t: itemField = std::make_unique<RField<double>>("_0"); break;
481 case EDataType::kBool_t: itemField = std::make_unique<RField<bool>>("_0"); break;
482 default: throw RException(R__FAIL("unsupported value type"));
483 }
484 }
485
486 fItemSize = itemField->GetValueSize();
487 Attach(std::move(itemField));
488}
489
490std::unique_ptr<ROOT::Experimental::RFieldBase>
492{
493 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
494 return std::unique_ptr<RProxiedCollectionField>(
495 new RProxiedCollectionField(newName, GetTypeName(), std::move(newItemField)));
496}
497
499{
500 std::size_t nbytes = 0;
501 unsigned count = 0;
502 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), const_cast<void *>(from));
503 for (auto ptr : RCollectionIterableOnce{const_cast<void *>(from), fIFuncsWrite, fProxy.get(),
504 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
505 nbytes += CallAppendOn(*fSubFields[0], ptr);
506 count++;
507 }
508
509 fNWritten += count;
510 fPrincipalColumn->Append(&fNWritten);
511 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
512}
513
515{
516 NTupleSize_t nItems;
517 RClusterIndex collectionStart;
518 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
519
520 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), to);
521 void *obj =
522 fProxy->Allocate(static_cast<std::uint32_t>(nItems), (fProperties & TVirtualCollectionProxy::kNeedDelete));
523
524 unsigned i = 0;
525 for (auto elementPtr : RCollectionIterableOnce{obj, fIFuncsRead, fProxy.get(),
526 (fCollectionType == kSTLvector || obj != to ? fItemSize : 0U)}) {
527 CallReadOn(*fSubFields[0], collectionStart + (i++), elementPtr);
528 }
529 if (obj != to)
530 fProxy->Commit(obj);
531}
532
535{
536 static RColumnRepresentations representations(
538 {});
539 return representations;
540}
541
543{
544 GenerateColumnsImpl<Internal::RColumnIndex>();
545}
546
548{
549 GenerateColumnsImpl<Internal::RColumnIndex>(desc);
550}
551
553{
554 fProxy->New(where);
555}
556
557std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter>
559{
560 if (fProperties & TVirtualCollectionProxy::kNeedDelete) {
561 std::size_t itemSize = fCollectionType == kSTLvector ? fItemSize : 0U;
562 return std::make_unique<RProxiedCollectionDeleter>(fProxy, GetDeleterOf(*fSubFields[0]), itemSize);
563 }
564 return std::make_unique<RProxiedCollectionDeleter>(fProxy);
565}
566
568{
569 if (fItemDeleter) {
570 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), objPtr);
571 for (auto ptr : RCollectionIterableOnce{objPtr, fIFuncsWrite, fProxy.get(), fItemSize}) {
572 fItemDeleter->operator()(ptr, true /* dtorOnly */);
573 }
574 }
575 fProxy->Destructor(objPtr, true /* dtorOnly */);
576 RDeleter::operator()(objPtr, dtorOnly);
577}
578
579std::vector<ROOT::Experimental::RFieldBase::RValue>
581{
582 std::vector<RValue> result;
583 auto valueRawPtr = value.GetPtr<void>().get();
584 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), valueRawPtr);
585 for (auto ptr : RCollectionIterableOnce{valueRawPtr, fIFuncsWrite, fProxy.get(),
586 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
587 result.emplace_back(fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), ptr)));
588 }
589 return result;
590}
591
593{
594 visitor.VisitProxiedCollectionField(*this);
595}
596
597//------------------------------------------------------------------------------
598
599ROOT::Experimental::RMapField::RMapField(std::string_view fieldName, std::string_view typeName,
600 std::unique_ptr<RFieldBase> itemField)
601 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
602{
603 if (!dynamic_cast<RPairField *>(itemField.get()))
604 throw RException(R__FAIL("RMapField inner field type must be of RPairField"));
605
606 auto *itemClass = fProxy->GetValueClass();
607 fItemSize = itemClass->GetClassSize();
608
609 Attach(std::move(itemField));
610}
611
612//------------------------------------------------------------------------------
613
614ROOT::Experimental::RSetField::RSetField(std::string_view fieldName, std::string_view typeName,
615 std::unique_ptr<RFieldBase> itemField)
616 : ROOT::Experimental::RProxiedCollectionField(fieldName, typeName, std::move(itemField))
617{
618}
619
620//------------------------------------------------------------------------------
621
622namespace {
623
624/// Used in RStreamerField::AppendImpl() in order to record the encountered streamer info records
625class TBufferRecStreamer : public TBufferFile {
626public:
627 using RCallbackStreamerInfo = std::function<void(TVirtualStreamerInfo *)>;
628
629private:
630 RCallbackStreamerInfo fCallbackStreamerInfo;
631
632public:
633 TBufferRecStreamer(TBuffer::EMode mode, Int_t bufsiz, RCallbackStreamerInfo callbackStreamerInfo)
634 : TBufferFile(mode, bufsiz), fCallbackStreamerInfo(callbackStreamerInfo)
635 {
636 }
637 void TagStreamerInfo(TVirtualStreamerInfo *info) final { fCallbackStreamerInfo(info); }
638};
639
640} // anonymous namespace
641
642ROOT::Experimental::RStreamerField::RStreamerField(std::string_view fieldName, std::string_view className,
643 std::string_view typeAlias)
644 : RStreamerField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
645{
646 fTypeAlias = typeAlias;
647}
648
649ROOT::Experimental::RStreamerField::RStreamerField(std::string_view fieldName, std::string_view className,
650 TClass *classp)
651 : ROOT::Experimental::RFieldBase(fieldName, className, ENTupleStructure::kStreamer, false /* isSimple */),
652 fClass(classp),
653 fIndex(0)
654{
655 if (fClass == nullptr) {
656 throw RException(R__FAIL("RStreamerField: no I/O support for type " + std::string(className)));
657 }
658
664}
665
666std::unique_ptr<ROOT::Experimental::RFieldBase>
668{
669 return std::unique_ptr<RStreamerField>(new RStreamerField(newName, GetTypeName(), GetTypeAlias()));
670}
671
673{
674 TBufferRecStreamer buffer(TBuffer::kWrite, GetValueSize(),
675 [this](TVirtualStreamerInfo *info) { fStreamerInfos[info->GetNumber()] = info; });
676 fClass->Streamer(const_cast<void *>(from), buffer);
677
678 auto nbytes = buffer.Length();
679 fAuxiliaryColumn->AppendV(buffer.Buffer(), buffer.Length());
680 fIndex += nbytes;
681 fPrincipalColumn->Append(&fIndex);
682 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
683}
684
686{
687 RClusterIndex collectionStart;
688 NTupleSize_t nbytes;
689 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nbytes);
690
691 TBufferFile buffer(TBuffer::kRead, nbytes);
692 fAuxiliaryColumn->ReadV(collectionStart, nbytes, buffer.Buffer());
693 fClass->Streamer(to, buffer);
694}
695
698{
703 {});
704 return representations;
705}
706
708{
709 GenerateColumnsImpl<Internal::RColumnIndex, std::byte>();
710}
711
713{
714 GenerateColumnsImpl<Internal::RColumnIndex, std::byte>(desc);
715}
716
718{
719 fClass->New(where);
720}
721
723{
724 fClass->Destructor(objPtr, true /* dtorOnly */);
725 RDeleter::operator()(objPtr, dtorOnly);
726}
727
729{
731 extraTypeInfoBuilder.ContentId(EExtraTypeInfoIds::kStreamerInfo)
732 .TypeVersion(GetTypeVersion())
733 .TypeName(GetTypeName())
735 return extraTypeInfoBuilder.MoveDescriptor().Unwrap();
736}
737
739{
740 return std::min(alignof(std::max_align_t), GetValueSize()); // TODO(jblomer): fix me
741}
742
744{
745 return fClass->GetClassSize();
746}
747
749{
750 return fClass->GetClassVersion();
751}
752
754{
755 return fClass->GetCheckSum();
756}
757
759{
760 visitor.VisitStreamerField(*this);
761}
762
763//------------------------------------------------------------------------------
764
766{
767 if (auto dataMember = TObject::Class()->GetDataMember(name)) {
768 return dataMember->GetOffset();
769 }
770 throw RException(R__FAIL('\'' + std::string(name) + '\'' + " is an invalid data member"));
771}
772
773ROOT::Experimental::RField<TObject>::RField(std::string_view fieldName, const RField<TObject> &source)
774 : ROOT::Experimental::RFieldBase(fieldName, "TObject", ENTupleStructure::kRecord, false /* isSimple */)
775{
777 Attach(source.GetSubFields()[0]->Clone("fUniqueID"));
778 Attach(source.GetSubFields()[1]->Clone("fBits"));
779}
780
782 : ROOT::Experimental::RFieldBase(fieldName, "TObject", ENTupleStructure::kRecord, false /* isSimple */)
783{
784 assert(TObject::Class()->GetClassVersion() == 1);
785
787 Attach(std::make_unique<RField<UInt_t>>("fUniqueID"));
788 Attach(std::make_unique<RField<UInt_t>>("fBits"));
789}
790
791std::unique_ptr<ROOT::Experimental::RFieldBase>
793{
794 return std::unique_ptr<RField<TObject>>(new RField<TObject>(newName, *this));
795}
796
798{
799 // Cf. TObject::Streamer()
800
801 auto *obj = static_cast<const TObject *>(from);
802 if (obj->TestBit(TObject::kIsReferenced)) {
803 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
804 }
805
806 std::size_t nbytes = 0;
807 nbytes += CallAppendOn(*fSubFields[0], reinterpret_cast<const unsigned char *>(from) + GetOffsetUniqueID());
808
809 UInt_t bits = *reinterpret_cast<const UInt_t *>(reinterpret_cast<const unsigned char *>(from) + GetOffsetBits());
810 bits &= (~TObject::kIsOnHeap & ~TObject::kNotDeleted);
811 nbytes += CallAppendOn(*fSubFields[1], &bits);
812
813 return nbytes;
814}
815
817{
818 // Cf. TObject::Streamer()
819
820 auto *obj = static_cast<TObject *>(to);
821 if (obj->TestBit(TObject::kIsReferenced)) {
822 throw RException(R__FAIL("RNTuple I/O on referenced TObject is unsupported"));
823 }
824
825 CallReadOn(*fSubFields[0], globalIndex, static_cast<unsigned char *>(to) + GetOffsetUniqueID());
826
827 const UInt_t bitIsOnHeap = obj->TestBit(TObject::kIsOnHeap) ? TObject::kIsOnHeap : 0;
828 UInt_t bits;
829 CallReadOn(*fSubFields[1], globalIndex, &bits);
830 bits |= bitIsOnHeap | TObject::kNotDeleted;
831 *reinterpret_cast<UInt_t *>(reinterpret_cast<unsigned char *>(to) + GetOffsetBits()) = bits;
832}
833
835{
836 if (GetTypeVersion() != 1) {
837 throw RException(R__FAIL("unsupported on-disk version of TObject: " + std::to_string(GetTypeVersion())));
838 }
839}
840
842{
844}
845
847{
848 return TObject::Class()->GetCheckSum();
849}
850
852{
853 new (where) TObject();
854}
855
856std::vector<ROOT::Experimental::RFieldBase::RValue>
858{
859 std::vector<RValue> result;
860 auto basePtr = value.GetPtr<unsigned char>().get();
861 result.emplace_back(
862 fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + GetOffsetUniqueID())));
863 result.emplace_back(
864 fSubFields[1]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + GetOffsetBits())));
865 return result;
866}
867
869{
870 return sizeof(TObject);
871}
872
874{
875 return alignof(TObject);
876}
877
879{
880 visitor.VisitTObjectField(*this);
881}
882
883//------------------------------------------------------------------------------
884
885std::string
886ROOT::Experimental::RTupleField::RTupleField::GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields)
887{
888 std::string result;
889 if (itemFields.empty())
890 throw RException(R__FAIL("the type list for std::tuple must have at least one element"));
891 for (size_t i = 0; i < itemFields.size(); ++i) {
892 result += itemFields[i]->GetTypeName() + ",";
893 }
894 result.pop_back(); // remove trailing comma
895 return result;
896}
897
899 std::vector<std::unique_ptr<RFieldBase>> itemFields,
900 const std::vector<std::size_t> &offsets)
901 : ROOT::Experimental::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields) + ">")
902{
903 AttachItemFields(std::move(itemFields));
904 fOffsets = offsets;
905}
906
908 std::vector<std::unique_ptr<RFieldBase>> itemFields)
909 : ROOT::Experimental::RRecordField(fieldName, "std::tuple<" + GetTypeList(itemFields) + ">")
910{
911 AttachItemFields(std::move(itemFields));
912
913 auto *c = TClass::GetClass(GetTypeName().c_str());
914 if (!c)
915 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
916 fSize = c->Size();
917
918 // ISO C++ does not guarantee neither specific layout nor member names for `std::tuple`. However, most
919 // implementations including libstdc++ (gcc), libc++ (llvm), and MSVC name members as `_0`, `_1`, ..., `_N-1`,
920 // following the order of the type list.
921 // Use TClass to get their offsets; in case a particular `std::tuple` implementation does not define such
922 // members, the assertion below will fail.
923 for (unsigned i = 0; i < fSubFields.size(); ++i) {
924 std::string memberName("_" + std::to_string(i));
925 auto member = c->GetRealData(memberName.c_str());
926 if (!member)
927 throw RException(R__FAIL(memberName + ": no such member"));
928 fOffsets.push_back(member->GetThisOffset());
929 }
930}
931
932//------------------------------------------------------------------------------
933
934namespace {
935
936// Depending on the compiler, the variant tag is stored either in a trailing char or in a trailing unsigned int
937constexpr std::size_t GetVariantTagSize()
938{
939 // Should be all zeros except for the tag, which is 1
940 std::variant<char> t;
941 constexpr auto sizeOfT = sizeof(t);
942
943 static_assert(sizeOfT == 2 || sizeOfT == 8, "unsupported std::variant layout");
944 return sizeOfT == 2 ? 1 : 4;
945}
946
947template <std::size_t VariantSizeT>
948struct RVariantTag {
949 using ValueType_t = typename std::conditional_t<VariantSizeT == 1, std::uint8_t,
950 typename std::conditional_t<VariantSizeT == 4, std::uint32_t, void>>;
951};
952
953} // anonymous namespace
954
955std::string ROOT::Experimental::RVariantField::GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields)
956{
957 std::string result;
958 for (size_t i = 0; i < itemFields.size(); ++i) {
959 result += itemFields[i]->GetTypeName() + ",";
960 }
961 R__ASSERT(!result.empty()); // there is always at least one variant
962 result.pop_back(); // remove trailing comma
963 return result;
964}
965
967 : ROOT::Experimental::RFieldBase(name, source.GetTypeName(), ENTupleStructure::kVariant, false /* isSimple */),
968 fMaxItemSize(source.fMaxItemSize),
969 fMaxAlignment(source.fMaxAlignment),
970 fTagOffset(source.fTagOffset),
971 fVariantOffset(source.fVariantOffset),
972 fNWritten(source.fNWritten.size(), 0)
973{
974 for (const auto &f : source.GetSubFields())
975 Attach(f->Clone(f->GetFieldName()));
976 fTraits = source.fTraits;
977}
978
980 std::vector<std::unique_ptr<RFieldBase>> itemFields)
981 : ROOT::Experimental::RFieldBase(fieldName, "std::variant<" + GetTypeList(itemFields) + ">",
982 ENTupleStructure::kVariant, false /* isSimple */)
983{
984 // The variant needs to initialize its own tag member
985 fTraits |= kTraitTriviallyDestructible & ~kTraitTriviallyConstructible;
986
987 auto nFields = itemFields.size();
988 if (nFields == 0 || nFields > kMaxVariants) {
989 throw RException(R__FAIL("invalid number of variant fields (outside [1.." + std::to_string(kMaxVariants) + ")"));
990 }
991 fNWritten.resize(nFields, 0);
992 for (unsigned int i = 0; i < nFields; ++i) {
993 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
994 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
995 fTraits &= itemFields[i]->GetTraits();
996 Attach(std::move(itemFields[i]));
997 }
998
999 // With certain template parameters, the union of members of an std::variant starts at an offset > 0.
1000 // For instance, std::variant<std::optional<int>> on macOS.
1001 auto cl = TClass::GetClass(GetTypeName().c_str());
1002 assert(cl);
1003 auto dm = reinterpret_cast<TDataMember *>(cl->GetListOfDataMembers()->First());
1004 if (dm)
1005 fVariantOffset = dm->GetOffset();
1006
1007 const auto tagSize = GetVariantTagSize();
1008 const auto padding = tagSize - (fMaxItemSize % tagSize);
1009 fTagOffset = fVariantOffset + fMaxItemSize + ((padding == tagSize) ? 0 : padding);
1010}
1011
1012std::unique_ptr<ROOT::Experimental::RFieldBase>
1014{
1015 return std::unique_ptr<RVariantField>(new RVariantField(newName, *this));
1016}
1017
1018std::uint8_t ROOT::Experimental::RVariantField::GetTag(const void *variantPtr, std::size_t tagOffset)
1019{
1020 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
1021 auto tag = *reinterpret_cast<const TagType_t *>(reinterpret_cast<const unsigned char *>(variantPtr) + tagOffset);
1022 return (tag == TagType_t(-1)) ? 0 : tag + 1;
1023}
1024
1025void ROOT::Experimental::RVariantField::SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag)
1026{
1027 using TagType_t = RVariantTag<GetVariantTagSize()>::ValueType_t;
1028 auto tagPtr = reinterpret_cast<TagType_t *>(reinterpret_cast<unsigned char *>(variantPtr) + tagOffset);
1029 *tagPtr = (tag == 0) ? TagType_t(-1) : static_cast<TagType_t>(tag - 1);
1030}
1031
1033{
1034 auto tag = GetTag(from, fTagOffset);
1035 std::size_t nbytes = 0;
1036 auto index = 0;
1037 if (tag > 0) {
1038 nbytes += CallAppendOn(*fSubFields[tag - 1], reinterpret_cast<const unsigned char *>(from) + fVariantOffset);
1039 index = fNWritten[tag - 1]++;
1040 }
1041 Internal::RColumnSwitch varSwitch(index, tag);
1042 fPrincipalColumn->Append(&varSwitch);
1043 return nbytes + sizeof(Internal::RColumnSwitch);
1044}
1045
1047{
1048 RClusterIndex variantIndex;
1049 std::uint32_t tag;
1050 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
1051 R__ASSERT(tag < 256);
1052
1053 // If `tag` equals 0, the variant is in the invalid state, i.e, it does not hold any of the valid alternatives in
1054 // the type list. This happens, e.g., if the field was late added; in this case, keep the invalid tag, which makes
1055 // any `std::holds_alternative<T>` check fail later.
1056 if (R__likely(tag > 0)) {
1057 void *varPtr = reinterpret_cast<unsigned char *>(to) + fVariantOffset;
1058 CallConstructValueOn(*fSubFields[tag - 1], varPtr);
1059 CallReadOn(*fSubFields[tag - 1], variantIndex, varPtr);
1060 }
1061 SetTag(to, fTagOffset, tag);
1062}
1063
1066{
1067 static RColumnRepresentations representations({{EColumnType::kSwitch}}, {});
1068 return representations;
1069}
1070
1072{
1073 GenerateColumnsImpl<Internal::RColumnSwitch>();
1074}
1075
1077{
1078 GenerateColumnsImpl<Internal::RColumnSwitch>(desc);
1079}
1080
1082{
1083 memset(where, 0, GetValueSize());
1084 CallConstructValueOn(*fSubFields[0], reinterpret_cast<unsigned char *>(where) + fVariantOffset);
1085 SetTag(where, fTagOffset, 1);
1086}
1087
1089{
1090 auto tag = GetTag(objPtr, fTagOffset);
1091 if (tag > 0) {
1092 fItemDeleters[tag - 1]->operator()(reinterpret_cast<unsigned char *>(objPtr) + fVariantOffset, true /*dtorOnly*/);
1093 }
1094 RDeleter::operator()(objPtr, dtorOnly);
1095}
1096
1097std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RVariantField::GetDeleter() const
1098{
1099 std::vector<std::unique_ptr<RDeleter>> itemDeleters;
1100 itemDeleters.reserve(fSubFields.size());
1101 for (const auto &f : fSubFields) {
1102 itemDeleters.emplace_back(GetDeleterOf(*f));
1103 }
1104 return std::make_unique<RVariantDeleter>(fTagOffset, fVariantOffset, std::move(itemDeleters));
1105}
1106
1108{
1109 return std::max(fMaxAlignment, alignof(RVariantTag<GetVariantTagSize()>::ValueType_t));
1110}
1111
1113{
1114 const auto alignment = GetAlignment();
1115 const auto actualSize = fTagOffset + GetVariantTagSize();
1116 const auto padding = alignment - (actualSize % alignment);
1117 return actualSize + ((padding == alignment) ? 0 : padding);
1118}
1119
1121{
1122 std::fill(fNWritten.begin(), fNWritten.end(), 0);
1123}
Cppyy::TCppType_t fClass
#define R__likely(expr)
Definition RConfig.hxx:603
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:299
#define R__LOG_WARNING(...)
Definition RLogger.hxx: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)
Holds the index and the tag of a kSwitch column.
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)
Abstract interface to read data from an ntuple.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
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 BeforeConnectPageSource(Internal::RPageSource &pageSource) final
Called by ConnectPageSource() before connecting; derived classes may override this as appropriate.
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:154
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
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...
The field for an unscoped or scoped enum with dictionary.
Definition RField.hxx:214
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.
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
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.
friend class ROOT::Experimental::RClassField
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.
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:242
RField(std::string_view name)
Definition RField.hxx:245
RMapField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
The on-storage meta-data of an ntuple.
const RFieldDescriptor & GetFieldDescriptor(DescriptorId_t fieldId) const
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:161
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.
std::vector< Internal::RColumnIndex::ValueType > fNWritten
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)
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 ...
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
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.
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
constexpr DescriptorId_t kInvalidDescriptorId
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