Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RFieldBase.cxx
Go to the documentation of this file.
1/// \file RFieldBase.cxx
2/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
3/// \date 2024-11-19
4
5#include <ROOT/RError.hxx>
6#include <ROOT/RField.hxx>
7#include <ROOT/RFieldBase.hxx>
10#include <ROOT/RNTupleUtils.hxx>
11
12#include <TClass.h>
13#include <TClassEdit.h>
14#include <TEnum.h>
15
16#include <sstream>
17#include <string>
18#include <vector>
19
20namespace {
21
22/// Used as a thread local context storage for Create(); steers the behavior of the Create() call stack
23class CreateContextGuard;
24class CreateContext {
25 friend class CreateContextGuard;
26 /// All classes that were defined by Create() calls higher up in the stack. Finds cyclic type definitions.
27 std::vector<std::string> fClassesOnStack;
28 /// If set to true, Create() will create an RInvalidField on error instead of throwing an exception.
29 /// This is used in RFieldBase::Check() to identify unsupported sub fields.
30 bool fContinueOnError = false;
31
32public:
33 CreateContext() = default;
34 bool GetContinueOnError() const { return fContinueOnError; }
35};
36
37/// RAII for modifications of CreateContext
38class CreateContextGuard {
39 CreateContext &fCreateContext;
40 std::size_t fNOriginalClassesOnStack;
41 bool fOriginalContinueOnError;
42
43public:
44 CreateContextGuard(CreateContext &ctx)
45 : fCreateContext(ctx),
46 fNOriginalClassesOnStack(ctx.fClassesOnStack.size()),
47 fOriginalContinueOnError(ctx.fContinueOnError)
48 {
49 }
50 ~CreateContextGuard()
51 {
52 fCreateContext.fClassesOnStack.resize(fNOriginalClassesOnStack);
53 fCreateContext.fContinueOnError = fOriginalContinueOnError;
54 }
55
56 void AddClassToStack(const std::string &cl)
57 {
58 if (std::find(fCreateContext.fClassesOnStack.begin(), fCreateContext.fClassesOnStack.end(), cl) !=
59 fCreateContext.fClassesOnStack.end()) {
60 throw ROOT::RException(R__FAIL("cyclic class definition: " + cl));
61 }
62 fCreateContext.fClassesOnStack.emplace_back(cl);
63 }
64
65 void SetContinueOnError(bool value) { fCreateContext.fContinueOnError = value; }
66};
67
68} // anonymous namespace
69
79 ROOT::NTupleSize_t firstEntry)
80{
81 field.ConnectPageSink(sink, firstEntry);
82}
87
89ROOT::Internal::CallFieldBaseCreate(const std::string &fieldName, const std::string &typeName,
90 const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc,
92{
93 return RFieldBase::Create(fieldName, typeName, options, desc, fieldId);
94}
95
96//------------------------------------------------------------------------------
97
99{
100 // A single representations with an empty set of columns
103}
104
106 const Selection_t &deserializationExtraTypes)
107 : fSerializationTypes(serializationTypes), fDeserializationTypes(serializationTypes)
108{
109 fDeserializationTypes.insert(fDeserializationTypes.end(), deserializationExtraTypes.begin(),
110 deserializationExtraTypes.end());
111}
112
113//------------------------------------------------------------------------------
114
116{
117 // Set fObjPtr to an aliased shared_ptr of the input raw pointer. Note that
118 // fObjPtr will be non-empty but have use count zero.
120}
121
122//------------------------------------------------------------------------------
123
125 : fField(other.fField),
126 fValueSize(other.fValueSize),
127 fCapacity(other.fCapacity),
128 fSize(other.fSize),
129 fIsAdopted(other.fIsAdopted),
132{
133 std::swap(fDeleter, other.fDeleter);
134 std::swap(fValues, other.fValues);
135 std::swap(fMaskAvail, other.fMaskAvail);
136}
137
139{
140 std::swap(fField, other.fField);
141 std::swap(fDeleter, other.fDeleter);
142 std::swap(fValues, other.fValues);
143 std::swap(fValueSize, other.fValueSize);
144 std::swap(fCapacity, other.fCapacity);
145 std::swap(fSize, other.fSize);
146 std::swap(fIsAdopted, other.fIsAdopted);
147 std::swap(fMaskAvail, other.fMaskAvail);
148 std::swap(fNValidValues, other.fNValidValues);
149 std::swap(fFirstIndex, other.fFirstIndex);
150 return *this;
151}
152
158
160{
161 if (fIsAdopted)
162 return;
163
164 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyDestructible)) {
165 for (std::size_t i = 0; i < fCapacity; ++i) {
166 fDeleter->operator()(GetValuePtrAt(i), true /* dtorOnly */);
167 }
168 }
169
170 operator delete(fValues);
171}
172
174{
175 if (fCapacity < size) {
176 if (fIsAdopted) {
177 throw RException(R__FAIL("invalid attempt to bulk read beyond the adopted buffer"));
178 }
180 fValues = operator new(size * fValueSize);
181
182 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyConstructible)) {
183 for (std::size_t i = 0; i < size; ++i) {
184 fField->ConstructValue(GetValuePtrAt(i));
185 }
186 }
187
188 fMaskAvail = std::make_unique<bool[]>(size);
189 fCapacity = size;
190 }
191
192 std::fill(fMaskAvail.get(), fMaskAvail.get() + size, false);
193 fNValidValues = 0;
194
195 fFirstIndex = firstIndex;
196 fSize = size;
197}
198
199void ROOT::RFieldBase::RBulkValues::AdoptBuffer(void *buf, std::size_t capacity)
200{
202 fValues = buf;
203 fCapacity = capacity;
204 fSize = capacity;
205
206 fMaskAvail = std::make_unique<bool[]>(capacity);
207
209
210 fIsAdopted = true;
211}
212
213//------------------------------------------------------------------------------
214
216{
217 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "possibly leaking object from RField<T>::CreateObject<void>";
218}
219
220template <>
221std::unique_ptr<void, typename ROOT::RFieldBase::RCreateObjectDeleter<void>::deleter>
223{
225 return std::unique_ptr<void, RCreateObjectDeleter<void>::deleter>(CreateObjectRawPtr(), gDeleter);
226}
227
228//------------------------------------------------------------------------------
229
230ROOT::RFieldBase::RFieldBase(std::string_view name, std::string_view type, ROOT::ENTupleStructure structure,
231 bool isSimple, std::size_t nRepetitions)
232 : fName(name),
233 fType(type),
234 fStructure(structure),
235 fNRepetitions(nRepetitions),
236 fIsSimple(isSimple),
237 fParent(nullptr),
238 fPrincipalColumn(nullptr),
239 fTraits(isSimple ? kTraitMappable : 0)
240{
242}
243
245{
246 std::string result = GetFieldName();
247 auto parent = GetParent();
248 while (parent && !parent->GetFieldName().empty()) {
249 result = parent->GetFieldName() + "." + result;
250 parent = parent->GetParent();
251 }
252 return result;
253}
254
256ROOT::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
258 return R__FORWARD_RESULT(
261
262std::vector<ROOT::RFieldBase::RCheckResult>
263ROOT::RFieldBase::Check(const std::string &fieldName, const std::string &typeName)
264{
265 RFieldZero fieldZero;
267 cfOpts.SetReturnInvalidOnError(true);
268 cfOpts.SetEmulateUnknownTypes(false);
269 fieldZero.Attach(RFieldBase::Create(fieldName, typeName, cfOpts, nullptr, kInvalidDescriptorId).Unwrap());
270
271 std::vector<RCheckResult> result;
272 for (const auto &f : fieldZero) {
273 const bool isInvalidField = f.GetTraits() & RFieldBase::kTraitInvalidField;
274 if (!isInvalidField)
275 continue;
276
277 const auto &invalidField = static_cast<const RInvalidField &>(f);
278 result.emplace_back(
279 RCheckResult{invalidField.GetQualifiedFieldName(), invalidField.GetTypeName(), invalidField.GetError()});
280 }
281 return result;
282}
283
285ROOT::RFieldBase::Create(const std::string &fieldName, const std::string &typeName,
286 const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc,
287 ROOT::DescriptorId_t fieldId)
288{
291
292 const auto resolvedType = ROOT::Internal::GetCanonicalTypePrefix(TClassEdit::ResolveTypedef(typeName.c_str()));
293
294 thread_local CreateContext createContext;
295 CreateContextGuard createContextGuard(createContext);
296 if (options.GetReturnInvalidOnError())
297 createContextGuard.SetContinueOnError(true);
298
299 auto fnFail = [&fieldName,
300 &resolvedType](const std::string &errMsg,
302 RInvalidField::ECategory::kTypeError) -> RResult<std::unique_ptr<RFieldBase>> {
303 if (createContext.GetContinueOnError()) {
304 return std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, resolvedType, errMsg, cat));
305 } else {
306 return R__FAIL(errMsg);
307 }
308 };
309
310 if (resolvedType.empty())
311 return R__FORWARD_RESULT(fnFail("no type name specified for field '" + fieldName + "'"));
312
313 std::unique_ptr<ROOT::RFieldBase> result;
314
315 const auto maybeGetChildId = [desc, fieldId](int childId) {
316 if (desc) {
317 const auto &fieldDesc = desc->GetFieldDescriptor(fieldId);
318 return fieldDesc.GetLinkIds().at(childId);
319 } else {
321 }
322 };
323
324 // try-catch block to intercept any exception that may be thrown by Unwrap() so that this
325 // function never throws but returns RResult::Error instead.
326 try {
327 if (resolvedType == "bool") {
328 result = std::make_unique<RField<bool>>(fieldName);
329 } else if (resolvedType == "char") {
330 result = std::make_unique<RField<char>>(fieldName);
331 } else if (resolvedType == "std::byte") {
332 result = std::make_unique<RField<std::byte>>(fieldName);
333 } else if (resolvedType == "std::int8_t") {
334 result = std::make_unique<RField<std::int8_t>>(fieldName);
335 } else if (resolvedType == "std::uint8_t") {
336 result = std::make_unique<RField<std::uint8_t>>(fieldName);
337 } else if (resolvedType == "std::int16_t") {
338 result = std::make_unique<RField<std::int16_t>>(fieldName);
339 } else if (resolvedType == "std::uint16_t") {
340 result = std::make_unique<RField<std::uint16_t>>(fieldName);
341 } else if (resolvedType == "std::int32_t") {
342 result = std::make_unique<RField<std::int32_t>>(fieldName);
343 } else if (resolvedType == "std::uint32_t") {
344 result = std::make_unique<RField<std::uint32_t>>(fieldName);
345 } else if (resolvedType == "std::int64_t") {
346 result = std::make_unique<RField<std::int64_t>>(fieldName);
347 } else if (resolvedType == "std::uint64_t") {
348 result = std::make_unique<RField<std::uint64_t>>(fieldName);
349 } else if (resolvedType == "float") {
350 result = std::make_unique<RField<float>>(fieldName);
351 } else if (resolvedType == "double") {
352 result = std::make_unique<RField<double>>(fieldName);
353 } else if (resolvedType == "Double32_t") {
354 result = std::make_unique<RField<double>>(fieldName);
355 static_cast<RField<double> *>(result.get())->SetDouble32();
356 // Prevent the type alias from being reset by returning early
357 return result;
358 } else if (resolvedType == "std::string") {
359 result = std::make_unique<RField<std::string>>(fieldName);
360 } else if (resolvedType == "TObject") {
361 result = std::make_unique<RField<TObject>>(fieldName);
362 } else if (resolvedType == "std::vector<bool>") {
363 result = std::make_unique<RField<std::vector<bool>>>(fieldName);
364 } else if (resolvedType.substr(0, 12) == "std::vector<") {
365 std::string itemTypeName = resolvedType.substr(12, resolvedType.length() - 13);
366 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0));
367 result = std::make_unique<RVectorField>(fieldName, itemField.Unwrap());
368 } else if (resolvedType.substr(0, 19) == "ROOT::VecOps::RVec<") {
369 std::string itemTypeName = resolvedType.substr(19, resolvedType.length() - 20);
370 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0));
371 result = std::make_unique<RRVecField>(fieldName, itemField.Unwrap());
372 } else if (resolvedType.substr(0, 11) == "std::array<") {
373 auto arrayDef = TokenizeTypeList(resolvedType.substr(11, resolvedType.length() - 12));
374 if (arrayDef.size() != 2) {
375 return R__FORWARD_RESULT(fnFail("the template list for std::array must have exactly two elements"));
376 }
377 auto arrayLength = ParseUIntTypeToken(arrayDef[1]);
378 auto itemField = Create("_0", arrayDef[0], options, desc, maybeGetChildId(0));
379 result = std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arrayLength);
380 } else if (resolvedType.substr(0, 13) == "std::variant<") {
381 auto innerTypes = TokenizeTypeList(resolvedType.substr(13, resolvedType.length() - 14));
382 std::vector<std::unique_ptr<RFieldBase>> items;
383 items.reserve(innerTypes.size());
384 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
385 items.emplace_back(
386 Create("_" + std::to_string(i), innerTypes[i], options, desc, maybeGetChildId(i)).Unwrap());
387 }
388 result = std::make_unique<RVariantField>(fieldName, std::move(items));
389 } else if (resolvedType.substr(0, 10) == "std::pair<") {
390 auto innerTypes = TokenizeTypeList(resolvedType.substr(10, resolvedType.length() - 11));
391 if (innerTypes.size() != 2) {
392 return R__FORWARD_RESULT(fnFail("the type list for std::pair must have exactly two elements"));
393 }
394 std::array<std::unique_ptr<RFieldBase>, 2> items{
395 Create("_0", innerTypes[0], options, desc, maybeGetChildId(0)).Unwrap(),
396 Create("_1", innerTypes[1], options, desc, maybeGetChildId(1)).Unwrap()};
397 result = std::make_unique<RPairField>(fieldName, std::move(items));
398 } else if (resolvedType.substr(0, 11) == "std::tuple<") {
399 auto innerTypes = TokenizeTypeList(resolvedType.substr(11, resolvedType.length() - 12));
400 std::vector<std::unique_ptr<RFieldBase>> items;
401 items.reserve(innerTypes.size());
402 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
403 items.emplace_back(
404 Create("_" + std::to_string(i), innerTypes[i], options, desc, maybeGetChildId(i)).Unwrap());
405 }
406 result = std::make_unique<RTupleField>(fieldName, std::move(items));
407 } else if (resolvedType.substr(0, 12) == "std::bitset<") {
408 auto size = ParseUIntTypeToken(resolvedType.substr(12, resolvedType.length() - 13));
409 result = std::make_unique<RBitsetField>(fieldName, size);
410 } else if (resolvedType.substr(0, 16) == "std::unique_ptr<") {
411 std::string itemTypeName = resolvedType.substr(16, resolvedType.length() - 17);
412 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
413 result = std::make_unique<RUniquePtrField>(fieldName, std::move(itemField));
414 } else if (resolvedType.substr(0, 14) == "std::optional<") {
415 std::string itemTypeName = resolvedType.substr(14, resolvedType.length() - 15);
416 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
417 result = std::make_unique<ROptionalField>(fieldName, std::move(itemField));
418 } else if (resolvedType.substr(0, 9) == "std::set<") {
419 std::string itemTypeName = resolvedType.substr(9, resolvedType.length() - 10);
420 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
421 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kSet, std::move(itemField));
422 } else if (resolvedType.substr(0, 19) == "std::unordered_set<") {
423 std::string itemTypeName = resolvedType.substr(19, resolvedType.length() - 20);
424 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
425 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kUnorderedSet, std::move(itemField));
426 } else if (resolvedType.substr(0, 14) == "std::multiset<") {
427 std::string itemTypeName = resolvedType.substr(14, resolvedType.length() - 15);
428 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
429 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kMultiSet, std::move(itemField));
430 } else if (resolvedType.substr(0, 24) == "std::unordered_multiset<") {
431 std::string itemTypeName = resolvedType.substr(24, resolvedType.length() - 25);
432 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
433 auto normalizedInnerTypeName = itemField->GetTypeName();
434 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kUnorderedMultiSet, std::move(itemField));
435 } else if (resolvedType.substr(0, 9) == "std::map<") {
436 auto innerTypes = TokenizeTypeList(resolvedType.substr(9, resolvedType.length() - 10));
437 if (innerTypes.size() != 2) {
438 return R__FORWARD_RESULT(fnFail("the type list for std::map must have exactly two elements"));
439 }
440 auto itemField =
441 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
442 .Unwrap();
443 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kMap, std::move(itemField));
444 } else if (resolvedType.substr(0, 19) == "std::unordered_map<") {
445 auto innerTypes = TokenizeTypeList(resolvedType.substr(19, resolvedType.length() - 20));
446 if (innerTypes.size() != 2)
447 return R__FORWARD_RESULT(fnFail("the type list for std::unordered_map must have exactly two elements"));
448 auto itemField =
449 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
450 .Unwrap();
451 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kUnorderedMap, std::move(itemField));
452 } else if (resolvedType.substr(0, 14) == "std::multimap<") {
453 auto innerTypes = TokenizeTypeList(resolvedType.substr(14, resolvedType.length() - 15));
454 if (innerTypes.size() != 2)
455 return R__FORWARD_RESULT(fnFail("the type list for std::multimap must have exactly two elements"));
456 auto itemField =
457 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
458 .Unwrap();
459 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kMultiMap, std::move(itemField));
460 } else if (resolvedType.substr(0, 24) == "std::unordered_multimap<") {
461 auto innerTypes = TokenizeTypeList(resolvedType.substr(24, resolvedType.length() - 25));
462 if (innerTypes.size() != 2)
463 return R__FORWARD_RESULT(
464 fnFail("the type list for std::unordered_multimap must have exactly two elements"));
465 auto itemField =
466 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
467 .Unwrap();
468 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kUnorderedMultiMap, std::move(itemField));
469 } else if (resolvedType.substr(0, 12) == "std::atomic<") {
470 std::string itemTypeName = resolvedType.substr(12, resolvedType.length() - 13);
471 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
472 result = std::make_unique<RAtomicField>(fieldName, std::move(itemField));
473 } else if (resolvedType.substr(0, 25) == "ROOT::RNTupleCardinality<") {
474 auto innerTypes = TokenizeTypeList(resolvedType.substr(25, resolvedType.length() - 26));
475 if (innerTypes.size() != 1)
476 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + resolvedType));
477 const auto canonicalInnerType = ROOT::Internal::GetCanonicalTypePrefix(innerTypes[0]);
478 if (canonicalInnerType == "std::uint32_t") {
479 result = std::make_unique<RField<RNTupleCardinality<std::uint32_t>>>(fieldName);
480 } else if (canonicalInnerType == "std::uint64_t") {
481 result = std::make_unique<RField<RNTupleCardinality<std::uint64_t>>>(fieldName);
482 } else {
483 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + resolvedType));
484 }
485 }
487 if (!result) {
488 auto cl = TClass::GetClass(typeName.c_str());
489
490 if (cl && cl->GetState() > TClass::kForwardDeclared) {
491 createContextGuard.AddClassToStack(resolvedType);
492 if (cl->GetCollectionProxy()) {
493 result = std::make_unique<RProxiedCollectionField>(fieldName, typeName);
494 }
495 // NOTE: if the class is not at least "Interpreted" we currently don't try to construct
496 // the RClassField, as in that case we'd need to fetch the information from the StreamerInfo
497 // rather than from TClass. This might be desirable in the future, but for now in this
498 // situation we rely on field emulation instead.
499 else if (cl->GetState() >= TClass::kInterpreted) {
501 result = std::make_unique<ROOT::Experimental::RSoAField>(fieldName, typeName);
504 result = std::make_unique<RStreamerField>(fieldName, typeName);
505 } else {
506 result = std::make_unique<RClassField>(fieldName, typeName);
507 }
508 }
509 }
510
511 // If we get here then we failed to meet all the conditions to create a "properly typed" field.
512 // Resort to field emulation if the user asked us to.
513 if (!result && options.GetEmulateUnknownTypes()) {
514 assert(desc);
515 const auto &fieldDesc = desc->GetFieldDescriptor(fieldId);
516 if (fieldDesc.GetStructure() == ENTupleStructure::kRecord) {
517 std::vector<std::unique_ptr<RFieldBase>> memberFields;
518 memberFields.reserve(fieldDesc.GetLinkIds().size());
519 for (auto id : fieldDesc.GetLinkIds()) {
520 const auto &memberDesc = desc->GetFieldDescriptor(id);
521 auto field = Create(memberDesc.GetFieldName(), memberDesc.GetTypeName(), options, desc, id).Unwrap();
522 memberFields.emplace_back(std::move(field));
523 }
524 R__ASSERT(typeName == fieldDesc.GetTypeName());
525 auto recordField =
526 Internal::CreateEmulatedRecordField(fieldName, std::move(memberFields), fieldDesc.GetTypeName());
527 recordField->fTypeAlias = fieldDesc.GetTypeAlias();
528 return recordField;
529 } else if (fieldDesc.GetStructure() == ENTupleStructure::kCollection) {
530 if (fieldDesc.GetLinkIds().size() != 1)
531 throw ROOT::RException(R__FAIL("invalid structure for collection field " + fieldName));
532
533 auto itemFieldId = fieldDesc.GetLinkIds()[0];
534 const auto &itemFieldDesc = desc->GetFieldDescriptor(itemFieldId);
535 auto itemField =
536 Create(itemFieldDesc.GetFieldName(), itemFieldDesc.GetTypeName(), options, desc, itemFieldId)
537 .Unwrap();
538 auto vecField =
539 ROOT::Internal::CreateEmulatedVectorField(fieldName, std::move(itemField), fieldDesc.GetTypeName());
540 vecField->fTypeAlias = fieldDesc.GetTypeAlias();
541 return vecField;
542 }
543 }
545
546 if (!result) {
547 auto e = TEnum::GetEnum(resolvedType.c_str());
548 if (e != nullptr) {
549 result = std::make_unique<REnumField>(fieldName, typeName);
550 }
551 }
552 } catch (const RException &e) {
553 auto error = e.GetError();
554 if (createContext.GetContinueOnError()) {
555 return std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, typeName, error.GetReport(),
557 } else {
558 return error;
559 }
560 } catch (const std::logic_error &e) {
561 // Integer parsing error
562 if (createContext.GetContinueOnError()) {
563 return std::unique_ptr<RFieldBase>(
564 std::make_unique<RInvalidField>(fieldName, typeName, e.what(), RInvalidField::ECategory::kGeneric));
565 } else {
566 return R__FAIL(e.what());
567 }
568 }
569
570 if (result) {
571 const auto normOrigType = ROOT::Internal::GetNormalizedUnresolvedTypeName(typeName);
572 if (normOrigType != result->GetTypeName()) {
573 result->fTypeAlias = normOrigType;
574 }
575 return result;
576 }
577 return R__FORWARD_RESULT(fnFail("unknown type: " + typeName, RInvalidField::ECategory::kUnknownType));
578}
579
581{
582 static RColumnRepresentations representations;
583 return representations;
584}
585
586std::unique_ptr<ROOT::RFieldBase> ROOT::RFieldBase::Clone(std::string_view newName) const
587{
588 auto clone = CloneImpl(newName);
589 clone->fTypeAlias = fTypeAlias;
590 clone->fOnDiskId = fOnDiskId;
591 clone->fDescription = fDescription;
592 // We can just copy the references because fColumnRepresentatives point into a static structure
593 clone->fColumnRepresentatives = fColumnRepresentatives;
594 return clone;
595}
596
597std::size_t ROOT::RFieldBase::AppendImpl(const void * /* from */)
599 R__ASSERT(false && "A non-simple RField must implement its own AppendImpl");
600 return 0;
601}
602
604{
605 R__ASSERT(false);
606}
607
609{
610 ReadGlobalImpl(fPrincipalColumn->GetGlobalIndex(localIndex), to);
611}
612
613std::size_t ROOT::RFieldBase::ReadBulkImpl(const RBulkSpec &bulkSpec)
614{
615 const auto valueSize = GetValueSize();
616 std::size_t nRead = 0;
617 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
618 // Value not needed
619 if (bulkSpec.fMaskReq && !bulkSpec.fMaskReq[i])
620 continue;
622 // Value already present
623 if (bulkSpec.fMaskAvail[i])
624 continue;
626 Read(bulkSpec.fFirstIndex + i, reinterpret_cast<unsigned char *>(bulkSpec.fValues) + i * valueSize);
627 bulkSpec.fMaskAvail[i] = true;
628 nRead++;
629 }
630 return nRead;
631}
632
634{
635 void *where = operator new(GetValueSize());
636 R__ASSERT(where != nullptr);
637 ConstructValue(where);
638 return where;
639}
640
643 void *obj = CreateObjectRawPtr();
644 return RValue(this, std::shared_ptr<void>(obj, RSharedPtrDeleter(GetDeleter())));
645}
646
647std::vector<ROOT::RFieldBase::RValue> ROOT::RFieldBase::SplitValue(const RValue & /*value*/) const
649 return std::vector<RValue>();
650}
651
652void ROOT::RFieldBase::Attach(std::unique_ptr<ROOT::RFieldBase> child, std::string_view expectedChildName)
653{
654 // Note that technically the zero field would not need to have the extensible trait: because only its sub fields
655 // get connected by RPageSink::UpdateSchema, it does not change its initial state.
656 if (!(fTraits & kTraitExtensible) && (fState != EState::kUnconnected))
657 throw RException(R__FAIL("invalid attempt to attach subfield to already connected, non-extensible field"));
658
659 if (!expectedChildName.empty() && child->GetFieldName() != expectedChildName) {
660 throw RException(R__FAIL(std::string("invalid subfield name: ") + child->GetFieldName() +
661 " expected: " + std::string(expectedChildName)));
662 }
663
664 child->fParent = this;
665 fSubfields.emplace_back(std::move(child));
666}
667
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() == ROOT::ENTupleStructure::kCollection ||
674 parent->GetStructure() == ROOT::ENTupleStructure::kVariant)) {
675 return 0U;
677 result *= std::max(f->GetNRepetitions(), std::size_t{1U});
679 return result;
682std::vector<ROOT::RFieldBase *> ROOT::RFieldBase::GetMutableSubfields()
684 std::vector<RFieldBase *> result;
685 result.reserve(fSubfields.size());
686 for (const auto &f : fSubfields) {
687 result.emplace_back(f.get());
688 }
689 return result;
690}
691
692std::vector<const ROOT::RFieldBase *> ROOT::RFieldBase::GetConstSubfields() const
693{
694 std::vector<const RFieldBase *> result;
695 result.reserve(fSubfields.size());
696 for (const auto &f : fSubfields) {
697 result.emplace_back(f.get());
698 }
699 return result;
700}
701
703{
704 if (!fAvailableColumns.empty()) {
705 const auto activeRepresentationIndex = fPrincipalColumn->GetRepresentationIndex();
706 for (auto &column : fAvailableColumns) {
707 if (column->GetRepresentationIndex() == activeRepresentationIndex) {
708 column->Flush();
709 }
710 }
711 }
712}
713
715{
716 if (!fAvailableColumns.empty()) {
717 const auto activeRepresentationIndex = fPrincipalColumn->GetRepresentationIndex();
718 for (auto &column : fAvailableColumns) {
719 if (column->GetRepresentationIndex() == activeRepresentationIndex) {
720 column->Flush();
721 } else {
722 column->CommitSuppressed();
723 }
724 }
725 }
727}
728
729void ROOT::RFieldBase::SetDescription(std::string_view description)
730{
732 throw RException(R__FAIL("cannot set field description once field is connected"));
733 fDescription = std::string(description);
734}
735
737{
739 throw RException(R__FAIL("cannot set field ID once field is connected"));
740 fOnDiskId = id;
741}
742
743/// Write the given value into columns. The value object has to be of the same type as the field.
744/// Returns the number of uncompressed bytes written.
745std::size_t ROOT::RFieldBase::Append(const void *from)
746{
747 if (~fTraits & kTraitMappable)
748 return AppendImpl(from);
749
750 fPrincipalColumn->Append(from);
751 return fPrincipalColumn->GetElement()->GetPackedSize();
752}
753
758
760{
761 return RValue(this, objPtr);
762}
763
764std::size_t ROOT::RFieldBase::ReadBulk(const RBulkSpec &bulkSpec)
765{
766 if (fIsSimple) {
767 /// For simple types, ignore the mask and memcopy the values into the destination
768 fPrincipalColumn->ReadV(bulkSpec.fFirstIndex, bulkSpec.fCount, bulkSpec.fValues);
769 std::fill(bulkSpec.fMaskAvail, bulkSpec.fMaskAvail + bulkSpec.fCount, true);
770 return RBulkSpec::kAllSet;
771 }
772
773 if (fIsArtificial || !fReadCallbacks.empty()) {
774 // Fields with schema evolution treatment must not go through an optimized read
775 return RFieldBase::ReadBulkImpl(bulkSpec);
776 }
777
778 return ReadBulkImpl(bulkSpec);
779}
780
785
790
795
800
805
810
812{
813 if (fColumnRepresentatives.empty()) {
814 return {GetColumnRepresentations().GetSerializationDefault()};
815 }
816
818 result.reserve(fColumnRepresentatives.size());
819 for (const auto &r : fColumnRepresentatives) {
820 result.emplace_back(r.get());
821 }
822 return result;
823}
824
826{
828 throw RException(R__FAIL("cannot set column representative once field is connected"));
829 const auto &validTypes = GetColumnRepresentations().GetSerializationTypes();
831 fColumnRepresentatives.reserve(representatives.size());
832 for (const auto &r : representatives) {
833 auto itRepresentative = std::find(validTypes.begin(), validTypes.end(), r);
834 if (itRepresentative == std::end(validTypes))
835 throw RException(R__FAIL("invalid column representative"));
836
837 // don't add a duplicate representation
838 if (std::find_if(fColumnRepresentatives.begin(), fColumnRepresentatives.end(),
839 [&r](const auto &rep) { return r == rep.get(); }) == fColumnRepresentatives.end())
840 fColumnRepresentatives.emplace_back(*itRepresentative);
841 }
842}
843
846 std::uint16_t representationIndex) const
847{
848 static const ColumnRepresentation_t kEmpty;
849
851 throw RException(R__FAIL("No on-disk field information for `" + GetQualifiedFieldName() + "`"));
852
853 ColumnRepresentation_t onDiskTypes;
854 for (const auto &c : desc.GetColumnIterable(fOnDiskId)) {
855 if (c.GetRepresentationIndex() == representationIndex)
856 onDiskTypes.emplace_back(c.GetType());
857 }
858 if (onDiskTypes.empty()) {
859 if (representationIndex == 0) {
860 throw RException(R__FAIL("No on-disk column information for field `" + GetQualifiedFieldName() + "`"));
861 }
862 return kEmpty;
863 }
864
865 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
866 if (t == onDiskTypes)
867 return t;
868 }
869
870 std::string columnTypeNames;
871 for (const auto &t : onDiskTypes) {
872 if (!columnTypeNames.empty())
873 columnTypeNames += ", ";
874 columnTypeNames += std::string("`") + ROOT::Internal::RColumnElementBase::GetColumnTypeName(t) + "`";
875 }
876 throw RException(R__FAIL("On-disk column types {" + columnTypeNames + "} for field `" + GetQualifiedFieldName() +
877 "` cannot be matched to its in-memory type `" + GetTypeName() + "` " +
878 "(representation index: " + std::to_string(representationIndex) + ")"));
879}
880
882{
883 fReadCallbacks.push_back(func);
884 fIsSimple = false;
885 return fReadCallbacks.size() - 1;
886}
887
889{
890 fReadCallbacks.erase(fReadCallbacks.begin() + idx);
892}
893
919
921{
922 if (dynamic_cast<ROOT::RFieldZero *>(this))
923 throw RException(R__FAIL("invalid attempt to connect zero field to page sink"));
925 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page sink"));
926
928
930 for (auto &column : fAvailableColumns) {
931 // Only the first column of every representation can be a deferred column. In all column representations,
932 // larger column indexes are data columns of collections (string, streamer) and thus
933 // they have no elements on late model extension
934 auto firstElementIndex = (column->GetIndex() == 0) ? EntryToColumnElementIndex(firstEntry) : 0;
935 column->ConnectPageSink(fOnDiskId, pageSink, firstElementIndex);
936 }
937
938 if (HasExtraTypeInfo()) {
941 }
942
944}
945
947{
948 if (dynamic_cast<ROOT::RFieldZero *>(this)) {
949 for (auto &f : fSubfields)
950 f->ConnectPageSource(pageSource);
951 return;
952 }
953
955 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page source"));
956
957 if (!fColumnRepresentatives.empty())
958 throw RException(R__FAIL("fixed column representative only valid when connecting to a page sink"));
959 if (!fDescription.empty())
960 throw RException(R__FAIL("setting description only valid when connecting to a page sink"));
961
962 if (!fIsArtificial) {
964 // Handle moving from on-disk std::atomic<T> to (compatible of) T in memory centrally because otherwise
965 // we would need to handle it in each and every ReconcileOnDiskField()
966 // Note that we have to do this before calling BeforeConnectPageSource(), which already may compare the field
967 // to its on-disk description.
968 const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
969 if (!dynamic_cast<RAtomicField *>(this) &&
971 SetOnDiskId(desc.GetFieldDescriptor(GetOnDiskId()).GetLinkIds()[0]);
972 }
973 }
974
975 auto substitute = BeforeConnectPageSource(pageSource);
976 if (substitute) {
977 const RFieldBase *itr = this;
978 while (itr->GetParent()) {
979 itr = itr->GetParent();
980 }
981 if (typeid(*itr) == typeid(RFieldZero) && static_cast<const RFieldZero *>(itr)->GetAllowFieldSubstitutions()) {
982 for (auto &f : fParent->fSubfields) {
983 if (f.get() != this)
984 continue;
985
986 f = std::move(substitute);
987 f->ConnectPageSource(pageSource);
988 return;
989 }
990 R__ASSERT(false); // never here
991 } else {
992 throw RException(R__FAIL("invalid attempt to substitute field " + GetQualifiedFieldName()));
993 }
994 }
995
996 if (!fIsArtificial) {
997 const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
999 }
1000
1001 for (auto &f : fSubfields) {
1002 if (f->GetOnDiskId() == ROOT::kInvalidDescriptorId) {
1003 f->SetOnDiskId(pageSource.GetSharedDescriptorGuard()->FindFieldId(f->GetFieldName(), GetOnDiskId()));
1004 }
1005 f->ConnectPageSource(pageSource);
1006 }
1007
1008 // Do not generate columns nor set fColumnRepresentatives for artificial fields.
1009 if (!fIsArtificial) {
1010 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
1011 const ROOT::RNTupleDescriptor &desc = descriptorGuard.GetRef();
1012 GenerateColumns(desc);
1013 if (fColumnRepresentatives.empty()) {
1014 // If we didn't get columns from the descriptor, ensure that we actually expect a field without columns
1015 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
1016 if (t.empty()) {
1018 break;
1019 }
1020 }
1021 }
1024 const auto &fieldDesc = desc.GetFieldDescriptor(fOnDiskId);
1025 fOnDiskTypeVersion = fieldDesc.GetTypeVersion();
1026 if (fieldDesc.GetTypeChecksum().has_value())
1027 fOnDiskTypeChecksum = *fieldDesc.GetTypeChecksum();
1028 }
1029 }
1030 for (auto &column : fAvailableColumns)
1031 column->ConnectPageSource(fOnDiskId, pageSource);
1032
1034}
1035
1037{
1038 // The default implementation throws an exception if there are any meaningful differences to the on-disk field.
1039 // Derived classes may overwrite this and relax the checks to support automatic schema evolution.
1040 EnsureMatchingOnDiskField(desc).ThrowOnError();
1041}
1042
1044ROOT::RFieldBase::EnsureMatchingOnDiskField(const RNTupleDescriptor &desc, std::uint32_t ignoreBits) const
1045{
1046 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1047 const std::uint32_t diffBits = CompareOnDiskField(fieldDesc, ignoreBits);
1048 if (diffBits == 0)
1049 return RResult<void>::Success();
1050
1051 std::ostringstream errMsg;
1052 errMsg << "in-memory field " << GetQualifiedFieldName() << " of type " << GetTypeName() << " is incompatible "
1053 << "with on-disk field " << fieldDesc.GetFieldName() << ":";
1054 if (diffBits & kDiffFieldVersion) {
1055 errMsg << " field version " << GetFieldVersion() << " vs. " << fieldDesc.GetFieldVersion() << ";";
1056 }
1057 if (diffBits & kDiffTypeVersion) {
1058 errMsg << " type version " << GetTypeVersion() << " vs. " << fieldDesc.GetTypeVersion() << ";";
1059 }
1060 if (diffBits & kDiffStructure) {
1061 errMsg << " structural role " << GetStructure() << " vs. " << fieldDesc.GetStructure() << ";";
1062 }
1063 if (diffBits & kDiffTypeName) {
1064 errMsg << " incompatible on-disk type name " << fieldDesc.GetTypeName() << ";";
1065 }
1066 if (diffBits & kDiffNRepetitions) {
1067 errMsg << " repetition count " << GetNRepetitions() << " vs. " << fieldDesc.GetNRepetitions() << ";";
1068 }
1069 return R__FAIL(errMsg.str() + "\n" + Internal::GetTypeTraceReport(*this, desc));
1070}
1071
1073{
1074 std::uint32_t ignoreBits = kDiffTypeName;
1075 if (desc.GetFieldDescriptor(GetOnDiskId()).IsSoACollection())
1076 ignoreBits |= kDiffTypeVersion;
1077 return EnsureMatchingOnDiskField(desc, ignoreBits);
1078}
1079
1081 const std::vector<std::string> &prefixes) const
1082{
1083 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1084 for (const auto &p : prefixes) {
1085 if (fieldDesc.GetTypeName().rfind(p, 0) == 0)
1086 return RResult<void>::Success();
1087 }
1088 return R__FAIL("incompatible type " + fieldDesc.GetTypeName() + " for field " + GetQualifiedFieldName() + "\n" +
1089 Internal::GetTypeTraceReport(*this, desc));
1090}
1091
1092std::uint32_t ROOT::RFieldBase::CompareOnDiskField(const RFieldDescriptor &fieldDesc, std::uint32_t ignoreBits) const
1093{
1094 std::uint32_t diffBits = 0;
1095 if ((~ignoreBits & kDiffFieldVersion) && (GetFieldVersion() != fieldDesc.GetFieldVersion()))
1096 diffBits |= kDiffFieldVersion;
1097 if ((~ignoreBits & kDiffTypeVersion) && (GetTypeVersion() != fieldDesc.GetTypeVersion()))
1098 diffBits |= kDiffTypeVersion;
1099 if ((~ignoreBits & kDiffStructure) && (GetStructure() != fieldDesc.GetStructure()))
1100 diffBits |= kDiffStructure;
1101 if ((~ignoreBits & kDiffTypeName) && (GetTypeName() != fieldDesc.GetTypeName()))
1102 diffBits |= kDiffTypeName;
1103 if ((~ignoreBits & kDiffNRepetitions) && (GetNRepetitions() != fieldDesc.GetNRepetitions()))
1104 diffBits |= kDiffNRepetitions;
1105
1106 return diffBits;
1107}
1108
1110{
1111 visitor.VisitField(*this);
1112}
ROOT::R::TRInterface & r
Definition Object.C:4
#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:357
#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
XFontStruct * id
Definition TGX11.cxx:147
char name[80]
Definition TGX11.cxx:148
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitField(const ROOT::RFieldBase &field)=0
static const char * GetColumnTypeName(ROOT::ENTupleColumnType type)
Abstract interface to write data into an ntuple.
void RegisterOnCommitDatasetCallback(Callback_t callback)
The registered callback is executed at the beginning of CommitDataset();.
const ROOT::RNTupleWriteOptions & GetWriteOptions() const
Returns the sink's write options.
virtual void UpdateExtraTypeInfo(const ROOT::RExtraTypeInfoDescriptor &extraTypeInfo)=0
Adds an extra type information record to schema.
const ROOT::RNTupleDescriptor & GetRef() const
Abstract interface to read data from an ntuple.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
Template specializations for C++ std::atomic.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
void ConstructValue(void *where) const final
size_t GetValueSize() const final
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.hxx:206
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Points to an array of objects with RNTuple I/O support, used for bulk reading.
std::unique_ptr< bool[]> fMaskAvail
Masks invalid values in the array.
std::unique_ptr< RFieldBase::RDeleter > fDeleter
void * GetValuePtrAt(std::size_t idx) const
std::size_t fNValidValues
The sum of non-zero elements in the fMask.
bool fIsAdopted
True if the user provides the memory buffer for fValues.
void Reset(RNTupleLocalIndex firstIndex, std::size_t size)
Sets a new range for the bulk.
void * fValues
Cached deleter of fField.
std::size_t fCapacity
The size of the array memory block in number of values.
std::size_t fValueSize
Cached copy of RFieldBase::GetValueSize().
RFieldBase * fField
The field that created the array of values.
RBulkValues & operator=(const RBulkValues &)=delete
RBulkValues(RFieldBase *field)
std::size_t fSize
The number of available values in the array (provided their mask is set).
void AdoptBuffer(void *buf, std::size_t capacity)
RNTupleLocalIndex fFirstIndex
Index of the first value of the array.
The list of column representations a field can have.
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 passed during construction.
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
std::shared_ptr< void > fObjPtr
Set by Bind() or by RFieldBase::CreateValue(), RFieldBase::SplitValue() or RFieldBase::BindValue().
void BindRawPtr(void *rawPtr)
A field translates read and write calls from/to underlying columns to/from tree values.
ROOT::DescriptorId_t fOnDiskId
ROOT::ENTupleStructure GetStructure() const
virtual size_t GetValueSize() const =0
The number of bytes taken by a value of the appropriate type.
RSchemaIterator end()
void Attach(std::unique_ptr< RFieldBase > child, std::string_view expectedChildName="")
Add a new subfield to the list of nested fields.
void SetColumnRepresentatives(const RColumnRepresentations::Selection_t &representatives)
Fixes a column representative.
ROOT::Internal::RColumn * fPrincipalColumn
All fields that have columns have a distinct main column.
virtual void ReconcileOnDiskField(const RNTupleDescriptor &desc)
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
ROOT::NTupleSize_t EntryToColumnElementIndex(ROOT::NTupleSize_t globalIndex) const
Translate an entry index to a column element index of the principal column and vice versa.
virtual void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const
void FlushColumns()
Flushes data from active columns.
virtual void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to)
std::vector< std::unique_ptr< RFieldBase > > fSubfields
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
bool fIsSimple
A field qualifies as simple if it is mappable (which implies it has a single principal column),...
RConstSchemaIterator cbegin() const
std::unique_ptr< T, typename RCreateObjectDeleter< T >::deleter > CreateObject() const
Generates an object of the field type and allocates new initialized memory according to the type.
Definition RField.hxx:567
void AutoAdjustColumnTypes(const ROOT::RNTupleWriteOptions &options)
When connecting a field to a page sink, the field's default column representation is subject to adjus...
std::vector< const RFieldBase * > GetConstSubfields() const
void SetOnDiskId(ROOT::DescriptorId_t id)
void RemoveReadCallback(size_t idx)
@ kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
@ kTraitTriviallyConstructible
No constructor needs to be called, i.e.
@ kTraitMappable
A field of a fundamental type that can be directly mapped via RField<T>::Map(), i....
@ kTraitInvalidField
This field is an instance of RInvalidField and can be safely static_cast to it.
virtual void GenerateColumns()
Implementations in derived classes should create the backing columns corresponding to the field type ...
const RFieldBase * GetParent() const
std::vector< RFieldBase * > GetMutableSubfields()
static std::vector< RCheckResult > Check(const std::string &fieldName, const std::string &typeName)
Checks if the given type is supported by RNTuple.
RSchemaIterator begin()
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...
RResult< void > EnsureMatchingOnDiskCollection(const RNTupleDescriptor &desc) const
Convenience wrapper for the common case of calling EnsureMatchinOnDiskField() for collections.
RConstSchemaIterator cend() const
std::size_t fNRepetitions
For fixed sized arrays, the array length.
std::function< void(void *)> ReadCallback_t
std::size_t Append(const void *from)
Write the given value into columns.
RValue CreateValue()
Generates an object of the field's type, wraps it in a shared pointer and returns it as an RValue con...
RSchemaIteratorTemplate< false > RSchemaIterator
const ColumnRepresentation_t & EnsureCompatibleColumnTypes(const ROOT::RNTupleDescriptor &desc, std::uint16_t representationIndex) const
Returns the on-disk column types found in the provided descriptor for fOnDiskId and the given represe...
virtual std::vector< RValue > SplitValue(const RValue &value) const
Creates the list of direct child values given an existing value for this field.
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots (grandparent.parent....
RBulkValues CreateBulk()
Creates a new, initially empty bulk.
const std::string & GetFieldName() const
void ConnectPageSink(ROOT::Internal::RPageSink &pageSink, ROOT::NTupleSize_t firstEntry=0)
Fields and their columns live in the void until connected to a physical page storage.
std::size_t ReadBulk(const RBulkSpec &bulkSpec)
Returns the number of newly available values, that is the number of bools in bulkSpec....
std::vector< ROOT::ENTupleColumnType > ColumnRepresentation_t
std::vector< ReadCallback_t > fReadCallbacks
List of functions to be called after reading a value.
RResult< void > EnsureMatchingOnDiskField(const RNTupleDescriptor &desc, std::uint32_t ignoreBits=0) const
Compares the field to the corresponding on-disk field information in the provided descriptor.
virtual void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to)
virtual void CommitClusterImpl()
std::vector< std::reference_wrapper< const ColumnRepresentation_t > > fColumnRepresentatives
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
virtual std::size_t AppendImpl(const void *from)
Operations on values of complex types, e.g.
RFieldBase * fParent
Subfields point to their mother field.
std::vector< std::unique_ptr< ROOT::Internal::RColumn > > fAvailableColumns
The columns are connected either to a sink or to a source (not to both); they are owned by the field.
RFieldBase(std::string_view name, std::string_view type, ROOT::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.
friend class RFieldZero
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
Factory method to resurrect a field from the stored on-disk type information.
virtual std::uint32_t GetFieldVersion() const
Indicates an evolution of the mapping scheme from C++ type to columns.
virtual std::unique_ptr< RFieldBase > BeforeConnectPageSource(ROOT::Internal::RPageSource &)
Called by ConnectPageSource() before connecting; derived classes may override this as appropriate,...
std::uint32_t CompareOnDiskField(const RFieldDescriptor &fieldDesc, std::uint32_t ignoreBits) const
Returns a combination of kDiff... flags, indicating peroperties that are different between the field ...
std::string fType
The C++ type captured by this field.
RColumnRepresentations::Selection_t GetColumnRepresentatives() const
Returns the fColumnRepresentative pointee or, if unset (always the case for artificial fields),...
RSchemaIteratorTemplate< true > RConstSchemaIterator
std::size_t GetNRepetitions() const
std::uint32_t fOnDiskTypeChecksum
TClass checksum cached from the descriptor after a call to ConnectPageSource().
const std::string & GetTypeName() const
ROOT::ENTupleStructure fStructure
The role of this field in the data model structure.
RValue BindValue(std::shared_ptr< void > objPtr)
Creates a value from a memory location with an already constructed object.
void SetDescription(std::string_view description)
ROOT::DescriptorId_t GetOnDiskId() const
std::uint32_t fOnDiskTypeVersion
C++ type version cached from the descriptor after a call to ConnectPageSource().
std::unique_ptr< RFieldBase > Clone(std::string_view newName) const
Copies the field and its subfields using a possibly new name and a new, unconnected set of columns.
std::string fName
The field name relative to its parent field.
void CommitCluster()
Flushes data from active columns to disk and calls CommitClusterImpl().
void ConnectPageSource(ROOT::Internal::RPageSource &pageSource)
Connects the field and its subfield tree to the given page source.
RResult< void > EnsureMatchingTypePrefix(const RNTupleDescriptor &desc, const std::vector< std::string > &prefixes) const
Many fields accept a range of type prefixes for schema evolution, e.g.
virtual ROOT::RExtraTypeInfoDescriptor GetExtraTypeInfo() const
virtual std::uint32_t GetTypeVersion() const
Indicates an evolution of the C++ type itself.
void * CreateObjectRawPtr() const
Factory method for the field's type. The caller owns the returned pointer.
void Read(ROOT::NTupleSize_t globalIndex, void *to)
virtual bool HasExtraTypeInfo() const
bool fIsArtificial
A field that is not backed on disk but computed, e.g.
virtual std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec)
General implementation of bulk read.
bool HasDefaultColumnRepresentative() const
Whether or not an explicit column representative was set.
@ kDiffStructure
The in-memory field and the on-disk field differ in their structural roles.
@ kDiffTypeName
The in-memory field and the on-disk field have different type names.
@ kDiffTypeVersion
The in-memory field and the on-disk field differ in the type version.
@ kDiffFieldVersion
The in-memory field and the on-disk field differ in the field version.
@ kDiffNRepetitions
The in-memory field and the on-disk field have different repetition counts.
Metadata stored for every field of an RNTuple.
std::uint32_t GetFieldVersion() const
ROOT::ENTupleStructure GetStructure() const
const std::vector< ROOT::DescriptorId_t > & GetLinkIds() const
std::uint64_t GetNRepetitions() const
std::uint32_t GetTypeVersion() const
const std::string & GetTypeName() const
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:58
void Attach(std::unique_ptr< RFieldBase > child)
A public version of the Attach method that allows piece-wise construction of the zero field.
Definition RField.cxx:40
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:320
Used in RFieldBase::Check() to record field creation failures.
Definition RField.hxx:96
@ kGeneric
Generic unrecoverable error.
Definition RField.hxx:100
@ kUnknownType
The type given to RFieldBase::Create was unknown.
Definition RField.hxx:104
@ kTypeError
The type given to RFieldBase::Create was invalid.
Definition RField.hxx:102
The on-storage metadata of an RNTuple.
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
RColumnDescriptorIterable GetColumnIterable() const
ROOT::DescriptorId_t FindFieldId(std::string_view fieldName, ROOT::DescriptorId_t parentId) const
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Common user-tunable settings for storing RNTuples.
std::uint32_t GetCompression() const
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
@ kInterpreted
Definition TClass.h:129
@ kForwardDeclared
Definition TClass.h:127
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:2994
static TEnum * GetEnum(const std::type_info &ti, ESearchAction sa=kALoadAndInterpLookup)
Definition TEnum.cxx:181
std::vector< std::string > TokenizeTypeList(std::string_view templateType, std::size_t maxArgs=0)
Used in RFieldBase::Create() in order to get the comma-separated list of template types E....
std::unique_ptr< RFieldBase > CreateEmulatedVectorField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::string_view emulatedFromType)
Definition RField.cxx:598
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.
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
void CallCommitClusterOnField(RFieldBase &)
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
unsigned long long ParseUIntTypeToken(const std::string &uintToken)
std::unique_ptr< RFieldBase > CreateEmulatedRecordField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields, std::string_view emulatedFromType)
Definition RField.cxx:590
std::string GetRNTupleSoARecord(const TClass *cl)
Checks if the "rntuple.SoARecord" class attribute is set in the dictionary.
ROOT::RResult< std::unique_ptr< ROOT::RFieldBase > > CallFieldBaseCreate(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
std::string GetTypeTraceReport(const RFieldBase &field, const RNTupleDescriptor &desc)
Prints the hierarchy of types with their field names and field IDs for the given in-memory field and ...
auto MakeAliasedSharedPtr(T *rawPtr)
std::string GetCanonicalTypePrefix(const std::string &typeName)
Applies RNTuple specific type name normalization rules (see specs) that help the string parsing in RF...
void CallFlushColumnsOnField(RFieldBase &)
std::string GetNormalizedUnresolvedTypeName(const std::string &origName)
Applies all RNTuple type normalization rules except typedef resolution.
ERNTupleSerializationMode GetRNTupleSerializationMode(const TClass *cl)
bool IsStdAtomicFieldDesc(const RFieldDescriptor &fieldDesc)
Tells if the field describes a std::atomic<T> type.
void CallConnectPageSinkOnField(RFieldBase &, ROOT::Internal::RPageSink &, ROOT::NTupleSize_t firstEntry=0)
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
constexpr DescriptorId_t kInvalidDescriptorId
ENTupleStructure
The fields in the RNTuple data model tree can carry different structural information about the type s...
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
Input parameter to RFieldBase::ReadBulk() and RFieldBase::ReadBulkImpl().
static const std::size_t kAllSet
Possible return value of ReadBulk() and ReadBulkImpl(), which indicates that the full bulk range was ...
RNTupleLocalIndex fFirstIndex
Start of the bulk range.
void * fValues
The destination area, which has to be an array of valid objects of the correct type large enough to h...
std::size_t fCount
Size of the bulk range.
bool * fMaskAvail
A bool array of size fCount, indicating the valid values in fValues.
const bool * fMaskReq
A bool array of size fCount, indicating the required values in the requested range.
Used in the return value of the Check() method.
RCreateObjectDeleter< void > deleter
Definition RField.hxx:580