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 <TRealData.h>
35
36#include <algorithm>
37#include <cctype> // for isspace
38#include <charconv>
39#include <cstdint>
40#include <cstdlib> // for malloc, free
41#include <cstring> // for memset
42#include <exception>
43#include <iostream>
44#include <new> // hardware_destructive_interference_size
45#include <type_traits>
46#include <unordered_map>
47
48namespace {
49
50static const std::unordered_map<std::string_view, std::string_view> typeTranslationMap{
51 {"Bool_t", "bool"},
52 {"Float_t", "float"},
53 {"Double_t", "double"},
54 {"string", "std::string"},
55
56 {"Char_t", "char"},
57 {"int8_t", "std::int8_t"},
58 {"signed char", "char"},
59 {"UChar_t", "std::uint8_t"},
60 {"unsigned char", "std::uint8_t"},
61 {"uint8_t", "std::uint8_t"},
62
63 {"Short_t", "std::int16_t"},
64 {"int16_t", "std::int16_t"},
65 {"short", "std::int16_t"},
66 {"UShort_t", "std::uint16_t"},
67 {"unsigned short", "std::uint16_t"},
68 {"uint16_t", "std::uint16_t"},
69
70 {"Int_t", "std::int32_t"},
71 {"int32_t", "std::int32_t"},
72 {"int", "std::int32_t"},
73 {"UInt_t", "std::uint32_t"},
74 {"unsigned", "std::uint32_t"},
75 {"unsigned int", "std::uint32_t"},
76 {"uint32_t", "std::uint32_t"},
77
78 {"Long_t", "std::int64_t"},
79 {"Long64_t", "std::int64_t"},
80 {"int64_t", "std::int64_t"},
81 {"long", "std::int64_t"},
82 {"ULong64_t", "std::uint64_t"},
83 {"unsigned long", "std::uint64_t"},
84 {"uint64_t", "std::uint64_t"}
85};
86
87/// Used in CreateField() in order to get the comma-separated list of template types
88/// E.g., gets {"int", "std::variant<double,int>"} from "int,std::variant<double,int>"
89std::vector<std::string> TokenizeTypeList(std::string templateType) {
90 std::vector<std::string> result;
91 if (templateType.empty())
92 return result;
93
94 const char *eol = templateType.data() + templateType.length();
95 const char *typeBegin = templateType.data();
96 const char *typeCursor = templateType.data();
97 unsigned int nestingLevel = 0;
98 while (typeCursor != eol) {
99 switch (*typeCursor) {
100 case '<':
101 ++nestingLevel;
102 break;
103 case '>':
104 --nestingLevel;
105 break;
106 case ',':
107 if (nestingLevel == 0) {
108 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
109 typeBegin = typeCursor + 1;
110 }
111 break;
112 }
113 typeCursor++;
114 }
115 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
116 return result;
117}
118
119/// Parse a type name of the form `T[n][m]...` and return the base type `T` and a vector that contains,
120/// in order, the declared size for each dimension, e.g. for `unsigned char[1][2][3]` it returns the tuple
121/// `{"unsigned char", {1, 2, 3}}`. Extra whitespace in `typeName` should be removed before calling this function.
122///
123/// If `typeName` is not an array type, it returns a tuple `{T, {}}`. On error, it returns a default-constructed tuple.
124std::tuple<std::string, std::vector<size_t>> ParseArrayType(std::string_view typeName)
125{
126 std::vector<size_t> sizeVec;
127
128 /// Only parse outer array definition, i.e. the right `]` should be at the end of the type name
129 while (typeName.back() == ']') {
130 auto posRBrace = typeName.size() - 1;
131 auto posLBrace = typeName.find_last_of("[", posRBrace);
132 if (posLBrace == std::string_view::npos)
133 return {};
134
135 size_t size;
136 if (std::from_chars(typeName.data() + posLBrace + 1, typeName.data() + posRBrace, size).ec != std::errc{})
137 return {};
138 sizeVec.insert(sizeVec.begin(), size);
139 typeName.remove_suffix(typeName.size() - posLBrace);
140 }
141 return std::make_tuple(std::string{typeName}, sizeVec);
142}
143
144std::string GetNormalizedType(const std::string &typeName) {
145 std::string normalizedType(
147 /*mode=*/2).c_str()));
148
149 auto translatedType = typeTranslationMap.find(normalizedType);
150 if (translatedType != typeTranslationMap.end())
151 normalizedType = translatedType->second;
152
153 if (normalizedType.substr(0, 7) == "vector<") normalizedType = "std::" + normalizedType;
154 if (normalizedType.substr(0, 6) == "array<") normalizedType = "std::" + normalizedType;
155 if (normalizedType.substr(0, 8) == "variant<") normalizedType = "std::" + normalizedType;
156 if (normalizedType.substr(0, 5) == "pair<") normalizedType = "std::" + normalizedType;
157 if (normalizedType.substr(0, 6) == "tuple<") normalizedType = "std::" + normalizedType;
158
159 return normalizedType;
160}
161
162/// Retrieve the addresses of the data members of a generic RVec from a pointer to the beginning of the RVec object.
163/// Returns pointers to fBegin, fSize and fCapacity in a std::tuple.
164std::tuple<void **, std::int32_t *, std::int32_t *> GetRVecDataMembers(void *rvecPtr)
165{
166 void **begin = reinterpret_cast<void **>(rvecPtr);
167 // int32_t fSize is the second data member (after 1 void*)
168 std::int32_t *size = reinterpret_cast<std::int32_t *>(begin + 1);
169 R__ASSERT(*size >= 0);
170 // int32_t fCapacity is the third data member (1 int32_t after fSize)
171 std::int32_t *capacity = size + 1;
172 R__ASSERT(*capacity >= -1);
173 return {begin, size, capacity};
174}
175
176} // anonymous namespace
177
178
179//------------------------------------------------------------------------------
180
182 ENTupleStructure structure, bool isSimple, std::size_t nRepetitions)
183 : fName(name), fType(type), fStructure(structure), fNRepetitions(nRepetitions), fIsSimple(isSimple),
184 fParent(nullptr), fPrincipalColumn(nullptr), fTraits(isSimple ? kTraitMappable : 0)
185{
186}
187
189{
190}
191
193ROOT::Experimental::Detail::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
194{
195 std::string normalizedType(GetNormalizedType(typeName));
196 if (normalizedType.empty())
197 return R__FAIL("no type name specified for Field " + fieldName);
198
199 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> result;
200
201 if (auto [arrayBaseType, arraySize] = ParseArrayType(normalizedType); !arraySize.empty()) {
202 // TODO(jalopezg): support multi-dimensional row-major (C order) arrays in RArrayField
203 if (arraySize.size() > 1)
204 return R__FAIL("multi-dimensional array type not supported " + normalizedType);
205 auto itemField = Create(GetNormalizedType(arrayBaseType), arrayBaseType);
206 return {std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arraySize[0])};
207 }
208
209 if (normalizedType == "ROOT::Experimental::ClusterSize_t") {
210 result = std::make_unique<RField<ClusterSize_t>>(fieldName);
211 } else if (normalizedType == "bool") {
212 result = std::make_unique<RField<bool>>(fieldName);
213 } else if (normalizedType == "char") {
214 result = std::make_unique<RField<char>>(fieldName);
215 } else if (normalizedType == "std::int8_t") {
216 result = std::make_unique<RField<std::int8_t>>(fieldName);
217 } else if (normalizedType == "std::uint8_t") {
218 result = std::make_unique<RField<std::uint8_t>>(fieldName);
219 } else if (normalizedType == "std::int16_t") {
220 result = std::make_unique<RField<std::int16_t>>(fieldName);
221 } else if (normalizedType == "std::uint16_t") {
222 result = std::make_unique<RField<std::uint16_t>>(fieldName);
223 } else if (normalizedType == "std::int32_t") {
224 result = std::make_unique<RField<std::int32_t>>(fieldName);
225 } else if (normalizedType == "std::uint32_t") {
226 result = std::make_unique<RField<std::uint32_t>>(fieldName);
227 } else if (normalizedType == "std::int64_t") {
228 result = std::make_unique<RField<std::int64_t>>(fieldName);
229 } else if (normalizedType == "std::uint64_t") {
230 result = std::make_unique<RField<std::uint64_t>>(fieldName);
231 } else if (normalizedType == "float") {
232 result = std::make_unique<RField<float>>(fieldName);
233 } else if (normalizedType == "double") {
234 result = std::make_unique<RField<double>>(fieldName);
235 } else if (normalizedType == "std::string") {
236 result = std::make_unique<RField<std::string>>(fieldName);
237 } else if (normalizedType == "std::vector<bool>") {
238 result = std::make_unique<RField<std::vector<bool>>>(fieldName);
239 } else if (normalizedType.substr(0, 12) == "std::vector<") {
240 std::string itemTypeName = normalizedType.substr(12, normalizedType.length() - 13);
241 auto itemField = Create("_0", itemTypeName);
242 result = std::make_unique<RVectorField>(fieldName, itemField.Unwrap());
243 } else if (normalizedType.substr(0, 19) == "ROOT::VecOps::RVec<") {
244 std::string itemTypeName = normalizedType.substr(19, normalizedType.length() - 20);
245 auto itemField = Create("_0", itemTypeName);
246 result = std::make_unique<RRVecField>(fieldName, itemField.Unwrap());
247 } else if (normalizedType.substr(0, 11) == "std::array<") {
248 auto arrayDef = TokenizeTypeList(normalizedType.substr(11, normalizedType.length() - 12));
249 R__ASSERT(arrayDef.size() == 2);
250 auto arrayLength = std::stoi(arrayDef[1]);
251 auto itemField = Create(GetNormalizedType(arrayDef[0]), arrayDef[0]);
252 result = std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arrayLength);
253 }
254 if (normalizedType.substr(0, 13) == "std::variant<") {
255 auto innerTypes = TokenizeTypeList(normalizedType.substr(13, normalizedType.length() - 14));
256 std::vector<RFieldBase *> items;
257 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
258 items.emplace_back(Create("_" + std::to_string(i), innerTypes[i]).Unwrap().release());
259 }
260 result = std::make_unique<RVariantField>(fieldName, items);
261 }
262 if (normalizedType.substr(0, 10) == "std::pair<") {
263 auto innerTypes = TokenizeTypeList(normalizedType.substr(10, normalizedType.length() - 11));
264 if (innerTypes.size() != 2)
265 return R__FAIL("the type list for std::pair must have exactly two elements");
266 std::array<std::unique_ptr<RFieldBase>, 2> items{Create("_0", innerTypes[0]).Unwrap(),
267 Create("_1", innerTypes[1]).Unwrap()};
268 result = std::make_unique<RPairField>(fieldName, items);
269 }
270 if (normalizedType.substr(0, 11) == "std::tuple<") {
271 auto innerTypes = TokenizeTypeList(normalizedType.substr(11, normalizedType.length() - 12));
272 std::vector<std::unique_ptr<RFieldBase>> items;
273 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
274 items.emplace_back(Create("_" + std::to_string(i), innerTypes[i]).Unwrap());
275 }
276 result = std::make_unique<RTupleField>(fieldName, items);
277 }
278 // TODO: create an RCollectionField?
279 if (normalizedType == ":Collection:")
280 result = std::make_unique<RField<ClusterSize_t>>(fieldName);
281
282 if (!result) {
283 auto cl = TClass::GetClass(normalizedType.c_str());
284 if (cl != nullptr) {
285 if (cl->GetCollectionProxy())
286 result = std::make_unique<RCollectionClassField>(fieldName, normalizedType);
287 else
288 result = std::make_unique<RClassField>(fieldName, normalizedType);
289 }
290 }
291
292 if (result)
293 return result;
294 return R__FAIL(std::string("Field ") + fieldName + " has unknown type " + normalizedType);
295}
296
299{
300 if (fieldName == "") {
301 return R__FAIL("name cannot be empty string \"\"");
302 } else if (fieldName.find(".") != std::string::npos) {
303 return R__FAIL("name '" + std::string(fieldName) + "' cannot contain dot characters '.'");
304 }
305 return RResult<void>::Success();
306}
307
308std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
310{
311 auto clone = CloneImpl(newName);
312 clone->fOnDiskId = fOnDiskId;
313 clone->fDescription = fDescription;
314 return clone;
315}
316
318{
319 R__ASSERT(false && "A non-simple RField must implement its own AppendImpl");
320 return 0;
321}
322
325 RFieldValue* /*value*/)
326{
327 R__ASSERT(false);
328}
329
331{
332 void *where = malloc(GetValueSize());
333 R__ASSERT(where != nullptr);
334 return GenerateValue(where);
335}
336
338{
339 if (!dtorOnly)
340 free(value.GetRawPtr());
341}
342
343std::vector<ROOT::Experimental::Detail::RFieldValue>
345{
346 return std::vector<RFieldValue>();
347}
348
350 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> child)
351{
352 child->fParent = this;
353 fSubFields.emplace_back(std::move(child));
354}
355
356
357std::vector<ROOT::Experimental::Detail::RFieldBase *> ROOT::Experimental::Detail::RFieldBase::GetSubFields() const
358{
359 std::vector<RFieldBase *> result;
360 for (const auto &f : fSubFields) {
361 result.emplace_back(f.get());
362 }
363 return result;
364}
365
366
368{
369 for (auto& column : fColumns) {
370 column->Flush();
371 }
372}
373
374
376 const std::vector<EColumnType> &requestedTypes, unsigned int columnIndex, const RNTupleDescriptor &desc)
377{
378 R__ASSERT(!requestedTypes.empty());
379 auto columnId = desc.FindColumnId(fOnDiskId, columnIndex);
380 if (columnId == kInvalidDescriptorId) {
381 throw RException(R__FAIL("Column missing: column #" + std::to_string(columnIndex) +
382 " for field " + fName));
383 }
384
385 const auto &columnDesc = desc.GetColumnDescriptor(columnId);
386 for (auto type : requestedTypes) {
387 if (type == columnDesc.GetModel().GetType())
388 return type;
389 }
390 throw RException(R__FAIL(
391 "On-disk type `" + RColumnElementBase::GetTypeName(columnDesc.GetModel().GetType()) +
392 "` of column #" + std::to_string(columnIndex) + " for field `" + fName +
393 "` is not convertible to the requested type" + [&]{
394 std::string typeStr = requestedTypes.size() > 1 ? "s " : " ";
395 for (std::size_t i = 0; i < requestedTypes.size(); i++) {
396 typeStr += "`" + RColumnElementBase::GetTypeName(requestedTypes[i]) + "`";
397 if (i != requestedTypes.size() - 1) {
398 typeStr += ", ";
399 }
400 }
401 return typeStr;
402 }()
403 ));
404 return columnDesc.GetModel().GetType();
405}
406
408{
409 fReadCallbacks.push_back(func);
410 fIsSimple = false;
411 return fReadCallbacks.size() - 1;
412}
413
415{
416 fReadCallbacks.erase(fReadCallbacks.begin() + idx);
417 fIsSimple = (fTraits & kTraitMappable) && fReadCallbacks.empty();
418}
419
421{
422 R__ASSERT(fColumns.empty());
423 GenerateColumnsImpl();
424 if (!fColumns.empty())
425 fPrincipalColumn = fColumns[0].get();
426 for (auto& column : fColumns)
427 column->Connect(fOnDiskId, &pageSink);
428}
429
430
432{
433 R__ASSERT(fColumns.empty());
434 {
435 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
436 GenerateColumnsImpl(descriptorGuard.GetRef());
437 }
438 if (!fColumns.empty())
439 fPrincipalColumn = fColumns[0].get();
440 for (auto& column : fColumns)
441 column->Connect(fOnDiskId, &pageSource);
442}
443
444
446{
447 visitor.VisitField(*this);
448}
449
450
452{
453 if (fSubFields.empty()) return RSchemaIterator(this, -1);
454 return RSchemaIterator(this->fSubFields[0].get(), 0);
455}
456
457
459{
460 return RSchemaIterator(this, -1);
461}
462
463
464//-----------------------------------------------------------------------------
465
466
468{
469 auto itr = fStack.rbegin();
470 if (!itr->fFieldPtr->fSubFields.empty()) {
471 fStack.emplace_back(Position(itr->fFieldPtr->fSubFields[0].get(), 0));
472 return;
473 }
474
475 unsigned int nextIdxInParent = ++(itr->fIdxInParent);
476 while (nextIdxInParent >= itr->fFieldPtr->fParent->fSubFields.size()) {
477 if (fStack.size() == 1) {
478 itr->fFieldPtr = itr->fFieldPtr->fParent;
479 itr->fIdxInParent = -1;
480 return;
481 }
482 fStack.pop_back();
483 itr = fStack.rbegin();
484 nextIdxInParent = ++(itr->fIdxInParent);
485 }
486 itr->fFieldPtr = itr->fFieldPtr->fParent->fSubFields[nextIdxInParent].get();
487}
488
489
490//------------------------------------------------------------------------------
491
492
493std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
494ROOT::Experimental::RFieldZero::CloneImpl(std::string_view /*newName*/) const
495{
496 auto result = std::make_unique<RFieldZero>();
497 for (auto &f : fSubFields)
498 result->Attach(f->Clone(f->GetName()));
499 return result;
500}
501
502
504{
505 visitor.VisitFieldZero(*this);
506}
507
508
509//------------------------------------------------------------------------------
510
511
513{
514 RColumnModel model(EColumnType::kIndex, true /* isSorted*/);
515 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
516 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(model, 0)));
517}
518
520{
521 EnsureColumnType({EColumnType::kIndex}, 0, desc);
522 GenerateColumnsImpl();
523}
524
526{
527 visitor.VisitClusterSizeField(*this);
528}
529
530//------------------------------------------------------------------------------
531
533{
534 RColumnModel model(EColumnType::kChar, false /* isSorted*/);
535 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
536 char, EColumnType::kChar>(model, 0)));
537}
538
540{
541 EnsureColumnType({EColumnType::kChar}, 0, desc);
542 GenerateColumnsImpl();
543}
544
546{
547 visitor.VisitCharField(*this);
548}
549
550//------------------------------------------------------------------------------
551
553{
554 RColumnModel model(EColumnType::kInt8, false /* isSorted*/);
555 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
556 std::int8_t, EColumnType::kInt8>(model, 0)));
557}
558
559void ROOT::Experimental::RField<std::int8_t>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
560{
561 EnsureColumnType({EColumnType::kInt8}, 0, desc);
562 GenerateColumnsImpl();
563}
564
565void ROOT::Experimental::RField<std::int8_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
566{
567 visitor.VisitInt8Field(*this);
568}
569
570//------------------------------------------------------------------------------
571
573{
574 RColumnModel model(EColumnType::kInt8, false /* isSorted*/);
575 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
576 std::uint8_t, EColumnType::kInt8>(model, 0)));
577}
578
580{
581 EnsureColumnType({EColumnType::kInt8}, 0, desc);
582 GenerateColumnsImpl();
583}
584
585void ROOT::Experimental::RField<std::uint8_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
586{
587 visitor.VisitUInt8Field(*this);
588}
589
590//------------------------------------------------------------------------------
591
592
594{
595 RColumnModel model(EColumnType::kBit, false /* isSorted*/);
596 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
597 Detail::RColumn::Create<bool, EColumnType::kBit>(model, 0)));
598}
599
601{
602 EnsureColumnType({EColumnType::kBit}, 0, desc);
603 GenerateColumnsImpl();
604}
605
607{
608 visitor.VisitBoolField(*this);
609}
610
611//------------------------------------------------------------------------------
612
613
615{
616 RColumnModel model(EColumnType::kReal32, false /* isSorted*/);
617 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
618 Detail::RColumn::Create<float, EColumnType::kReal32>(model, 0)));
619}
620
622{
623 EnsureColumnType({EColumnType::kReal32}, 0, desc);
624 GenerateColumnsImpl();
625}
626
628{
629 visitor.VisitFloatField(*this);
630}
631
632
633//------------------------------------------------------------------------------
634
636{
637 RColumnModel model(EColumnType::kReal64, false /* isSorted*/);
638 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
639 Detail::RColumn::Create<double, EColumnType::kReal64>(model, 0)));
640}
641
643{
644 EnsureColumnType({EColumnType::kReal64}, 0, desc);
645 GenerateColumnsImpl();
646}
647
649{
650 visitor.VisitDoubleField(*this);
651}
652
653//------------------------------------------------------------------------------
654
656{
657 RColumnModel model(EColumnType::kInt16, false /* isSorted*/);
658 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
659 std::int16_t, EColumnType::kInt16>(model, 0)));
660}
661
663{
664 EnsureColumnType({EColumnType::kInt16}, 0, desc);
665 GenerateColumnsImpl();
666}
667
668void ROOT::Experimental::RField<std::int16_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
669{
670 visitor.VisitInt16Field(*this);
671}
672
673//------------------------------------------------------------------------------
674
676{
677 RColumnModel model(EColumnType::kInt16, false /* isSorted*/);
678 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
679 std::uint16_t, EColumnType::kInt16>(model, 0)));
680}
681
683{
684 EnsureColumnType({EColumnType::kInt16}, 0, desc);
685 GenerateColumnsImpl();
686}
687
688void ROOT::Experimental::RField<std::uint16_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
689{
690 visitor.VisitUInt16Field(*this);
691}
692
693//------------------------------------------------------------------------------
694
696{
697 RColumnModel model(EColumnType::kInt32, false /* isSorted*/);
698 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
699 std::int32_t, EColumnType::kInt32>(model, 0)));
700}
701
703{
704 EnsureColumnType({EColumnType::kInt32}, 0, desc);
705 GenerateColumnsImpl();
706}
707
708void ROOT::Experimental::RField<std::int32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
709{
710 visitor.VisitIntField(*this);
711}
712
713//------------------------------------------------------------------------------
714
716{
717 RColumnModel model(EColumnType::kInt32, false /* isSorted*/);
718 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
719 Detail::RColumn::Create<std::uint32_t, EColumnType::kInt32>(model, 0)));
720}
721
723{
724 EnsureColumnType({EColumnType::kInt32}, 0, desc);
725 GenerateColumnsImpl();
726}
727
728void ROOT::Experimental::RField<std::uint32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
729{
730 visitor.VisitUInt32Field(*this);
731}
732
733//------------------------------------------------------------------------------
734
736{
737 RColumnModel model(EColumnType::kInt64, false /* isSorted*/);
738 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
739 Detail::RColumn::Create<std::uint64_t, EColumnType::kInt64>(model, 0)));
740}
741
743{
744 EnsureColumnType({EColumnType::kInt64}, 0, desc);
745 GenerateColumnsImpl();
746}
747
748void ROOT::Experimental::RField<std::uint64_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
749{
750 visitor.VisitUInt64Field(*this);
751}
752
753//------------------------------------------------------------------------------
754
756{
757 RColumnModel model(EColumnType::kInt64, false /* isSorted*/);
758 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
759 Detail::RColumn::Create<std::int64_t, EColumnType::kInt64>(model, 0)));
760}
761
763{
764 auto type = EnsureColumnType({EColumnType::kInt64, EColumnType::kInt32}, 0, desc);
765 RColumnModel model(type, false /* isSorted*/);
766 if (type == EColumnType::kInt64) {
767 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
768 Detail::RColumn::Create<std::int64_t, EColumnType::kInt64>(model, 0)));
769 } else {
770 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
771 Detail::RColumn::Create<std::int64_t, EColumnType::kInt32>(model, 0)));
772 }
773}
774
775void ROOT::Experimental::RField<std::int64_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
776{
777 visitor.VisitInt64Field(*this);
778}
779
780//------------------------------------------------------------------------------
781
783{
784 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
785 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
786 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
787
788 RColumnModel modelChars(EColumnType::kChar, false /* isSorted*/);
789 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
790 Detail::RColumn::Create<char, EColumnType::kChar>(modelChars, 1)));
791}
792
793void ROOT::Experimental::RField<std::string>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
794{
795 EnsureColumnType({EColumnType::kIndex}, 0, desc);
796 EnsureColumnType({EColumnType::kChar}, 1, desc);
797 GenerateColumnsImpl();
798}
799
801{
802 auto typedValue = value.Get<std::string>();
803 auto length = typedValue->length();
804 Detail::RColumnElement<char> elemChars(const_cast<char*>(typedValue->data()));
805 fColumns[1]->AppendV(elemChars, length);
806 fIndex += length;
807 fColumns[0]->Append(fElemIndex);
808 return length + sizeof(fElemIndex);
809}
810
813{
814 auto typedValue = value->Get<std::string>();
815 RClusterIndex collectionStart;
816 ClusterSize_t nChars;
817 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nChars);
818 if (nChars == 0) {
819 typedValue->clear();
820 } else {
821 typedValue->resize(nChars);
822 Detail::RColumnElement<char> elemChars(const_cast<char*>(typedValue->data()));
823 fColumns[1]->ReadV(collectionStart, nChars, &elemChars);
824 }
825}
826
828{
829 fIndex = 0;
830}
831
832void ROOT::Experimental::RField<std::string>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
833{
834 visitor.VisitStringField(*this);
835}
836
837//------------------------------------------------------------------------------
838
839
840ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className)
841 : RClassField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
842{
843}
844
845ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
846 : ROOT::Experimental::Detail::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */)
847 , fClass(classp)
848{
849 if (fClass == nullptr) {
850 throw RException(R__FAIL("RField: no I/O support for type " + std::string(className)));
851 }
852 // Avoid accidentally supporting std types through TClass.
854 throw RException(R__FAIL(std::string(className) + " is not supported"));
855 }
856 if (fClass->GetCollectionProxy()) {
857 throw RException(
858 R__FAIL(std::string(className) + " has an associated collection proxy; use RCollectionClassField instead"));
859 }
860
865
866 int i = 0;
868 TClass *c = baseClass->GetClassPointer();
869 auto subField = Detail::RFieldBase::Create(std::string(kPrefixInherited) + "_" + std::to_string(i),
870 c->GetName()).Unwrap();
871 fTraits &= subField->GetTraits();
872 Attach(std::move(subField),
873 RSubFieldInfo{kBaseClass, static_cast<std::size_t>(baseClass->GetDelta())});
874 i++;
875 }
877 // Skip, for instance, unscoped enum constants defined in the class
878 if (dataMember->Property() & kIsStatic)
879 continue;
880 // Skip members explicitly marked as transient by user comment
881 if (!dataMember->IsPersistent()) {
882 // TODO(jblomer): we could do better
884 continue;
885 }
886
887 std::string typeName{dataMember->GetFullTypeName()};
888 // For C-style arrays, complete the type name with the size for each dimension, e.g. `int[4][2]`
889 if (dataMember->Property() & kIsArray) {
890 for (int dim = 0, n = dataMember->GetArrayDim(); dim < n; ++dim)
891 typeName += "[" + std::to_string(dataMember->GetMaxIndex(dim)) + "]";
892 }
893 auto subField = Detail::RFieldBase::Create(dataMember->GetName(), typeName).Unwrap();
894 fTraits &= subField->GetTraits();
895 Attach(std::move(subField),
896 RSubFieldInfo{kDataMember, static_cast<std::size_t>(dataMember->GetOffset())});
897 }
898}
899
900void ROOT::Experimental::RClassField::Attach(std::unique_ptr<Detail::RFieldBase> child, RSubFieldInfo info)
901{
902 fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
903 fSubFieldsInfo.push_back(info);
904 RFieldBase::Attach(std::move(child));
905}
906
907std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
908ROOT::Experimental::RClassField::CloneImpl(std::string_view newName) const
909{
910 return std::unique_ptr<RClassField>(new RClassField(newName, GetType(), fClass));
911}
912
914 std::size_t nbytes = 0;
915 for (unsigned i = 0; i < fSubFields.size(); i++) {
916 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fSubFieldsInfo[i].fOffset);
917 nbytes += fSubFields[i]->Append(memberValue);
918 }
919 return nbytes;
920}
921
923{
924 for (unsigned i = 0; i < fSubFields.size(); i++) {
925 auto memberValue = fSubFields[i]->CaptureValue(value->Get<unsigned char>() + fSubFieldsInfo[i].fOffset);
926 fSubFields[i]->Read(globalIndex, &memberValue);
927 }
928}
929
931{
932 for (unsigned i = 0; i < fSubFields.size(); i++) {
933 auto memberValue = fSubFields[i]->CaptureValue(value->Get<unsigned char>() + fSubFieldsInfo[i].fOffset);
934 fSubFields[i]->Read(clusterIndex, &memberValue);
935 }
936}
937
939{
940}
941
943{
944}
945
947{
948 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
949}
950
952{
953 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
954 if (!dtorOnly)
955 free(value.GetRawPtr());
956}
957
959{
960 return Detail::RFieldValue(true /* captureFlat */, this, where);
961}
962
963
964std::vector<ROOT::Experimental::Detail::RFieldValue>
966{
967 std::vector<Detail::RFieldValue> result;
968 for (unsigned i = 0; i < fSubFields.size(); i++) {
969 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fSubFieldsInfo[i].fOffset);
970 result.emplace_back(memberValue);
971 }
972 return result;
973}
974
975
977{
978 return fClass->GetClassSize();
979}
980
982{
983 visitor.VisitClassField(*this);
984}
985
986//------------------------------------------------------------------------------
987
988ROOT::Experimental::RCollectionClassField::RCollectionClassField(std::string_view fieldName, std::string_view className)
989 : RCollectionClassField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
990{
991}
992
993ROOT::Experimental::RCollectionClassField::RCollectionClassField(std::string_view fieldName, std::string_view className,
994 TClass *classp)
995 : ROOT::Experimental::Detail::RFieldBase(fieldName, className, ENTupleStructure::kCollection, false /* isSimple */),
996 fNWritten(0)
997{
998 if (classp == nullptr)
999 throw RException(R__FAIL("RField: no I/O support for collection proxy type " + std::string(className)));
1000 if (!classp->GetCollectionProxy())
1001 throw RException(R__FAIL(std::string(className) + " has no associated collection proxy"));
1002
1003 fProxy.reset(classp->GetCollectionProxy()->Generate());
1004 if (fProxy->HasPointers())
1005 throw RException(R__FAIL("collection proxies whose value type is a pointer are not supported"));
1006 if (fProxy->GetProperties() & TVirtualCollectionProxy::kIsAssociative)
1007 throw RException(R__FAIL("associative collections not supported"));
1008
1009 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> itemField;
1010 if (auto valueClass = fProxy->GetValueClass()) {
1011 // Element type is a class
1012 itemField = RFieldBase::Create("_0", valueClass->GetName()).Unwrap();
1013 } else {
1014 switch (fProxy->GetType()) {
1015 case EDataType::kChar_t: itemField = std::make_unique<RField<char>>("_0"); break;
1016 case EDataType::kUChar_t: itemField = std::make_unique<RField<std::uint8_t>>("_0"); break;
1017 case EDataType::kShort_t: itemField = std::make_unique<RField<std::int16_t>>("_0"); break;
1018 case EDataType::kUShort_t: itemField = std::make_unique<RField<std::uint16_t>>("_0"); break;
1019 case EDataType::kInt_t: itemField = std::make_unique<RField<std::int32_t>>("_0"); break;
1020 case EDataType::kUInt_t: itemField = std::make_unique<RField<std::uint32_t>>("_0"); break;
1021 case EDataType::kLong_t:
1023 itemField = std::make_unique<RField<std::int64_t>>("_0");
1024 break;
1027 itemField = std::make_unique<RField<std::uint64_t>>("_0");
1028 break;
1029 case EDataType::kFloat_t: itemField = std::make_unique<RField<float>>("_0"); break;
1030 case EDataType::kDouble_t: itemField = std::make_unique<RField<double>>("_0"); break;
1031 case EDataType::kBool_t: itemField = std::make_unique<RField<bool>>("_0"); break;
1032 default:
1033 throw RException(R__FAIL("unsupported value type"));
1034 }
1035 }
1036 fItemSize = itemField->GetValueSize();
1037 Attach(std::move(itemField));
1038}
1039
1040std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1042{
1043 return std::unique_ptr<RCollectionClassField>(
1044 new RCollectionClassField(newName, GetType(), fProxy->GetCollectionClass()));
1045}
1046
1048{
1049 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), value.GetRawPtr());
1050 std::size_t nbytes = 0;
1051 auto count = fProxy->Size();
1052 for (unsigned i = 0; i < count; ++i) {
1053 auto itemValue = fSubFields[0]->CaptureValue(fProxy->At(i));
1054 nbytes += fSubFields[0]->Append(itemValue);
1055 }
1056 Detail::RColumnElement<ClusterSize_t> elemIndex(&fNWritten);
1057 fNWritten += count;
1058 fColumns[0]->Append(elemIndex);
1059 return nbytes + sizeof(elemIndex);
1060}
1061
1063{
1064 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), value->GetRawPtr());
1065
1066 ClusterSize_t nItems;
1067 RClusterIndex collectionStart;
1068 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1069
1070 // `TVirtualCollectionProxy::Clear()` is responsible for destroying the items in the collection
1071 fProxy->Clear("force");
1072
1073 // Avoid heap fragmentation at the cost of temporarily allocating slightly more memory
1074 const size_t buffSize = std::max(kReadChunkSize, fItemSize);
1075 const std::uint32_t nItemsPerChunk = buffSize / fItemSize;
1076 auto buff = std::make_unique<unsigned char[]>(buffSize);
1077
1078 auto nItemsLeft = static_cast<std::uint32_t>(nItems);
1079 while (nItemsLeft > 0) {
1080 auto count = std::min(nItemsLeft, nItemsPerChunk);
1081 for (std::size_t i = 0; i < count; ++i) {
1082 auto itemValue = fSubFields[0]->GenerateValue(buff.get() + (i * fItemSize));
1083 fSubFields[0]->Read(collectionStart + i, &itemValue);
1084 }
1085 fProxy->Insert(buff.get(), value->GetRawPtr(), count);
1086 for (std::size_t i = 0; i < count; ++i) {
1087 auto itemValue = fSubFields[0]->CaptureValue(buff.get() + (i * fItemSize));
1088 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1089 }
1090 collectionStart = collectionStart + count;
1091 nItemsLeft -= count;
1092 }
1093}
1094
1096{
1097 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
1098 fColumns.emplace_back(
1099 std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
1100}
1101
1103{
1104 EnsureColumnType({EColumnType::kIndex}, 0, desc);
1105 GenerateColumnsImpl();
1106}
1107
1109{
1110 return Detail::RFieldValue(true /* captureFlag */, this, fProxy->New(where));
1111}
1112
1114{
1115 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), value.GetRawPtr());
1116 if (fProxy->GetProperties() & TVirtualCollectionProxy::kNeedDelete) {
1117 auto nItems = fProxy->Size();
1118 for (unsigned i = 0; i < nItems; ++i) {
1119 auto itemValue = fSubFields[0]->CaptureValue(fProxy->At(i));
1120 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1121 }
1122 }
1123 fProxy->Destructor(value.GetRawPtr(), true /* dtorOnly */);
1124 if (!dtorOnly)
1125 free(value.GetRawPtr());
1126}
1127
1129{
1130 return Detail::RFieldValue(true /* captureFlag */, this, where);
1131}
1132
1133std::vector<ROOT::Experimental::Detail::RFieldValue>
1135{
1136 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), value.GetRawPtr());
1137 auto nItems = fProxy->Size();
1138 std::vector<Detail::RFieldValue> result;
1139 for (unsigned i = 0; i < nItems; ++i) {
1140 result.emplace_back(fSubFields[0]->CaptureValue(fProxy->At(i)));
1141 }
1142 return result;
1143}
1144
1146{
1147 fNWritten = 0;
1148}
1149
1151{
1152 visitor.VisitCollectionClassField(*this);
1153}
1154
1155//------------------------------------------------------------------------------
1156
1158 std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields,
1159 const std::vector<std::size_t> &offsets, std::string_view typeName)
1160 : ROOT::Experimental::Detail::RFieldBase(fieldName, typeName, ENTupleStructure::kRecord, false /* isSimple */),
1161 fOffsets(offsets)
1162{
1164 for (auto &item : itemFields) {
1165 fMaxAlignment = std::max(fMaxAlignment, item->GetAlignment());
1166 fSize += GetItemPadding(fSize, item->GetAlignment()) + item->GetValueSize();
1167 fTraits &= item->GetTraits();
1168 Attach(std::move(item));
1169 }
1170}
1171
1173 std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields)
1174 : ROOT::Experimental::Detail::RFieldBase(fieldName, "", ENTupleStructure::kRecord, false /* isSimple */)
1175{
1177 for (auto &item : itemFields) {
1178 fSize += GetItemPadding(fSize, item->GetAlignment());
1179 fOffsets.push_back(fSize);
1180 fMaxAlignment = std::max(fMaxAlignment, item->GetAlignment());
1181 fSize += item->GetValueSize();
1182 fTraits &= item->GetTraits();
1183 Attach(std::move(item));
1184 }
1185 // Trailing padding: although this is implementation-dependent, most add enough padding to comply with the
1186 // requirements of the type with strictest alignment
1188}
1189
1191 std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields)
1192 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields))
1193{
1194}
1195
1196std::size_t ROOT::Experimental::RRecordField::GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
1197{
1198 if (itemAlignment > 1) {
1199 auto remainder = baseOffset % itemAlignment;
1200 if (remainder != 0)
1201 return itemAlignment - remainder;
1202 }
1203 return 0;
1204}
1205
1206std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1207ROOT::Experimental::RRecordField::CloneImpl(std::string_view newName) const
1208{
1209 std::vector<std::unique_ptr<Detail::RFieldBase>> cloneItems;
1210 for (auto &item : fSubFields)
1211 cloneItems.emplace_back(item->Clone(item->GetName()));
1212 return std::unique_ptr<RRecordField>(new RRecordField(newName, std::move(cloneItems), fOffsets, GetType()));
1213}
1214
1216 std::size_t nbytes = 0;
1217 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1218 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fOffsets[i]);
1219 nbytes += fSubFields[i]->Append(memberValue);
1220 }
1221 return nbytes;
1222}
1223
1225{
1226 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1227 auto memberValue = fSubFields[i]->CaptureValue(value->Get<unsigned char>() + fOffsets[i]);
1228 fSubFields[i]->Read(globalIndex, &memberValue);
1229 }
1230}
1231
1233{
1234 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1235 auto memberValue = fSubFields[i]->CaptureValue(value->Get<unsigned char>() + fOffsets[i]);
1236 fSubFields[i]->Read(clusterIndex, &memberValue);
1237 }
1238}
1239
1241{
1242 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1243 fSubFields[i]->GenerateValue(static_cast<unsigned char *>(where) + fOffsets[i]);
1244 }
1245 return Detail::RFieldValue(true /* captureFlag */, this, where);
1246}
1247
1249{
1250 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1251 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fOffsets[i]);
1252 fSubFields[i]->DestroyValue(memberValue, true /* dtorOnly */);
1253 }
1254
1255 if (!dtorOnly)
1256 free(value.GetRawPtr());
1257}
1258
1260{
1261 return Detail::RFieldValue(true /* captureFlag */, this, where);
1262}
1263
1264
1265std::vector<ROOT::Experimental::Detail::RFieldValue>
1267{
1268 std::vector<Detail::RFieldValue> result;
1269 for (unsigned i = 0; i < fSubFields.size(); ++i) {
1270 result.emplace_back(fSubFields[i]->CaptureValue(value.Get<unsigned char>() + fOffsets[i]));
1271 }
1272 return result;
1273}
1274
1275
1277{
1278 visitor.VisitRecordField(*this);
1279}
1280
1281//------------------------------------------------------------------------------
1282
1283
1285 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
1286 : ROOT::Experimental::Detail::RFieldBase(
1287 fieldName, "std::vector<" + itemField->GetType() + ">", ENTupleStructure::kCollection, false /* isSimple */)
1288 , fItemSize(itemField->GetValueSize()), fNWritten(0)
1289{
1290 Attach(std::move(itemField));
1291}
1292
1293std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1294ROOT::Experimental::RVectorField::CloneImpl(std::string_view newName) const
1295{
1296 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
1297 return std::make_unique<RVectorField>(newName, std::move(newItemField));
1298}
1299
1301 auto typedValue = value.Get<std::vector<char>>();
1302 R__ASSERT((typedValue->size() % fItemSize) == 0);
1303 std::size_t nbytes = 0;
1304 auto count = typedValue->size() / fItemSize;
1305 for (unsigned i = 0; i < count; ++i) {
1306 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
1307 nbytes += fSubFields[0]->Append(itemValue);
1308 }
1309 Detail::RColumnElement<ClusterSize_t> elemIndex(&fNWritten);
1310 fNWritten += count;
1311 fColumns[0]->Append(elemIndex);
1312 return nbytes + sizeof(elemIndex);
1313}
1314
1316{
1317 auto typedValue = value->Get<std::vector<char>>();
1318
1319 ClusterSize_t nItems;
1320 RClusterIndex collectionStart;
1321 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1322
1323 if (fSubFields[0]->GetTraits() & kTraitTrivialType) {
1324 typedValue->resize(nItems * fItemSize);
1325 } else {
1326 // See "semantics of reading non-trivial objects" in RNTuple's architecture.md
1327 const auto oldNItems = typedValue->size() / fItemSize;
1328 const bool canRealloc = oldNItems < nItems;
1329 bool allDeallocated = false;
1330 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible)) {
1331 allDeallocated = canRealloc;
1332 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
1333 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
1334 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1335 }
1336 }
1337 typedValue->resize(nItems * fItemSize);
1338 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyConstructible)) {
1339 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
1340 fSubFields[0]->GenerateValue(typedValue->data() + (i * fItemSize));
1341 }
1342 }
1343 }
1344
1345 for (std::size_t i = 0; i < nItems; ++i) {
1346 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
1347 fSubFields[0]->Read(collectionStart + i, &itemValue);
1348 }
1349}
1350
1352{
1353 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
1354 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
1355 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
1356}
1357
1359{
1360 EnsureColumnType({EColumnType::kIndex}, 0, desc);
1361 GenerateColumnsImpl();
1362}
1363
1365{
1366 return Detail::RFieldValue(this, reinterpret_cast<std::vector<char>*>(where));
1367}
1368
1370{
1371 auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
1372 R__ASSERT((vec->size() % fItemSize) == 0);
1373 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible)) {
1374 auto nItems = vec->size() / fItemSize;
1375 for (unsigned i = 0; i < nItems; ++i) {
1376 auto itemValue = fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize));
1377 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1378 }
1379 }
1380 vec->~vector();
1381 if (!dtorOnly)
1382 free(vec);
1383}
1384
1386{
1387 return Detail::RFieldValue(true /* captureFlag */, this, where);
1388}
1389
1390std::vector<ROOT::Experimental::Detail::RFieldValue>
1392{
1393 auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
1394 R__ASSERT((vec->size() % fItemSize) == 0);
1395 auto nItems = vec->size() / fItemSize;
1396 std::vector<Detail::RFieldValue> result;
1397 for (unsigned i = 0; i < nItems; ++i) {
1398 result.emplace_back(fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize)));
1399 }
1400 return result;
1401}
1402
1404{
1405 fNWritten = 0;
1406}
1407
1409{
1410 visitor.VisitVectorField(*this);
1411}
1412
1413
1414//------------------------------------------------------------------------------
1415
1416ROOT::Experimental::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
1417 : ROOT::Experimental::Detail::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetType() + ">",
1418 ENTupleStructure::kCollection, false /* isSimple */),
1419 fItemSize(itemField->GetValueSize()), fNWritten(0)
1420{
1421 Attach(std::move(itemField));
1422 fValueSize = EvalValueSize(); // requires fSubFields to be populated
1423}
1424
1425std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1426ROOT::Experimental::RRVecField::CloneImpl(std::string_view newName) const
1427{
1428 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
1429 return std::make_unique<RRVecField>(newName, std::move(newItemField));
1430}
1431
1433{
1434 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(value.GetRawPtr());
1435
1436 std::size_t nbytes = 0;
1437 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
1438 for (std::int32_t i = 0; i < *sizePtr; ++i) {
1439 auto elementValue = fSubFields[0]->CaptureValue(begin + i * fItemSize);
1440 nbytes += fSubFields[0]->Append(elementValue);
1441 }
1442
1443 Detail::RColumnElement<ClusterSize_t> elemIndex(&fNWritten);
1444 fNWritten += *sizePtr;
1445 fColumns[0]->Append(elemIndex);
1446 return nbytes + sizeof(elemIndex);
1447}
1448
1450{
1451 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
1452 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
1453
1454 auto [beginPtr, sizePtr, capacityPtr] = GetRVecDataMembers(value->GetRawPtr());
1455
1456 // Read collection info for this entry
1457 ClusterSize_t nItems;
1458 RClusterIndex collectionStart;
1459 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1460 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
1461 const std::size_t oldSize = *sizePtr;
1462
1463 // See "semantics of reading non-trivial objects" in RNTuple's architecture.md for details
1464 // on the element construction/destrution.
1465 const bool needsConstruct = !(fSubFields[0]->GetTraits() & kTraitTriviallyConstructible);
1466 const bool needsDestruct = !(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible);
1467
1468 // Destroy excess elements, if any
1469 if (needsDestruct) {
1470 for (std::size_t i = nItems; i < oldSize; ++i) {
1471 auto itemValue = fSubFields[0]->CaptureValue(begin + (i * fItemSize));
1472 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1473 }
1474 }
1475
1476 // Resize RVec (capacity and size)
1477 if (std::int32_t(nItems) > *capacityPtr) { // must reallocate
1478 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
1479 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
1480 if (needsDestruct) {
1481 for (std::size_t i = 0u; i < oldSize; ++i) {
1482 auto itemValue = fSubFields[0]->CaptureValue(begin + (i * fItemSize));
1483 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1484 }
1485 }
1486
1487 // TODO Increment capacity by a factor rather than just enough to fit the elements.
1488 free(*beginPtr);
1489 // We trust that malloc returns a buffer with large enough alignment.
1490 // This might not be the case if T in RVec<T> is over-aligned.
1491 *beginPtr = malloc(nItems * fItemSize);
1492 R__ASSERT(*beginPtr != nullptr);
1493 begin = reinterpret_cast<char *>(*beginPtr);
1494 *capacityPtr = nItems;
1495
1496 // Placement new for elements that were already there before the resize
1497 if (needsConstruct) {
1498 for (std::size_t i = 0u; i < oldSize; ++i)
1499 fSubFields[0]->GenerateValue(begin + (i * fItemSize));
1500 }
1501 }
1502 *sizePtr = nItems;
1503
1504 // Placement new for new elements, if any
1505 if (needsConstruct) {
1506 for (std::size_t i = oldSize; i < nItems; ++i)
1507 fSubFields[0]->GenerateValue(begin + (i * fItemSize));
1508 }
1509
1510 // Read the new values into the collection elements
1511 for (std::size_t i = 0; i < nItems; ++i) {
1512 auto itemValue = fSubFields[0]->CaptureValue(begin + (i * fItemSize));
1513 fSubFields[0]->Read(collectionStart + i, &itemValue);
1514 }
1515}
1516
1518{
1519 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
1520 fColumns.emplace_back(
1521 std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
1522}
1523
1525{
1526 EnsureColumnType({EColumnType::kIndex}, 0, desc);
1527 GenerateColumnsImpl();
1528}
1529
1531{
1532 // initialize data members fBegin, fSize, fCapacity
1533 // currently the inline buffer is left uninitialized
1534 void **beginPtr = new (where)(void *)(nullptr);
1535 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
1536 new (sizePtr + 1) std::int32_t(0);
1537
1538 return Detail::RFieldValue(/*captureTag*/ true, this, where);
1539}
1540
1542{
1543 auto [beginPtr, sizePtr, capacityPtr] = GetRVecDataMembers(value.GetRawPtr());
1544
1545 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
1546 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible)) {
1547 for (std::int32_t i = 0; i < *sizePtr; ++i) {
1548 auto elementValue = fSubFields[0]->CaptureValue(begin + i * fItemSize);
1549 fSubFields[0]->DestroyValue(elementValue, true /* dtorOnly */);
1550 }
1551 }
1552
1553 // figure out if we are in the small state, i.e. begin == &inlineBuffer
1554 // there might be padding between fCapacity and the inline buffer, so we compute it here
1555 constexpr auto dataMemberSz = sizeof(void *) + 2 * sizeof(std::int32_t);
1556 const auto alignOfT = fSubFields[0]->GetAlignment();
1557 auto paddingMiddle = dataMemberSz % alignOfT;
1558 if (paddingMiddle != 0)
1559 paddingMiddle = alignOfT - paddingMiddle;
1560 const bool isSmall = (reinterpret_cast<void *>(begin) == (beginPtr + dataMemberSz + paddingMiddle));
1561
1562 const bool owns = (*capacityPtr != -1);
1563 if (!isSmall && owns)
1564 free(begin);
1565
1566 if (!dtorOnly)
1567 free(beginPtr);
1568}
1569
1571{
1572 return Detail::RFieldValue(true /* captureFlag */, this, where);
1573}
1574
1575std::vector<ROOT::Experimental::Detail::RFieldValue>
1577{
1578 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(value.GetRawPtr());
1579
1580 std::vector<Detail::RFieldValue> result;
1581 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
1582 for (std::int32_t i = 0; i < *sizePtr; ++i) {
1583 auto elementValue = fSubFields[0]->CaptureValue(begin + i * fItemSize);
1584 result.emplace_back(std::move(elementValue));
1585 }
1586 return result;
1587}
1588
1590{
1591 // the size of an RVec<T> is the size of its 4 data-members + optional padding:
1592 //
1593 // data members:
1594 // - void *fBegin
1595 // - int32_t fSize
1596 // - int32_t fCapacity
1597 // - the char[] inline storage, which is aligned like T
1598 //
1599 // padding might be present:
1600 // - between fCapacity and the char[] buffer aligned like T
1601 // - after the char[] buffer
1602
1603 constexpr auto dataMemberSz = sizeof(void *) + 2 * sizeof(std::int32_t);
1604 const auto alignOfT = fSubFields[0]->GetAlignment();
1605 const auto sizeOfT = fSubFields[0]->GetValueSize();
1606
1607 // mimic the logic of RVecInlineStorageSize, but at runtime
1608 const auto inlineStorageSz = [&] {
1609#ifdef R__HAS_HARDWARE_INTERFERENCE_SIZE
1610 // hardware_destructive_interference_size is a C++17 feature but many compilers do not implement it yet
1611 constexpr unsigned cacheLineSize = std::hardware_destructive_interference_size;
1612#else
1613 constexpr unsigned cacheLineSize = 64u;
1614#endif
1615 const unsigned elementsPerCacheLine = (cacheLineSize - dataMemberSz) / sizeOfT;
1616 constexpr unsigned maxInlineByteSize = 1024;
1617 const unsigned nElements =
1618 elementsPerCacheLine >= 8 ? elementsPerCacheLine : (sizeOfT * 8 > maxInlineByteSize ? 0 : 8);
1619 return nElements * sizeOfT;
1620 }();
1621
1622 // compute padding between first 3 datamembers and inline buffer
1623 // (there should be no padding between the first 3 data members)
1624 auto paddingMiddle = dataMemberSz % alignOfT;
1625 if (paddingMiddle != 0)
1626 paddingMiddle = alignOfT - paddingMiddle;
1627
1628 // padding at the end of the object
1629 const auto alignOfRVecT = GetAlignment();
1630 auto paddingEnd = (dataMemberSz + paddingMiddle + inlineStorageSz) % alignOfRVecT;
1631 if (paddingEnd != 0)
1632 paddingEnd = alignOfRVecT - paddingEnd;
1633
1634 return dataMemberSz + inlineStorageSz + paddingMiddle + paddingEnd;
1635}
1636
1638{
1639 return fValueSize;
1640}
1641
1643{
1644 // the alignment of an RVec<T> is the largest among the alignments of its data members
1645 // (including the inline buffer which has the same alignment as the RVec::value_type)
1646 return std::max({alignof(void *), alignof(std::int32_t), fSubFields[0]->GetAlignment()});
1647}
1648
1650{
1651 fNWritten = 0;
1652}
1653
1655{
1656 visitor.VisitRVecField(*this);
1657}
1658
1659//------------------------------------------------------------------------------
1660
1662 : ROOT::Experimental::Detail::RFieldBase(name, "std::vector<bool>", ENTupleStructure::kCollection,
1663 false /* isSimple */)
1664{
1665 Attach(std::make_unique<RField<bool>>("_0"));
1666}
1667
1668std::size_t ROOT::Experimental::RField<std::vector<bool>>::AppendImpl(const Detail::RFieldValue& value) {
1669 auto typedValue = value.Get<std::vector<bool>>();
1670 auto count = typedValue->size();
1671 for (unsigned i = 0; i < count; ++i) {
1672 bool bval = (*typedValue)[i];
1673 auto itemValue = fSubFields[0]->CaptureValue(&bval);
1674 fSubFields[0]->Append(itemValue);
1675 }
1676 Detail::RColumnElement<ClusterSize_t> elemIndex(&fNWritten);
1677 fNWritten += count;
1678 fColumns[0]->Append(elemIndex);
1679 return count + sizeof(elemIndex);
1680}
1681
1682void ROOT::Experimental::RField<std::vector<bool>>::ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue* value)
1683{
1684 auto typedValue = value->Get<std::vector<bool>>();
1685
1686 ClusterSize_t nItems;
1687 RClusterIndex collectionStart;
1688 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1689
1690 typedValue->resize(nItems);
1691 for (unsigned i = 0; i < nItems; ++i) {
1692 bool bval;
1693 auto itemValue = fSubFields[0]->GenerateValue(&bval);
1694 fSubFields[0]->Read(collectionStart + i, &itemValue);
1695 (*typedValue)[i] = bval;
1696 }
1697}
1698
1699void ROOT::Experimental::RField<std::vector<bool>>::GenerateColumnsImpl()
1700{
1701 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
1702 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
1703 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
1704}
1705
1706void ROOT::Experimental::RField<std::vector<bool>>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1707{
1708 EnsureColumnType({EColumnType::kIndex}, 0, desc);
1709 GenerateColumnsImpl();
1710}
1711
1712std::vector<ROOT::Experimental::Detail::RFieldValue>
1713ROOT::Experimental::RField<std::vector<bool>>::SplitValue(const Detail::RFieldValue& value) const
1714{
1715 const static bool trueValue = true;
1716 const static bool falseValue = false;
1717
1718 auto typedValue = value.Get<std::vector<bool>>();
1719 auto count = typedValue->size();
1720 std::vector<Detail::RFieldValue> result;
1721 for (unsigned i = 0; i < count; ++i) {
1722 if ((*typedValue)[i])
1723 result.emplace_back(fSubFields[0]->CaptureValue(const_cast<bool *>(&trueValue)));
1724 else
1725 result.emplace_back(fSubFields[0]->CaptureValue(const_cast<bool *>(&falseValue)));
1726 }
1727 return result;
1728}
1729
1730
1731void ROOT::Experimental::RField<std::vector<bool>>::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
1732{
1733 auto vec = static_cast<std::vector<bool>*>(value.GetRawPtr());
1734 vec->~vector();
1735 if (!dtorOnly)
1736 free(vec);
1737}
1738
1739void ROOT::Experimental::RField<std::vector<bool>>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1740{
1741 visitor.VisitVectorBoolField(*this);
1742}
1743
1744
1745//------------------------------------------------------------------------------
1746
1747
1749 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField, std::size_t arrayLength)
1750 : ROOT::Experimental::Detail::RFieldBase(
1751 fieldName, "std::array<" + itemField->GetType() + "," + std::to_string(arrayLength) + ">",
1752 ENTupleStructure::kLeaf, false /* isSimple */, arrayLength)
1753 , fItemSize(itemField->GetValueSize()), fArrayLength(arrayLength)
1754{
1755 fTraits |= itemField->GetTraits() & ~kTraitMappable;
1756 Attach(std::move(itemField));
1757}
1758
1759std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1760ROOT::Experimental::RArrayField::CloneImpl(std::string_view newName) const
1761{
1762 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
1763 return std::make_unique<RArrayField>(newName, std::move(newItemField), fArrayLength);
1764}
1765
1767 std::size_t nbytes = 0;
1768 auto arrayPtr = value.Get<unsigned char>();
1769 for (unsigned i = 0; i < fArrayLength; ++i) {
1770 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
1771 nbytes += fSubFields[0]->Append(itemValue);
1772 }
1773 return nbytes;
1774}
1775
1777{
1778 auto arrayPtr = value->Get<unsigned char>();
1779 for (unsigned i = 0; i < fArrayLength; ++i) {
1780 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
1781 fSubFields[0]->Read(globalIndex * fArrayLength + i, &itemValue);
1782 }
1783}
1784
1786{
1787 auto arrayPtr = value->Get<unsigned char>();
1788 for (unsigned i = 0; i < fArrayLength; ++i) {
1789 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
1790 fSubFields[0]->Read(RClusterIndex(clusterIndex.GetClusterId(), clusterIndex.GetIndex() * fArrayLength + i),
1791 &itemValue);
1792 }
1793}
1794
1796{
1797}
1798
1800{
1801}
1802
1804{
1805 if (fSubFields[0]->GetTraits() & kTraitTriviallyConstructible)
1806 return Detail::RFieldValue(true /* captureFlag */, this, where);
1807
1808 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
1809 for (unsigned i = 0; i < fArrayLength; ++i) {
1810 fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
1811 }
1812 return Detail::RFieldValue(true /* captureFlag */, this, where);
1813}
1814
1816{
1817 auto arrayPtr = value.Get<unsigned char>();
1818 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible)) {
1819 for (unsigned i = 0; i < fArrayLength; ++i) {
1820 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
1821 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
1822 }
1823 }
1824 if (!dtorOnly)
1825 free(arrayPtr);
1826}
1827
1829{
1830 return Detail::RFieldValue(true /* captureFlag */, this, where);
1831}
1832
1833std::vector<ROOT::Experimental::Detail::RFieldValue>
1835{
1836 auto arrayPtr = value.Get<unsigned char>();
1837 std::vector<Detail::RFieldValue> result;
1838 for (unsigned i = 0; i < fArrayLength; ++i) {
1839 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
1840 result.emplace_back(itemValue);
1841 }
1842 return result;
1843}
1844
1846{
1847 visitor.VisitArrayField(*this);
1848}
1849
1850//------------------------------------------------------------------------------
1851
1852std::string ROOT::Experimental::RVariantField::GetTypeList(const std::vector<Detail::RFieldBase *> &itemFields)
1853{
1854 std::string result;
1855 for (size_t i = 0; i < itemFields.size(); ++i) {
1856 result += itemFields[i]->GetType() + ",";
1857 }
1858 R__ASSERT(!result.empty()); // there is always at least one variant
1859 result.pop_back(); // remove trailing comma
1860 return result;
1861}
1862
1864 std::string_view fieldName, const std::vector<Detail::RFieldBase *> &itemFields)
1865 : ROOT::Experimental::Detail::RFieldBase(fieldName,
1866 "std::variant<" + GetTypeList(itemFields) + ">", ENTupleStructure::kVariant, false /* isSimple */)
1867{
1868 // The variant needs to initialize its own tag member
1869 fTraits |= kTraitTriviallyDestructible & ~kTraitTriviallyConstructible;
1870
1871 auto nFields = itemFields.size();
1872 R__ASSERT(nFields > 0);
1873 fNWritten.resize(nFields, 0);
1874 for (unsigned int i = 0; i < nFields; ++i) {
1875 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
1876 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
1877 fTraits &= itemFields[i]->GetTraits();
1878 Attach(std::unique_ptr<Detail::RFieldBase>(itemFields[i]));
1879 }
1881}
1882
1883std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
1885{
1886 auto nFields = fSubFields.size();
1887 std::vector<Detail::RFieldBase *> itemFields;
1888 for (unsigned i = 0; i < nFields; ++i) {
1889 // TODO(jblomer): use unique_ptr in RVariantField constructor
1890 itemFields.emplace_back(fSubFields[i]->Clone(fSubFields[i]->GetName()).release());
1891 }
1892 return std::make_unique<RVariantField>(newName, itemFields);
1893}
1894
1895std::uint32_t ROOT::Experimental::RVariantField::GetTag(void *variantPtr) const
1896{
1897 auto index = *(reinterpret_cast<char *>(variantPtr) + fTagOffset);
1898 return (index < 0) ? 0 : index + 1;
1899}
1900
1901void ROOT::Experimental::RVariantField::SetTag(void *variantPtr, std::uint32_t tag) const
1902{
1903 auto index = reinterpret_cast<char *>(variantPtr) + fTagOffset;
1904 *index = static_cast<char>(tag - 1);
1905}
1906
1908{
1909 auto tag = GetTag(value.GetRawPtr());
1910 std::size_t nbytes = 0;
1911 auto index = 0;
1912 if (tag > 0) {
1913 auto itemValue = fSubFields[tag - 1]->CaptureValue(value.GetRawPtr());
1914 nbytes += fSubFields[tag - 1]->Append(itemValue);
1915 index = fNWritten[tag - 1]++;
1916 }
1917 RColumnSwitch varSwitch(ClusterSize_t(index), tag);
1918 Detail::RColumnElement<RColumnSwitch> elemSwitch(&varSwitch);
1919 fColumns[0]->Append(elemSwitch);
1920 return nbytes + sizeof(RColumnSwitch);
1921}
1922
1924{
1925 RClusterIndex variantIndex;
1926 std::uint32_t tag;
1927 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
1928 R__ASSERT(tag > 0); // TODO(jblomer): deal with invalid variants
1929
1930 auto itemValue = fSubFields[tag - 1]->GenerateValue(value->GetRawPtr());
1931 fSubFields[tag - 1]->Read(variantIndex, &itemValue);
1932 SetTag(value->GetRawPtr(), tag);
1933}
1934
1936{
1937 RColumnModel modelSwitch(EColumnType::kSwitch, false);
1938 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
1939 Detail::RColumn::Create<RColumnSwitch, EColumnType::kSwitch>(modelSwitch, 0)));
1940}
1941
1943{
1944 EnsureColumnType({EColumnType::kSwitch}, 0, desc);
1945 GenerateColumnsImpl();
1946}
1947
1949{
1950 memset(where, 0, GetValueSize());
1951 fSubFields[0]->GenerateValue(where);
1952 SetTag(where, 1);
1953 return Detail::RFieldValue(this, reinterpret_cast<unsigned char *>(where));
1954}
1955
1957{
1958 auto variantPtr = value.GetRawPtr();
1959 auto tag = GetTag(variantPtr);
1960 if (tag > 0) {
1961 auto itemValue = fSubFields[tag - 1]->CaptureValue(variantPtr);
1962 fSubFields[tag - 1]->DestroyValue(itemValue, true /* dtorOnly */);
1963 }
1964 if (!dtorOnly)
1965 free(variantPtr);
1966}
1967
1969{
1970 return Detail::RFieldValue(true /* captureFlag */, this, where);
1971}
1972
1974{
1975 return fMaxItemSize + fMaxAlignment; // TODO: fix for more than 255 items
1976}
1977
1979{
1980 std::fill(fNWritten.begin(), fNWritten.end(), 0);
1981}
1982
1983//------------------------------------------------------------------------------
1984
1985std::string ROOT::Experimental::RPairField::RPairField::GetTypeList(
1986 const std::array<std::unique_ptr<Detail::RFieldBase>, 2> &itemFields)
1987{
1988 return itemFields[0]->GetType() + "," + itemFields[1]->GetType();
1989}
1990
1992 std::array<std::unique_ptr<Detail::RFieldBase>, 2> &&itemFields,
1993 const std::array<std::size_t, 2> &offsets)
1994 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), offsets,
1995 "std::pair<" + GetTypeList(itemFields) + ">")
1996{
1997}
1998
2000 std::array<std::unique_ptr<Detail::RFieldBase>, 2> &itemFields)
2001 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), {},
2002 "std::pair<" + GetTypeList(itemFields) + ">")
2003{
2004 // ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
2005 fClass = TClass::GetClass(GetType().c_str());
2006 if (!fClass)
2007 throw RException(R__FAIL("cannot get type information for " + GetType()));
2008 fSize = fClass->Size();
2009 fOffsets[0] = fClass->GetDataMember("first")->GetOffset();
2010 fOffsets[1] = fClass->GetDataMember("second")->GetOffset();
2011}
2012
2013std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2014ROOT::Experimental::RPairField::CloneImpl(std::string_view newName) const
2015{
2016 std::array<std::unique_ptr<Detail::RFieldBase>, 2> items{fSubFields[0]->Clone(fSubFields[0]->GetName()),
2017 fSubFields[1]->Clone(fSubFields[1]->GetName())};
2018
2019 std::unique_ptr<RPairField> result(new RPairField(newName, std::move(items), {fOffsets[0], fOffsets[1]}));
2020 result->fClass = fClass;
2021 return result;
2022}
2023
2025{
2026 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
2027}
2028
2030{
2031 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
2032 if (!dtorOnly)
2033 free(value.GetRawPtr());
2034}
2035
2036//------------------------------------------------------------------------------
2037
2038std::string ROOT::Experimental::RTupleField::RTupleField::GetTypeList(
2039 const std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields)
2040{
2041 std::string result;
2042 if (itemFields.empty())
2043 throw RException(R__FAIL("the type list for std::tuple must have at least one element"));
2044 for (size_t i = 0; i < itemFields.size(); ++i) {
2045 result += itemFields[i]->GetType() + ",";
2046 }
2047 result.pop_back(); // remove trailing comma
2048 return result;
2049}
2050
2052 std::vector<std::unique_ptr<Detail::RFieldBase>> &&itemFields,
2053 const std::vector<std::size_t> &offsets)
2054 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), offsets,
2055 "std::tuple<" + GetTypeList(itemFields) + ">")
2056{
2057}
2058
2060 std::vector<std::unique_ptr<Detail::RFieldBase>> &itemFields)
2061 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), {},
2062 "std::tuple<" + GetTypeList(itemFields) + ">")
2063{
2064 fClass = TClass::GetClass(GetType().c_str());
2065 if (!fClass)
2066 throw RException(R__FAIL("cannot get type information for " + GetType()));
2067 fSize = fClass->Size();
2068
2069 // ISO C++ does not guarantee neither specific layout nor member names for `std::tuple`. However, most
2070 // implementations including libstdc++ (gcc), libc++ (llvm), and MSVC name members as `_0`, `_1`, ..., `_N-1`,
2071 // following the order of the type list.
2072 // Use TClass to get their offsets; in case a particular `std::tuple` implementation does not define such
2073 // members, the assertion below will fail.
2074 for (unsigned i = 0; i < fSubFields.size(); ++i) {
2075 std::string memberName("_" + std::to_string(i));
2076 auto member = fClass->GetRealData(memberName.c_str());
2077 if (!member)
2078 throw RException(R__FAIL(memberName + ": no such member"));
2079 fOffsets.push_back(member->GetThisOffset());
2080 }
2081}
2082
2083std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2084ROOT::Experimental::RTupleField::CloneImpl(std::string_view newName) const
2085{
2086 std::vector<std::unique_ptr<Detail::RFieldBase>> items;
2087 for (const auto &item : fSubFields)
2088 items.push_back(item->Clone(item->GetName()));
2089
2090 std::unique_ptr<RTupleField> result(new RTupleField(newName, std::move(items), fOffsets));
2091 result->fClass = fClass;
2092 return result;
2093}
2094
2096{
2097 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
2098}
2099
2101{
2102 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
2103 if (!dtorOnly)
2104 free(value.GetRawPtr());
2105}
2106
2107//------------------------------------------------------------------------------
2108
2110 std::string_view name,
2111 std::shared_ptr<RCollectionNTupleWriter> collectionNTuple,
2112 std::unique_ptr<RNTupleModel> collectionModel)
2113 : RFieldBase(name, "", ENTupleStructure::kCollection, true /* isSimple */)
2114 , fCollectionNTuple(collectionNTuple)
2115{
2116 for (unsigned i = 0; i < collectionModel->GetFieldZero()->fSubFields.size(); ++i) {
2117 auto& subField = collectionModel->GetFieldZero()->fSubFields[i];
2118 Attach(std::move(subField));
2119 }
2120 SetDescription(collectionModel->GetDescription());
2121}
2122
2123
2125{
2126 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
2127 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
2128 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
2129}
2130
2132{
2133 EnsureColumnType({EColumnType::kIndex}, 0, desc);
2134 GenerateColumnsImpl();
2135}
2136
2137
2138std::unique_ptr<ROOT::Experimental::Detail::RFieldBase>
2140{
2141 auto result = std::make_unique<RCollectionField>(newName, fCollectionNTuple, RNTupleModel::Create());
2142 for (auto& f : fSubFields) {
2143 auto clone = f->Clone(f->GetName());
2144 result->Attach(std::move(clone));
2145 }
2146 return result;
2147}
2148
2149
2151 *fCollectionNTuple->GetOffsetPtr() = 0;
2152}
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 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:117
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)
Pairs of C++ type and column type, like float and EColumnType::kReal32.
static RColumn * Create(const RColumnModel &model, std::uint32_t index)
Definition RColumn.hxx:103
Iterates over the sub tree of fields in depth-first search order.
Definition RField.hxx:166
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:467
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:114
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:181
int fTraits
Properties of the type that allow for optimizations of collections of that type.
Definition RField.hxx:124
virtual void DestroyValue(const RFieldValue &value, bool dtorOnly=false)
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition RField.cxx:337
static constexpr int kTraitTrivialType
Shorthand for types that are both trivially constructible and destructible.
Definition RField.hxx:92
friend class ROOT::Experimental::RCollectionField
Definition RField.hxx:78
void ConnectPageSink(RPageSink &pageSink)
Fields and their columns live in the void until connected to a physical page storage.
Definition RField.cxx:420
ROOT::Experimental::EColumnType EnsureColumnType(const std::vector< EColumnType > &requestedTypes, unsigned int columnIndex, const RNTupleDescriptor &desc)
Throws an exception if the column given by fOnDiskId and the columnIndex in the provided descriptor i...
Definition RField.cxx:375
void Flush() const
Ensure that all received items are written from page buffers to the storage.
Definition RField.cxx:367
virtual void CommitCluster()
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.hxx:280
void SetDescription(std::string_view description)
Definition RField.hxx:295
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:344
static RResult< void > EnsureValidFieldName(std::string_view fieldName)
Check whether a given string is a valid field name.
Definition RField.cxx:298
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:193
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:407
void ConnectPageSource(RPageSource &pageSource)
Definition RField.cxx:431
virtual std::size_t AppendImpl(const RFieldValue &value)
Operations on values of complex types, e.g.
Definition RField.cxx:317
std::function< void(RFieldValue &)> ReadCallback_t
Definition RField.hxx:80
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:309
virtual void AcceptVisitor(RFieldVisitor &visitor) const
Definition RField.cxx:445
virtual void ReadGlobalImpl(NTupleSize_t globalIndex, RFieldValue *value)
Definition RField.cxx:323
void Attach(std::unique_ptr< Detail::RFieldBase > child)
Add a new subfield to the list of nested fields.
Definition RField.cxx:349
std::vector< RFieldBase * > GetSubFields() const
Definition RField.cxx:357
static constexpr int kTraitTriviallyConstructible
No constructor needs to be called, i.e.
Definition RField.hxx:85
static constexpr int kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. DestroyValue() is a no-op.
Definition RField.hxx:87
RFieldValue GenerateValue()
Generates an object of the field type and allocates new initialized memory according to the type.
Definition RField.cxx:330
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitBoolField(const RField< bool > &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.
Abstract interface to read data from an ntuple.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
The available trivial, native content types of a column.
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:1834
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1828
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1785
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1776
RArrayField(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField, std::size_t arrayLength)
Definition RField.cxx:1748
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1845
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1795
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:1815
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1766
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:1760
The field for a class with dictionary.
Definition RField.hxx:339
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:958
static constexpr const char * kPrefixInherited
Prefix used in the subfield names generated for base classes.
Definition RField.hxx:350
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:976
void Attach(std::unique_ptr< Detail::RFieldBase > child, RSubFieldInfo info)
Definition RField.cxx:900
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:965
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:908
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:913
void AcceptVisitor(Detail::RFieldVisitor &visitor) const override
Definition RField.cxx:981
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition RField.cxx:930
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:938
RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
Definition RField.cxx:845
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:922
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:951
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
The field for a class representing a collection of elements via TVirtualCollectionProxy.
Definition RField.hxx:392
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:1113
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:1134
std::unique_ptr< TVirtualCollectionProxy > fProxy
Definition RField.hxx:397
RCollectionClassField(std::string_view fieldName, std::string_view className, TClass *classp)
Definition RField.cxx:993
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:1041
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1062
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1128
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1047
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1150
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1095
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:1145
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:2150
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:2124
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:2139
Holds the static meta-data of a column in a tree.
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:503
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:494
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:640
The on-storage meta-data of an ntuple.
const RColumnDescriptor & GetColumnDescriptor(DescriptorId_t columnId) const
DescriptorId_t FindColumnId(DescriptorId_t fieldId, std::uint32_t columnIndex) const
static std::unique_ptr< RNTupleModel > Create()
The generic field for std::pair<T1, T2> types.
Definition RField.hxx:778
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:2014
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:2029
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:1991
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1570
std::size_t EvalValueSize() const
Evaluate the constant returned by GetValueSize.
Definition RField.cxx:1589
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:1541
RRVecField(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition RField.cxx:1416
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:1649
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) override
Definition RField.cxx:1449
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1654
size_t GetAlignment() const override
For many types, the alignment requirement is equal to the size; otherwise override.
Definition RField.cxx:1642
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:1426
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:1637
std::size_t AppendImpl(const Detail::RFieldValue &value) override
Operations on values of complex types, e.g.
Definition RField.cxx:1432
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:1576
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1517
The field for an untyped record.
Definition RField.hxx:437
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:1207
std::vector< std::size_t > fOffsets
Definition RField.hxx:441
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1215
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:1157
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:1196
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1224
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1259
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:1266
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:1248
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1232
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1276
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:801
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:2084
RTupleField(std::string_view fieldName, std::vector< std::unique_ptr< Detail::RFieldBase > > &&itemFields, const std::vector< std::size_t > &offsets)
Definition RField.cxx:2051
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:2100
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1907
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:1973
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:1956
std::vector< ClusterSize_t::ValueType > fNWritten
Definition RField.hxx:607
size_t fTagOffset
In the std::variant memory layout, at which byte number is the index stored.
Definition RField.hxx:606
void SetTag(void *variantPtr, std::uint32_t tag) const
Definition RField.cxx:1901
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1935
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:1895
static std::string GetTypeList(const std::vector< Detail::RFieldBase * > &itemFields)
Definition RField.cxx:1852
RVariantField(std::string_view fieldName, const std::vector< Detail::RFieldBase * > &itemFields)
Definition RField.cxx:1863
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1923
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition RField.hxx:633
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1968
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:1884
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:1978
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition RField.cxx:1385
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition RField.cxx:1403
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:1294
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1408
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:1391
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition RField.cxx:1315
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1351
RVectorField(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition RField.cxx:1284
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:1369
std::size_t AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition RField.cxx:1300
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 TVirtualCollectionProxy * Generate() const =0
const Int_t n
Definition legend1.C:16
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 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 32bit integer in a struct in order to avoid template specialization clash with std::uint32_t...