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