Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldBase.cxx
Go to the documentation of this file.
1/// \file RFieldBase.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
4/// \date 2024-11-19
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8#include <ROOT/RError.hxx>
9#include <ROOT/RField.hxx>
10#include <ROOT/RFieldBase.hxx>
12#include "RFieldUtils.hxx"
13
14#include <TClass.h>
15#include <TClassEdit.h>
16#include <TEnum.h>
17
18#include <string>
19#include <vector>
20
21namespace {
22
23/// Return the canonical name of a type, resolving typedefs to their underlying types if needed. A canonical type has
24/// typedefs stripped out from the type name.
25std::string GetCanonicalTypeName(const std::string &typeName)
26{
27 // The following types are asummed to be canonical names; thus, do not perform `typedef` resolution on those
28 if (typeName.substr(0, 5) == "std::" || typeName.substr(0, 25) == "ROOT::RNTupleCardinality<")
29 return typeName;
30
31 return TClassEdit::ResolveTypedef(typeName.c_str());
32}
33
34/// Used as a thread local context storage for Create(); steers the behavior of the Create() call stack
35class CreateContextGuard;
36class CreateContext {
37 friend class CreateContextGuard;
38 /// All classes that were defined by Create() calls higher up in the stack. Finds cyclic type definitions.
39 std::vector<std::string> fClassesOnStack;
40 /// If set to true, Create() will create an RInvalidField on error instead of throwing an exception.
41 /// This is used in RFieldBase::Check() to identify unsupported sub fields.
42 bool fContinueOnError = false;
43
44public:
45 CreateContext() = default;
46 bool GetContinueOnError() const { return fContinueOnError; }
47};
48
49/// RAII for modifications of CreateContext
50class CreateContextGuard {
51 CreateContext &fCreateContext;
52 std::size_t fNOriginalClassesOnStack;
53 bool fOriginalContinueOnError;
54
55public:
56 CreateContextGuard(CreateContext &ctx)
57 : fCreateContext(ctx),
58 fNOriginalClassesOnStack(ctx.fClassesOnStack.size()),
59 fOriginalContinueOnError(ctx.fContinueOnError)
60 {
61 }
62 ~CreateContextGuard()
63 {
64 fCreateContext.fClassesOnStack.resize(fNOriginalClassesOnStack);
65 fCreateContext.fContinueOnError = fOriginalContinueOnError;
66 }
67
68 void AddClassToStack(const std::string &cl)
69 {
70 if (std::find(fCreateContext.fClassesOnStack.begin(), fCreateContext.fClassesOnStack.end(), cl) !=
71 fCreateContext.fClassesOnStack.end()) {
72 throw ROOT::RException(R__FAIL("cyclic class definition: " + cl));
73 }
74 fCreateContext.fClassesOnStack.emplace_back(cl);
75 }
76
77 void SetContinueOnError(bool value) { fCreateContext.fContinueOnError = value; }
78};
79
80} // anonymous namespace
81
83{
84 field.FlushColumns();
85}
87{
88 field.CommitCluster();
89}
91 NTupleSize_t firstEntry)
92{
93 field.ConnectPageSink(sink, firstEntry);
94}
96{
97 field.ConnectPageSource(source);
98}
99
100//------------------------------------------------------------------------------
101
103{
104 // A single representations with an empty set of columns
107}
108
110 const Selection_t &serializationTypes, const Selection_t &deserializationExtraTypes)
111 : fSerializationTypes(serializationTypes), fDeserializationTypes(serializationTypes)
112{
113 fDeserializationTypes.insert(fDeserializationTypes.end(), deserializationExtraTypes.begin(),
114 deserializationExtraTypes.end());
115}
116
117//------------------------------------------------------------------------------
118
120{
121 // Set fObjPtr to an aliased shared_ptr of the input raw pointer. Note that
122 // fObjPtr will be non-empty but have use count zero.
124}
125
126//------------------------------------------------------------------------------
127
129 : fField(other.fField),
130 fValueSize(other.fValueSize),
131 fCapacity(other.fCapacity),
132 fSize(other.fSize),
133 fIsAdopted(other.fIsAdopted),
134 fNValidValues(other.fNValidValues),
135 fFirstIndex(other.fFirstIndex)
136{
137 std::swap(fDeleter, other.fDeleter);
138 std::swap(fValues, other.fValues);
139 std::swap(fMaskAvail, other.fMaskAvail);
140}
141
143{
144 std::swap(fField, other.fField);
145 std::swap(fDeleter, other.fDeleter);
146 std::swap(fValues, other.fValues);
147 std::swap(fValueSize, other.fValueSize);
148 std::swap(fCapacity, other.fCapacity);
149 std::swap(fSize, other.fSize);
150 std::swap(fIsAdopted, other.fIsAdopted);
151 std::swap(fMaskAvail, other.fMaskAvail);
152 std::swap(fNValidValues, other.fNValidValues);
153 std::swap(fFirstIndex, other.fFirstIndex);
154 return *this;
155}
156
158{
159 if (fValues)
160 ReleaseValues();
161}
162
164{
165 if (fIsAdopted)
166 return;
167
168 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyDestructible)) {
169 for (std::size_t i = 0; i < fCapacity; ++i) {
170 fDeleter->operator()(GetValuePtrAt(i), true /* dtorOnly */);
171 }
172 }
173
174 operator delete(fValues);
175}
176
178{
179 if (fCapacity < size) {
180 if (fIsAdopted) {
181 throw RException(R__FAIL("invalid attempt to bulk read beyond the adopted buffer"));
182 }
183 ReleaseValues();
184 fValues = operator new(size * fValueSize);
185
186 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyConstructible)) {
187 for (std::size_t i = 0; i < size; ++i) {
188 fField->ConstructValue(GetValuePtrAt(i));
189 }
190 }
191
192 fMaskAvail = std::make_unique<bool[]>(size);
193 fCapacity = size;
194 }
195
196 std::fill(fMaskAvail.get(), fMaskAvail.get() + size, false);
197 fNValidValues = 0;
198
199 fFirstIndex = firstIndex;
200 fSize = size;
201}
202
204{
205 fNValidValues = 0;
206 for (std::size_t i = 0; i < fSize; ++i)
207 fNValidValues += static_cast<std::size_t>(fMaskAvail[i]);
208}
209
210void ROOT::Experimental::RFieldBase::RBulk::AdoptBuffer(void *buf, std::size_t capacity)
211{
212 ReleaseValues();
213 fValues = buf;
214 fCapacity = capacity;
215 fSize = capacity;
216
217 fMaskAvail = std::make_unique<bool[]>(capacity);
218
219 fFirstIndex = RClusterIndex();
220
221 fIsAdopted = true;
222}
223
224//------------------------------------------------------------------------------
225
227{
228 R__LOG_WARNING(NTupleLog()) << "possibly leaking object from RField<T>::CreateObject<void>";
229}
230
231template <>
232std::unique_ptr<void, typename ROOT::Experimental::RFieldBase::RCreateObjectDeleter<void>::deleter>
233ROOT::Experimental::RFieldBase::CreateObject<void>() const
234{
236 return std::unique_ptr<void, RCreateObjectDeleter<void>::deleter>(CreateObjectRawPtr(), gDeleter);
237}
238
239//------------------------------------------------------------------------------
240
241ROOT::Experimental::RFieldBase::RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure,
242 bool isSimple, std::size_t nRepetitions)
243 : fName(name),
244 fType(type),
245 fStructure(structure),
246 fNRepetitions(nRepetitions),
247 fIsSimple(isSimple),
248 fParent(nullptr),
249 fPrincipalColumn(nullptr),
250 fTraits(isSimple ? kTraitMappable : 0)
251{
253}
254
256{
257 std::string result = GetFieldName();
258 auto parent = GetParent();
259 while (parent && !parent->GetFieldName().empty()) {
260 result = parent->GetFieldName() + "." + result;
261 parent = parent->GetParent();
262 }
263 return result;
264}
265
267ROOT::Experimental::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
268{
269 auto typeAlias = Internal::GetNormalizedTypeName(typeName);
270 auto canonicalType = Internal::GetNormalizedTypeName(GetCanonicalTypeName(typeAlias));
271 return R__FORWARD_RESULT(RFieldBase::Create(fieldName, canonicalType, typeAlias));
272}
273
274std::vector<ROOT::Experimental::RFieldBase::RCheckResult>
275ROOT::Experimental::RFieldBase::Check(const std::string &fieldName, const std::string &typeName)
276{
277 auto typeAlias = Internal::GetNormalizedTypeName(typeName);
278 auto canonicalType = Internal::GetNormalizedTypeName(GetCanonicalTypeName(typeAlias));
279
280 RFieldZero fieldZero;
281 fieldZero.Attach(RFieldBase::Create(fieldName, canonicalType, typeAlias, true /* continueOnError */).Unwrap());
282
283 std::vector<RCheckResult> result;
284 for (const auto &f : fieldZero) {
285 auto invalidField = dynamic_cast<const RInvalidField *>(&f);
286 if (!invalidField)
287 continue;
288
289 result.emplace_back(
290 RCheckResult{invalidField->GetQualifiedFieldName(), invalidField->GetTypeName(), invalidField->GetError()});
291 }
292 return result;
293}
294
296ROOT::Experimental::RFieldBase::Create(const std::string &fieldName, const std::string &canonicalType,
297 const std::string &typeAlias, bool continueOnError)
298{
299 thread_local CreateContext createContext;
300 CreateContextGuard createContextGuard(createContext);
301 if (continueOnError)
302 createContextGuard.SetContinueOnError(true);
303
304 auto fnFail = [&fieldName, &canonicalType](const std::string &errMsg) -> RResult<std::unique_ptr<RFieldBase>> {
305 if (createContext.GetContinueOnError()) {
306 return std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, canonicalType, errMsg));
307 } else {
308 return R__FAIL(errMsg);
309 }
310 };
311
312 if (canonicalType.empty())
313 return R__FORWARD_RESULT(fnFail("no type name specified for field '" + fieldName + "'"));
314
315 std::unique_ptr<ROOT::Experimental::RFieldBase> result;
316
317 // try-catch block to intercept any exception that may be thrown by Unwrap() so that this
318 // function never throws but returns RResult::Error instead.
319 try {
320 if (auto [arrayBaseType, arraySizes] = Internal::ParseArrayType(canonicalType); !arraySizes.empty()) {
321 std::unique_ptr<RFieldBase> arrayField = Create("_0", arrayBaseType).Unwrap();
322 for (int i = arraySizes.size() - 1; i >= 0; --i) {
323 arrayField =
324 std::make_unique<RArrayField>((i == 0) ? fieldName : "_0", std::move(arrayField), arraySizes[i]);
325 }
326 return arrayField;
327 }
328
329 if (canonicalType == "bool") {
330 result = std::make_unique<RField<bool>>(fieldName);
331 } else if (canonicalType == "char") {
332 result = std::make_unique<RField<char>>(fieldName);
333 } else if (canonicalType == "signed char") {
334 result = std::make_unique<RField<signed char>>(fieldName);
335 } else if (canonicalType == "unsigned char") {
336 result = std::make_unique<RField<unsigned char>>(fieldName);
337 } else if (canonicalType == "short") {
338 result = std::make_unique<RField<short>>(fieldName);
339 } else if (canonicalType == "unsigned short") {
340 result = std::make_unique<RField<unsigned short>>(fieldName);
341 } else if (canonicalType == "int") {
342 result = std::make_unique<RField<int>>(fieldName);
343 } else if (canonicalType == "unsigned int") {
344 result = std::make_unique<RField<unsigned int>>(fieldName);
345 } else if (canonicalType == "long") {
346 result = std::make_unique<RField<long>>(fieldName);
347 } else if (canonicalType == "unsigned long") {
348 result = std::make_unique<RField<unsigned long>>(fieldName);
349 } else if (canonicalType == "long long") {
350 result = std::make_unique<RField<long long>>(fieldName);
351 } else if (canonicalType == "unsigned long long") {
352 result = std::make_unique<RField<unsigned long long>>(fieldName);
353 } else if (canonicalType == "std::byte") {
354 result = std::make_unique<RField<std::byte>>(fieldName);
355 } else if (canonicalType == "std::int8_t") {
356 result = std::make_unique<RField<std::int8_t>>(fieldName);
357 } else if (canonicalType == "std::uint8_t") {
358 result = std::make_unique<RField<std::uint8_t>>(fieldName);
359 } else if (canonicalType == "std::int16_t") {
360 result = std::make_unique<RField<std::int16_t>>(fieldName);
361 } else if (canonicalType == "std::uint16_t") {
362 result = std::make_unique<RField<std::uint16_t>>(fieldName);
363 } else if (canonicalType == "std::int32_t") {
364 result = std::make_unique<RField<std::int32_t>>(fieldName);
365 } else if (canonicalType == "std::uint32_t") {
366 result = std::make_unique<RField<std::uint32_t>>(fieldName);
367 } else if (canonicalType == "std::int64_t") {
368 result = std::make_unique<RField<std::int64_t>>(fieldName);
369 } else if (canonicalType == "std::uint64_t") {
370 result = std::make_unique<RField<std::uint64_t>>(fieldName);
371 } else if (canonicalType == "float") {
372 result = std::make_unique<RField<float>>(fieldName);
373 } else if (canonicalType == "double") {
374 result = std::make_unique<RField<double>>(fieldName);
375 } else if (canonicalType == "Double32_t") {
376 result = std::make_unique<RField<double>>(fieldName);
377 static_cast<RField<double> *>(result.get())->SetDouble32();
378 // Prevent the type alias from being reset by returning early
379 return result;
380 } else if (canonicalType == "std::string") {
381 result = std::make_unique<RField<std::string>>(fieldName);
382 } else if (canonicalType == "TObject") {
383 result = std::make_unique<RField<TObject>>(fieldName);
384 } else if (canonicalType == "std::vector<bool>") {
385 result = std::make_unique<RField<std::vector<bool>>>(fieldName);
386 } else if (canonicalType.substr(0, 12) == "std::vector<") {
387 std::string itemTypeName = canonicalType.substr(12, canonicalType.length() - 13);
388 auto itemField = Create("_0", itemTypeName);
389 result = std::make_unique<RVectorField>(fieldName, itemField.Unwrap());
390 } else if (canonicalType.substr(0, 19) == "ROOT::VecOps::RVec<") {
391 std::string itemTypeName = canonicalType.substr(19, canonicalType.length() - 20);
392 auto itemField = Create("_0", itemTypeName);
393 result = std::make_unique<RRVecField>(fieldName, itemField.Unwrap());
394 } else if (canonicalType.substr(0, 11) == "std::array<") {
395 auto arrayDef = Internal::TokenizeTypeList(canonicalType.substr(11, canonicalType.length() - 12));
396 if (arrayDef.size() != 2) {
397 return R__FORWARD_RESULT(fnFail("the template list for std::array must have exactly two elements"));
398 }
399 auto arrayLength = std::stoi(arrayDef[1]);
400 auto itemField = Create("_0", arrayDef[0]);
401 result = std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arrayLength);
402 } else if (canonicalType.substr(0, 13) == "std::variant<") {
403 auto innerTypes = Internal::TokenizeTypeList(canonicalType.substr(13, canonicalType.length() - 14));
404 std::vector<std::unique_ptr<RFieldBase>> items;
405 items.reserve(innerTypes.size());
406 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
407 items.emplace_back(Create("_" + std::to_string(i), innerTypes[i]).Unwrap());
408 }
409 result = std::make_unique<RVariantField>(fieldName, std::move(items));
410 } else if (canonicalType.substr(0, 10) == "std::pair<") {
411 auto innerTypes = Internal::TokenizeTypeList(canonicalType.substr(10, canonicalType.length() - 11));
412 if (innerTypes.size() != 2) {
413 return R__FORWARD_RESULT(fnFail("the type list for std::pair must have exactly two elements"));
414 }
415 std::array<std::unique_ptr<RFieldBase>, 2> items{Create("_0", innerTypes[0]).Unwrap(),
416 Create("_1", innerTypes[1]).Unwrap()};
417 result = std::make_unique<RPairField>(fieldName, std::move(items));
418 } else if (canonicalType.substr(0, 11) == "std::tuple<") {
419 auto innerTypes = Internal::TokenizeTypeList(canonicalType.substr(11, canonicalType.length() - 12));
420 std::vector<std::unique_ptr<RFieldBase>> items;
421 items.reserve(innerTypes.size());
422 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
423 items.emplace_back(Create("_" + std::to_string(i), innerTypes[i]).Unwrap());
424 }
425 result = std::make_unique<RTupleField>(fieldName, std::move(items));
426 } else if (canonicalType.substr(0, 12) == "std::bitset<") {
427 auto size = std::stoull(canonicalType.substr(12, canonicalType.length() - 13));
428 result = std::make_unique<RBitsetField>(fieldName, size);
429 } else if (canonicalType.substr(0, 16) == "std::unique_ptr<") {
430 std::string itemTypeName = canonicalType.substr(16, canonicalType.length() - 17);
431 auto itemField = Create("_0", itemTypeName).Unwrap();
432 auto normalizedInnerTypeName = itemField->GetTypeName();
433 result = std::make_unique<RUniquePtrField>(fieldName, "std::unique_ptr<" + normalizedInnerTypeName + ">",
434 std::move(itemField));
435 } else if (canonicalType.substr(0, 14) == "std::optional<") {
436 std::string itemTypeName = canonicalType.substr(14, canonicalType.length() - 15);
437 auto itemField = Create("_0", itemTypeName).Unwrap();
438 auto normalizedInnerTypeName = itemField->GetTypeName();
439 result = std::make_unique<ROptionalField>(fieldName, "std::optional<" + normalizedInnerTypeName + ">",
440 std::move(itemField));
441 } else if (canonicalType.substr(0, 9) == "std::set<") {
442 std::string itemTypeName = canonicalType.substr(9, canonicalType.length() - 10);
443 auto itemField = Create("_0", itemTypeName).Unwrap();
444 auto normalizedInnerTypeName = itemField->GetTypeName();
445 result =
446 std::make_unique<RSetField>(fieldName, "std::set<" + normalizedInnerTypeName + ">", std::move(itemField));
447 } else if (canonicalType.substr(0, 19) == "std::unordered_set<") {
448 std::string itemTypeName = canonicalType.substr(19, canonicalType.length() - 20);
449 auto itemField = Create("_0", itemTypeName).Unwrap();
450 auto normalizedInnerTypeName = itemField->GetTypeName();
451 result = std::make_unique<RSetField>(fieldName, "std::unordered_set<" + normalizedInnerTypeName + ">",
452 std::move(itemField));
453 } else if (canonicalType.substr(0, 14) == "std::multiset<") {
454 std::string itemTypeName = canonicalType.substr(14, canonicalType.length() - 15);
455 auto itemField = Create("_0", itemTypeName).Unwrap();
456 auto normalizedInnerTypeName = itemField->GetTypeName();
457 result = std::make_unique<RSetField>(fieldName, "std::multiset<" + normalizedInnerTypeName + ">",
458 std::move(itemField));
459 } else if (canonicalType.substr(0, 24) == "std::unordered_multiset<") {
460 std::string itemTypeName = canonicalType.substr(24, canonicalType.length() - 25);
461 auto itemField = Create("_0", itemTypeName).Unwrap();
462 auto normalizedInnerTypeName = itemField->GetTypeName();
463 result = std::make_unique<RSetField>(fieldName, "std::unordered_multiset<" + normalizedInnerTypeName + ">",
464 std::move(itemField));
465 } else if (canonicalType.substr(0, 9) == "std::map<") {
466 auto innerTypes = Internal::TokenizeTypeList(canonicalType.substr(9, canonicalType.length() - 10));
467 if (innerTypes.size() != 2) {
468 return R__FORWARD_RESULT(fnFail("the type list for std::map must have exactly two elements"));
469 }
470
471 auto itemField = Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">").Unwrap();
472
473 // We use the type names of subfields of the newly created item fields to create the map's type name to ensure
474 // the inner type names are properly normalized.
475 auto keyTypeName = itemField->GetSubFields()[0]->GetTypeName();
476 auto valueTypeName = itemField->GetSubFields()[1]->GetTypeName();
477
478 result = std::make_unique<RMapField>(fieldName, "std::map<" + keyTypeName + "," + valueTypeName + ">",
479 std::move(itemField));
480 } else if (canonicalType.substr(0, 19) == "std::unordered_map<") {
481 auto innerTypes = Internal::TokenizeTypeList(canonicalType.substr(19, canonicalType.length() - 20));
482 if (innerTypes.size() != 2)
483 return R__FORWARD_RESULT(fnFail("the type list for std::unordered_map must have exactly two elements"));
484
485 auto itemField = Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">").Unwrap();
486
487 // We use the type names of subfields of the newly created item fields to create the map's type name to ensure
488 // the inner type names are properly normalized.
489 auto keyTypeName = itemField->GetSubFields()[0]->GetTypeName();
490 auto valueTypeName = itemField->GetSubFields()[1]->GetTypeName();
491
492 result = std::make_unique<RMapField>(
493 fieldName, "std::unordered_map<" + keyTypeName + "," + valueTypeName + ">", std::move(itemField));
494 } else if (canonicalType.substr(0, 14) == "std::multimap<") {
495 auto innerTypes = Internal::TokenizeTypeList(canonicalType.substr(14, canonicalType.length() - 15));
496 if (innerTypes.size() != 2)
497 return R__FORWARD_RESULT(fnFail("the type list for std::multimap must have exactly two elements"));
498
499 auto itemField = Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">").Unwrap();
500
501 // We use the type names of subfields of the newly created item fields to create the map's type name to ensure
502 // the inner type names are properly normalized.
503 auto keyTypeName = itemField->GetSubFields()[0]->GetTypeName();
504 auto valueTypeName = itemField->GetSubFields()[1]->GetTypeName();
505
506 result = std::make_unique<RMapField>(fieldName, "std::multimap<" + keyTypeName + "," + valueTypeName + ">",
507 std::move(itemField));
508 } else if (canonicalType.substr(0, 24) == "std::unordered_multimap<") {
509 auto innerTypes = Internal::TokenizeTypeList(canonicalType.substr(24, canonicalType.length() - 25));
510 if (innerTypes.size() != 2)
511 return R__FORWARD_RESULT(
512 fnFail("the type list for std::unordered_multimap must have exactly two elements"));
513
514 auto itemField = Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">").Unwrap();
515
516 // We use the type names of subfields of the newly created item fields to create the map's type name to ensure
517 // the inner type names are properly normalized.
518 auto keyTypeName = itemField->GetSubFields()[0]->GetTypeName();
519 auto valueTypeName = itemField->GetSubFields()[1]->GetTypeName();
520
521 result = std::make_unique<RMapField>(
522 fieldName, "std::unordered_multimap<" + keyTypeName + "," + valueTypeName + ">", std::move(itemField));
523 } else if (canonicalType.substr(0, 12) == "std::atomic<") {
524 std::string itemTypeName = canonicalType.substr(12, canonicalType.length() - 13);
525 auto itemField = Create("_0", itemTypeName).Unwrap();
526 auto normalizedInnerTypeName = itemField->GetTypeName();
527 result = std::make_unique<RAtomicField>(fieldName, "std::atomic<" + normalizedInnerTypeName + ">",
528 std::move(itemField));
529 } else if (canonicalType.substr(0, 25) == "ROOT::RNTupleCardinality<") {
530 auto innerTypes = Internal::TokenizeTypeList(canonicalType.substr(25, canonicalType.length() - 26));
531 if (innerTypes.size() != 1)
532 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + canonicalType));
533 if (innerTypes[0] == "std::uint32_t") {
534 result = std::make_unique<RField<RNTupleCardinality<std::uint32_t>>>(fieldName);
535 } else if (innerTypes[0] == "std::uint64_t") {
536 result = std::make_unique<RField<RNTupleCardinality<std::uint64_t>>>(fieldName);
537 } else {
538 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + canonicalType));
539 }
540 }
541
542 if (!result) {
543 auto e = TEnum::GetEnum(canonicalType.c_str());
544 if (e != nullptr) {
545 result = std::make_unique<REnumField>(fieldName, canonicalType);
546 }
547 }
548
549 if (!result) {
550 auto cl = TClass::GetClass(canonicalType.c_str());
551 if (cl != nullptr) {
552 createContextGuard.AddClassToStack(canonicalType);
553 if (cl->GetCollectionProxy()) {
554 result = std::make_unique<RProxiedCollectionField>(fieldName, canonicalType);
555 } else {
558 result = std::make_unique<RStreamerField>(fieldName, canonicalType);
559 } else {
560 result = std::make_unique<RClassField>(fieldName, canonicalType);
561 }
562 }
563 }
564 }
565 } catch (RException &e) {
566 auto error = e.GetError();
567 if (createContext.GetContinueOnError()) {
568 return std::unique_ptr<RFieldBase>(
569 std::make_unique<RInvalidField>(fieldName, canonicalType, error.GetReport()));
570 } else {
571 return error;
572 }
573 }
574
575 if (result) {
576 if (typeAlias != canonicalType)
577 result->fTypeAlias = typeAlias;
578 return result;
579 }
580 return R__FORWARD_RESULT(fnFail("unknown type: " + canonicalType));
581}
582
585{
586 static RColumnRepresentations representations;
587 return representations;
588}
589
590std::unique_ptr<ROOT::Experimental::RFieldBase> ROOT::Experimental::RFieldBase::Clone(std::string_view newName) const
591{
592 auto clone = CloneImpl(newName);
593 clone->fTypeAlias = fTypeAlias;
594 clone->fOnDiskId = fOnDiskId;
595 clone->fDescription = fDescription;
596 // We can just copy the references because fColumnRepresentatives point into a static structure
597 clone->fColumnRepresentatives = fColumnRepresentatives;
598 return clone;
599}
600
601std::size_t ROOT::Experimental::RFieldBase::AppendImpl(const void * /* from */)
602{
603 R__ASSERT(false && "A non-simple RField must implement its own AppendImpl");
604 return 0;
605}
606
608{
609 R__ASSERT(false);
610}
611
613{
614 ReadGlobalImpl(fPrincipalColumn->GetGlobalIndex(clusterIndex), to);
615}
616
618{
619 const auto valueSize = GetValueSize();
620 std::size_t nRead = 0;
621 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
622 // Value not needed
623 if (bulkSpec.fMaskReq && !bulkSpec.fMaskReq[i])
624 continue;
625
626 // Value already present
627 if (bulkSpec.fMaskAvail[i])
628 continue;
629
630 Read(bulkSpec.fFirstIndex + i, reinterpret_cast<unsigned char *>(bulkSpec.fValues) + i * valueSize);
631 bulkSpec.fMaskAvail[i] = true;
632 nRead++;
633 }
634 return nRead;
635}
636
638{
639 void *where = operator new(GetValueSize());
640 R__ASSERT(where != nullptr);
641 ConstructValue(where);
642 return where;
643}
644
646{
647 void *obj = CreateObjectRawPtr();
648 return RValue(this, std::shared_ptr<void>(obj, RSharedPtrDeleter(GetDeleter())));
649}
650
651std::vector<ROOT::Experimental::RFieldBase::RValue>
653{
654 return std::vector<RValue>();
655}
656
657void ROOT::Experimental::RFieldBase::Attach(std::unique_ptr<ROOT::Experimental::RFieldBase> child)
658{
659 // Note that during a model update, new fields will be attached to the zero field. The zero field, however,
660 // does not change its inital state because only its sub fields get connected by RPageSink::UpdateSchema.
661 if (fState != EState::kUnconnected)
662 throw RException(R__FAIL("invalid attempt to attach subfield to already connected field"));
663 child->fParent = this;
664 fSubFields.emplace_back(std::move(child));
665}
666
669{
670 std::size_t result = globalIndex;
671 for (auto f = this; f != nullptr; f = f->GetParent()) {
672 auto parent = f->GetParent();
673 if (parent && (parent->GetStructure() == kCollection || parent->GetStructure() == kVariant))
674 return 0U;
675 result *= std::max(f->GetNRepetitions(), std::size_t{1U});
676 }
677 return result;
678}
679
680std::vector<ROOT::Experimental::RFieldBase *> ROOT::Experimental::RFieldBase::GetSubFields()
681{
682 std::vector<RFieldBase *> result;
683 result.reserve(fSubFields.size());
684 for (const auto &f : fSubFields) {
685 result.emplace_back(f.get());
686 }
687 return result;
688}
689
690std::vector<const ROOT::Experimental::RFieldBase *> ROOT::Experimental::RFieldBase::GetSubFields() const
691{
692 std::vector<const RFieldBase *> result;
693 result.reserve(fSubFields.size());
694 for (const auto &f : fSubFields) {
695 result.emplace_back(f.get());
696 }
697 return result;
698}
699
701{
702 if (!fAvailableColumns.empty()) {
703 const auto activeRepresentationIndex = fPrincipalColumn->GetRepresentationIndex();
704 for (auto &column : fAvailableColumns) {
705 if (column->GetRepresentationIndex() == activeRepresentationIndex) {
706 column->Flush();
707 }
708 }
709 }
710}
711
713{
714 if (!fAvailableColumns.empty()) {
715 const auto activeRepresentationIndex = fPrincipalColumn->GetRepresentationIndex();
716 for (auto &column : fAvailableColumns) {
717 if (column->GetRepresentationIndex() == activeRepresentationIndex) {
718 column->Flush();
719 } else {
720 column->CommitSuppressed();
721 }
722 }
723 }
724 CommitClusterImpl();
725}
726
727void ROOT::Experimental::RFieldBase::SetDescription(std::string_view description)
728{
729 if (fState != EState::kUnconnected)
730 throw RException(R__FAIL("cannot set field description once field is connected"));
731 fDescription = std::string(description);
732}
733
735{
736 if (fState != EState::kUnconnected)
737 throw RException(R__FAIL("cannot set field ID once field is connected"));
738 fOnDiskId = id;
739}
740
741/// Write the given value into columns. The value object has to be of the same type as the field.
742/// Returns the number of uncompressed bytes written.
743std::size_t ROOT::Experimental::RFieldBase::Append(const void *from)
744{
745 if (~fTraits & kTraitMappable)
746 return AppendImpl(from);
747
748 fPrincipalColumn->Append(from);
749 return fPrincipalColumn->GetElement()->GetPackedSize();
750}
751
753{
754 return RBulk(this);
755}
756
758{
759 return RValue(this, objPtr);
760}
761
763{
764 if (fIsSimple) {
765 /// For simple types, ignore the mask and memcopy the values into the destination
766 fPrincipalColumn->ReadV(bulkSpec.fFirstIndex, bulkSpec.fCount, bulkSpec.fValues);
767 std::fill(bulkSpec.fMaskAvail, bulkSpec.fMaskAvail + bulkSpec.fCount, true);
768 return RBulkSpec::kAllSet;
769 }
770
771 return ReadBulkImpl(bulkSpec);
772}
773
775{
776 return fSubFields.empty() ? RSchemaIterator(this, -1) : RSchemaIterator(fSubFields[0].get(), 0);
777}
778
780{
781 return RSchemaIterator(this, -1);
782}
783
785{
786 return fSubFields.empty() ? RConstSchemaIterator(this, -1) : RConstSchemaIterator(fSubFields[0].get(), 0);
787}
788
790{
791 return RConstSchemaIterator(this, -1);
792}
793
795{
796 return fSubFields.empty() ? RConstSchemaIterator(this, -1) : RConstSchemaIterator(fSubFields[0].get(), 0);
797}
798
800{
801 return RConstSchemaIterator(this, -1);
802}
803
806{
807 if (fColumnRepresentatives.empty()) {
808 return {GetColumnRepresentations().GetSerializationDefault()};
809 }
810
812 result.reserve(fColumnRepresentatives.size());
813 for (const auto &r : fColumnRepresentatives) {
814 result.emplace_back(r.get());
815 }
816 return result;
817}
818
820 const RColumnRepresentations::Selection_t &representatives)
821{
822 if (fState != EState::kUnconnected)
823 throw RException(R__FAIL("cannot set column representative once field is connected"));
824 const auto &validTypes = GetColumnRepresentations().GetSerializationTypes();
825 fColumnRepresentatives.clear();
826 fColumnRepresentatives.reserve(representatives.size());
827 for (const auto &r : representatives) {
828 auto itRepresentative = std::find(validTypes.begin(), validTypes.end(), r);
829 if (itRepresentative == std::end(validTypes))
830 throw RException(R__FAIL("invalid column representative"));
831 fColumnRepresentatives.emplace_back(*itRepresentative);
832 }
833}
834
837 std::uint16_t representationIndex) const
838{
839 static const ColumnRepresentation_t kEmpty;
840
841 if (fOnDiskId == kInvalidDescriptorId)
842 throw RException(R__FAIL("No on-disk field information for `" + GetQualifiedFieldName() + "`"));
843
844 ColumnRepresentation_t onDiskTypes;
845 for (const auto &c : desc.GetColumnIterable(fOnDiskId)) {
846 if (c.GetRepresentationIndex() == representationIndex)
847 onDiskTypes.emplace_back(c.GetType());
848 }
849 if (onDiskTypes.empty()) {
850 if (representationIndex == 0) {
851 throw RException(R__FAIL("No on-disk column information for field `" + GetQualifiedFieldName() + "`"));
852 }
853 return kEmpty;
854 }
855
856 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
857 if (t == onDiskTypes)
858 return t;
859 }
860
861 std::string columnTypeNames;
862 for (const auto &t : onDiskTypes) {
863 if (!columnTypeNames.empty())
864 columnTypeNames += ", ";
865 columnTypeNames += std::string("`") + Internal::RColumnElementBase::GetColumnTypeName(t) + "`";
866 }
867 throw RException(R__FAIL("On-disk column types {" + columnTypeNames + "} for field `" + GetQualifiedFieldName() +
868 "` cannot be matched to its in-memory type `" + GetTypeName() + "` " +
869 "(representation index: " + std::to_string(representationIndex) + ")"));
870}
871
873{
874 fReadCallbacks.push_back(func);
875 fIsSimple = false;
876 return fReadCallbacks.size() - 1;
877}
878
880{
881 fReadCallbacks.erase(fReadCallbacks.begin() + idx);
882 fIsSimple = (fTraits & kTraitMappable) && !fIsArtificial && fReadCallbacks.empty();
883}
884
886{
887 if ((options.GetCompression() == 0) && HasDefaultColumnRepresentative()) {
888 ColumnRepresentation_t rep = GetColumnRepresentations().GetSerializationDefault();
889 for (auto &colType : rep) {
890 switch (colType) {
893 case EColumnType::kSplitReal64: colType = EColumnType::kReal64; break;
894 case EColumnType::kSplitReal32: colType = EColumnType::kReal32; break;
895 case EColumnType::kSplitInt64: colType = EColumnType::kInt64; break;
896 case EColumnType::kSplitInt32: colType = EColumnType::kInt32; break;
897 case EColumnType::kSplitInt16: colType = EColumnType::kInt16; break;
898 case EColumnType::kSplitUInt64: colType = EColumnType::kUInt64; break;
899 case EColumnType::kSplitUInt32: colType = EColumnType::kUInt32; break;
900 case EColumnType::kSplitUInt16: colType = EColumnType::kUInt16; break;
901 default: break;
902 }
903 }
904 SetColumnRepresentatives({rep});
905 }
906
907 if (fTypeAlias == "Double32_t")
908 SetColumnRepresentatives({{EColumnType::kSplitReal32}});
909}
910
912{
913 if (dynamic_cast<ROOT::Experimental::RFieldZero *>(this))
914 throw RException(R__FAIL("invalid attempt to connect zero field to page sink"));
915 if (fState != EState::kUnconnected)
916 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page sink"));
917
918 AutoAdjustColumnTypes(pageSink.GetWriteOptions());
919
920 GenerateColumns();
921 for (auto &column : fAvailableColumns) {
922 // Only the first column of every representation can be a deferred column. In all column representations,
923 // larger column indexes are data columns of collections (string, streamer) and thus
924 // they have no elements on late model extension
925 auto firstElementIndex = (column->GetIndex() == 0) ? EntryToColumnElementIndex(firstEntry) : 0;
926 column->ConnectPageSink(fOnDiskId, pageSink, firstElementIndex);
927 }
928
929 if (HasExtraTypeInfo()) {
931 [this](Internal::RPageSink &sink) { sink.UpdateExtraTypeInfo(GetExtraTypeInfo()); });
932 }
933
934 fState = EState::kConnectedToSink;
935}
936
938{
939 if (dynamic_cast<ROOT::Experimental::RFieldZero *>(this))
940 throw RException(R__FAIL("invalid attempt to connect zero field to page source"));
941 if (fState != EState::kUnconnected)
942 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page source"));
943
944 if (!fColumnRepresentatives.empty())
945 throw RException(R__FAIL("fixed column representative only valid when connecting to a page sink"));
946 if (!fDescription.empty())
947 throw RException(R__FAIL("setting description only valid when connecting to a page sink"));
948
949 BeforeConnectPageSource(pageSource);
950
951 for (auto &f : fSubFields) {
952 if (f->GetOnDiskId() == kInvalidDescriptorId) {
953 f->SetOnDiskId(pageSource.GetSharedDescriptorGuard()->FindFieldId(f->GetFieldName(), GetOnDiskId()));
954 }
955 f->ConnectPageSource(pageSource);
956 }
957
958 // Do not generate columns nor set fColumnRepresentatives for artificial fields.
959 if (!fIsArtificial) {
960 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
961 const RNTupleDescriptor &desc = descriptorGuard.GetRef();
962 GenerateColumns(desc);
963 if (fColumnRepresentatives.empty()) {
964 // If we didn't get columns from the descriptor, ensure that we actually expect a field without columns
965 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
966 if (t.empty()) {
967 fColumnRepresentatives = {t};
968 break;
969 }
970 }
971 }
972 R__ASSERT(!fColumnRepresentatives.empty());
973 if (fOnDiskId != kInvalidDescriptorId) {
974 const auto &fieldDesc = desc.GetFieldDescriptor(fOnDiskId);
975 fOnDiskTypeVersion = fieldDesc.GetTypeVersion();
976 if (fieldDesc.GetTypeChecksum().has_value())
977 fOnDiskTypeChecksum = *fieldDesc.GetTypeChecksum();
978 }
979 }
980 for (auto &column : fAvailableColumns)
981 column->ConnectPageSource(fOnDiskId, pageSource);
982 OnConnectPageSource();
983
984 fState = EState::kConnectedToSource;
985}
986
988{
989 visitor.VisitField(*this);
990}
size_t fValueSize
dim_t fSize
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:301
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:299
#define R__LOG_WARNING(...)
Definition RLogger.hxx:363
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
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 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
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitField(const RFieldBase &field)=0
static const char * GetColumnTypeName(EColumnType type)
Abstract interface to write data into an ntuple.
virtual void UpdateExtraTypeInfo(const RExtraTypeInfoDescriptor &extraTypeInfo)=0
Adds an extra type information record to schema.
const RNTupleWriteOptions & GetWriteOptions() const
Returns the sink's write options.
void RegisterOnCommitDatasetCallback(Callback_t callback)
The registered callback is executed at the beginning of CommitDataset();.
Abstract interface to read data from an ntuple.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Similar to RValue but manages an array of consecutive values.
std::unique_ptr< bool[]> fMaskAvail
Masks invalid values in the array.
void AdoptBuffer(void *buf, std::size_t capacity)
RBulk & operator=(const RBulk &)=delete
void Reset(RClusterIndex firstIndex, std::size_t size)
Sets a new range for the bulk.
void * fValues
Cached deleter of fField.
std::unique_ptr< RFieldBase::RDeleter > fDeleter
Some fields have multiple possible column representations, e.g.
std::vector< ColumnRepresentation_t > Selection_t
A list of column representations.
Selection_t fDeserializationTypes
The union of the serialization types and the deserialization extra types.
Iterates over the sub tree of fields in depth-first search order.
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
A field translates read and write calls from/to underlying columns to/from tree values.
RBulk CreateBulk()
The returned bulk is initially empty; RBulk::ReadBulk will construct the array of values.
static constexpr int kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
void Attach(std::unique_ptr< RFieldBase > child)
Add a new subfield to the list of nested fields.
void AutoAdjustColumnTypes(const RNTupleWriteOptions &options)
When connecting a field to a page sink, the field's default column representation is subject to adjus...
void SetColumnRepresentatives(const RColumnRepresentations::Selection_t &representatives)
Fixes a column representative.
ENTupleStructure fStructure
The role of this field in the data model structure.
std::vector< RFieldBase * > GetSubFields()
static std::vector< RCheckResult > Check(const std::string &fieldName, const std::string &typeName)
Checks if the given type is supported by RNTuple.
static constexpr int kTraitMappable
A field of a fundamental type that can be directly mapped via RField<T>::Map(), i....
std::function< void(void *)> ReadCallback_t
static constexpr int kTraitTriviallyConstructible
No constructor needs to be called, i.e.
virtual void AcceptVisitor(Detail::RFieldVisitor &visitor) const
std::size_t fNRepetitions
For fixed sized arrays, the array length.
RFieldBase * fParent
Sub fields point to their mother field.
void FlushColumns()
Flushes data from active columns.
int fTraits
Properties of the type that allow for optimizations of collections of that type.
void ConnectPageSink(Internal::RPageSink &pageSink, NTupleSize_t firstEntry=0)
Fields and their columns live in the void until connected to a physical page storage.
virtual std::size_t AppendImpl(const void *from)
Operations on values of complex types, e.g.
bool fIsSimple
A field qualifies as simple if it is mappable (which implies it has a single principal column),...
RConstSchemaIterator cend() const
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots ("grandparent.parent....
std::vector< EColumnType > ColumnRepresentation_t
virtual std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec)
General implementation of bulk read.
std::size_t Append(const void *from)
Write the given value into columns.
virtual void ReadInClusterImpl(RClusterIndex clusterIndex, void *to)
void RemoveReadCallback(size_t idx)
void * CreateObjectRawPtr() const
Factory method for the field's type. The caller owns the returned pointer.
void CommitCluster()
Flushes data from active columns to disk and calls CommitClusterImpl.
const ColumnRepresentation_t & EnsureCompatibleColumnTypes(const RNTupleDescriptor &desc, std::uint16_t representationIndex) const
Returns the on-disk column types found in the provided descriptor for fOnDiskId and the given represe...
void ConnectPageSource(Internal::RPageSource &pageSource)
Connects the field and its sub field tree to the given page source.
RValue CreateValue()
Generates an object of the field type and wraps the created object in a shared pointer and returns it...
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.
std::size_t ReadBulk(const RBulkSpec &bulkSpec)
Returns the number of newly available values, that is the number of bools in bulkSpec....
RConstSchemaIterator cbegin() const
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &canonicalType, const std::string &typeAlias, bool continueOnError=false)
Factory method to resurrect a field from the stored on-disk type information.
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...
virtual std::vector< RValue > SplitValue(const RValue &value) const
Creates the list of direct child values given a value for this field.
void SetOnDiskId(DescriptorId_t id)
RColumnRepresentations::Selection_t GetColumnRepresentatives() const
Returns the fColumnRepresentative pointee or, if unset (always the case for artificial fields),...
std::string fName
The field name relative to its parent field.
std::string fType
The C++ type captured by this field.
Internal::RColumn * fPrincipalColumn
All fields that have columns have a distinct main column.
void SetDescription(std::string_view description)
NTupleSize_t EntryToColumnElementIndex(NTupleSize_t globalIndex) const
Translate an entry index to a column element index of the principal column and viceversa.
RValue BindValue(std::shared_ptr< void > objPtr)
Creates a value from a memory location with an already constructed object.
virtual void ReadGlobalImpl(NTupleSize_t globalIndex, void *to)
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.
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:58
void Attach(std::unique_ptr< RFieldBase > child)
Add a new subfield to the list of nested fields.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:242
Used in RFieldBase::Check() to record field creation failures.
Definition RField.hxx:76
The on-storage meta-data of an ntuple.
RColumnDescriptorIterable GetColumnIterable() const
DescriptorId_t FindFieldId(std::string_view fieldName, DescriptorId_t parentId) const
const RFieldDescriptor & GetFieldDescriptor(DescriptorId_t fieldId) const
Common user-tunable settings for storing ntuples.
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
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:197
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:3037
static TEnum * GetEnum(const std::type_info &ti, ESearchAction sa=kALoadAndInterpLookup)
Definition TEnum.cxx:175
RResult< void > EnsureValidNameForRNTuple(std::string_view name, std::string_view where)
Check whether a given string is a valid name according to the RNTuple specification.
std::vector< std::string > TokenizeTypeList(std::string_view templateType)
Used in RFieldBase::Create() in order to get the comma-separated list of template types E....
std::string GetNormalizedTypeName(const std::string &typeName)
Applies type name normalization rules that lead to the final name used to create a RField,...
auto MakeAliasedSharedPtr(T *rawPtr)
void CallConnectPageSinkOnField(RFieldBase &, RPageSink &, NTupleSize_t firstEntry=0)
void CallFlushColumnsOnField(RFieldBase &)
void CallConnectPageSourceOnField(RFieldBase &, RPageSource &)
ERNTupleSerializationMode GetRNTupleSerializationMode(TClass *cl)
void CallCommitClusterOnField(RFieldBase &)
std::tuple< std::string, std::vector< size_t > > ParseArrayType(std::string_view typeName)
Parse a type name of the form T[n][m]... and return the base type T and a vector that contains,...
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.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
constexpr DescriptorId_t kInvalidDescriptorId
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
void * fValues
The destination area, which has to be a big enough array of valid objects of the correct type.
const bool * fMaskReq
A bool array of size fCount, indicating the required values in the requested range.
bool * fMaskAvail
A bool array of size fCount, indicating the valid values in fValues.
std::size_t fCount
Size of the bulk range.
RClusterIndex fFirstIndex
Start of the bulk range.
Used in the return value of the Check() method.