Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldBase.cxx
Go to the documentation of this file.
1/// \file RFieldBase.cxx
2/// \ingroup NTuple
3/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
4/// \date 2024-11-19
5
6#include <ROOT/RError.hxx>
7#include <ROOT/RField.hxx>
8#include <ROOT/RFieldBase.hxx>
10#include <ROOT/RFieldUtils.hxx>
11#include <ROOT/RNTupleUtils.hxx>
12
13#include <TClass.h>
14#include <TClassEdit.h>
15#include <TEnum.h>
16
17#include <sstream>
18#include <string>
19#include <vector>
20
21namespace {
22
23/// Used as a thread local context storage for Create(); steers the behavior of the Create() call stack
24class CreateContextGuard;
25class CreateContext {
26 friend class CreateContextGuard;
27 /// All classes that were defined by Create() calls higher up in the stack. Finds cyclic type definitions.
28 std::vector<std::string> fClassesOnStack;
29 /// If set to true, Create() will create an RInvalidField on error instead of throwing an exception.
30 /// This is used in RFieldBase::Check() to identify unsupported sub fields.
31 bool fContinueOnError = false;
32
33public:
34 CreateContext() = default;
35 bool GetContinueOnError() const { return fContinueOnError; }
36};
37
38/// RAII for modifications of CreateContext
39class CreateContextGuard {
40 CreateContext &fCreateContext;
41 std::size_t fNOriginalClassesOnStack;
42 bool fOriginalContinueOnError;
43
44public:
45 CreateContextGuard(CreateContext &ctx)
46 : fCreateContext(ctx),
47 fNOriginalClassesOnStack(ctx.fClassesOnStack.size()),
48 fOriginalContinueOnError(ctx.fContinueOnError)
49 {
50 }
52 {
53 fCreateContext.fClassesOnStack.resize(fNOriginalClassesOnStack);
54 fCreateContext.fContinueOnError = fOriginalContinueOnError;
55 }
56
57 void AddClassToStack(const std::string &cl)
58 {
59 if (std::find(fCreateContext.fClassesOnStack.begin(), fCreateContext.fClassesOnStack.end(), cl) !=
60 fCreateContext.fClassesOnStack.end()) {
61 throw ROOT::RException(R__FAIL("cyclic class definition: " + cl));
62 }
63 fCreateContext.fClassesOnStack.emplace_back(cl);
64 }
65
66 void SetContinueOnError(bool value) { fCreateContext.fContinueOnError = value; }
67};
68
69} // anonymous namespace
70
88
90ROOT::Internal::CallFieldBaseCreate(const std::string &fieldName, const std::string &typeName,
91 const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc,
93{
94 return RFieldBase::Create(fieldName, typeName, options, desc, fieldId);
95}
96
97//------------------------------------------------------------------------------
98
100{
101 // A single representations with an empty set of columns
104}
105
113
114//------------------------------------------------------------------------------
115
117{
118 // Set fObjPtr to an aliased shared_ptr of the input raw pointer. Note that
119 // fObjPtr will be non-empty but have use count zero.
121}
122
123//------------------------------------------------------------------------------
124
126 : fField(other.fField),
128 fCapacity(other.fCapacity),
130 fIsAdopted(other.fIsAdopted),
131 fNValidValues(other.fNValidValues),
132 fFirstIndex(other.fFirstIndex)
133{
134 std::swap(fDeleter, other.fDeleter);
135 std::swap(fValues, other.fValues);
136 std::swap(fMaskAvail, other.fMaskAvail);
137}
138
140{
141 std::swap(fField, other.fField);
142 std::swap(fDeleter, other.fDeleter);
143 std::swap(fValues, other.fValues);
144 std::swap(fValueSize, other.fValueSize);
145 std::swap(fCapacity, other.fCapacity);
146 std::swap(fSize, other.fSize);
147 std::swap(fIsAdopted, other.fIsAdopted);
148 std::swap(fMaskAvail, other.fMaskAvail);
149 std::swap(fNValidValues, other.fNValidValues);
150 std::swap(fFirstIndex, other.fFirstIndex);
151 return *this;
152}
153
155{
156 if (fValues)
157 ReleaseValues();
158}
159
161{
162 if (fIsAdopted)
163 return;
164
165 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyDestructible)) {
166 for (std::size_t i = 0; i < fCapacity; ++i) {
167 fDeleter->operator()(GetValuePtrAt(i), true /* dtorOnly */);
168 }
169 }
170
171 operator delete(fValues);
172}
173
175{
176 if (fCapacity < size) {
177 if (fIsAdopted) {
178 throw RException(R__FAIL("invalid attempt to bulk read beyond the adopted buffer"));
179 }
180 ReleaseValues();
181 fValues = operator new(size * fValueSize);
182
183 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyConstructible)) {
184 for (std::size_t i = 0; i < size; ++i) {
185 fField->ConstructValue(GetValuePtrAt(i));
186 }
187 }
188
189 fMaskAvail = std::make_unique<bool[]>(size);
190 fCapacity = size;
191 }
192
193 std::fill(fMaskAvail.get(), fMaskAvail.get() + size, false);
194 fNValidValues = 0;
195
196 fFirstIndex = firstIndex;
197 fSize = size;
198}
199
200void ROOT::RFieldBase::RBulkValues::AdoptBuffer(void *buf, std::size_t capacity)
201{
202 ReleaseValues();
203 fValues = buf;
204 fCapacity = capacity;
205 fSize = capacity;
206
207 fMaskAvail = std::make_unique<bool[]>(capacity);
208
209 fFirstIndex = RNTupleLocalIndex();
210
211 fIsAdopted = true;
212}
213
214//------------------------------------------------------------------------------
215
217{
218 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "possibly leaking object from RField<T>::CreateObject<void>";
219}
220
221template <>
222std::unique_ptr<void, typename ROOT::RFieldBase::RCreateObjectDeleter<void>::deleter>
223ROOT::RFieldBase::CreateObject<void>() const
224{
226 return std::unique_ptr<void, RCreateObjectDeleter<void>::deleter>(CreateObjectRawPtr(), gDeleter);
227}
228
229//------------------------------------------------------------------------------
230
231ROOT::RFieldBase::RFieldBase(std::string_view name, std::string_view type, ROOT::ENTupleStructure structure,
232 bool isSimple, std::size_t nRepetitions)
233 : fName(name),
234 fType(type),
235 fStructure(structure),
238 fParent(nullptr),
239 fPrincipalColumn(nullptr),
241{
243}
244
246{
247 std::string result = GetFieldName();
248 auto parent = GetParent();
249 while (parent && !parent->GetFieldName().empty()) {
250 result = parent->GetFieldName() + "." + result;
251 parent = parent->GetParent();
252 }
253 return result;
254}
255
257ROOT::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
258{
259 return R__FORWARD_RESULT(
261}
262
263std::vector<ROOT::RFieldBase::RCheckResult>
264ROOT::RFieldBase::Check(const std::string &fieldName, const std::string &typeName)
265{
268 cfOpts.SetReturnInvalidOnError(true);
269 cfOpts.SetEmulateUnknownTypes(false);
270 fieldZero.Attach(RFieldBase::Create(fieldName, typeName, cfOpts, nullptr, kInvalidDescriptorId).Unwrap());
271
272 std::vector<RCheckResult> result;
273 for (const auto &f : fieldZero) {
274 const bool isInvalidField = f.GetTraits() & RFieldBase::kTraitInvalidField;
275 if (!isInvalidField)
276 continue;
277
278 const auto &invalidField = static_cast<const RInvalidField &>(f);
279 result.emplace_back(
280 RCheckResult{invalidField.GetQualifiedFieldName(), invalidField.GetTypeName(), invalidField.GetError()});
281 }
282 return result;
283}
284
286ROOT::RFieldBase::Create(const std::string &fieldName, const std::string &typeName,
287 const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc,
289{
292
294
295 thread_local CreateContext createContext;
296 CreateContextGuard createContextGuard(createContext);
297 if (options.GetReturnInvalidOnError())
298 createContextGuard.SetContinueOnError(true);
299
300 auto fnFail = [&fieldName,
301 &resolvedType](const std::string &errMsg,
303 RInvalidField::ECategory::kTypeError) -> RResult<std::unique_ptr<RFieldBase>> {
304 if (createContext.GetContinueOnError()) {
305 return std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, resolvedType, errMsg, cat));
306 } else {
307 return R__FAIL(errMsg);
308 }
309 };
310
311 if (resolvedType.empty())
312 return R__FORWARD_RESULT(fnFail("no type name specified for field '" + fieldName + "'"));
313
314 std::unique_ptr<ROOT::RFieldBase> result;
315
316 const auto maybeGetChildId = [desc, fieldId](int childId) {
317 if (desc) {
318 const auto &fieldDesc = desc->GetFieldDescriptor(fieldId);
319 return fieldDesc.GetLinkIds().at(childId);
320 } else {
322 }
323 };
324
325 // try-catch block to intercept any exception that may be thrown by Unwrap() so that this
326 // function never throws but returns RResult::Error instead.
327 try {
328 if (resolvedType == "bool") {
329 result = std::make_unique<RField<bool>>(fieldName);
330 } else if (resolvedType == "char") {
331 result = std::make_unique<RField<char>>(fieldName);
332 } else if (resolvedType == "std::byte") {
333 result = std::make_unique<RField<std::byte>>(fieldName);
334 } else if (resolvedType == "std::int8_t") {
335 result = std::make_unique<RField<std::int8_t>>(fieldName);
336 } else if (resolvedType == "std::uint8_t") {
337 result = std::make_unique<RField<std::uint8_t>>(fieldName);
338 } else if (resolvedType == "std::int16_t") {
339 result = std::make_unique<RField<std::int16_t>>(fieldName);
340 } else if (resolvedType == "std::uint16_t") {
341 result = std::make_unique<RField<std::uint16_t>>(fieldName);
342 } else if (resolvedType == "std::int32_t") {
343 result = std::make_unique<RField<std::int32_t>>(fieldName);
344 } else if (resolvedType == "std::uint32_t") {
345 result = std::make_unique<RField<std::uint32_t>>(fieldName);
346 } else if (resolvedType == "std::int64_t") {
347 result = std::make_unique<RField<std::int64_t>>(fieldName);
348 } else if (resolvedType == "std::uint64_t") {
349 result = std::make_unique<RField<std::uint64_t>>(fieldName);
350 } else if (resolvedType == "float") {
351 result = std::make_unique<RField<float>>(fieldName);
352 } else if (resolvedType == "double") {
353 result = std::make_unique<RField<double>>(fieldName);
354 } else if (resolvedType == "Double32_t") {
355 result = std::make_unique<RField<double>>(fieldName);
356 static_cast<RField<double> *>(result.get())->SetDouble32();
357 // Prevent the type alias from being reset by returning early
358 return result;
359 } else if (resolvedType == "std::string") {
360 result = std::make_unique<RField<std::string>>(fieldName);
361 } else if (resolvedType == "TObject") {
362 result = std::make_unique<RField<TObject>>(fieldName);
363 } else if (resolvedType == "std::vector<bool>") {
364 result = std::make_unique<RField<std::vector<bool>>>(fieldName);
365 } else if (resolvedType.substr(0, 12) == "std::vector<") {
366 std::string itemTypeName = resolvedType.substr(12, resolvedType.length() - 13);
367 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0));
368 result = std::make_unique<RVectorField>(fieldName, itemField.Unwrap());
369 } else if (resolvedType.substr(0, 19) == "ROOT::VecOps::RVec<") {
370 std::string itemTypeName = resolvedType.substr(19, resolvedType.length() - 20);
371 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0));
372 result = std::make_unique<RRVecField>(fieldName, itemField.Unwrap());
373 } else if (resolvedType.substr(0, 11) == "std::array<") {
374 auto arrayDef = TokenizeTypeList(resolvedType.substr(11, resolvedType.length() - 12));
375 if (arrayDef.size() != 2) {
376 return R__FORWARD_RESULT(fnFail("the template list for std::array must have exactly two elements"));
377 }
379 auto itemField = Create("_0", arrayDef[0], options, desc, maybeGetChildId(0));
380 result = std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arrayLength);
381 } else if (resolvedType.substr(0, 13) == "std::variant<") {
382 auto innerTypes = TokenizeTypeList(resolvedType.substr(13, resolvedType.length() - 14));
383 std::vector<std::unique_ptr<RFieldBase>> items;
384 items.reserve(innerTypes.size());
385 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
386 items.emplace_back(
387 Create("_" + std::to_string(i), innerTypes[i], options, desc, maybeGetChildId(i)).Unwrap());
388 }
389 result = std::make_unique<RVariantField>(fieldName, std::move(items));
390 } else if (resolvedType.substr(0, 10) == "std::pair<") {
391 auto innerTypes = TokenizeTypeList(resolvedType.substr(10, resolvedType.length() - 11));
392 if (innerTypes.size() != 2) {
393 return R__FORWARD_RESULT(fnFail("the type list for std::pair must have exactly two elements"));
394 }
395 std::array<std::unique_ptr<RFieldBase>, 2> items{
396 Create("_0", innerTypes[0], options, desc, maybeGetChildId(0)).Unwrap(),
397 Create("_1", innerTypes[1], options, desc, maybeGetChildId(1)).Unwrap()};
398 result = std::make_unique<RPairField>(fieldName, std::move(items));
399 } else if (resolvedType.substr(0, 11) == "std::tuple<") {
400 auto innerTypes = TokenizeTypeList(resolvedType.substr(11, resolvedType.length() - 12));
401 std::vector<std::unique_ptr<RFieldBase>> items;
402 items.reserve(innerTypes.size());
403 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
404 items.emplace_back(
405 Create("_" + std::to_string(i), innerTypes[i], options, desc, maybeGetChildId(i)).Unwrap());
406 }
407 result = std::make_unique<RTupleField>(fieldName, std::move(items));
408 } else if (resolvedType.substr(0, 12) == "std::bitset<") {
409 auto size = ParseUIntTypeToken(resolvedType.substr(12, resolvedType.length() - 13));
410 result = std::make_unique<RBitsetField>(fieldName, size);
411 } else if (resolvedType.substr(0, 16) == "std::unique_ptr<") {
412 std::string itemTypeName = resolvedType.substr(16, resolvedType.length() - 17);
413 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
414 result = std::make_unique<RUniquePtrField>(fieldName, std::move(itemField));
415 } else if (resolvedType.substr(0, 14) == "std::optional<") {
416 std::string itemTypeName = resolvedType.substr(14, resolvedType.length() - 15);
417 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
418 result = std::make_unique<ROptionalField>(fieldName, std::move(itemField));
419 } else if (resolvedType.substr(0, 9) == "std::set<") {
420 std::string itemTypeName = resolvedType.substr(9, resolvedType.length() - 10);
421 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
422 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kSet, std::move(itemField));
423 } else if (resolvedType.substr(0, 19) == "std::unordered_set<") {
424 std::string itemTypeName = resolvedType.substr(19, resolvedType.length() - 20);
425 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
426 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kUnorderedSet, std::move(itemField));
427 } else if (resolvedType.substr(0, 14) == "std::multiset<") {
428 std::string itemTypeName = resolvedType.substr(14, resolvedType.length() - 15);
429 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
430 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kMultiSet, std::move(itemField));
431 } else if (resolvedType.substr(0, 24) == "std::unordered_multiset<") {
432 std::string itemTypeName = resolvedType.substr(24, resolvedType.length() - 25);
433 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
434 auto normalizedInnerTypeName = itemField->GetTypeName();
435 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kUnorderedMultiSet, std::move(itemField));
436 } else if (resolvedType.substr(0, 9) == "std::map<") {
437 auto innerTypes = TokenizeTypeList(resolvedType.substr(9, resolvedType.length() - 10));
438 if (innerTypes.size() != 2) {
439 return R__FORWARD_RESULT(fnFail("the type list for std::map must have exactly two elements"));
440 }
441 auto itemField =
442 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
443 .Unwrap();
444 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kMap, std::move(itemField));
445 } else if (resolvedType.substr(0, 19) == "std::unordered_map<") {
446 auto innerTypes = TokenizeTypeList(resolvedType.substr(19, resolvedType.length() - 20));
447 if (innerTypes.size() != 2)
448 return R__FORWARD_RESULT(fnFail("the type list for std::unordered_map must have exactly two elements"));
449 auto itemField =
450 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
451 .Unwrap();
452 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kUnorderedMap, std::move(itemField));
453 } else if (resolvedType.substr(0, 14) == "std::multimap<") {
454 auto innerTypes = TokenizeTypeList(resolvedType.substr(14, resolvedType.length() - 15));
455 if (innerTypes.size() != 2)
456 return R__FORWARD_RESULT(fnFail("the type list for std::multimap must have exactly two elements"));
457 auto itemField =
458 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
459 .Unwrap();
460 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kMultiMap, std::move(itemField));
461 } else if (resolvedType.substr(0, 24) == "std::unordered_multimap<") {
462 auto innerTypes = TokenizeTypeList(resolvedType.substr(24, resolvedType.length() - 25));
463 if (innerTypes.size() != 2)
464 return R__FORWARD_RESULT(
465 fnFail("the type list for std::unordered_multimap must have exactly two elements"));
466 auto itemField =
467 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
468 .Unwrap();
469 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kUnorderedMultiMap, std::move(itemField));
470 } else if (resolvedType.substr(0, 12) == "std::atomic<") {
471 std::string itemTypeName = resolvedType.substr(12, resolvedType.length() - 13);
472 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
473 result = std::make_unique<RAtomicField>(fieldName, std::move(itemField));
474 } else if (resolvedType.substr(0, 25) == "ROOT::RNTupleCardinality<") {
475 auto innerTypes = TokenizeTypeList(resolvedType.substr(25, resolvedType.length() - 26));
476 if (innerTypes.size() != 1)
477 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + resolvedType));
479 if (canonicalInnerType == "std::uint32_t") {
480 result = std::make_unique<RField<RNTupleCardinality<std::uint32_t>>>(fieldName);
481 } else if (canonicalInnerType == "std::uint64_t") {
482 result = std::make_unique<RField<RNTupleCardinality<std::uint64_t>>>(fieldName);
483 } else {
484 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + resolvedType));
485 }
486 }
487
488 if (!result) {
489 auto e = TEnum::GetEnum(resolvedType.c_str());
490 if (e != nullptr) {
491 result = std::make_unique<REnumField>(fieldName, typeName);
492 }
493 }
494
495 if (!result) {
496 auto cl = TClass::GetClass(typeName.c_str());
497
498 if (cl && cl->GetState() > TClass::kForwardDeclared) {
499 createContextGuard.AddClassToStack(resolvedType);
500 if (cl->GetCollectionProxy()) {
501 result = std::make_unique<RProxiedCollectionField>(fieldName, typeName);
502 }
503 // NOTE: if the class is not at least "Interpreted" we currently don't try to construct
504 // the RClassField, as in that case we'd need to fetch the information from the StreamerInfo
505 // rather than from TClass. This might be desirable in the future, but for now in this
506 // situation we rely on field emulation instead.
507 else if (cl->GetState() >= TClass::kInterpreted) {
510 result = std::make_unique<RStreamerField>(fieldName, typeName);
511 } else {
512 result = std::make_unique<RClassField>(fieldName, typeName);
513 }
514 }
515 }
516
517 // If we get here then we failed to meet all the conditions to create a "properly typed" field.
518 // Resort to field emulation if the user asked us to.
519 if (!result && options.GetEmulateUnknownTypes()) {
520 assert(desc);
521 const auto &fieldDesc = desc->GetFieldDescriptor(fieldId);
522 if (fieldDesc.GetStructure() == ENTupleStructure::kRecord) {
523 std::vector<std::unique_ptr<RFieldBase>> memberFields;
524 memberFields.reserve(fieldDesc.GetLinkIds().size());
525 for (auto id : fieldDesc.GetLinkIds()) {
526 const auto &memberDesc = desc->GetFieldDescriptor(id);
527 auto field = Create(memberDesc.GetFieldName(), memberDesc.GetTypeName(), options, desc, id).Unwrap();
528 memberFields.emplace_back(std::move(field));
529 }
530 R__ASSERT(typeName == fieldDesc.GetTypeName());
531 auto recordField =
533 recordField->fTypeAlias = fieldDesc.GetTypeAlias();
534 return recordField;
535 } else if (fieldDesc.GetStructure() == ENTupleStructure::kCollection) {
536 if (fieldDesc.GetLinkIds().size() != 1)
537 throw ROOT::RException(R__FAIL("invalid structure for collection field " + fieldName));
538
539 auto itemFieldId = fieldDesc.GetLinkIds()[0];
540 const auto &itemFieldDesc = desc->GetFieldDescriptor(itemFieldId);
541 auto itemField =
542 Create(itemFieldDesc.GetFieldName(), itemFieldDesc.GetTypeName(), options, desc, itemFieldId)
543 .Unwrap();
544 auto vecField =
546 vecField->fTypeAlias = fieldDesc.GetTypeAlias();
547 return vecField;
548 }
549 }
550 }
551 } catch (const RException &e) {
552 auto error = e.GetError();
553 if (createContext.GetContinueOnError()) {
554 return std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, typeName, error.GetReport(),
556 } else {
557 return error;
558 }
559 } catch (const std::logic_error &e) {
560 // Integer parsing error
561 if (createContext.GetContinueOnError()) {
562 return std::unique_ptr<RFieldBase>(
563 std::make_unique<RInvalidField>(fieldName, typeName, e.what(), RInvalidField::ECategory::kGeneric));
564 } else {
565 return R__FAIL(e.what());
566 }
567 }
568
569 if (result) {
571 if (normOrigType != result->GetTypeName()) {
572 result->fTypeAlias = normOrigType;
573 }
574 return result;
575 }
576 return R__FORWARD_RESULT(fnFail("unknown type: " + typeName, RInvalidField::ECategory::kUnknownType));
577}
578
584
585std::unique_ptr<ROOT::RFieldBase> ROOT::RFieldBase::Clone(std::string_view newName) const
586{
587 auto clone = CloneImpl(newName);
588 clone->fTypeAlias = fTypeAlias;
589 clone->fOnDiskId = fOnDiskId;
590 clone->fDescription = fDescription;
591 // We can just copy the references because fColumnRepresentatives point into a static structure
592 clone->fColumnRepresentatives = fColumnRepresentatives;
593 return clone;
594}
595
596std::size_t ROOT::RFieldBase::AppendImpl(const void * /* from */)
597{
598 R__ASSERT(false && "A non-simple RField must implement its own AppendImpl");
599 return 0;
600}
601
603{
604 R__ASSERT(false);
605}
606
608{
609 ReadGlobalImpl(fPrincipalColumn->GetGlobalIndex(localIndex), to);
610}
611
613{
614 const auto valueSize = GetValueSize();
615 std::size_t nRead = 0;
616 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
617 // Value not needed
618 if (bulkSpec.fMaskReq && !bulkSpec.fMaskReq[i])
619 continue;
620
621 // Value already present
622 if (bulkSpec.fMaskAvail[i])
623 continue;
624
625 Read(bulkSpec.fFirstIndex + i, reinterpret_cast<unsigned char *>(bulkSpec.fValues) + i * valueSize);
626 bulkSpec.fMaskAvail[i] = true;
627 nRead++;
628 }
629 return nRead;
630}
631
633{
634 void *where = operator new(GetValueSize());
635 R__ASSERT(where != nullptr);
636 ConstructValue(where);
637 return where;
638}
639
641{
642 void *obj = CreateObjectRawPtr();
643 return RValue(this, std::shared_ptr<void>(obj, RSharedPtrDeleter(GetDeleter())));
644}
645
646std::vector<ROOT::RFieldBase::RValue> ROOT::RFieldBase::SplitValue(const RValue & /*value*/) const
647{
648 return std::vector<RValue>();
649}
650
651void ROOT::RFieldBase::Attach(std::unique_ptr<ROOT::RFieldBase> child)
652{
653 // Note that during a model update, new fields will be attached to the zero field. The zero field, however,
654 // does not change its inital state because only its sub fields get connected by RPageSink::UpdateSchema.
655 if (fState != EState::kUnconnected)
656 throw RException(R__FAIL("invalid attempt to attach subfield to already connected field"));
657 child->fParent = this;
658 fSubfields.emplace_back(std::move(child));
659}
660
662{
663 std::size_t result = globalIndex;
664 for (auto f = this; f != nullptr; f = f->GetParent()) {
665 auto parent = f->GetParent();
666 if (parent && (parent->GetStructure() == ROOT::ENTupleStructure::kCollection ||
667 parent->GetStructure() == ROOT::ENTupleStructure::kVariant)) {
668 return 0U;
669 }
670 result *= std::max(f->GetNRepetitions(), std::size_t{1U});
671 }
672 return result;
673}
674
675std::vector<ROOT::RFieldBase *> ROOT::RFieldBase::GetMutableSubfields()
676{
677 std::vector<RFieldBase *> result;
678 result.reserve(fSubfields.size());
679 for (const auto &f : fSubfields) {
680 result.emplace_back(f.get());
681 }
682 return result;
683}
684
685std::vector<const ROOT::RFieldBase *> ROOT::RFieldBase::GetConstSubfields() const
686{
687 std::vector<const RFieldBase *> result;
688 result.reserve(fSubfields.size());
689 for (const auto &f : fSubfields) {
690 result.emplace_back(f.get());
691 }
692 return result;
693}
694
696{
697 if (!fAvailableColumns.empty()) {
698 const auto activeRepresentationIndex = fPrincipalColumn->GetRepresentationIndex();
699 for (auto &column : fAvailableColumns) {
700 if (column->GetRepresentationIndex() == activeRepresentationIndex) {
701 column->Flush();
702 }
703 }
704 }
705}
706
708{
709 if (!fAvailableColumns.empty()) {
710 const auto activeRepresentationIndex = fPrincipalColumn->GetRepresentationIndex();
711 for (auto &column : fAvailableColumns) {
712 if (column->GetRepresentationIndex() == activeRepresentationIndex) {
713 column->Flush();
714 } else {
715 column->CommitSuppressed();
716 }
717 }
718 }
719 CommitClusterImpl();
720}
721
723{
724 if (fState != EState::kUnconnected)
725 throw RException(R__FAIL("cannot set field description once field is connected"));
726 fDescription = std::string(description);
727}
728
730{
731 if (fState != EState::kUnconnected)
732 throw RException(R__FAIL("cannot set field ID once field is connected"));
733 fOnDiskId = id;
734}
735
736/// Write the given value into columns. The value object has to be of the same type as the field.
737/// Returns the number of uncompressed bytes written.
738std::size_t ROOT::RFieldBase::Append(const void *from)
739{
740 if (~fTraits & kTraitMappable)
741 return AppendImpl(from);
742
743 fPrincipalColumn->Append(from);
744 return fPrincipalColumn->GetElement()->GetPackedSize();
745}
746
751
753{
754 return RValue(this, objPtr);
755}
756
758{
759 if (fIsSimple) {
760 /// For simple types, ignore the mask and memcopy the values into the destination
761 fPrincipalColumn->ReadV(bulkSpec.fFirstIndex, bulkSpec.fCount, bulkSpec.fValues);
762 std::fill(bulkSpec.fMaskAvail, bulkSpec.fMaskAvail + bulkSpec.fCount, true);
763 return RBulkSpec::kAllSet;
764 }
765
766 if (fIsArtificial || !fReadCallbacks.empty()) {
767 // Fields with schema evolution treatment must not go through an optimized read
769 }
770
771 return ReadBulkImpl(bulkSpec);
772}
773
775{
776 return fSubfields.empty() ? RSchemaIterator(this, -1) : RSchemaIterator(fSubfields[0].get(), 0);
777}
778
783
785{
786 return fSubfields.empty() ? RConstSchemaIterator(this, -1) : RConstSchemaIterator(fSubfields[0].get(), 0);
787}
788
793
795{
796 return fSubfields.empty() ? RConstSchemaIterator(this, -1) : RConstSchemaIterator(fSubfields[0].get(), 0);
797}
798
803
805{
806 if (fColumnRepresentatives.empty()) {
807 return {GetColumnRepresentations().GetSerializationDefault()};
808 }
809
811 result.reserve(fColumnRepresentatives.size());
812 for (const auto &r : fColumnRepresentatives) {
813 result.emplace_back(r.get());
814 }
815 return result;
816}
817
819{
820 if (fState != EState::kUnconnected)
821 throw RException(R__FAIL("cannot set column representative once field is connected"));
822 const auto &validTypes = GetColumnRepresentations().GetSerializationTypes();
823 fColumnRepresentatives.clear();
824 fColumnRepresentatives.reserve(representatives.size());
825 for (const auto &r : representatives) {
826 auto itRepresentative = std::find(validTypes.begin(), validTypes.end(), r);
827 if (itRepresentative == std::end(validTypes))
828 throw RException(R__FAIL("invalid column representative"));
829
830 // don't add a duplicate representation
831 if (std::find_if(fColumnRepresentatives.begin(), fColumnRepresentatives.end(),
832 [&r](const auto &rep) { return r == rep.get(); }) == fColumnRepresentatives.end())
833 fColumnRepresentatives.emplace_back(*itRepresentative);
834 }
835}
836
839 std::uint16_t representationIndex) const
840{
841 static const ColumnRepresentation_t kEmpty;
842
843 if (fOnDiskId == ROOT::kInvalidDescriptorId)
844 throw RException(R__FAIL("No on-disk field information for `" + GetQualifiedFieldName() + "`"));
845
847 for (const auto &c : desc.GetColumnIterable(fOnDiskId)) {
848 if (c.GetRepresentationIndex() == representationIndex)
849 onDiskTypes.emplace_back(c.GetType());
850 }
851 if (onDiskTypes.empty()) {
852 if (representationIndex == 0) {
853 throw RException(R__FAIL("No on-disk column information for field `" + GetQualifiedFieldName() + "`"));
854 }
855 return kEmpty;
856 }
857
858 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
859 if (t == onDiskTypes)
860 return t;
861 }
862
863 std::string columnTypeNames;
864 for (const auto &t : onDiskTypes) {
865 if (!columnTypeNames.empty())
866 columnTypeNames += ", ";
868 }
869 throw RException(R__FAIL("On-disk column types {" + columnTypeNames + "} for field `" + GetQualifiedFieldName() +
870 "` cannot be matched to its in-memory type `" + GetTypeName() + "` " +
871 "(representation index: " + std::to_string(representationIndex) + ")"));
872}
873
875{
876 fReadCallbacks.push_back(func);
877 fIsSimple = false;
878 return fReadCallbacks.size() - 1;
879}
880
882{
883 fReadCallbacks.erase(fReadCallbacks.begin() + idx);
884 fIsSimple = (fTraits & kTraitMappable) && !fIsArtificial && fReadCallbacks.empty();
885}
886
912
914{
915 if (dynamic_cast<ROOT::RFieldZero *>(this))
916 throw RException(R__FAIL("invalid attempt to connect zero field to page sink"));
917 if (fState != EState::kUnconnected)
918 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page sink"));
919
920 AutoAdjustColumnTypes(pageSink.GetWriteOptions());
921
922 GenerateColumns();
923 for (auto &column : fAvailableColumns) {
924 // Only the first column of every representation can be a deferred column. In all column representations,
925 // larger column indexes are data columns of collections (string, streamer) and thus
926 // they have no elements on late model extension
927 auto firstElementIndex = (column->GetIndex() == 0) ? EntryToColumnElementIndex(firstEntry) : 0;
928 column->ConnectPageSink(fOnDiskId, pageSink, firstElementIndex);
929 }
930
931 if (HasExtraTypeInfo()) {
932 pageSink.RegisterOnCommitDatasetCallback(
933 [this](ROOT::Internal::RPageSink &sink) { sink.UpdateExtraTypeInfo(GetExtraTypeInfo()); });
934 }
935
936 fState = EState::kConnectedToSink;
937}
938
940{
941 if (dynamic_cast<ROOT::RFieldZero *>(this)) {
942 for (auto &f : fSubfields)
943 f->ConnectPageSource(pageSource);
944 return;
945 }
946
947 if (fState != EState::kUnconnected)
948 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page source"));
949
950 if (!fColumnRepresentatives.empty())
951 throw RException(R__FAIL("fixed column representative only valid when connecting to a page sink"));
952 if (!fDescription.empty())
953 throw RException(R__FAIL("setting description only valid when connecting to a page sink"));
954
955 auto substitute = BeforeConnectPageSource(pageSource);
956 if (substitute) {
957 const RFieldBase *itr = this;
958 while (itr->GetParent()) {
959 itr = itr->GetParent();
960 }
961 if (typeid(*itr) == typeid(RFieldZero) && static_cast<const RFieldZero *>(itr)->GetAllowFieldSubstitutions()) {
962 for (auto &f : fParent->fSubfields) {
963 if (f.get() != this)
964 continue;
965
966 f = std::move(substitute);
967 f->ConnectPageSource(pageSource);
968 return;
969 }
970 R__ASSERT(false); // never here
971 } else {
972 throw RException(R__FAIL("invalid attempt to substitute field " + GetQualifiedFieldName()));
973 }
974 }
975
976 if (!fIsArtificial) {
977 R__ASSERT(fOnDiskId != kInvalidDescriptorId);
978 ReconcileOnDiskField(pageSource.GetSharedDescriptorGuard().GetRef());
979 }
980
981 for (auto &f : fSubfields) {
982 if (f->GetOnDiskId() == ROOT::kInvalidDescriptorId) {
983 f->SetOnDiskId(pageSource.GetSharedDescriptorGuard()->FindFieldId(f->GetFieldName(), GetOnDiskId()));
984 }
985 f->ConnectPageSource(pageSource);
986 }
987
988 // Do not generate columns nor set fColumnRepresentatives for artificial fields.
989 if (!fIsArtificial) {
990 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
991 const ROOT::RNTupleDescriptor &desc = descriptorGuard.GetRef();
992 GenerateColumns(desc);
993 if (fColumnRepresentatives.empty()) {
994 // If we didn't get columns from the descriptor, ensure that we actually expect a field without columns
995 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
996 if (t.empty()) {
997 fColumnRepresentatives = {t};
998 break;
999 }
1000 }
1001 }
1002 R__ASSERT(!fColumnRepresentatives.empty());
1003 if (fOnDiskId != ROOT::kInvalidDescriptorId) {
1004 const auto &fieldDesc = desc.GetFieldDescriptor(fOnDiskId);
1005 fOnDiskTypeVersion = fieldDesc.GetTypeVersion();
1006 if (fieldDesc.GetTypeChecksum().has_value())
1007 fOnDiskTypeChecksum = *fieldDesc.GetTypeChecksum();
1008 }
1009 }
1010 for (auto &column : fAvailableColumns)
1011 column->ConnectPageSource(fOnDiskId, pageSource);
1012
1013 fState = EState::kConnectedToSource;
1014}
1015
1017{
1018 // The default implementation throws an exception if the on-disk ID is set and there are any meaningful differences
1019 // to the on-disk field. Derived classes may overwrite this and relax the checks to support automatic schema
1020 // evolution.
1021 EnsureMatchingOnDiskField(desc.GetFieldDescriptor(fOnDiskId)).ThrowOnError();
1022}
1023
1026{
1027 const std::uint32_t diffBits = CompareOnDiskField(fieldDesc, ignoreBits);
1028 if (diffBits == 0)
1029 return RResult<void>::Success();
1030
1031 std::ostringstream errMsg;
1032 errMsg << "in-memory field " << GetQualifiedFieldName() << " of type " << GetTypeName() << " is incompatible "
1033 << "with on-disk field " << fieldDesc.GetFieldName() << ":";
1034 if (diffBits & kDiffFieldVersion) {
1035 errMsg << " field version " << GetFieldVersion() << " vs. " << fieldDesc.GetFieldVersion() << ";";
1036 }
1037 if (diffBits & kDiffTypeVersion) {
1038 errMsg << " type version " << GetTypeVersion() << " vs. " << fieldDesc.GetTypeVersion() << ";";
1039 }
1040 if (diffBits & kDiffStructure) {
1041 errMsg << " structural role " << GetStructure() << " vs. " << fieldDesc.GetStructure() << ";";
1042 }
1043 if (diffBits & kDiffTypeName) {
1044 errMsg << " incompatible on-disk type name " << fieldDesc.GetTypeName() << ";";
1045 }
1046 if (diffBits & kDiffNRepetitions) {
1047 errMsg << " repetition count " << GetNRepetitions() << " vs. " << fieldDesc.GetNRepetitions() << ";";
1048 }
1049 return R__FAIL(errMsg.str());
1050}
1051
1053 const std::vector<std::string> &prefixes) const
1054{
1055 for (const auto &p : prefixes) {
1056 if (fieldDesc.GetTypeName().rfind(p, 0) == 0)
1057 return RResult<void>::Success();
1058 }
1059 return R__FAIL("incompatible type " + fieldDesc.GetTypeName() + " for field " + GetQualifiedFieldName());
1060}
1061
1063{
1064 std::uint32_t diffBits = 0;
1065 if ((~ignoreBits & kDiffFieldVersion) && (GetFieldVersion() != fieldDesc.GetFieldVersion()))
1066 diffBits |= kDiffFieldVersion;
1067 if ((~ignoreBits & kDiffTypeVersion) && (GetTypeVersion() != fieldDesc.GetTypeVersion()))
1068 diffBits |= kDiffTypeVersion;
1069 if ((~ignoreBits & kDiffStructure) && (GetStructure() != fieldDesc.GetStructure()))
1070 diffBits |= kDiffStructure;
1071 if ((~ignoreBits & kDiffTypeName) && (GetTypeName() != fieldDesc.GetTypeName()))
1072 diffBits |= kDiffTypeName;
1073 if ((~ignoreBits & kDiffNRepetitions) && (GetNRepetitions() != fieldDesc.GetNRepetitions()))
1074 diffBits |= kDiffNRepetitions;
1075
1076 return diffBits;
1077}
1078
1080{
1081 visitor.VisitField(*this);
1082}
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:302
#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:300
#define R__LOG_WARNING(...)
Definition RLogger.hxx:358
#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
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
winID h TVirtualViewer3D TVirtualGLPainter p
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.
static const char * GetColumnTypeName(ROOT::ENTupleColumnType type)
Abstract interface to write data into an ntuple.
Abstract interface to read data from an ntuple.
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
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 Reset(RNTupleLocalIndex firstIndex, std::size_t size)
Sets a new range for the bulk.
void * fValues
Cached deleter of fField.
RBulkValues & operator=(const RBulkValues &)=delete
RBulkValues(RFieldBase *field)
void AdoptBuffer(void *buf, std::size_t capacity)
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.
void BindRawPtr(void *rawPtr)
A field translates read and write calls from/to underlying columns to/from tree values.
RSchemaIterator end()
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.
void Attach(std::unique_ptr< RFieldBase > child)
Add a new subfield to the list of nested fields.
virtual void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const
void FlushColumns()
Flushes data from active columns.
virtual void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to)
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
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)
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...
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...
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.
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
RResult< void > EnsureMatchingTypePrefix(const RFieldDescriptor &fieldDesc, const std::vector< std::string > &prefixes) const
Many fields accept a range of type prefixes for schema evolution, e.g.
virtual void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to)
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.
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.
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.
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),...
@ 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.
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)
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 > EnsureMatchingOnDiskField(const RFieldDescriptor &fieldDesc, std::uint32_t ignoreBits=0) const
Compares the field to the provieded on-disk field descriptor.
void * CreateObjectRawPtr() const
Factory method for the field's type. The caller owns the returned pointer.
virtual std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec)
General implementation of bulk read.
Metadata stored for every field of an RNTuple.
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:59
Used in RFieldBase::Check() to record field creation failures.
Definition RField.hxx:93
@ kGeneric
Generic unrecoverable error.
@ kUnknownType
The type given to RFieldBase::Create was unknown.
@ kTypeError
The type given to RFieldBase::Create was invalid.
The on-storage metadata of an RNTuple.
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
RColumnDescriptorIterable GetColumnIterable() 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
const_iterator begin() const
const_iterator end() 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:198
@ 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:2973
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:586
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:578
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)
ERNTupleSerializationMode GetRNTupleSerializationMode(TClass *cl)
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.
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().
Used in the return value of the Check() method.