Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RField.cxx
Go to the documentation of this file.
1/// \file RField.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-15
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/*************************************************************************
9 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#include <ROOT/RColumn.hxx>
17#include <ROOT/RColumnModel.hxx>
18#include <ROOT/REntry.hxx>
19#include <ROOT/RError.hxx>
20#include <ROOT/RField.hxx>
21#include <ROOT/RFieldValue.hxx>
23#include <ROOT/RLogger.hxx>
24#include <ROOT/RNTuple.hxx>
25#include <ROOT/RNTupleModel.hxx>
26
27#include <TBaseClass.h>
28#include <TClass.h>
29#include <TClassEdit.h>
30#include <TCollection.h>
31#include <TDataMember.h>
32#include <TError.h>
33#include <TList.h>
34#include <TObjArray.h>
35#include <TObjString.h>
36#include <TRealData.h>
37#include <TSchemaRule.h>
38#include <TSchemaRuleSet.h>
39#include <TVirtualObject.h>
40
41#include <algorithm>
42#include <cctype> // for isspace
43#include <charconv>
44#include <cstdint>
45#include <cstdlib> // for malloc, free
46#include <cstring> // for memset
47#include <exception>
48#include <iostream>
49#include <new> // hardware_destructive_interference_size
50#include <type_traits>
51#include <unordered_map>
52
53namespace {
54
55static const std::unordered_map<std::string_view, std::string_view> typeTranslationMap{
56 {"Bool_t", "bool"},
57 {"Float_t", "float"},
58 {"Double_t", "double"},
59 {"string", "std::string"},
60
61 {"Char_t", "char"},
62 {"int8_t", "std::int8_t"},
63 {"signed char", "char"},
64 {"UChar_t", "std::uint8_t"},
65 {"unsigned char", "std::uint8_t"},
66 {"uint8_t", "std::uint8_t"},
67
68 {"Short_t", "std::int16_t"},
69 {"int16_t", "std::int16_t"},
70 {"short", "std::int16_t"},
71 {"UShort_t", "std::uint16_t"},
72 {"unsigned short", "std::uint16_t"},
73 {"uint16_t", "std::uint16_t"},
74
75 {"Int_t", "std::int32_t"},
76 {"int32_t", "std::int32_t"},
77 {"int", "std::int32_t"},
78 {"UInt_t", "std::uint32_t"},
79 {"unsigned", "std::uint32_t"},
80 {"unsigned int", "std::uint32_t"},
81 {"uint32_t", "std::uint32_t"},
82
83 {"Long_t", "std::int64_t"},
84 {"Long64_t", "std::int64_t"},
85 {"int64_t", "std::int64_t"},
86 {"long", "std::int64_t"},
87 {"ULong64_t", "std::uint64_t"},
88 {"unsigned long", "std::uint64_t"},
89 {"uint64_t", "std::uint64_t"}
90};
91
92/// Used in CreateField() in order to get the comma-separated list of template types
93/// E.g., gets {"int", "std::variant<double,int>"} from "int,std::variant<double,int>"
94std::vector<std::string> TokenizeTypeList(std::string templateType) {
95 std::vector<std::string> result;
96 if (templateType.empty())
97 return result;
98
99 const char *eol = templateType.data() + templateType.length();
100 const char *typeBegin = templateType.data();
101 const char *typeCursor = templateType.data();
102 unsigned int nestingLevel = 0;
103 while (typeCursor != eol) {
104 switch (*typeCursor) {
105 case '<':
106 ++nestingLevel;
107 break;
108 case '>':
109 --nestingLevel;
110 break;
111 case ',':
112 if (nestingLevel == 0) {
113 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
114 typeBegin = typeCursor + 1;
115 }
116 break;
117 }
118 typeCursor++;
119 }
120 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
121 return result;
122}
123
124/// Parse a type name of the form `T[n][m]...` and return the base type `T` and a vector that contains,
125/// in order, the declared size for each dimension, e.g. for `unsigned char[1][2][3]` it returns the tuple
126/// `{"unsigned char", {1, 2, 3}}`. Extra whitespace in `typeName` should be removed before calling this function.
127///
128/// If `typeName` is not an array type, it returns a tuple `{T, {}}`. On error, it returns a default-constructed tuple.
129std::tuple<std::string, std::vector<size_t>> ParseArrayType(std::string_view typeName)
130{
131 std::vector<size_t> sizeVec;
132
133 // Only parse outer array definition, i.e. the right `]` should be at the end of the type name
134 while (typeName.back() == ']') {
135 auto posRBrace = typeName.size() - 1;
136 auto posLBrace = typeName.find_last_of("[", posRBrace);
137 if (posLBrace == std::string_view::npos)
138 return {};
139
140 size_t size;
141 if (std::from_chars(typeName.data() + posLBrace + 1, typeName.data() + posRBrace, size).ec != std::errc{})
142 return {};
143 sizeVec.insert(sizeVec.begin(), size);
144 typeName.remove_suffix(typeName.size() - posLBrace);
145 }
146 return std::make_tuple(std::string{typeName}, sizeVec);
147}
148
149std::string GetNormalizedType(const std::string &typeName) {
150 std::string normalizedType(TClassEdit::CleanType(typeName.c_str(), /*mode=*/2));
151 // The following types are asummed to be canonical names; thus, do not perform `typedef` resolution on those
152 if (normalizedType == "ROOT::Experimental::ClusterSize_t")
153 return normalizedType;
154
155 normalizedType = TClassEdit::ResolveTypedef(normalizedType.c_str());
156 auto translatedType = typeTranslationMap.find(normalizedType);
157 if (translatedType != typeTranslationMap.end())
158 normalizedType = translatedType->second;
159
160 if (normalizedType.substr(0, 7) == "vector<")
161 normalizedType = "std::" + normalizedType;
162 if (normalizedType.substr(0, 6) == "array<")
163 normalizedType = "std::" + normalizedType;
164 if (normalizedType.substr(0, 8) == "variant<")
165 normalizedType = "std::" + normalizedType;
166 if (normalizedType.substr(0, 5) == "pair<")
167 normalizedType = "std::" + normalizedType;
168 if (normalizedType.substr(0, 6) == "tuple<")
169 normalizedType = "std::" + normalizedType;
170 if (normalizedType.substr(0, 7) == "bitset<")
171 normalizedType = "std::" + normalizedType;
172 if (normalizedType.substr(0, 11) == "unique_ptr<")
173 normalizedType = "std::" + normalizedType;
174
175 return normalizedType;
176}
177
178/// Retrieve the addresses of the data members of a generic RVec from a pointer to the beginning of the RVec object.
179/// Returns pointers to fBegin, fSize and fCapacity in a std::tuple.
180std::tuple<void **, std::int32_t *, std::int32_t *> GetRVecDataMembers(void *rvecPtr)
181{
182 void **begin = reinterpret_cast<void **>(rvecPtr);
183 // int32_t fSize is the second data member (after 1 void*)
184 std::int32_t *size = reinterpret_cast<std::int32_t *>(begin + 1);
185 R__ASSERT(*size >= 0);
186 // int32_t fCapacity is the third data member (1 int32_t after fSize)
187 std::int32_t *capacity = size + 1;
188 R__ASSERT(*capacity >= -1);
189 return {begin, size, capacity};
190}
191
192} // anonymous namespace
193
194//------------------------------------------------------------------------------
195
197{
198 // A single representations with an empty set of columns
201}
202
204 const TypesList_t &serializationTypes, const TypesList_t &deserializationExtraTypes)
205 : fSerializationTypes(serializationTypes), fDeserializationTypes(serializationTypes)
206{
208 deserializationExtraTypes.begin(), deserializationExtraTypes.end());
209}
210
211//------------------------------------------------------------------------------
212
214 ENTupleStructure structure, bool isSimple, std::size_t nRepetitions)
215 : fName(name), fType(type), fStructure(structure), fNRepetitions(nRepetitions), fIsSimple(isSimple),
216 fParent(nullptr), fPrincipalColumn(nullptr), fTraits(isSimple ? kTraitMappable : 0)
217{
218}
219
221{
222}
223
225{
226 std::string result = GetName();
227 RFieldBase *parent = GetParent();
228 while (parent && !parent->GetName().empty()) {
229 result = parent->GetName() + "." + result;
230 parent = parent->GetParent();
231 }
232 return result;
233}
234
236ROOT::Experimental::Detail::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
237{
238 std::string normalizedType(GetNormalizedType(typeName));
239 if (normalizedType.empty())
240 return R__FAIL("no type name specified for Field " + fieldName);
241
242 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> result;
243
244 if (auto [arrayBaseType, arraySize] = ParseArrayType(normalizedType); !arraySize.empty()) {
245 // TODO(jalopezg): support multi-dimensional row-major (C order) arrays in RArrayField
246 if (arraySize.size() > 1)
247 return R__FAIL("multi-dimensional array type not supported " + normalizedType);
248 auto itemField = Create(GetNormalizedType(arrayBaseType), arrayBaseType);
249 return {std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arraySize[0])};
250 }
251
252 if (normalizedType == "ROOT::Experimental::ClusterSize_t") {
253 result = std::make_unique<RField<ClusterSize_t>>(fieldName);
254 } else if (normalizedType == "ROOT::Experimental::RNTupleCardinality") {
255 result = std::make_unique<RField<RNTupleCardinality>>(fieldName);
256 } else if (normalizedType == "bool") {
257 result = std::make_unique<RField<bool>>(fieldName);
258 } else if (normalizedType == "char") {
259 result = std::make_unique<RField<char>>(fieldName);
260 } else if (normalizedType == "std::int8_t") {
261 result = std::make_unique<RField<std::int8_t>>(fieldName);
262 } else if (normalizedType == "std::uint8_t") {
263 result = std::make_unique<RField<std::uint8_t>>(fieldName);
264 } else if (normalizedType == "std::int16_t") {
265 result = std::make_unique<RField<std::int16_t>>(fieldName);
266 } else if (normalizedType == "std::uint16_t") {
267 result = std::make_unique<RField<std::uint16_t>>(fieldName);
268 } else if (normalizedType == "std::int32_t") {
269 result = std::make_unique<RField<std::int32_t>>(fieldName);
270 } else if (normalizedType == "std::uint32_t") {
271 result = std::make_unique<RField<std::uint32_t>>(fieldName);
272 } else if (normalizedType == "std::int64_t") {
273 result = std::make_unique<RField<std::int64_t>>(fieldName);
274 } else if (normalizedType == "std::uint64_t") {
275 result = std::make_unique<RField<std::uint64_t>>(fieldName);
276 } else if (normalizedType == "float") {
277 result = std::make_unique<RField<float>>(fieldName);
278 } else if (normalizedType == "double") {
279 result = std::make_unique<RField<double>>(fieldName);
280 } else if (normalizedType == "std::string") {
281 result = std::make_unique<RField<std::string>>(fieldName);
282 } else if (normalizedType == "std::vector<bool>") {
283 result = std::make_unique<RField<std::vector<bool>>>(fieldName);
284 } else if (normalizedType.substr(0, 12) == "std::vector<") {
285 std::string itemTypeName = normalizedType.substr(12, normalizedType.length() - 13);
286 auto itemField = Create("_0", itemTypeName);
287 result = std::make_unique<RVectorField>(fieldName, itemField.Unwrap());
288 } else if (normalizedType.substr(0, 19) == "ROOT::VecOps::RVec<") {
289 std::string itemTypeName = normalizedType.substr(19, normalizedType.length() - 20);
290 auto itemField = Create("_0", itemTypeName);
291 result = std::make_unique<RRVecField>(fieldName, itemField.Unwrap());
292 } else if (normalizedType.substr(0, 11) == "std::array<") {
293 auto arrayDef = TokenizeTypeList(normalizedType.substr(11, normalizedType.length() - 12));
294 R__ASSERT(arrayDef.size() == 2);
295 auto arrayLength = std::stoi(arrayDef[1]);
296 auto itemField = Create(GetNormalizedType(arrayDef[0]), arrayDef[0]);
297 result = std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arrayLength);
298 }
299 if (normalizedType.substr(0, 13) == "std::variant<") {
300 auto innerTypes = TokenizeTypeList(normalizedType.substr(13, normalizedType.length() - 14));
301 std::vector<RFieldBase *> items;
302 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
303 items.emplace_back(Create("_" + std::to_string(i), innerTypes[i]).Unwrap().release());
304 }
305 result = std::make_unique<RVariantField>(fieldName, items);
306 }
307 if (normalizedType.substr(0, 10) == "std::pair<") {
308 auto innerTypes = TokenizeTypeList(normalizedType.substr(10, normalizedType.length() - 11));
309 if (innerTypes.size() != 2)
310 return R__FAIL("the type list for std::pair must have exactly two elements");
311 std::array<std::unique_ptr<RFieldBase>, 2> items{Create("_0", innerTypes[0]).Unwrap(),
312 Create("_1", innerTypes[1]).Unwrap()};
313 result = std::make_unique<RPairField>(fieldName, items);
314 }
315 if (normalizedType.substr(0, 11) == "std::tuple<") {
316 auto innerTypes = TokenizeTypeList(normalizedType.substr(11, normalizedType.length() - 12));
317 std::vector<std::unique_ptr<RFieldBase>> items;
318 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
319 items.emplace_back(Create("_" + std::to_string(i), innerTypes[i]).Unwrap());
320 }
321 result = std::make_unique<RTupleField>(fieldName, items);
322 }
323 if (normalizedType.substr(0, 12) == "std::bitset<") {
324 auto size = std::stoull(normalizedType.substr(12, normalizedType.length() - 13));
325 result = std::make_unique<RBitsetField>(fieldName, size);
326 }
327 if (normalizedType.substr(0, 16) == "std::unique_ptr<") {
328 std::string itemTypeName = normalizedType.substr(16, normalizedType.length() - 17);
329 auto itemField = Create("_0", itemTypeName).Unwrap();
330 auto normalizedInnerTypeName = itemField->GetType();
331 result = std::make_unique<RUniquePtrField>(fieldName, "std::unique_ptr<" + normalizedInnerTypeName + ">",
332 std::move(itemField));
333 }
334 // TODO: create an RCollectionField?
335 if (normalizedType == ":Collection:")
336 result = std::make_unique<RField<ClusterSize_t>>(fieldName);
337
338 if (!result) {
339 auto cl = TClass::GetClass(normalizedType.c_str());
340 if (cl != nullptr) {
341 if (cl->GetCollectionProxy())
342 result = std::make_unique<RCollectionClassField>(fieldName, normalizedType);
343 else
344 result = std::make_unique<RClassField>(fieldName, normalizedType);
345 }
346 }
347
348 if (result)
349 return result;
350 return R__FAIL(std::string("Field ") + fieldName + " has unknown type " + normalizedType);
351}
352
355{
356 if (fieldName == "") {
357 return R__FAIL("name cannot be empty string \"\"");
358 } else if (fieldName.find(".") != std::string::npos) {
359 return R__FAIL("name '" + std::string(fieldName) + "' cannot contain dot characters '.'");
360 }
361 return RResult<void>::Success();
362}
363
366{
367 static RColumnRepresentations representations;
368 return representations;
369}
370
371std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
373{
374 auto clone = CloneImpl(newName);
375 clone->fOnDiskId = fOnDiskId;
376 clone->fDescription = fDescription;
377 // We can just copy the pointer because fColumnRepresentative points into a static structure
378 clone->fColumnRepresentative = fColumnRepresentative;
379 return clone;
380}
381
383{
384 R__ASSERT(false && "A non-simple RField must implement its own AppendImpl");
385 return 0;
386}
387
390 RFieldValue* /*value*/)
391{
392 R__ASSERT(false);
393}
394
396{
397 void *where = malloc(GetValueSize());
398 R__ASSERT(where != nullptr);
399 return GenerateValue(where);
400}
401
403{
404 if (!dtorOnly)
405 free(value.GetRawPtr());
406}
407
408std::vector<ROOT::Experimental::Detail::RFieldValue>
410{
411 return std::vector<RFieldValue>();
412}
413
415 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> child)
416{
417 child->fParent = this;
418 fSubFields.emplace_back(std::move(child));
419}
420
421
422std::vector<ROOT::Experimental::Detail::RFieldBase *> ROOT::Experimental::Detail::RFieldBase::GetSubFields() const
423{
424 std::vector<RFieldBase *> result;
425 for (const auto &f : fSubFields) {
426 result.emplace_back(f.get());
427 }
428 return result;
429}
430
431
433{
434 for (auto& column : fColumns) {
435 column->Flush();
436 }
437}
438
441{
442 if (fColumnRepresentative)
443 return *fColumnRepresentative;
444 return GetColumnRepresentations().GetSerializationDefault();
445}
446
448{
449 if (!fColumns.empty())
450 throw RException(R__FAIL("cannot set column representative once field is connected"));
451 const auto &validTypes = GetColumnRepresentations().GetSerializationTypes();
452 auto itRepresentative = std::find(validTypes.begin(), validTypes.end(), representative);
453 if (itRepresentative == std::end(validTypes))
454 throw RException(R__FAIL("invalid column representative"));
455 fColumnRepresentative = &(*itRepresentative);
456}
457
460{
461 if (fOnDiskId == kInvalidDescriptorId)
462 throw RException(R__FAIL("No on-disk column information for for field `" + GetQualifiedFieldName() + "`"));
463
464 ColumnRepresentation_t onDiskTypes;
465 for (const auto &c : desc.GetColumnIterable(fOnDiskId)) {
466 onDiskTypes.emplace_back(c.GetModel().GetType());
467 }
468 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
469 if (t == onDiskTypes)
470 return t;
471 }
472
473 std::string columnTypeNames;
474 for (const auto &t : onDiskTypes) {
475 if (!columnTypeNames.empty())
476 columnTypeNames += ", ";
477 columnTypeNames += RColumnElementBase::GetTypeName(t);
478 }
479 throw RException(R__FAIL("On-disk column types `" + columnTypeNames + "` for field `" + GetQualifiedFieldName() +
480 "` cannot be matched."));
481}
482
484{
485 fReadCallbacks.push_back(func);
486 fIsSimple = false;
487 return fReadCallbacks.size() - 1;
488}
489
491{
492 fReadCallbacks.erase(fReadCallbacks.begin() + idx);
493 fIsSimple = (fTraits & kTraitMappable) && fReadCallbacks.empty();
494}
495
497{
498 if ((options.GetCompression() == 0) && HasDefaultColumnRepresentative()) {
499 ColumnRepresentation_t rep = GetColumnRepresentative();
500 for (auto &colType : rep) {
501 switch (colType) {
504 case EColumnType::kSplitReal64: colType = EColumnType::kReal64; break;
505 case EColumnType::kSplitReal32: colType = EColumnType::kReal32; break;
506 case EColumnType::kSplitInt64: colType = EColumnType::kInt64; break;
507 case EColumnType::kSplitInt32: colType = EColumnType::kInt32; break;
508 case EColumnType::kSplitInt16: colType = EColumnType::kInt16; break;
509 default: break;
510 }
511 }
512 SetColumnRepresentative(rep);
513 }
514
515 if (options.GetHasSmallClusters()) {
516 ColumnRepresentation_t rep = GetColumnRepresentative();
517 for (auto &colType : rep) {
518 switch (colType) {
520 case EColumnType::kIndex64: colType = EColumnType::kIndex32; break;
521 default: break;
522 }
523 }
524 SetColumnRepresentative(rep);
525 }
526}
527
529{
530 R__ASSERT(fColumns.empty());
531
532 AutoAdjustColumnTypes(pageSink.GetWriteOptions());
533
534 GenerateColumnsImpl();
535 if (!fColumns.empty())
536 fPrincipalColumn = fColumns[0].get();
537 for (auto& column : fColumns)
538 column->Connect(fOnDiskId, &pageSink);
539}
540
541
543{
544 R__ASSERT(fColumns.empty());
545 if (fColumnRepresentative)
546 throw RException(R__FAIL("fixed column representative only valid when connecting to a page sink"));
547
548 {
549 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
550 const RNTupleDescriptor &desc = descriptorGuard.GetRef();
551 GenerateColumnsImpl(desc);
552 ColumnRepresentation_t onDiskColumnTypes;
553 for (const auto &c : fColumns) {
554 onDiskColumnTypes.emplace_back(c->GetModel().GetType());
555 }
556 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
557 if (t == onDiskColumnTypes)
558 fColumnRepresentative = &t;
559 }
560 R__ASSERT(fColumnRepresentative);
561 if (fOnDiskId != kInvalidDescriptorId)
562 fOnDiskTypeVersion = desc.GetFieldDescriptor(fOnDiskId).GetTypeVersion();
563 }
564 if (!fColumns.empty())
565 fPrincipalColumn = fColumns[0].get();
566 for (auto& column : fColumns)
567 column->Connect(fOnDiskId, &pageSource);
568 OnConnectPageSource();
569}
570
571
573{
574 visitor.VisitField(*this);
575}
576
577
579{
580 if (fSubFields.empty()) return RSchemaIterator(this, -1);
581 return RSchemaIterator(this->fSubFields[0].get(), 0);
582}
583
584
586{
587 return RSchemaIterator(this, -1);
588}
589
590
591//-----------------------------------------------------------------------------
592
593
595{
596 auto itr = fStack.rbegin();
597 if (!itr->fFieldPtr->fSubFields.empty()) {
598 fStack.emplace_back(Position(itr->fFieldPtr->fSubFields[0].get(), 0));
599 return;
600 }
601
602 unsigned int nextIdxInParent = ++(itr->fIdxInParent);
603 while (nextIdxInParent >= itr->fFieldPtr->fParent->fSubFields.size()) {
604 if (fStack.size() == 1) {
605 itr->fFieldPtr = itr->fFieldPtr->fParent;
606 itr->fIdxInParent = -1;
607 return;
608 }
609 fStack.pop_back();
610 itr = fStack.rbegin();
611 nextIdxInParent = ++(itr->fIdxInParent);
612 }
613 itr->fFieldPtr = itr->fFieldPtr->fParent->fSubFields[nextIdxInParent].get();
614}
615
616
617//------------------------------------------------------------------------------
618
619
620std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
621ROOT::Experimental::RFieldZero::CloneImpl(std::string_view /*newName*/) const
622{
623 auto result = std::make_unique<RFieldZero>();
624 for (auto &f : fSubFields)
625 result->Attach(f->Clone(f->GetName()));
626 return result;
627}
628
629
631{
632 visitor.VisitFieldZero(*this);
633}
634
635
636//------------------------------------------------------------------------------
637
640{
641 static RColumnRepresentations representations(
643 {});
644 return representations;
645}
646
648{
649 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
650}
651
653{
654 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
655 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
656}
657
659{
660 visitor.VisitClusterSizeField(*this);
661}
662
663//------------------------------------------------------------------------------
664
667{
668 static RColumnRepresentations representations(
670 {});
671 return representations;
672}
673
675 const RNTupleDescriptor &desc)
676{
677 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
678 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
679}
680
682 Detail::RFieldVisitor &visitor) const
683{
684 visitor.VisitCardinalityField(*this);
685}
686
687//------------------------------------------------------------------------------
688
691{
692 static RColumnRepresentations representations({{EColumnType::kChar}}, {{}});
693 return representations;
694}
695
697{
698 fColumns.emplace_back(Detail::RColumn::Create<char>(RColumnModel(GetColumnRepresentative()[0]), 0));
699}
700
702{
703 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
704 fColumns.emplace_back(Detail::RColumn::Create<char>(RColumnModel(onDiskTypes[0]), 0));
705}
706
708{
709 visitor.VisitCharField(*this);
710}
711
712//------------------------------------------------------------------------------
713
716{
717 static RColumnRepresentations representations({{EColumnType::kInt8}}, {{}});
718 return representations;
719}
720
722{
723 fColumns.emplace_back(Detail::RColumn::Create<std::int8_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
724}
725
726void ROOT::Experimental::RField<std::int8_t>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
727{
728 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
729 fColumns.emplace_back(Detail::RColumn::Create<std::int8_t>(RColumnModel(onDiskTypes[0]), 0));
730}
731
732void ROOT::Experimental::RField<std::int8_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
733{
734 visitor.VisitInt8Field(*this);
735}
736
737//------------------------------------------------------------------------------
738
741{
742 static RColumnRepresentations representations({{EColumnType::kInt8}}, {{}});
743 return representations;
744}
745
747{
748 fColumns.emplace_back(Detail::RColumn::Create<std::uint8_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
749}
750
752{
753 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
754 fColumns.emplace_back(Detail::RColumn::Create<std::uint8_t>(RColumnModel(onDiskTypes[0]), 0));
755}
756
757void ROOT::Experimental::RField<std::uint8_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
758{
759 visitor.VisitUInt8Field(*this);
760}
761
762//------------------------------------------------------------------------------
763
766{
767 static RColumnRepresentations representations({{EColumnType::kBit}}, {{}});
768 return representations;
769}
770
772{
773 fColumns.emplace_back(Detail::RColumn::Create<bool>(RColumnModel(GetColumnRepresentative()[0]), 0));
774}
775
777{
778 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
779 fColumns.emplace_back(Detail::RColumn::Create<bool>(RColumnModel(onDiskTypes[0]), 0));
780}
781
783{
784 visitor.VisitBoolField(*this);
785}
786
787//------------------------------------------------------------------------------
788
791{
792 static RColumnRepresentations representations({{EColumnType::kSplitReal32}, {EColumnType::kReal32}}, {{}});
793 return representations;
794}
795
797{
798 fColumns.emplace_back(Detail::RColumn::Create<float>(RColumnModel(GetColumnRepresentative()[0]), 0));
799}
800
802{
803 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
804 fColumns.emplace_back(Detail::RColumn::Create<float>(RColumnModel(onDiskTypes[0]), 0));
805}
806
808{
809 visitor.VisitFloatField(*this);
810}
811
812
813//------------------------------------------------------------------------------
814
817{
818 static RColumnRepresentations representations({{EColumnType::kSplitReal64}, {EColumnType::kReal64}}, {{}});
819 return representations;
820}
821
823{
824 fColumns.emplace_back(Detail::RColumn::Create<double>(RColumnModel(GetColumnRepresentative()[0]), 0));
825}
826
828{
829 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
830 fColumns.emplace_back(Detail::RColumn::Create<double>(RColumnModel(onDiskTypes[0]), 0));
831}
832
834{
835 visitor.VisitDoubleField(*this);
836}
837
838//------------------------------------------------------------------------------
839
842{
843 static RColumnRepresentations representations({{EColumnType::kSplitInt16}, {EColumnType::kInt16}}, {{}});
844 return representations;
845}
846
848{
849 fColumns.emplace_back(Detail::RColumn::Create<std::int16_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
850}
851
853{
854 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
855 fColumns.emplace_back(Detail::RColumn::Create<std::int16_t>(RColumnModel(onDiskTypes[0]), 0));
856}
857
858void ROOT::Experimental::RField<std::int16_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
859{
860 visitor.VisitInt16Field(*this);
861}
862
863//------------------------------------------------------------------------------
864
867{
868 static RColumnRepresentations representations({{EColumnType::kSplitInt16}, {EColumnType::kInt16}}, {{}});
869 return representations;
870}
871
873{
874 fColumns.emplace_back(Detail::RColumn::Create<std::uint16_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
875}
876
878{
879 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
880 fColumns.emplace_back(Detail::RColumn::Create<std::uint16_t>(RColumnModel(onDiskTypes[0]), 0));
881}
882
883void ROOT::Experimental::RField<std::uint16_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
884{
885 visitor.VisitUInt16Field(*this);
886}
887
888//------------------------------------------------------------------------------
889
892{
893 static RColumnRepresentations representations({{EColumnType::kSplitInt32}, {EColumnType::kInt32}}, {{}});
894 return representations;
895}
896
898{
899 fColumns.emplace_back(Detail::RColumn::Create<std::int32_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
900}
901
903{
904 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
905 fColumns.emplace_back(Detail::RColumn::Create<std::int32_t>(RColumnModel(onDiskTypes[0]), 0));
906}
907
908void ROOT::Experimental::RField<std::int32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
909{
910 visitor.VisitIntField(*this);
911}
912
913//------------------------------------------------------------------------------
914
917{
918 static RColumnRepresentations representations({{EColumnType::kSplitInt32}, {EColumnType::kInt32}}, {{}});
919 return representations;
920}
921
923{
924 fColumns.emplace_back(Detail::RColumn::Create<std::uint32_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
925}
926
928{
929 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
930 fColumns.emplace_back(Detail::RColumn::Create<std::uint32_t>(RColumnModel(onDiskTypes[0]), 0));
931}
932
933void ROOT::Experimental::RField<std::uint32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
934{
935 visitor.VisitUInt32Field(*this);
936}
937
938//------------------------------------------------------------------------------
939
942{
943 static RColumnRepresentations representations({{EColumnType::kSplitInt64}, {EColumnType::kInt64}}, {{}});
944 return representations;
945}
946
948{
949 fColumns.emplace_back(Detail::RColumn::Create<std::uint64_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
950}
951
953{
954 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
955 fColumns.emplace_back(Detail::RColumn::Create<std::uint64_t>(RColumnModel(onDiskTypes[0]), 0));
956}
957
958void ROOT::Experimental::RField<std::uint64_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
959{
960 visitor.VisitUInt64Field(*this);
961}
962
963//------------------------------------------------------------------------------
964
967{
968 static RColumnRepresentations representations({{EColumnType::kSplitInt64}, {EColumnType::kInt64}},
970 return representations;
971}
972
974{
975 fColumns.emplace_back(Detail::RColumn::Create<std::int64_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
976}
977
979{
980 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
981 fColumns.emplace_back(Detail::RColumn::Create<std::int64_t>(RColumnModel(onDiskTypes[0]), 0));
982}
983
984void ROOT::Experimental::RField<std::int64_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
985{
986 visitor.VisitInt64Field(*this);
987}
988
989//------------------------------------------------------------------------------
990
993{
994 static RColumnRepresentations representations({{EColumnType::kSplitIndex64, EColumnType::kChar},
998 {});
999 return representations;
1000}
1001
1003{
1004 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1005 fColumns.emplace_back(Detail::RColumn::Create<char>(RColumnModel(GetColumnRepresentative()[1]), 1));
1006}
1007
1008void ROOT::Experimental::RField<std::string>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1009{
1010 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1011 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
1012 fColumns.emplace_back(Detail::RColumn::Create<char>(RColumnModel(onDiskTypes[1]), 1));
1013}
1014
1016{
1017 auto typedValue = value.Get<std::string>();
1018 auto length = typedValue->length();
1019 Detail::RColumnElement<char> elemChars(const_cast<char*>(typedValue->data()));
1020 fColumns[1]->AppendV(elemChars, length);
1021 fIndex += length;
1022 fColumns[0]->Append(fElemIndex);
1023 return length + sizeof(fElemIndex);
1024}
1025
1028{
1029 auto typedValue = value->Get<std::string>();
1030 RClusterIndex collectionStart;
1031 ClusterSize_t nChars;
1032 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nChars);
1033 if (nChars == 0) {
1034 typedValue->clear();
1035 } else {
1036 typedValue->resize(nChars);
1037 Detail::RColumnElement<char> elemChars(const_cast<char*>(typedValue->data()));
1038 fColumns[1]->ReadV(collectionStart, nChars, &elemChars);
1039 }
1040}
1041
1043{
1044 fIndex = 0;
1045}
1046
1047void ROOT::Experimental::RField<std::string>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1048{
1049 visitor.VisitStringField(*this);
1050}
1051
1052//------------------------------------------------------------------------------
1053
1054
1055ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className)
1056 : RClassField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
1057{
1058}
1059
1060ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
1061 : ROOT::Experimental::Detail::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */)
1062 , fClass(classp)
1063{
1064 if (fClass == nullptr) {
1065 throw RException(R__FAIL("RField: no I/O support for type " + std::string(className)));
1066 }
1067 // Avoid accidentally supporting std types through TClass.
1068 if (fClass->Property() & kIsDefinedInStd) {
1069 throw RException(R__FAIL(std::string(className) + " is not supported"));
1070 }
1071 if (fClass->GetCollectionProxy()) {
1072 throw RException(
1073 R__FAIL(std::string(className) + " has an associated collection proxy; use RCollectionClassField instead"));
1074 }
1075
1080
1081 int i = 0;
1083 TClass *c = baseClass->GetClassPointer();
1084 auto subField = Detail::RFieldBase::Create(std::string(kPrefixInherited) + "_" + std::to_string(i),
1085 c->GetName()).Unwrap();
1086 fTraits &= subField->GetTraits();
1087 Attach(std::move(subField),
1088 RSubFieldInfo{kBaseClass, static_cast<std::size_t>(baseClass->GetDelta())});
1089 i++;
1090 }
1092 // Skip, for instance, unscoped enum constants defined in the class
1093 if (dataMember->Property() & kIsStatic)
1094 continue;
1095 // Skip members explicitly marked as transient by user comment
1096 if (!dataMember->IsPersistent()) {
1097 // TODO(jblomer): we could do better
1099 continue;
1100 }
1101
1102 std::string typeName{dataMember->GetFullTypeName()};
1103 // For C-style arrays, complete the type name with the size for each dimension, e.g. `int[4][2]`
1104 if (dataMember->Property() & kIsArray) {
1105 for (int dim = 0, n = dataMember->GetArrayDim(); dim < n; ++dim)
1106 typeName += "[" + std::to_string(dataMember->GetMaxIndex(dim)) + "]";
1107 }
1108 auto subField = Detail::RFieldBase::Create(dataMember->GetName(), typeName).Unwrap();
1109 fTraits &= subField->GetTraits();
1110 Attach(std::move(subField),
1111 RSubFieldInfo{kDataMember, static_cast<std::size_t>(dataMember->GetOffset())});
1112 }
1113}
1114
1115void ROOT::Experimental::RClassField::Attach(std::unique_ptr<Detail::RFieldBase> child, RSubFieldInfo info)
1116{
1117 fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
1118 fSubFieldsInfo.push_back(info);
1119 RFieldBase::Attach(std::move(child));
1120}
1121
1122void ROOT::Experimental::RClassField::AddReadCallbacksFromIORules(const std::span<const ROOT::TSchemaRule *> rules,
1123 TClass *classp)
1124{
1125 for (const auto rule : rules) {
1126 if (rule->GetRuleType() != ROOT::TSchemaRule::kReadRule) {
1127 R__LOG_WARNING(NTupleLog()) << "ignoring I/O customization rule with unsupported type";
1128 continue;
1129 }
1130 auto func = rule->GetReadFunctionPointer();
1131 R__ASSERT(func != nullptr);
1132 fReadCallbacks.emplace_back([func, classp](Detail::RFieldValue &value) {
1133 TVirtualObject oldObj{nullptr};
1134 oldObj.fClass = classp;
1135 oldObj.fObject = value.GetRawPtr();
1136 func(static_cast<char *>(value.GetRawPtr()), &oldObj);
1137 oldObj.fClass = nullptr; // TVirtualObject does not own the value
1138 });
1139 }
1140}
1141
1142std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1143ROOT::Experimental::RClassField::CloneImpl(std::string_view newName) const
1144{
1145 return std::unique_ptr<RClassField>(new RClassField(newName, GetType(), fClass));
1146}
1147
1149 std::size_t nbytes = 0;
1150 for (unsigned i = 0; i < fSubFields.size(); i++) {
1151 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fSubFieldsInfo[i].fOffset);
1152 nbytes += fSubFields[i]->Append(memberValue);
1153 }
1154 return nbytes;
1155}
1156
1158{
1159 for (unsigned i = 0; i < fSubFields.size(); i++) {
1160 auto memberValue = fSubFields[i]->CaptureValue(value->Get<unsigned char>() + fSubFieldsInfo[i].fOffset);
1161 fSubFields[i]->Read(globalIndex, &memberValue);
1162 }
1163}
1164
1166{
1167 for (unsigned i = 0; i < fSubFields.size(); i++) {
1168 auto memberValue = fSubFields[i]->CaptureValue(value->Get<unsigned char>() + fSubFieldsInfo[i].fOffset);
1169 fSubFields[i]->Read(clusterIndex, &memberValue);
1170 }
1171}
1172
1174{
1175 // Add post-read callbacks for I/O customization rules; only rules that target transient members are allowed for now
1176 // TODO(jalopezg): revise after supporting schema evolution
1177 const auto ruleset = fClass->GetSchemaRules();
1178 if (!ruleset)
1179 return;
1180 auto referencesNonTransientMembers = [klass = fClass](const ROOT::TSchemaRule *rule) {
1181 if (rule->GetTarget() == nullptr)
1182 return false;
1183 for (auto target : ROOT::Detail::TRangeStaticCast<TObjString>(*rule->GetTarget())) {
1184 const auto dataMember = klass->GetDataMember(target->GetString());
1185 if (!dataMember || dataMember->IsPersistent()) {
1186 R__LOG_WARNING(NTupleLog()) << "ignoring I/O customization rule with non-transient member: "
1187 << dataMember->GetName();
1188 return true;
1189 }
1190 }
1191 return false;
1192 };
1193
1194 auto rules = ruleset->FindRules(fClass->GetName(), static_cast<Int_t>(GetOnDiskTypeVersion()));
1195 rules.erase(std::remove_if(rules.begin(), rules.end(), referencesNonTransientMembers), rules.end());
1196 AddReadCallbacksFromIORules(rules, fClass);
1197}
1198
1200{
1201 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
1202}
1203
1205{
1206 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
1207 if (!dtorOnly)
1208 free(value.GetRawPtr());
1209}
1210
1212{
1213 return Detail::RFieldValue(true /* captureFlat */, this, where);
1214}
1215
1216
1217std::vector<ROOT::Experimental::Detail::RFieldValue>
1219{
1220 std::vector<Detail::RFieldValue> result;
1221 for (unsigned i = 0; i < fSubFields.size(); i++) {
1222 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fSubFieldsInfo[i].fOffset);
1223 result.emplace_back(memberValue);
1224 }
1225 return result;
1226}
1227
1228
1230{
1231 return fClass->GetClassSize();
1232}
1233
1235{
1236 return fClass->GetClassVersion();
1237}
1238
1240{
1241 visitor.VisitClassField(*this);
1242}
1243
1244//------------------------------------------------------------------------------
1245
1248 bool readOnly)
1249{
1250 RIteratorFuncs ifuncs;
1251 ifuncs.fCreateIterators = proxy->GetFunctionCreateIterators(readOnly);
1252 ifuncs.fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(readOnly);
1253 ifuncs.fNext = proxy->GetFunctionNext(readOnly);
1254 R__ASSERT((ifuncs.fCreateIterators != nullptr) && (ifuncs.fDeleteTwoIterators != nullptr) &&
1255 (ifuncs.fNext != nullptr));
1256 return ifuncs;
1257}
1258
1259ROOT::Experimental::RCollectionClassField::RCollectionClassField(std::string_view fieldName, std::string_view className)
1260 : RCollectionClassField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
1261{
1262}
1263
1264ROOT::Experimental::RCollectionClassField::RCollectionClassField(std::string_view fieldName, std::string_view className,
1265 TClass *classp)
1266 : ROOT::Experimental::Detail::RFieldBase(fieldName, className, ENTupleStructure::kCollection, false /* isSimple */),
1267 fNWritten(0)
1268{
1269 if (classp == nullptr)
1270 throw RException(R__FAIL("RField: no I/O support for collection proxy type " + std::string(className)));
1271 if (!classp->GetCollectionProxy())
1272 throw RException(R__FAIL(std::string(className) + " has no associated collection proxy"));
1273
1274 fProxy.reset(classp->GetCollectionProxy()->Generate());
1275 fProperties = fProxy->GetProperties();
1276 if (fProxy->HasPointers())
1277 throw RException(R__FAIL("collection proxies whose value type is a pointer are not supported"));
1279 throw RException(R__FAIL("associative collections not supported"));
1280
1281 fIFuncsRead = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), true /* readOnly */);
1282 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readOnly */);
1283
1284 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> itemField;
1285 if (auto valueClass = fProxy->GetValueClass()) {
1286 // Element type is a class
1287 itemField = RFieldBase::Create("_0", valueClass->GetName()).Unwrap();
1288 } else {
1289 switch (fProxy->GetType()) {
1290 case EDataType::kChar_t: itemField = std::make_unique<RField<char>>("_0"); break;
1291 case EDataType::kUChar_t: itemField = std::make_unique<RField<std::uint8_t>>("_0"); break;
1292 case EDataType::kShort_t: itemField = std::make_unique<RField<std::int16_t>>("_0"); break;
1293 case EDataType::kUShort_t: itemField = std::make_unique<RField<std::uint16_t>>("_0"); break;
1294 case EDataType::kInt_t: itemField = std::make_unique<RField<std::int32_t>>("_0"); break;
1295 case EDataType::kUInt_t: itemField = std::make_unique<RField<std::uint32_t>>("_0"); break;
1296 case EDataType::kLong_t:
1298 itemField = std::make_unique<RField<std::int64_t>>("_0");
1299 break;
1302 itemField = std::make_unique<RField<std::uint64_t>>("_0");
1303 break;
1304 case EDataType::kFloat_t: itemField = std::make_unique<RField<float>>("_0"); break;
1305 case EDataType::kDouble_t: itemField = std::make_unique<RField<double>>("_0"); break;
1306 case EDataType::kBool_t: itemField = std::make_unique<RField<bool>>("_0"); break;
1307 default:
1308 throw RException(R__FAIL("unsupported value type"));
1309 }
1310 }
1311 fItemSize = itemField->GetValueSize();
1312 Attach(std::move(itemField));
1313}
1314
1315std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1317{
1318 return std::unique_ptr<RCollectionClassField>(
1319 new RCollectionClassField(newName, GetType(), fProxy->GetCollectionClass()));
1320}
1321
1323{
1324 std::size_t nbytes = 0;
1325 unsigned count = 0;
1326 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), value.GetRawPtr());
1327 for (auto ptr : RCollectionIterableOnce{value.GetRawPtr(), fIFuncsRead, fProxy.get()}) {
1328 auto itemValue = fSubFields[0]->CaptureValue(ptr);
1329 nbytes += fSubFields[0]->Append(itemValue);
1330 count++;
1331 }
1332
1333 Detail::RColumnElement<ClusterSize_t> elemIndex(&fNWritten);
1334 fNWritten += count;
1335 fColumns[0]->Append(elemIndex);
1336 return nbytes + sizeof(elemIndex);
1337}
1338
1340{
1341 ClusterSize_t nItems;
1342 RClusterIndex collectionStart;
1343 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1344
1345 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), value->GetRawPtr());
1346 void *obj =
1347 fProxy->Allocate(static_cast<std::uint32_t>(nItems), (fProperties & TVirtualCollectionProxy::kNeedDelete));
1348 unsigned i = 0;
1349 // TODO(jalopezg): we might be able to further optimize this in case `GetCollectionType() == kSTLvector`
1350 for (auto ptr : RCollectionIterableOnce{obj, fIFuncsWrite, fProxy.get()}) {
1351 auto itemValue = fSubFields[0]->CaptureValue(ptr);
1352 fSubFields[0]->Read(collectionStart + i, &itemValue);
1353 i++;
1354 }
1355 if (obj != value->GetRawPtr())
1356 fProxy->Commit(obj);
1357}
1358
1361{
1362 static RColumnRepresentations representations(
1364 {});
1365 return representations;
1366}
1367
1369{
1370 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1371}
1372
1374{
1375 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1376 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
1377}
1378
1380{
1381 return Detail::RFieldValue(true /* captureFlag */, this, fProxy->New(where));
1382}
1383
1385{
1386 if (fProperties & TVirtualCollectionProxy::kNeedDelete) {
1387 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), value.GetRawPtr());
1388 for (auto ptr : RCollectionIterableOnce{value.GetRawPtr(), fIFuncsWrite, fProxy.get()}) {
1389 auto itemValue = fSubFields[0]->CaptureValue(ptr);
1390 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1391 }
1392 }
1393 fProxy->Destructor(value.GetRawPtr(), true /* dtorOnly */);
1394 if (!dtorOnly)
1395 free(value.GetRawPtr());
1396}
1397
1399{
1400 return Detail::RFieldValue(true /* captureFlag */, this, where);
1401}
1402
1403std::vector<ROOT::Experimental::Detail::RFieldValue>
1405{
1406 std::vector<Detail::RFieldValue> result;
1407 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), value.GetRawPtr());
1408 for (auto ptr : RCollectionIterableOnce{value.GetRawPtr(), fIFuncsRead, fProxy.get()}) {
1409 result.emplace_back(fSubFields[0]->CaptureValue(ptr));
1410 }
1411 return result;
1412}
1413
1415{
1416 fNWritten = 0;
1417}
1418
1420{
1421 visitor.VisitCollectionClassField(*this);
1422}
1423
1424//------------------------------------------------------------------------------
1425
1427 std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields,
1428 const std::vector<std::size_t> &offsets, std::string_view typeName)
1429 : ROOT::Experimental::Detail::RFieldBase(fieldName, typeName, ENTupleStructure::kRecord, false /* isSimple */),
1430 fOffsets(offsets)
1431{
1433 for (auto &item : itemFields) {
1434 fMaxAlignment = std::max(fMaxAlignment, item->GetAlignment());
1435 fSize += GetItemPadding(fSize, item->GetAlignment()) + item->GetValueSize();
1436 fTraits &= item->GetTraits();
1437 Attach(std::move(item));
1438 }
1439}
1440
1442 std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields)
1443 : ROOT::Experimental::Detail::RFieldBase(fieldName, "", ENTupleStructure::kRecord, false /* isSimple */)
1444{
1446 for (auto &item : itemFields) {
1447 fSize += GetItemPadding(fSize, item->GetAlignment());
1448 fOffsets.push_back(fSize);
1449 fMaxAlignment = std::max(fMaxAlignment, item->GetAlignment());
1450 fSize += item->GetValueSize();
1451 fTraits &= item->GetTraits();
1452 Attach(std::move(item));
1453 }
1454 // Trailing padding: although this is implementation-dependent, most add enough padding to comply with the
1455 // requirements of the type with strictest alignment
1457}
1458
1460 std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields)
1461 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields))
1462{
1463}
1464
1465std::size_t ROOT::Experimental::RRecordField::GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
1466{
1467 if (itemAlignment > 1) {
1468 auto remainder = baseOffset % itemAlignment;
1469 if (remainder != 0)
1470 return itemAlignment - remainder;
1471 }
1472 return 0;
1473}
1474
1475std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1476ROOT::Experimental::RRecordField::CloneImpl(std::string_view newName) const
1477{
1478 std::vector<std::unique_ptr<Detail::RFieldBase>> cloneItems;
1479 for (auto &item : fSubFields)
1480 cloneItems.emplace_back(item->Clone(item->GetName()));
1481 return std::unique_ptr<RRecordField>(new RRecordField(newName, std::move(cloneItems), fOffsets, GetType()));
1482}
1483
1485 std::size_t nbytes = 0;
1486 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1487 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fOffsets[i]);
1488 nbytes += fSubFields[i]->Append(memberValue);
1489 }
1490 return nbytes;
1491}
1492
1494{
1495 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1496 auto memberValue = fSubFields[i]->CaptureValue(value->Get<unsigned char>() + fOffsets[i]);
1497 fSubFields[i]->Read(globalIndex, &memberValue);
1498 }
1499}
1500
1502{
1503 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1504 auto memberValue = fSubFields[i]->CaptureValue(value->Get<unsigned char>() + fOffsets[i]);
1505 fSubFields[i]->Read(clusterIndex, &memberValue);
1506 }
1507}
1508
1510{
1511 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1512 fSubFields[i]->GenerateValue(static_cast<unsigned char *>(where) + fOffsets[i]);
1513 }
1514 return Detail::RFieldValue(true /* captureFlag */, this, where);
1515}
1516
1518{
1519 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1520 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fOffsets[i]);
1521 fSubFields[i]->DestroyValue(memberValue, true /* dtorOnly */);
1522 }
1523
1524 if (!dtorOnly)
1525 free(value.GetRawPtr());
1526}
1527
1529{
1530 return Detail::RFieldValue(true /* captureFlag */, this, where);
1531}
1532
1533
1534std::vector<ROOT::Experimental::Detail::RFieldValue>
1536{
1537 std::vector<Detail::RFieldValue> result;
1538 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1539 result.emplace_back(fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fOffsets[i]));
1540 }
1541 return result;
1542}
1543
1544
1546{
1547 visitor.VisitRecordField(*this);
1548}
1549
1550//------------------------------------------------------------------------------
1551
1552
1554 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
1555 : ROOT::Experimental::Detail::RFieldBase(
1556 fieldName, "std::vector<" + itemField->GetType() + ">", ENTupleStructure::kCollection, false /* isSimple */)
1557 , fItemSize(itemField->GetValueSize()), fNWritten(0)
1558{
1559 Attach(std::move(itemField));
1560}
1561
1562std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1563ROOT::Experimental::RVectorField::CloneImpl(std::string_view newName) const
1564{
1565 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
1566 return std::make_unique<RVectorField>(newName, std::move(newItemField));
1567}
1568
1570 auto typedValue = value.Get<std::vector<char>>();
1571 R__ASSERT((typedValue->size() % fItemSize) == 0);
1572 std::size_t nbytes = 0;
1573 auto count = typedValue->size() / fItemSize;
1574 for (unsigned i = 0; i < count; ++i) {
1575 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
1576 nbytes += fSubFields[0]->Append(itemValue);
1577 }
1578 Detail::RColumnElement<ClusterSize_t> elemIndex(&fNWritten);
1579 fNWritten += count;
1580 fColumns[0]->Append(elemIndex);
1581 return nbytes + sizeof(elemIndex);
1582}
1583
1585{
1586 auto typedValue = value->Get<std::vector<char>>();
1587
1588 ClusterSize_t nItems;
1589 RClusterIndex collectionStart;
1590 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1591
1592 if (fSubFields[0]->GetTraits() & kTraitTrivialType) {
1593 typedValue->resize(nItems * fItemSize);
1594 } else {
1595 // See "semantics of reading non-trivial objects" in RNTuple's architecture.md
1596 const auto oldNItems = typedValue->size() / fItemSize;
1597 const bool canRealloc = oldNItems < nItems;
1598 bool allDeallocated = false;
1599 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible)) {
1600 allDeallocated = canRealloc;
1601 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
1602 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
1603 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1604 }
1605 }
1606 typedValue->resize(nItems * fItemSize);
1607 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyConstructible)) {
1608 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
1609 fSubFields[0]->GenerateValue(typedValue->data() + (i * fItemSize));
1610 }
1611 }
1612 }
1613
1614 for (std::size_t i = 0; i < nItems; ++i) {
1615 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
1616 fSubFields[0]->Read(collectionStart + i, &itemValue);
1617 }
1618}
1619
1622{
1623 static RColumnRepresentations representations(
1625 {});
1626 return representations;
1627}
1628
1630{
1631 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1632}
1633
1635{
1636 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1637 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
1638}
1639
1641{
1642 return Detail::RFieldValue(this, reinterpret_cast<std::vector<char>*>(where));
1643}
1644
1646{
1647 auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
1648 R__ASSERT((vec->size() % fItemSize) == 0);
1649 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible)) {
1650 auto nItems = vec->size() / fItemSize;
1651 for (unsigned i = 0; i < nItems; ++i) {
1652 auto itemValue = fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize));
1653 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1654 }
1655 }
1656 vec->~vector();
1657 if (!dtorOnly)
1658 free(vec);
1659}
1660
1662{
1663 return Detail::RFieldValue(true /* captureFlag */, this, where);
1664}
1665
1666std::vector<ROOT::Experimental::Detail::RFieldValue>
1668{
1669 auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
1670 R__ASSERT((vec->size() % fItemSize) == 0);
1671 auto nItems = vec->size() / fItemSize;
1672 std::vector<Detail::RFieldValue> result;
1673 for (unsigned i = 0; i < nItems; ++i) {
1674 result.emplace_back(fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize)));
1675 }
1676 return result;
1677}
1678
1680{
1681 fNWritten = 0;
1682}
1683
1685{
1686 visitor.VisitVectorField(*this);
1687}
1688
1689
1690//------------------------------------------------------------------------------
1691
1692ROOT::Experimental::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
1693 : ROOT::Experimental::Detail::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetType() + ">",
1694 ENTupleStructure::kCollection, false /* isSimple */),
1695 fItemSize(itemField->GetValueSize()), fNWritten(0)
1696{
1697 Attach(std::move(itemField));
1698 fValueSize = EvalValueSize(); // requires fSubFields to be populated
1699}
1700
1701std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1702ROOT::Experimental::RRVecField::CloneImpl(std::string_view newName) const
1703{
1704 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
1705 return std::make_unique<RRVecField>(newName, std::move(newItemField));
1706}
1707
1709{
1710 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(value.GetRawPtr());
1711
1712 std::size_t nbytes = 0;
1713 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
1714 for (std::int32_t i = 0; i < *sizePtr; ++i) {
1715 auto elementValue = fSubFields[0]->CaptureValue(begin + i * fItemSize);
1716 nbytes += fSubFields[0]->Append(elementValue);
1717 }
1718
1719 Detail::RColumnElement<ClusterSize_t> elemIndex(&fNWritten);
1720 fNWritten += *sizePtr;
1721 fColumns[0]->Append(elemIndex);
1722 return nbytes + sizeof(elemIndex);
1723}
1724
1726{
1727 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
1728 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
1729
1730 auto [beginPtr, sizePtr, capacityPtr] = GetRVecDataMembers(value->GetRawPtr());
1731
1732 // Read collection info for this entry
1733 ClusterSize_t nItems;
1734 RClusterIndex collectionStart;
1735 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1736 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
1737 const std::size_t oldSize = *sizePtr;
1738
1739 // See "semantics of reading non-trivial objects" in RNTuple's architecture.md for details
1740 // on the element construction/destrution.
1741 const bool needsConstruct = !(fSubFields[0]->GetTraits() & kTraitTriviallyConstructible);
1742 const bool needsDestruct = !(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible);
1743
1744 // Destroy excess elements, if any
1745 if (needsDestruct) {
1746 for (std::size_t i = nItems; i < oldSize; ++i) {
1747 auto itemValue = fSubFields[0]->CaptureValue(begin + (i * fItemSize));
1748 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1749 }
1750 }
1751
1752 // Resize RVec (capacity and size)
1753 if (std::int32_t(nItems) > *capacityPtr) { // must reallocate
1754 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
1755 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
1756 if (needsDestruct) {
1757 for (std::size_t i = 0u; i < oldSize; ++i) {
1758 auto itemValue = fSubFields[0]->CaptureValue(begin + (i * fItemSize));
1759 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1760 }
1761 }
1762
1763 // TODO Increment capacity by a factor rather than just enough to fit the elements.
1764 free(*beginPtr);
1765 // We trust that malloc returns a buffer with large enough alignment.
1766 // This might not be the case if T in RVec<T> is over-aligned.
1767 *beginPtr = malloc(nItems * fItemSize);
1768 R__ASSERT(*beginPtr != nullptr);
1769 begin = reinterpret_cast<char *>(*beginPtr);
1770 *capacityPtr = nItems;
1771
1772 // Placement new for elements that were already there before the resize
1773 if (needsConstruct) {
1774 for (std::size_t i = 0u; i < oldSize; ++i)
1775 fSubFields[0]->GenerateValue(begin + (i * fItemSize));
1776 }
1777 }
1778 *sizePtr = nItems;
1779
1780 // Placement new for new elements, if any
1781 if (needsConstruct) {
1782 for (std::size_t i = oldSize; i < nItems; ++i)
1783 fSubFields[0]->GenerateValue(begin + (i * fItemSize));
1784 }
1785
1786 // Read the new values into the collection elements
1787 for (std::size_t i = 0; i < nItems; ++i) {
1788 auto itemValue = fSubFields[0]->CaptureValue(begin + (i * fItemSize));
1789 fSubFields[0]->Read(collectionStart + i, &itemValue);
1790 }
1791}
1792
1795{
1796 static RColumnRepresentations representations(
1798 {});
1799 return representations;
1800}
1801
1803{
1804 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1805}
1806
1808{
1809 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1810 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
1811}
1812
1814{
1815 // initialize data members fBegin, fSize, fCapacity
1816 // currently the inline buffer is left uninitialized
1817 void **beginPtr = new (where)(void *)(nullptr);
1818 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
1819 new (sizePtr + 1) std::int32_t(0);
1820
1821 return Detail::RFieldValue(/*captureTag*/ true, this, where);
1822}
1823
1825{
1826 auto [beginPtr, sizePtr, capacityPtr] = GetRVecDataMembers(value.GetRawPtr());
1827
1828 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
1829 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible)) {
1830 for (std::int32_t i = 0; i < *sizePtr; ++i) {
1831 auto elementValue = fSubFields[0]->CaptureValue(begin + i * fItemSize);
1832 fSubFields[0]->DestroyValue(elementValue, true /* dtorOnly */);
1833 }
1834 }
1835
1836 // figure out if we are in the small state, i.e. begin == &inlineBuffer
1837 // there might be padding between fCapacity and the inline buffer, so we compute it here
1838 constexpr auto dataMemberSz = sizeof(void *) + 2 * sizeof(std::int32_t);
1839 const auto alignOfT = fSubFields[0]->GetAlignment();
1840 auto paddingMiddle = dataMemberSz % alignOfT;
1841 if (paddingMiddle != 0)
1842 paddingMiddle = alignOfT - paddingMiddle;
1843 const bool isSmall = (reinterpret_cast<void *>(begin) == (beginPtr + dataMemberSz + paddingMiddle));
1844
1845 const bool owns = (*capacityPtr != -1);
1846 if (!isSmall && owns)
1847 free(begin);
1848
1849 if (!dtorOnly)
1850 free(beginPtr);
1851}
1852
1854{
1855 return Detail::RFieldValue(true /* captureFlag */, this, where);
1856}
1857
1858std::vector<ROOT::Experimental::Detail::RFieldValue>
1860{
1861 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(value.GetRawPtr());
1862
1863 std::vector<Detail::RFieldValue> result;
1864 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
1865 for (std::int32_t i = 0; i < *sizePtr; ++i) {
1866 auto elementValue = fSubFields[0]->CaptureValue(begin + i * fItemSize);
1867 result.emplace_back(std::move(elementValue));
1868 }
1869 return result;
1870}
1871
1873{
1874 // the size of an RVec<T> is the size of its 4 data-members + optional padding:
1875 //
1876 // data members:
1877 // - void *fBegin
1878 // - int32_t fSize
1879 // - int32_t fCapacity
1880 // - the char[] inline storage, which is aligned like T
1881 //
1882 // padding might be present:
1883 // - between fCapacity and the char[] buffer aligned like T
1884 // - after the char[] buffer
1885
1886 constexpr auto dataMemberSz = sizeof(void *) + 2 * sizeof(std::int32_t);
1887 const auto alignOfT = fSubFields[0]->GetAlignment();
1888 const auto sizeOfT = fSubFields[0]->GetValueSize();
1889
1890 // mimic the logic of RVecInlineStorageSize, but at runtime
1891 const auto inlineStorageSz = [&] {
1892#ifdef R__HAS_HARDWARE_INTERFERENCE_SIZE
1893 // hardware_destructive_interference_size is a C++17 feature but many compilers do not implement it yet
1894 constexpr unsigned cacheLineSize = std::hardware_destructive_interference_size;
1895#else
1896 constexpr unsigned cacheLineSize = 64u;
1897#endif
1898 const unsigned elementsPerCacheLine = (cacheLineSize - dataMemberSz) / sizeOfT;
1899 constexpr unsigned maxInlineByteSize = 1024;
1900 const unsigned nElements =
1901 elementsPerCacheLine >= 8 ? elementsPerCacheLine : (sizeOfT * 8 > maxInlineByteSize ? 0 : 8);
1902 return nElements * sizeOfT;
1903 }();
1904
1905 // compute padding between first 3 datamembers and inline buffer
1906 // (there should be no padding between the first 3 data members)
1907 auto paddingMiddle = dataMemberSz % alignOfT;
1908 if (paddingMiddle != 0)
1909 paddingMiddle = alignOfT - paddingMiddle;
1910
1911 // padding at the end of the object
1912 const auto alignOfRVecT = GetAlignment();
1913 auto paddingEnd = (dataMemberSz + paddingMiddle + inlineStorageSz) % alignOfRVecT;
1914 if (paddingEnd != 0)
1915 paddingEnd = alignOfRVecT - paddingEnd;
1916
1917 return dataMemberSz + inlineStorageSz + paddingMiddle + paddingEnd;
1918}
1919
1921{
1922 return fValueSize;
1923}
1924
1926{
1927 // the alignment of an RVec<T> is the largest among the alignments of its data members
1928 // (including the inline buffer which has the same alignment as the RVec::value_type)
1929 return std::max({alignof(void *), alignof(std::int32_t), fSubFields[0]->GetAlignment()});
1930}
1931
1933{
1934 fNWritten = 0;
1935}
1936
1938{
1939 visitor.VisitRVecField(*this);
1940}
1941
1942//------------------------------------------------------------------------------
1943
1945 : ROOT::Experimental::Detail::RFieldBase(name, "std::vector<bool>", ENTupleStructure::kCollection,
1946 false /* isSimple */)
1947{
1948 Attach(std::make_unique<RField<bool>>("_0"));
1949}
1950
1951std::size_t ROOT::Experimental::RField<std::vector<bool>>::AppendImpl(const Detail::RFieldValue& value) {
1952 auto typedValue = value.Get<std::vector<bool>>();
1953 auto count = typedValue->size();
1954 for (unsigned i = 0; i < count; ++i) {
1955 bool bval = (*typedValue)[i];
1956 auto itemValue = fSubFields[0]->CaptureValue(&bval);
1957 fSubFields[0]->Append(itemValue);
1958 }
1959 Detail::RColumnElement<ClusterSize_t> elemIndex(&fNWritten);
1960 fNWritten += count;
1961 fColumns[0]->Append(elemIndex);
1962 return count + sizeof(elemIndex);
1963}
1964
1965void ROOT::Experimental::RField<std::vector<bool>>::ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue* value)
1966{
1967 auto typedValue = value->Get<std::vector<bool>>();
1968
1969 ClusterSize_t nItems;
1970 RClusterIndex collectionStart;
1971 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1972
1973 typedValue->resize(nItems);
1974 for (unsigned i = 0; i < nItems; ++i) {
1975 bool bval;
1976 auto itemValue = fSubFields[0]->GenerateValue(&bval);
1977 fSubFields[0]->Read(collectionStart + i, &itemValue);
1978 (*typedValue)[i] = bval;
1979 }
1980}
1981
1983ROOT::Experimental::RField<std::vector<bool>>::GetColumnRepresentations() const
1984{
1985 static RColumnRepresentations representations(
1987 {});
1988 return representations;
1989}
1990
1991void ROOT::Experimental::RField<std::vector<bool>>::GenerateColumnsImpl()
1992{
1993 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1994}
1995
1996void ROOT::Experimental::RField<std::vector<bool>>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1997{
1998 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1999 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
2000}
2001
2002std::vector<ROOT::Experimental::Detail::RFieldValue>
2003ROOT::Experimental::RField<std::vector<bool>>::SplitValue(const Detail::RFieldValue& value) const
2004{
2005 const static bool trueValue = true;
2006 const static bool falseValue = false;
2007
2008 auto typedValue = value.Get<std::vector<bool>>();
2009 auto count = typedValue->size();
2010 std::vector<Detail::RFieldValue> result;
2011 for (unsigned i = 0; i < count; ++i) {
2012 if ((*typedValue)[i])
2013 result.emplace_back(fSubFields[0]->CaptureValue(const_cast<bool *>(&trueValue)));
2014 else
2015 result.emplace_back(fSubFields[0]->CaptureValue(const_cast<bool *>(&falseValue)));
2016 }
2017 return result;
2018}
2019
2020
2021void ROOT::Experimental::RField<std::vector<bool>>::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
2022{
2023 auto vec = static_cast<std::vector<bool>*>(value.GetRawPtr());
2024 vec->~vector();
2025 if (!dtorOnly)
2026 free(vec);
2027}
2028
2029void ROOT::Experimental::RField<std::vector<bool>>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
2030{
2031 visitor.VisitVectorBoolField(*this);
2032}
2033
2034
2035//------------------------------------------------------------------------------
2036
2037
2039 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField, std::size_t arrayLength)
2040 : ROOT::Experimental::Detail::RFieldBase(
2041 fieldName, "std::array<" + itemField->GetType() + "," + std::to_string(arrayLength) + ">",
2042 ENTupleStructure::kLeaf, false /* isSimple */, arrayLength)
2043 , fItemSize(itemField->GetValueSize()), fArrayLength(arrayLength)
2044{
2045 fTraits |= itemField->GetTraits() & ~kTraitMappable;
2046 Attach(std::move(itemField));
2047}
2048
2049std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2050ROOT::Experimental::RArrayField::CloneImpl(std::string_view newName) const
2051{
2052 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
2053 return std::make_unique<RArrayField>(newName, std::move(newItemField), fArrayLength);
2054}
2055
2057 std::size_t nbytes = 0;
2058 auto arrayPtr = value.Get<unsigned char>();
2059 for (unsigned i = 0; i < fArrayLength; ++i) {
2060 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
2061 nbytes += fSubFields[0]->Append(itemValue);
2062 }
2063 return nbytes;
2064}
2065
2067{
2068 auto arrayPtr = value->Get<unsigned char>();
2069 for (unsigned i = 0; i < fArrayLength; ++i) {
2070 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
2071 fSubFields[0]->Read(globalIndex * fArrayLength + i, &itemValue);
2072 }
2073}
2074
2076{
2077 auto arrayPtr = value->Get<unsigned char>();
2078 for (unsigned i = 0; i < fArrayLength; ++i) {
2079 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
2080 fSubFields[0]->Read(RClusterIndex(clusterIndex.GetClusterId(), clusterIndex.GetIndex() * fArrayLength + i),
2081 &itemValue);
2082 }
2083}
2084
2086{
2087 if (fSubFields[0]->GetTraits() & kTraitTriviallyConstructible)
2088 return Detail::RFieldValue(true /* captureFlag */, this, where);
2089
2090 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
2091 for (unsigned i = 0; i < fArrayLength; ++i) {
2092 fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
2093 }
2094 return Detail::RFieldValue(true /* captureFlag */, this, where);
2095}
2096
2098{
2099 auto arrayPtr = value.Get<unsigned char>();
2100 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible)) {
2101 for (unsigned i = 0; i < fArrayLength; ++i) {
2102 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
2103 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
2104 }
2105 }
2106 if (!dtorOnly)
2107 free(arrayPtr);
2108}
2109
2111{
2112 return Detail::RFieldValue(true /* captureFlag */, this, where);
2113}
2114
2115std::vector<ROOT::Experimental::Detail::RFieldValue>
2117{
2118 auto arrayPtr = value.Get<unsigned char>();
2119 std::vector<Detail::RFieldValue> result;
2120 for (unsigned i = 0; i < fArrayLength; ++i) {
2121 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
2122 result.emplace_back(itemValue);
2123 }
2124 return result;
2125}
2126
2128{
2129 visitor.VisitArrayField(*this);
2130}
2131
2132//------------------------------------------------------------------------------
2133
2134ROOT::Experimental::RBitsetField::RBitsetField(std::string_view fieldName, std::size_t N)
2135 : ROOT::Experimental::Detail::RFieldBase(fieldName, "std::bitset<" + std::to_string(N) + ">",
2136 ENTupleStructure::kLeaf, false /* isSimple */, N),
2137 fN(N)
2138{
2140}
2141
2144{
2145 static RColumnRepresentations representations({{EColumnType::kBit}}, {});
2146 return representations;
2147}
2148
2150{
2151 fColumns.emplace_back(Detail::RColumn::Create<bool>(RColumnModel(GetColumnRepresentative()[0]), 0));
2152}
2153
2155{
2156 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
2157 fColumns.emplace_back(Detail::RColumn::Create<bool>(RColumnModel(onDiskTypes[0]), 0));
2158}
2159
2161{
2162 const auto *asULongArray = value.Get<Word_t>();
2163 bool elementValue;
2164 Detail::RColumnElement<bool> element(&elementValue);
2165 std::size_t i = 0;
2166 for (std::size_t word = 0; word < (fN + kBitsPerWord - 1) / kBitsPerWord; ++word) {
2167 for (std::size_t mask = 0; (mask < kBitsPerWord) && (i < fN); ++mask, ++i) {
2168 elementValue = (asULongArray[word] & (static_cast<Word_t>(1) << mask)) != 0;
2169 fColumns[0]->Append(element);
2170 }
2171 }
2172 return fN;
2173}
2174
2176{
2177 auto *asULongArray = value->Get<Word_t>();
2178 bool elementValue;
2179 Detail::RColumnElement<bool> element(&elementValue);
2180 for (std::size_t i = 0; i < fN; ++i) {
2181 fColumns[0]->Read(globalIndex * fN + i, &element);
2182 Word_t mask = static_cast<Word_t>(1) << (i % kBitsPerWord);
2183 Word_t bit = static_cast<Word_t>(elementValue) << (i % kBitsPerWord);
2184 asULongArray[i / kBitsPerWord] = (asULongArray[i / kBitsPerWord] & ~mask) | bit;
2185 }
2186}
2187
2189{
2190 visitor.VisitBitsetField(*this);
2191}
2192
2193//------------------------------------------------------------------------------
2194
2195std::string ROOT::Experimental::RVariantField::GetTypeList(const std::vector<Detail::RFieldBase *> &itemFields)
2196{
2197 std::string result;
2198 for (size_t i = 0; i < itemFields.size(); ++i) {
2199 result += itemFields[i]->GetType() + ",";
2200 }
2201 R__ASSERT(!result.empty()); // there is always at least one variant
2202 result.pop_back(); // remove trailing comma
2203 return result;
2204}
2205
2207 std::string_view fieldName, const std::vector<Detail::RFieldBase *> &itemFields)
2208 : ROOT::Experimental::Detail::RFieldBase(fieldName,
2209 "std::variant<" + GetTypeList(itemFields) + ">", ENTupleStructure::kVariant, false /* isSimple */)
2210{
2211 // The variant needs to initialize its own tag member
2212 fTraits |= kTraitTriviallyDestructible & ~kTraitTriviallyConstructible;
2213
2214 auto nFields = itemFields.size();
2215 R__ASSERT(nFields > 0);
2216 fNWritten.resize(nFields, 0);
2217 for (unsigned int i = 0; i < nFields; ++i) {
2218 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
2219 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
2220 fTraits &= itemFields[i]->GetTraits();
2221 Attach(std::unique_ptr<Detail::RFieldBase>(itemFields[i]));
2222 }
2224}
2225
2226std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2228{
2229 auto nFields = fSubFields.size();
2230 std::vector<Detail::RFieldBase *> itemFields;
2231 for (unsigned i = 0; i < nFields; ++i) {
2232 // TODO(jblomer): use unique_ptr in RVariantField constructor
2233 itemFields.emplace_back(fSubFields[i]->Clone(fSubFields[i]->GetName()).release());
2234 }
2235 return std::make_unique<RVariantField>(newName, itemFields);
2236}
2237
2238std::uint32_t ROOT::Experimental::RVariantField::GetTag(void *variantPtr) const
2239{
2240 auto index = *(reinterpret_cast<char *>(variantPtr) + fTagOffset);
2241 return (index < 0) ? 0 : index + 1;
2242}
2243
2244void ROOT::Experimental::RVariantField::SetTag(void *variantPtr, std::uint32_t tag) const
2245{
2246 auto index = reinterpret_cast<char *>(variantPtr) + fTagOffset;
2247 *index = static_cast<char>(tag - 1);
2248}
2249
2251{
2252 auto tag = GetTag(value.GetRawPtr());
2253 std::size_t nbytes = 0;
2254 auto index = 0;
2255 if (tag > 0) {
2256 auto itemValue = fSubFields[tag - 1]->CaptureValue(value.GetRawPtr());
2257 nbytes += fSubFields[tag - 1]->Append(itemValue);
2258 index = fNWritten[tag - 1]++;
2259 }
2260 RColumnSwitch varSwitch(ClusterSize_t(index), tag);
2261 Detail::RColumnElement<RColumnSwitch> elemSwitch(&varSwitch);
2262 fColumns[0]->Append(elemSwitch);
2263 return nbytes + sizeof(RColumnSwitch);
2264}
2265
2267{
2268 RClusterIndex variantIndex;
2269 std::uint32_t tag;
2270 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
2271 R__ASSERT(tag > 0); // TODO(jblomer): deal with invalid variants
2272
2273 auto itemValue = fSubFields[tag - 1]->GenerateValue(value->GetRawPtr());
2274 fSubFields[tag - 1]->Read(variantIndex, &itemValue);
2275 SetTag(value->GetRawPtr(), tag);
2276}
2277
2280{
2281 static RColumnRepresentations representations({{EColumnType::kSwitch}}, {{}});
2282 return representations;
2283}
2284
2286{
2287 fColumns.emplace_back(Detail::RColumn::Create<RColumnSwitch>(RColumnModel(GetColumnRepresentative()[0]), 0));
2288}
2289
2291{
2292 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
2293 fColumns.emplace_back(Detail::RColumn::Create<RColumnSwitch>(RColumnModel(onDiskTypes[0]), 0));
2294}
2295
2297{
2298 memset(where, 0, GetValueSize());
2299 fSubFields[0]->GenerateValue(where);
2300 SetTag(where, 1);
2301 return Detail::RFieldValue(this, reinterpret_cast<unsigned char *>(where));
2302}
2303
2305{
2306 auto variantPtr = value.GetRawPtr();
2307 auto tag = GetTag(variantPtr);
2308 if (tag > 0) {
2309 auto itemValue = fSubFields[tag - 1]->CaptureValue(variantPtr);
2310 fSubFields[tag - 1]->DestroyValue(itemValue, true /* dtorOnly */);
2311 }
2312 if (!dtorOnly)
2313 free(variantPtr);
2314}
2315
2317{
2318 return Detail::RFieldValue(true /* captureFlag */, this, where);
2319}
2320
2322{
2323 return fMaxItemSize + fMaxAlignment; // TODO: fix for more than 255 items
2324}
2325
2327{
2328 std::fill(fNWritten.begin(), fNWritten.end(), 0);
2329}
2330
2331//------------------------------------------------------------------------------
2332
2333ROOT::Experimental::RNullableField::RNullableField(std::string_view fieldName, std::string_view typeName,
2334 std::unique_ptr<Detail::RFieldBase> itemField)
2335 : ROOT::Experimental::Detail::RFieldBase(fieldName, typeName, ENTupleStructure::kCollection, false /* isSimple */)
2336{
2337 Attach(std::move(itemField));
2338}
2339
2341{
2342 if (fDefaultItemValue.GetField()) {
2343 fDefaultItemValue.GetField()->DestroyValue(fDefaultItemValue);
2344 }
2345}
2346
2349{
2350 static RColumnRepresentations representations(
2352 {EColumnType::kBit}}, {});
2353 return representations;
2354}
2355
2357{
2358 if (HasDefaultColumnRepresentative()) {
2359 if (fSubFields[0]->GetValueSize() < 4) {
2360 SetColumnRepresentative({EColumnType::kBit});
2361 }
2362 }
2363 if (IsDense()) {
2364 fDefaultItemValue = fSubFields[0]->GenerateValue();
2365 fColumns.emplace_back(Detail::RColumn::Create<bool>(RColumnModel(EColumnType::kBit), 0));
2366 } else {
2367 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
2368 }
2369}
2370
2372{
2373 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
2374 if (onDiskTypes[0] == EColumnType::kBit) {
2375 fColumns.emplace_back(Detail::RColumn::Create<bool>(RColumnModel(EColumnType::kBit), 0));
2376 } else {
2377 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
2378 }
2379}
2380
2382{
2383 if (IsDense()) {
2384 bool mask = false;
2385 Detail::RColumnElement<bool> maskElement(&mask);
2386 fPrincipalColumn->Append(maskElement);
2387 return 1 + fSubFields[0]->Append(fDefaultItemValue);
2388 } else {
2389 Detail::RColumnElement<ClusterSize_t> offsetElement(&fNWritten);
2390 fPrincipalColumn->Append(offsetElement);
2391 return sizeof(ClusterSize_t);
2392 }
2393}
2394
2396{
2397 auto nbytesItem = fSubFields[0]->Append(value);
2398 if (IsDense()) {
2399 bool mask = true;
2400 Detail::RColumnElement<bool> maskElement(&mask);
2401 fPrincipalColumn->Append(maskElement);
2402 return 1 + nbytesItem;
2403 } else {
2404 fNWritten++;
2405 Detail::RColumnElement<ClusterSize_t> offsetElement(&fNWritten);
2406 fPrincipalColumn->Append(offsetElement);
2407 return sizeof(ClusterSize_t) + nbytesItem;
2408 }
2409}
2410
2412{
2413 RClusterIndex nullIndex;
2414 if (IsDense()) {
2415 const bool isValidItem = *fPrincipalColumn->Map<bool>(globalIndex);
2416 return isValidItem ? fPrincipalColumn->GetClusterIndex(globalIndex) : nullIndex;
2417 } else {
2418 RClusterIndex collectionStart;
2419 ClusterSize_t collectionSize;
2420 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &collectionSize);
2421 return (collectionSize == 0) ? nullIndex : collectionStart;
2422 }
2423}
2424
2426{
2427 visitor.VisitNullableField(*this);
2428}
2429
2430//------------------------------------------------------------------------------
2431
2432ROOT::Experimental::RUniquePtrField::RUniquePtrField(std::string_view fieldName, std::string_view typeName,
2433 std::unique_ptr<Detail::RFieldBase> itemField)
2434 : RNullableField(fieldName, typeName, std::move(itemField))
2435{
2436}
2437
2438std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2440{
2441 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
2442 return std::make_unique<RUniquePtrField>(newName, GetType(), std::move(newItemField));
2443}
2444
2446{
2447 auto typedValue = value.Get<std::unique_ptr<char>>();
2448 if (*typedValue) {
2449 auto itemValue = fSubFields[0]->CaptureValue(typedValue->get());
2450 return AppendValue(itemValue);
2451 } else {
2452 return AppendNull();
2453 }
2454}
2455
2457{
2458 auto ptr = value->Get<std::unique_ptr<char>>();
2459 bool isValidValue = static_cast<bool>(*ptr);
2460
2461 auto itemIndex = GetItemIndex(globalIndex);
2462 bool isValidItem = itemIndex.GetIndex() != kInvalidClusterIndex;
2463
2464 Detail::RFieldValue itemValue;
2465 if (isValidValue)
2466 itemValue = fSubFields[0]->CaptureValue(ptr->get());
2467
2468 if (isValidValue && !isValidItem) {
2469 ptr->release();
2470 fSubFields[0]->DestroyValue(itemValue, false /* dtorOnly */);
2471 return;
2472 }
2473
2474 if (!isValidItem) // On-disk value missing; nothing else to do
2475 return;
2476
2477 if (!isValidValue) {
2478 itemValue = fSubFields[0]->GenerateValue();
2479 ptr->reset(itemValue.Get<char>());
2480 }
2481
2482 fSubFields[0]->Read(itemIndex, &itemValue);
2483}
2484
2486{
2487 return Detail::RFieldValue(this, reinterpret_cast<std::unique_ptr<char> *>(where));
2488}
2489
2491{
2492 auto ptr = value.Get<std::unique_ptr<char>>();
2493 if (*ptr) {
2494 auto itemValue = fSubFields[0]->CaptureValue(ptr->get());
2495 fSubFields[0]->DestroyValue(itemValue, false /* dtorOnly */);
2496 ptr->release();
2497 }
2498 if (!dtorOnly)
2499 free(ptr);
2500}
2501
2503{
2504 return Detail::RFieldValue(true /* captureFlag */, this, where);
2505}
2506
2507std::vector<ROOT::Experimental::Detail::RFieldValue>
2509{
2510 std::vector<Detail::RFieldValue> result;
2511 auto ptr = value.Get<std::unique_ptr<char>>();
2512 if (*ptr) {
2513 auto itemValue = fSubFields[0]->CaptureValue(ptr->get());
2514 result.emplace_back(itemValue);
2515 }
2516 return result;
2517}
2518
2519//------------------------------------------------------------------------------
2520
2521std::string ROOT::Experimental::RPairField::RPairField::GetTypeList(
2522 const std::array<std::unique_ptr<Detail::RFieldBase>, 2> &itemFields)
2523{
2524 return itemFields[0]->GetType() + "," + itemFields[1]->GetType();
2525}
2526
2528 std::array<std::unique_ptr<Detail::RFieldBase>, 2> &&itemFields,
2529 const std::array<std::size_t, 2> &offsets)
2530 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), offsets,
2531 "std::pair<" + GetTypeList(itemFields) + ">")
2532{
2533}
2534
2536 std::array<std::unique_ptr<Detail::RFieldBase>, 2> &itemFields)
2537 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), {},
2538 "std::pair<" + GetTypeList(itemFields) + ">")
2539{
2540 // ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
2541 fClass = TClass::GetClass(GetType().c_str());
2542 if (!fClass)
2543 throw RException(R__FAIL("cannot get type information for " + GetType()));
2544 fSize = fClass->Size();
2545 fOffsets[0] = fClass->GetDataMember("first")->GetOffset();
2546 fOffsets[1] = fClass->GetDataMember("second")->GetOffset();
2547}
2548
2549std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2550ROOT::Experimental::RPairField::CloneImpl(std::string_view newName) const
2551{
2552 std::array<std::unique_ptr<Detail::RFieldBase>, 2> items{fSubFields[0]->Clone(fSubFields[0]->GetName()),
2553 fSubFields[1]->Clone(fSubFields[1]->GetName())};
2554
2555 std::unique_ptr<RPairField> result(new RPairField(newName, std::move(items), {fOffsets[0], fOffsets[1]}));
2556 result->fClass = fClass;
2557 return result;
2558}
2559
2561{
2562 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
2563}
2564
2566{
2567 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
2568 if (!dtorOnly)
2569 free(value.GetRawPtr());
2570}
2571
2572//------------------------------------------------------------------------------
2573
2574std::string ROOT::Experimental::RTupleField::RTupleField::GetTypeList(
2575 const std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields)
2576{
2577 std::string result;
2578 if (itemFields.empty())
2579 throw RException(R__FAIL("the type list for std::tuple must have at least one element"));
2580 for (size_t i = 0; i < itemFields.size(); ++i) {
2581 result += itemFields[i]->GetType() + ",";
2582 }
2583 result.pop_back(); // remove trailing comma
2584 return result;
2585}
2586
2588 std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields,
2589 const std::vector<std::size_t> &offsets)
2590 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), offsets,
2591 "std::tuple<" + GetTypeList(itemFields) + ">")
2592{
2593}
2594
2596 std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields)
2597 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), {},
2598 "std::tuple<" + GetTypeList(itemFields) + ">")
2599{
2600 fClass = TClass::GetClass(GetType().c_str());
2601 if (!fClass)
2602 throw RException(R__FAIL("cannot get type information for " + GetType()));
2603 fSize = fClass->Size();
2604
2605 // ISO C++ does not guarantee neither specific layout nor member names for `std::tuple`. However, most
2606 // implementations including libstdc++ (gcc), libc++ (llvm), and MSVC name members as `_0`, `_1`, ..., `_N-1`,
2607 // following the order of the type list.
2608 // Use TClass to get their offsets; in case a particular `std::tuple` implementation does not define such
2609 // members, the assertion below will fail.
2610 for (unsigned i = 0; i < fSubFields.size(); ++i) {
2611 std::string memberName("_" + std::to_string(i));
2612 auto member = fClass->GetRealData(memberName.c_str());
2613 if (!member)
2614 throw RException(R__FAIL(memberName + ": no such member"));
2615 fOffsets.push_back(member->GetThisOffset());
2616 }
2617}
2618
2619std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2620ROOT::Experimental::RTupleField::CloneImpl(std::string_view newName) const
2621{
2622 std::vector<std::unique_ptr<Detail::RFieldBase>> items;
2623 for (const auto &item : fSubFields)
2624 items.push_back(item->Clone(item->GetName()));
2625
2626 std::unique_ptr<RTupleField> result(new RTupleField(newName, std::move(items), fOffsets));
2627 result->fClass = fClass;
2628 return result;
2629}
2630
2632{
2633 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
2634}
2635
2637{
2638 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
2639 if (!dtorOnly)
2640 free(value.GetRawPtr());
2641}
2642
2643//------------------------------------------------------------------------------
2644
2646 std::string_view name,
2647 std::shared_ptr<RCollectionNTupleWriter> collectionNTuple,
2648 std::unique_ptr<RNTupleModel> collectionModel)
2649 : RFieldBase(name, "", ENTupleStructure::kCollection, true /* isSimple */)
2650 , fCollectionNTuple(collectionNTuple)
2651{
2652 for (unsigned i = 0; i < collectionModel->GetFieldZero()->fSubFields.size(); ++i) {
2653 auto& subField = collectionModel->GetFieldZero()->fSubFields[i];
2654 Attach(std::move(subField));
2655 }
2656 SetDescription(collectionModel->GetDescription());
2657}
2658
2661{
2662 static RColumnRepresentations representations(
2664 {});
2665 return representations;
2666}
2667
2669{
2670 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
2671}
2672
2674{
2675 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
2676 fColumns.emplace_back(Detail::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
2677}
2678
2679
2680std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2682{
2683 auto result = std::make_unique<RCollectionField>(newName, fCollectionNTuple, RNTupleModel::Create());
2684 for (auto& f : fSubFields) {
2685 auto clone = f->Clone(f->GetName());
2686 result->Attach(std::move(clone));
2687 }
2688 return result;
2689}
2690
2691
2693 *fCollectionNTuple->GetOffsetPtr() = 0;
2694}
size_t fSize
size_t fValueSize
Cppyy::TCppType_t fClass
#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:303
#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)
Definition TError.h:118
#define N
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t mask
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 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 length
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 GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
#define _(A, B)
Definition cfortran.h:108
#define free
Definition civetweb.c:1539
#define malloc
Definition civetweb.c:1536
static std::string GetTypeName(EColumnType type)
A column element points either to the content of an RFieldValue or into a memory mapped page.
Some fields have multiple possible column representations, e.g.
Definition RField.hxx:107
TypesList_t fDeserializationTypes
The union of the serialization types and the deserialization extra types.
Definition RField.hxx:122
std::vector< ColumnRepresentation_t > TypesList_t
Definition RField.hxx:109
Iterates over the sub tree of fields in depth-first search order.
Definition RField.hxx:211
void Advance()
Given that the iterator points to a valid field which is not the end iterator, go to the next field i...
Definition RField.cxx:594
virtual void GenerateColumnsImpl()=0
Creates the backing columns corresponsing to the field type for writing.
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Definition RField.hxx:151
RFieldBase * fParent
Sub fields point to their mother field.
Definition RField.hxx:153
RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple, std::size_t nRepetitions=0)
The constructor creates the underlying column objects and connects them to either a sink or a source.
Definition RField.cxx:213
int fTraits
Properties of the type that allow for optimizations of collections of that type.
Definition RField.hxx:161
virtual void DestroyValue(const RFieldValue &value, bool dtorOnly=false)
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:402
static constexpr int kTraitTrivialType
Shorthand for types that are both trivially constructible and destructible.
Definition RField.hxx:97
friend class ROOT::Experimental::RCollectionField
Definition RField.hxx:82
void ConnectPageSink(RPageSink &pageSink)
Fields and their columns live in the void until connected to a physical page storage.
Definition RField.cxx:528
void Flush() const
Ensure that all received items are written from page buffers to the storage.
Definition RField.cxx:432
virtual void CommitCluster()
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.hxx:326
void SetDescription(std::string_view description)
Definition RField.hxx:343
virtual std::vector< RFieldValue > SplitValue(const RFieldValue &value) const
Creates the list of direct child values given a value for this field.
Definition RField.cxx:409
static RResult< void > EnsureValidFieldName(std::string_view fieldName)
Check whether a given string is a valid field name.
Definition RField.cxx:354
bool fIsSimple
A field qualifies as simple if it is both mappable and has no post-read callback.
Definition RField.hxx:135
std::string fType
The C++ type captured by this field.
Definition RField.hxx:129
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName)
Factory method to resurrect a field from the stored on-disk type information.
Definition RField.cxx:236
std::string fName
The field name relative to its parent field.
Definition RField.hxx:127
size_t AddReadCallback(ReadCallback_t func)
Set a user-defined function to be called after reading a value, giving a chance to inspect and/or mod...
Definition RField.cxx:483
void ConnectPageSource(RPageSource &pageSource)
Definition RField.cxx:542
virtual std::size_t AppendImpl(const RFieldValue &value)
Operations on values of complex types, e.g.
Definition RField.cxx:382
std::function< void(RFieldValue &)> ReadCallback_t
Definition RField.hxx:84
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:365
std::unique_ptr< RFieldBase > Clone(std::string_view newName) const
Copies the field and its sub fields using a possibly new name and a new, unconnected set of columns.
Definition RField.cxx:372
std::size_t fNRepetitions
For fixed sized arrays, the array length.
Definition RField.hxx:133
virtual void AcceptVisitor(RFieldVisitor &visitor) const
Definition RField.cxx:572
virtual void ReadGlobalImpl(NTupleSize_t globalIndex, RFieldValue *value)
Definition RField.cxx:388
ENTupleStructure fStructure
The role of this field in the data model structure.
Definition RField.hxx:131
void AutoAdjustColumnTypes(const RNTupleWriteOptions &options)
When connecting a field to a page sink, the field's default column representation is subject to adjus...
Definition RField.cxx:496
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots ("grandparent.parent....
Definition RField.cxx:224
const ColumnRepresentation_t & GetColumnRepresentative() const
Returns the fColumnRepresentative pointee or, if unset, the field's default representative.
Definition RField.cxx:440
static constexpr int kTraitMappable
A field of a fundamental type that can be directly mapped via RField<T>::Map(), i....
Definition RField.hxx:95
void Attach(std::unique_ptr< Detail::RFieldBase > child)
Add a new subfield to the list of nested fields.
Definition RField.cxx:414
std::vector< RFieldBase * > GetSubFields() const
Definition RField.cxx:422
void SetColumnRepresentative(const ColumnRepresentation_t &representative)
Fixes a column representative.
Definition RField.cxx:447
static constexpr int kTraitTriviallyConstructible
No constructor needs to be called, i.e.
Definition RField.hxx:90
static constexpr int kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. DestroyValue() is a no-op.
Definition RField.hxx:92
const ColumnRepresentation_t & EnsureCompatibleColumnTypes(const RNTupleDescriptor &desc) const
Returns the on-disk column types found in the provided descriptor for fOnDiskId.
Definition RField.cxx:459
RFieldValue GenerateValue()
Generates an object of the field type and allocates new initialized memory according to the type.
Definition RField.cxx:395
std::vector< EColumnType > ColumnRepresentation_t
Definition RField.hxx:99
RColumn * fPrincipalColumn
Points into fColumns.
Definition RField.hxx:157
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitBoolField(const RField< bool > &field)
virtual void VisitBitsetField(const RBitsetField &field)
virtual void VisitNullableField(const RNullableField &field)
virtual void VisitFieldZero(const RFieldZero &field)
virtual void VisitRVecField(const RRVecField &field)
virtual void VisitCollectionClassField(const RCollectionClassField &field)
virtual void VisitField(const Detail::RFieldBase &field)=0
virtual void VisitDoubleField(const RField< double > &field)
virtual void VisitCharField(const RField< char > &field)
virtual void VisitArrayField(const RArrayField &field)
virtual void VisitClassField(const RClassField &field)
virtual void VisitRecordField(const RRecordField &field)
virtual void VisitVectorField(const RVectorField &field)
virtual void VisitFloatField(const RField< float > &field)
Abstract interface to write data into an ntuple.
const RNTupleWriteOptions & GetWriteOptions() const
Returns the sink's write options.
Abstract interface to read data from an ntuple.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:2116
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:2110
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition RField.cxx:2075
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:2066
RArrayField(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField, std::size_t arrayLength)
Definition RField.cxx:2038
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2127
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:2097
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:2056
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2050
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:2175
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:2143
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:2149
RBitsetField(std::string_view fieldName, std::size_t N)
Definition RField.cxx:2134
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:2160
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2188
The field for a class with dictionary.
Definition RField.hxx:399
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1211
static constexpr const char * kPrefixInherited
Prefix used in the subfield names generated for base classes.
Definition RField.hxx:410
void OnConnectPageSource() final
Called by ConnectPageSource() only once connected; derived classes may override this as appropriate.
Definition RField.cxx:1173
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:1229
void Attach(std::unique_ptr< Detail::RFieldBase > child, RSubFieldInfo info)
Definition RField.cxx:1115
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:1218
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1143
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1148
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.
Definition RField.cxx:1122
void AcceptVisitor(Detail::RFieldVisitor &visitor) const override
Definition RField.cxx:1239
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
Definition RField.cxx:1234
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1165
RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
Definition RField.cxx:1060
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1157
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:1204
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
DescriptorId_t GetClusterId() const
ClusterSize_t::ValueType GetIndex() const
Allows for iterating over the elements of a proxied collection.
Definition RField.hxx:462
static RIteratorFuncs GetIteratorFuncs(TVirtualCollectionProxy *proxy, bool readOnly)
Definition RField.cxx:1247
The field for a class representing a collection of elements via TVirtualCollectionProxy.
Definition RField.hxx:458
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:1384
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:1404
std::unique_ptr< TVirtualCollectionProxy > fProxy
Definition RField.hxx:513
RCollectionClassField(std::string_view fieldName, std::string_view className, TClass *classp)
Definition RField.cxx:1264
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1316
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1339
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1398
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1322
RCollectionIterableOnce::RIteratorFuncs fIFuncsWrite
Definition RField.hxx:517
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1419
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1368
RCollectionIterableOnce::RIteratorFuncs fIFuncsRead
Two sets of functions to operate on iterators, to be used depending on the access type.
Definition RField.hxx:516
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:1414
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:1360
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:2692
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:2668
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:2660
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2681
Holds the static meta-data of an RNTuple column.
Holds the index and the tag of a kSwitch column.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
A field translates read and write calls from/to underlying columns to/from tree values.
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:630
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:621
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:873
The on-storage meta-data of an ntuple.
RColumnDescriptorIterable GetColumnIterable(const RFieldDescriptor &fieldDesc) const
const RFieldDescriptor & GetFieldDescriptor(DescriptorId_t fieldId) const
static std::unique_ptr< RNTupleModel > Create()
Common user-tunable settings for storing ntuples.
The field for values that may or may not be present in an entry.
Definition RField.hxx:815
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:2356
const Detail::RFieldBase::RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:2348
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2425
RClusterIndex GetItemIndex(NTupleSize_t globalIndex)
Given the index of the nullable field, returns the corresponding global index of the subfield or,...
Definition RField.cxx:2411
RNullableField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition RField.cxx:2333
std::size_t AppendValue(const Detail::RFieldValue &value)
Definition RField.cxx:2395
The generic field for std::pair<T1, T2> types.
Definition RField.hxx:1022
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2550
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) override
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:2565
RPairField(std::string_view fieldName, std::array< std::unique_ptr< Detail::RFieldBase >, 2 > &&itemFields, const std::array< std::size_t, 2 > &offsets)
Definition RField.cxx:2527
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1853
std::size_t EvalValueSize() const
Evaluate the constant returned by GetValueSize.
Definition RField.cxx:1872
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) override
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:1824
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:1794
RRVecField(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition RField.cxx:1692
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:1932
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) override
Definition RField.cxx:1725
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1937
size_t GetAlignment() const override
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.cxx:1925
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1702
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:1920
std::size_t AppendImpl(const Detail::RFieldValue &value) override
Operations on values of complex types, e.g.
Definition RField.cxx:1708
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:1859
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1802
The field for an untyped record.
Definition RField.hxx:558
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1476
std::vector< std::size_t > fOffsets
Definition RField.hxx:562
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1484
RRecordField(std::string_view fieldName, std::vector< std::unique_ptr< Detail::RFieldBase > > &&itemFields, const std::vector< std::size_t > &offsets, std::string_view typeName="")
Definition RField.cxx:1426
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:1465
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1493
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1528
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:1535
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) override
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:1517
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1501
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1545
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:207
The generic field for std::tuple<Ts...> types.
Definition RField.hxx:1045
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2620
RTupleField(std::string_view fieldName, std::vector< std::unique_ptr< Detail::RFieldBase > > &&itemFields, const std::vector< std::size_t > &offsets)
Definition RField.cxx:2587
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) override
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:2636
RUniquePtrField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition RField.cxx:2432
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:2456
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:2502
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:2508
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:2490
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:2445
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2439
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:2250
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:2321
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:2279
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:2304
std::vector< ClusterSize_t::ValueType > fNWritten
Definition RField.hxx:776
size_t fTagOffset
In the std::variant memory layout, at which byte number is the index stored.
Definition RField.hxx:775
void SetTag(void *variantPtr, std::uint32_t tag) const
Definition RField.cxx:2244
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:2285
std::uint32_t GetTag(void *variantPtr) const
Extracts the index from an std::variant and transforms it into the 1-based index used for the switch ...
Definition RField.cxx:2238
static std::string GetTypeList(const std::vector< Detail::RFieldBase * > &itemFields)
Definition RField.cxx:2195
RVariantField(std::string_view fieldName, const std::vector< Detail::RFieldBase * > &itemFields)
Definition RField.cxx:2206
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:2266
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:803
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:2316
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2227
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:2326
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1661
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:1679
std::unique_ptr< Detail::RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1563
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1684
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:1667
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:1621
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1584
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1629
RVectorField(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition RField.cxx:1553
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:1645
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1569
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3770
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3636
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2897
Long_t ClassProperty() const
Return the C++ property of this class, eg.
Definition TClass.cxx:2396
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6086
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:2968
virtual Next_t GetFunctionNext(Bool_t read=kTRUE)=0
virtual DeleteTwoIterators_t GetFunctionDeleteTwoIterators(Bool_t read=kTRUE)=0
virtual TVirtualCollectionProxy * Generate() const =0
virtual CreateIterators_t GetFunctionCreateIterators(Bool_t read=kTRUE)=0
Wrapper around an object and giving indirect access to its content even if the object is not of a cla...
const Int_t n
Definition legend1.C:16
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.
constexpr ClusterSize_t kInvalidClusterIndex(std::uint64_t(-1))
constexpr DescriptorId_t kInvalidDescriptorId
clang::QualType GetNormalizedType(const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
Return the type normalized for ROOT, keeping only the ROOT opaque typedef (Double32_t,...
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
TClass * GetClass(T *)
Definition TClass.h:659
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
std::string CleanType(const char *typeDesc, int mode=0, const char **tail=nullptr)
Cleanup type description, redundant blanks removed and redundant tail ignored return *tail = pointer ...
Wrap the integer in a struct in order to avoid template specialization clash with std::uint32_t.