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