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/BitUtils.hxx>
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 }
51 ~CreateContextGuard()
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
80 ROOT::NTupleSize_t firstEntry)
81{
82 field.ConnectPageSink(sink, firstEntry);
83}
92
94ROOT::Internal::CallFieldBaseCreate(const std::string &fieldName, const std::string &typeName,
95 const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc,
97{
98 return RFieldBase::Create(fieldName, typeName, options, desc, fieldId);
99}
100
101//------------------------------------------------------------------------------
102
104{
105 operator delete(objPtr, std::align_val_t(fAlignment));
106}
107
108//------------------------------------------------------------------------------
109
111{
112 // A single representations with an empty set of columns
113 fSerializationTypes.emplace_back(ColumnRepresentation_t());
114 fDeserializationTypes.emplace_back(ColumnRepresentation_t());
115}
116
118 const Selection_t &deserializationExtraTypes)
119 : fSerializationTypes(serializationTypes), fDeserializationTypes(serializationTypes)
120{
121 fDeserializationTypes.insert(fDeserializationTypes.end(), deserializationExtraTypes.begin(),
122 deserializationExtraTypes.end());
123}
124
125//------------------------------------------------------------------------------
126
128{
129 // Set fObjPtr to an aliased shared_ptr of the input raw pointer. Note that
130 // fObjPtr will be non-empty but have use count zero.
131 fObjPtr = ROOT::Internal::MakeAliasedSharedPtr(rawPtr);
132}
133
134//------------------------------------------------------------------------------
135
137 : fField(other.fField),
138 fValueSize(other.fValueSize),
139 fCapacity(other.fCapacity),
140 fSize(other.fSize),
141 fIsAdopted(other.fIsAdopted),
142 fNValidValues(other.fNValidValues),
143 fFirstIndex(other.fFirstIndex)
144{
145 std::swap(fDeleter, other.fDeleter);
146 std::swap(fValues, other.fValues);
147 std::swap(fMaskAvail, other.fMaskAvail);
148}
149
151{
152 std::swap(fField, other.fField);
153 std::swap(fDeleter, other.fDeleter);
154 std::swap(fValues, other.fValues);
155 std::swap(fValueSize, other.fValueSize);
156 std::swap(fCapacity, other.fCapacity);
157 std::swap(fSize, other.fSize);
158 std::swap(fIsAdopted, other.fIsAdopted);
159 std::swap(fMaskAvail, other.fMaskAvail);
160 std::swap(fNValidValues, other.fNValidValues);
161 std::swap(fFirstIndex, other.fFirstIndex);
162 return *this;
163}
164
166{
167 if (fValues)
168 ReleaseValues();
169}
170
172{
173 if (fIsAdopted)
174 return;
175
176 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyDestructible)) {
177 for (std::size_t i = 0; i < fCapacity; ++i) {
178 fDeleter->operator()(GetValuePtrAt(i), true /* dtorOnly */);
179 }
180 }
181
182 operator delete(fValues, std::align_val_t(fField->GetAlignment()));
183}
184
186{
187 if (fCapacity < size) {
188 if (fIsAdopted) {
189 throw RException(R__FAIL("invalid attempt to bulk read beyond the adopted buffer"));
190 }
191 ReleaseValues();
192 fValues = operator new(size * fValueSize, std::align_val_t(fField->GetAlignment()));
193
194 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyConstructible)) {
195 for (std::size_t i = 0; i < size; ++i) {
196 fField->ConstructValue(GetValuePtrAt(i));
197 }
198 }
199
200 fMaskAvail = std::make_unique<bool[]>(size);
201 fCapacity = size;
202 }
203
204 std::fill(fMaskAvail.get(), fMaskAvail.get() + size, false);
205 fNValidValues = 0;
206
207 fFirstIndex = firstIndex;
208 fSize = size;
209}
210
212{
213 ReleaseValues();
214 fValues = buf;
215 fCapacity = capacity;
216 fSize = capacity;
217
218 fMaskAvail = std::make_unique<bool[]>(capacity);
219
220 fFirstIndex = RNTupleLocalIndex();
221
222 fIsAdopted = true;
223}
224
225//------------------------------------------------------------------------------
226
228{
229 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "possibly leaking object from RField<T>::CreateObject<void>";
230}
231
232template <>
233std::unique_ptr<void, typename ROOT::RFieldBase::RCreateObjectDeleter<void>::deleter>
234ROOT::RFieldBase::CreateObject<void>() const
235{
237 return std::unique_ptr<void, RCreateObjectDeleter<void>::deleter>(CreateObjectRawPtr(), gDeleter);
238}
239
240//------------------------------------------------------------------------------
241
242ROOT::RFieldBase::RFieldBase(std::string_view name, std::string_view type, ROOT::ENTupleStructure structure,
243 bool isSimple, std::size_t nRepetitions)
244 : fName(name),
245 fType(type),
246 fStructure(structure),
247 fNRepetitions(nRepetitions),
248 fIsSimple(isSimple),
249 fParent(nullptr),
250 fPrincipalColumn(nullptr),
251 fTraits(isSimple ? kTraitMappable : 0)
252{
254}
255
257{
258 std::string result = GetFieldName();
259 auto parent = GetParent();
260 while (parent && !parent->GetFieldName().empty()) {
261 result = parent->GetFieldName() + "." + result;
262 parent = parent->GetParent();
263 }
264 return result;
265}
266
268ROOT::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
269{
270 return R__FORWARD_RESULT(
272}
273
274std::vector<ROOT::RFieldBase::RCheckResult>
275ROOT::RFieldBase::Check(const std::string &fieldName, const std::string &typeName)
276{
277 RFieldZero fieldZero;
279 cfOpts.SetReturnInvalidOnError(true);
280 cfOpts.SetEmulateUnknownTypes(false);
281 fieldZero.Attach(RFieldBase::Create(fieldName, typeName, cfOpts, nullptr, kInvalidDescriptorId).Unwrap());
282
283 std::vector<RCheckResult> result;
284 for (const auto &f : fieldZero) {
285 const bool isInvalidField = f.GetTraits() & RFieldBase::kTraitInvalidField;
286 if (!isInvalidField)
287 continue;
288
289 const auto &invalidField = static_cast<const RInvalidField &>(f);
290 result.emplace_back(
291 RCheckResult{invalidField.GetQualifiedFieldName(), invalidField.GetTypeName(), invalidField.GetError()});
292 }
293 return result;
294}
295
297ROOT::RFieldBase::Create(const std::string &fieldName, const std::string &typeName,
298 const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc,
299 ROOT::DescriptorId_t fieldId)
300{
303
304 const auto resolvedType = ROOT::Internal::GetCanonicalTypePrefix(TClassEdit::ResolveTypedef(typeName.c_str()));
305
306 thread_local CreateContext createContext;
307 CreateContextGuard createContextGuard(createContext);
308 if (options.GetReturnInvalidOnError())
309 createContextGuard.SetContinueOnError(true);
310
311 auto fnFail = [&fieldName,
312 &resolvedType](const std::string &errMsg,
314 RInvalidField::ECategory::kTypeError) -> RResult<std::unique_ptr<RFieldBase>> {
315 if (createContext.GetContinueOnError()) {
316 return std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, resolvedType, errMsg, cat));
317 } else {
318 return R__FAIL(errMsg);
319 }
320 };
321
322 if (resolvedType.empty())
323 return R__FORWARD_RESULT(fnFail("no type name specified for field '" + fieldName + "'"));
324
325 std::unique_ptr<ROOT::RFieldBase> result;
326
327 const auto maybeGetChildId = [desc, fieldId](int childId) {
328 if (desc) {
329 const auto &fieldDesc = desc->GetFieldDescriptor(fieldId);
330 return fieldDesc.GetLinkIds().at(childId);
331 } else {
333 }
334 };
335
336 // try-catch block to intercept any exception that may be thrown by Unwrap() so that this
337 // function never throws but returns RResult::Error instead.
338 try {
339 if (resolvedType == "bool") {
340 result = std::make_unique<RField<bool>>(fieldName);
341 } else if (resolvedType == "char") {
342 result = std::make_unique<RField<char>>(fieldName);
343 } else if (resolvedType == "std::byte") {
344 result = std::make_unique<RField<std::byte>>(fieldName);
345 } else if (resolvedType == "std::int8_t") {
346 result = std::make_unique<RField<std::int8_t>>(fieldName);
347 } else if (resolvedType == "std::uint8_t") {
348 result = std::make_unique<RField<std::uint8_t>>(fieldName);
349 } else if (resolvedType == "std::int16_t") {
350 result = std::make_unique<RField<std::int16_t>>(fieldName);
351 } else if (resolvedType == "std::uint16_t") {
352 result = std::make_unique<RField<std::uint16_t>>(fieldName);
353 } else if (resolvedType == "std::int32_t") {
354 result = std::make_unique<RField<std::int32_t>>(fieldName);
355 } else if (resolvedType == "std::uint32_t") {
356 result = std::make_unique<RField<std::uint32_t>>(fieldName);
357 } else if (resolvedType == "std::int64_t") {
358 result = std::make_unique<RField<std::int64_t>>(fieldName);
359 } else if (resolvedType == "std::uint64_t") {
360 result = std::make_unique<RField<std::uint64_t>>(fieldName);
361 } else if (resolvedType == "float") {
362 result = std::make_unique<RField<float>>(fieldName);
363 } else if (resolvedType == "double") {
364 result = std::make_unique<RField<double>>(fieldName);
365 } else if (resolvedType == "Double32_t") {
366 result = std::make_unique<RField<double>>(fieldName);
367 static_cast<RField<double> *>(result.get())->SetDouble32();
368 // Prevent the type alias from being reset by returning early
369 return result;
370 } else if (resolvedType == "std::string") {
371 result = std::make_unique<RField<std::string>>(fieldName);
372 } else if (resolvedType == "TObject") {
373 result = std::make_unique<RField<TObject>>(fieldName);
374 } else if (resolvedType == "std::vector<bool>") {
375 result = std::make_unique<RField<std::vector<bool>>>(fieldName);
376 } else if (resolvedType.substr(0, 12) == "std::vector<") {
377 std::string itemTypeName = resolvedType.substr(12, resolvedType.length() - 13);
378 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0));
379 result = std::make_unique<RVectorField>(fieldName, itemField.Unwrap());
380 } else if (resolvedType.substr(0, 19) == "ROOT::VecOps::RVec<") {
381 std::string itemTypeName = resolvedType.substr(19, resolvedType.length() - 20);
382 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0));
383 result = std::make_unique<RRVecField>(fieldName, itemField.Unwrap());
384 } else if (resolvedType.substr(0, 11) == "std::array<") {
385 auto arrayDef = TokenizeTypeList(resolvedType.substr(11, resolvedType.length() - 12));
386 if (arrayDef.size() != 2) {
387 return R__FORWARD_RESULT(fnFail("the template list for std::array must have exactly two elements"));
388 }
389 auto arrayLength = ParseUIntTypeToken(arrayDef[1]);
390 auto itemField = Create("_0", arrayDef[0], options, desc, maybeGetChildId(0));
391 result = std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arrayLength);
392 } else if (resolvedType.substr(0, 13) == "std::variant<") {
393 auto innerTypes = TokenizeTypeList(resolvedType.substr(13, resolvedType.length() - 14));
394 std::vector<std::unique_ptr<RFieldBase>> items;
395 items.reserve(innerTypes.size());
396 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
397 items.emplace_back(
398 Create("_" + std::to_string(i), innerTypes[i], options, desc, maybeGetChildId(i)).Unwrap());
399 }
400 result = std::make_unique<RVariantField>(fieldName, std::move(items));
401 } else if (resolvedType.substr(0, 10) == "std::pair<") {
402 auto innerTypes = TokenizeTypeList(resolvedType.substr(10, resolvedType.length() - 11));
403 if (innerTypes.size() != 2) {
404 return R__FORWARD_RESULT(fnFail("the type list for std::pair must have exactly two elements"));
405 }
406 std::array<std::unique_ptr<RFieldBase>, 2> items{
407 Create("_0", innerTypes[0], options, desc, maybeGetChildId(0)).Unwrap(),
408 Create("_1", innerTypes[1], options, desc, maybeGetChildId(1)).Unwrap()};
409 result = std::make_unique<RPairField>(fieldName, std::move(items));
410 } else if (resolvedType.substr(0, 11) == "std::tuple<") {
411 auto innerTypes = TokenizeTypeList(resolvedType.substr(11, resolvedType.length() - 12));
412 std::vector<std::unique_ptr<RFieldBase>> items;
413 items.reserve(innerTypes.size());
414 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
415 items.emplace_back(
416 Create("_" + std::to_string(i), innerTypes[i], options, desc, maybeGetChildId(i)).Unwrap());
417 }
418 result = std::make_unique<RTupleField>(fieldName, std::move(items));
419 } else if (resolvedType.substr(0, 12) == "std::bitset<") {
420 auto size = ParseUIntTypeToken(resolvedType.substr(12, resolvedType.length() - 13));
421 result = std::make_unique<RBitsetField>(fieldName, size);
422 } else if (resolvedType.substr(0, 16) == "std::unique_ptr<") {
423 std::string itemTypeName = resolvedType.substr(16, resolvedType.length() - 17);
424 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
425 result = std::make_unique<RUniquePtrField>(fieldName, std::move(itemField));
426 } else if (resolvedType.substr(0, 14) == "std::optional<") {
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<ROptionalField>(fieldName, std::move(itemField));
430 } else if (resolvedType.substr(0, 9) == "std::set<") {
431 std::string itemTypeName = resolvedType.substr(9, resolvedType.length() - 10);
432 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
433 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kSet, std::move(itemField));
434 } else if (resolvedType.substr(0, 19) == "std::unordered_set<") {
435 std::string itemTypeName = resolvedType.substr(19, resolvedType.length() - 20);
436 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
437 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kUnorderedSet, std::move(itemField));
438 } else if (resolvedType.substr(0, 14) == "std::multiset<") {
439 std::string itemTypeName = resolvedType.substr(14, resolvedType.length() - 15);
440 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
441 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kMultiSet, std::move(itemField));
442 } else if (resolvedType.substr(0, 24) == "std::unordered_multiset<") {
443 std::string itemTypeName = resolvedType.substr(24, resolvedType.length() - 25);
444 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
445 result = std::make_unique<RSetField>(fieldName, RSetField::ESetType::kUnorderedMultiSet, std::move(itemField));
446 } else if (resolvedType.substr(0, 9) == "std::map<") {
447 auto innerTypes = TokenizeTypeList(resolvedType.substr(9, resolvedType.length() - 10));
448 if (innerTypes.size() != 2) {
449 return R__FORWARD_RESULT(fnFail("the type list for std::map must have exactly two elements"));
450 }
451 auto itemField =
452 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
453 .Unwrap();
454 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kMap, std::move(itemField));
455 } else if (resolvedType.substr(0, 19) == "std::unordered_map<") {
456 auto innerTypes = TokenizeTypeList(resolvedType.substr(19, resolvedType.length() - 20));
457 if (innerTypes.size() != 2)
458 return R__FORWARD_RESULT(fnFail("the type list for std::unordered_map must have exactly two elements"));
459 auto itemField =
460 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
461 .Unwrap();
462 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kUnorderedMap, std::move(itemField));
463 } else if (resolvedType.substr(0, 14) == "std::multimap<") {
464 auto innerTypes = TokenizeTypeList(resolvedType.substr(14, resolvedType.length() - 15));
465 if (innerTypes.size() != 2)
466 return R__FORWARD_RESULT(fnFail("the type list for std::multimap must have exactly two elements"));
467 auto itemField =
468 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
469 .Unwrap();
470 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kMultiMap, std::move(itemField));
471 } else if (resolvedType.substr(0, 24) == "std::unordered_multimap<") {
472 auto innerTypes = TokenizeTypeList(resolvedType.substr(24, resolvedType.length() - 25));
473 if (innerTypes.size() != 2)
474 return R__FORWARD_RESULT(
475 fnFail("the type list for std::unordered_multimap must have exactly two elements"));
476 auto itemField =
477 Create("_0", "std::pair<" + innerTypes[0] + "," + innerTypes[1] + ">", options, desc, maybeGetChildId(0))
478 .Unwrap();
479 result = std::make_unique<RMapField>(fieldName, RMapField::EMapType::kUnorderedMultiMap, std::move(itemField));
480 } else if (resolvedType.substr(0, 12) == "std::atomic<") {
481 std::string itemTypeName = resolvedType.substr(12, resolvedType.length() - 13);
482 auto itemField = Create("_0", itemTypeName, options, desc, maybeGetChildId(0)).Unwrap();
483 result = std::make_unique<RAtomicField>(fieldName, std::move(itemField));
484 } else if (resolvedType.substr(0, 25) == "ROOT::RNTupleCardinality<") {
485 auto innerTypes = TokenizeTypeList(resolvedType.substr(25, resolvedType.length() - 26));
486 if (innerTypes.size() != 1)
487 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + resolvedType));
488 const auto canonicalInnerType = ROOT::Internal::GetCanonicalTypePrefix(innerTypes[0]);
489 if (canonicalInnerType == "std::uint32_t") {
490 result = std::make_unique<RField<RNTupleCardinality<std::uint32_t>>>(fieldName);
491 } else if (canonicalInnerType == "std::uint64_t") {
492 result = std::make_unique<RField<RNTupleCardinality<std::uint64_t>>>(fieldName);
493 } else {
494 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + resolvedType));
495 }
496 }
497
498 if (!result) {
499 auto cl = TClass::GetClass(typeName.c_str());
500
501 if (cl && cl->GetState() > TClass::kForwardDeclared) {
502 createContextGuard.AddClassToStack(resolvedType);
503 if (cl->GetCollectionProxy()) {
504 result = std::make_unique<RProxiedCollectionField>(fieldName, typeName);
505 }
506 // NOTE: if the class is not at least "Interpreted" we currently don't try to construct
507 // the RClassField, as in that case we'd need to fetch the information from the StreamerInfo
508 // rather than from TClass. This might be desirable in the future, but for now in this
509 // situation we rely on field emulation instead.
510 else if (cl->GetState() >= TClass::kInterpreted) {
511 if (!ROOT::Internal::GetRNTupleSoARecord(cl).empty()) {
512 result = std::make_unique<RSoAField>(fieldName, typeName);
515 result = std::make_unique<RStreamerField>(fieldName, typeName);
516 } else {
517 result = std::make_unique<RClassField>(fieldName, typeName);
518 }
519 }
520 }
521 }
522
523 if (!result) {
524 auto e = TEnum::GetEnum(resolvedType.c_str());
525 if (e != nullptr) {
526 result = std::make_unique<REnumField>(fieldName, typeName);
527 }
528 }
529
530 // If we get here then we failed to meet all the conditions to create a "properly typed" field.
531 // Resort to field emulation if the user asked us to.
532 if (!result && options.GetEmulateUnknownTypes()) {
533 assert(desc);
534 const auto &fieldDesc = desc->GetFieldDescriptor(fieldId);
535 if (fieldDesc.GetStructure() == ENTupleStructure::kStreamer) {
536 auto streamerField = std::unique_ptr<RFieldBase>(new RStreamerField(fieldName, typeName));
537 streamerField->fTypeAlias = fieldDesc.GetTypeAlias();
538 return streamerField;
539 } else if (fieldDesc.GetStructure() == ENTupleStructure::kRecord) {
540 std::vector<std::unique_ptr<RFieldBase>> memberFields;
541 memberFields.reserve(fieldDesc.GetLinkIds().size());
542 for (auto id : fieldDesc.GetLinkIds()) {
543 const auto &memberDesc = desc->GetFieldDescriptor(id);
544 auto field = Create(memberDesc.GetFieldName(), memberDesc.GetTypeName(), options, desc, id).Unwrap();
545 memberFields.emplace_back(std::move(field));
546 }
547 R__ASSERT(typeName == fieldDesc.GetTypeName());
548 auto recordField = Internal::CreateEmulatedRecordField(fieldName, std::move(memberFields), fieldDesc);
549 recordField->fTypeAlias = fieldDesc.GetTypeAlias();
550 return recordField;
551 } else if (fieldDesc.GetStructure() == ENTupleStructure::kCollection) {
552 if (fieldDesc.GetLinkIds().size() != 1)
553 throw ROOT::RException(R__FAIL("invalid structure for collection field " + fieldName));
554
555 auto itemFieldId = fieldDesc.GetLinkIds()[0];
556 const auto &itemFieldDesc = desc->GetFieldDescriptor(itemFieldId);
557 auto itemField =
558 Create(itemFieldDesc.GetFieldName(), itemFieldDesc.GetTypeName(), options, desc, itemFieldId).Unwrap();
559 auto vecField = ROOT::Internal::CreateEmulatedVectorField(fieldName, std::move(itemField), fieldDesc);
560 vecField->fTypeAlias = fieldDesc.GetTypeAlias();
561 return vecField;
562 } else if (ROOT::Internal::IsCustomEnumFieldDesc(*desc, fieldDesc)) {
563 R__ASSERT(!fieldDesc.GetLinkIds().empty());
564 auto underlyingIntFieldId = fieldDesc.GetLinkIds()[0];
565 const auto &underlyingIntFieldDesc = desc->GetFieldDescriptor(underlyingIntFieldId);
566 auto enumField = ROOT::Internal::CreateEmulatedEnumField(fieldName, fieldDesc.GetTypeName(),
567 underlyingIntFieldDesc.GetTypeName());
568 enumField->fTypeAlias = fieldDesc.GetTypeAlias();
569 return enumField;
570 }
571 }
572 } catch (const RException &e) {
573 auto error = e.GetError();
574 if (createContext.GetContinueOnError()) {
575 return std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, typeName, error.GetReport(),
577 } else {
578 return error;
579 }
580 } catch (const std::logic_error &e) {
581 // Integer parsing error
582 if (createContext.GetContinueOnError()) {
583 return std::unique_ptr<RFieldBase>(
584 std::make_unique<RInvalidField>(fieldName, typeName, e.what(), RInvalidField::ECategory::kGeneric));
585 } else {
586 return R__FAIL(e.what());
587 }
588 }
589
590 if (result) {
591 const auto normOrigType = ROOT::Internal::GetNormalizedUnresolvedTypeName(typeName);
592 if (normOrigType != result->GetTypeName()) {
593 result->fTypeAlias = normOrigType;
594 }
595 return result;
596 }
597 return R__FORWARD_RESULT(fnFail("unknown type: " + typeName, RInvalidField::ECategory::kUnknownType));
598}
599
601{
602 static RColumnRepresentations representations;
603 return representations;
604}
605
606std::unique_ptr<ROOT::RFieldBase> ROOT::RFieldBase::Clone(std::string_view newName) const
607{
608 auto clone = CloneImpl(newName);
609 clone->fTypeAlias = fTypeAlias;
610 clone->fOnDiskId = fOnDiskId;
611 clone->fDescription = fDescription;
612 // We can just copy the references because fColumnRepresentatives point into a static structure
613 clone->fColumnRepresentatives = fColumnRepresentatives;
614 return clone;
615}
616
617std::size_t ROOT::RFieldBase::AppendImpl(const void * /* from */)
618{
619 R__ASSERT(false && "A non-simple RField must implement its own AppendImpl");
620 return 0;
621}
622
624{
625 R__ASSERT(false);
626}
627
629{
630 ReadGlobalImpl(fPrincipalColumn->GetGlobalIndex(localIndex), to);
631}
632
633std::size_t ROOT::RFieldBase::ReadBulkImpl(const RBulkSpec &bulkSpec)
634{
635 const auto valueSize = GetValueSize();
636 std::size_t nRead = 0;
637 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
638 // Value not needed
639 if (bulkSpec.fMaskReq && !bulkSpec.fMaskReq[i])
640 continue;
641
642 // Value already present
643 if (bulkSpec.fMaskAvail[i])
644 continue;
645
646 Read(bulkSpec.fFirstIndex + i, reinterpret_cast<unsigned char *>(bulkSpec.fValues) + i * valueSize);
647 bulkSpec.fMaskAvail[i] = true;
648 nRead++;
649 }
650 return nRead;
651}
652
654{
655 const auto align = GetAlignment();
656 void *where;
657 if (align <= sizeof(std::max_align_t)) {
658 // We use the normal operator new for regularly aligned types to not complicate the user code that
659 // deletes objects returned by CreateObject()
660 where = operator new(GetValueSize());
661 } else {
662 where = operator new(GetValueSize(), std::align_val_t(GetAlignment()));
663 }
664 R__ASSERT(where != nullptr);
665 ConstructValue(where);
666 return where;
667}
668
670{
671 void *obj = CreateObjectRawPtr();
672 return RValue(this, std::shared_ptr<void>(obj, RSharedPtrDeleter(GetDeleter())));
673}
674
675std::vector<ROOT::RFieldBase::RValue> ROOT::RFieldBase::SplitValue(const RValue & /*value*/) const
676{
677 return std::vector<RValue>();
678}
679
680void ROOT::RFieldBase::Attach(std::unique_ptr<ROOT::RFieldBase> child, std::string_view expectedChildName)
681{
682 // Note that technically the zero field would not need to have the extensible trait: because only its sub fields
683 // get connected by RPageSink::UpdateSchema, it does not change its initial state.
684 if (!(fTraits & kTraitExtensible) && (fState != EState::kUnconnected))
685 throw RException(R__FAIL("invalid attempt to attach subfield to already connected, non-extensible field"));
686
687 if (!expectedChildName.empty() && child->GetFieldName() != expectedChildName) {
688 throw RException(R__FAIL(std::string("invalid subfield name: ") + child->GetFieldName() +
689 " expected: " + std::string(expectedChildName)));
690 }
691
692 child->fParent = this;
693 fSubfields.emplace_back(std::move(child));
694}
695
697{
698 ROOT::NTupleSize_t result = globalIndex;
699 for (auto f = this; f != nullptr; f = f->GetParent()) {
700 auto parent = f->GetParent();
701 if (parent && (parent->GetStructure() == ROOT::ENTupleStructure::kCollection ||
702 parent->GetStructure() == ROOT::ENTupleStructure::kVariant)) {
703 return 0U;
704 }
705 result *= std::max<ROOT::NTupleSize_t>(f->GetNRepetitions(), ROOT::NTupleSize_t{1U});
706 }
707 return result;
708}
709
710std::vector<ROOT::RFieldBase *> ROOT::RFieldBase::GetMutableSubfields()
711{
712 std::vector<RFieldBase *> result;
713 result.reserve(fSubfields.size());
714 for (const auto &f : fSubfields) {
715 result.emplace_back(f.get());
716 }
717 return result;
718}
719
720std::vector<const ROOT::RFieldBase *> ROOT::RFieldBase::GetConstSubfields() const
721{
722 std::vector<const RFieldBase *> result;
723 result.reserve(fSubfields.size());
724 for (const auto &f : fSubfields) {
725 result.emplace_back(f.get());
726 }
727 return result;
728}
729
731{
732 if (!fAvailableColumns.empty()) {
733 const auto activeRepresentationIndex = fPrincipalColumn->GetRepresentationIndex();
734 for (auto &column : fAvailableColumns) {
735 if (column->GetRepresentationIndex() == activeRepresentationIndex) {
736 column->Flush();
737 }
738 }
739 }
740}
741
743{
744 if (!fAvailableColumns.empty()) {
745 const auto activeRepresentationIndex = fPrincipalColumn->GetRepresentationIndex();
746 for (auto &column : fAvailableColumns) {
747 if (column->GetRepresentationIndex() == activeRepresentationIndex) {
748 column->Flush();
749 } else {
750 column->CommitSuppressed();
751 }
752 }
753 }
754 CommitClusterImpl();
755}
756
757void ROOT::RFieldBase::SetDescription(std::string_view description)
758{
759 if (fState != EState::kUnconnected)
760 throw RException(R__FAIL("cannot set field description once field is connected"));
761 fDescription = std::string(description);
762}
763
765{
766 if (fState != EState::kUnconnected)
767 throw RException(R__FAIL("cannot set field ID once field is connected"));
768 fOnDiskId = id;
769}
770
771/// Write the given value into columns. The value object has to be of the same type as the field.
772/// Returns the number of uncompressed bytes written.
773std::size_t ROOT::RFieldBase::Append(const void *from)
774{
775 if (~fTraits & kTraitMappable)
776 return AppendImpl(from);
777
778 fPrincipalColumn->Append(from);
779 return fPrincipalColumn->GetElement()->GetPackedSize();
780}
781
786
788{
789 return RValue(this, std::move(objPtr));
790}
791
792std::size_t ROOT::RFieldBase::ReadBulk(const RBulkSpec &bulkSpec)
793{
794 if (fIsSimple) {
795 /// For simple types, ignore the mask and memcopy the values into the destination
796 fPrincipalColumn->ReadV(bulkSpec.fFirstIndex, bulkSpec.fCount, bulkSpec.fValues);
797 std::fill(bulkSpec.fMaskAvail, bulkSpec.fMaskAvail + bulkSpec.fCount, true);
798 return RBulkSpec::kAllSet;
799 }
800
801 if (fIsArtificial || !fReadCallbacks.empty()) {
802 // Fields with schema evolution treatment must not go through an optimized read
803 return RFieldBase::ReadBulkImpl(bulkSpec);
804 }
805
806 return ReadBulkImpl(bulkSpec);
807}
808
810{
811 return fSubfields.empty() ? RSchemaIterator(this, -1) : RSchemaIterator(fSubfields[0].get(), 0);
812}
813
818
820{
821 return fSubfields.empty() ? RConstSchemaIterator(this, -1) : RConstSchemaIterator(fSubfields[0].get(), 0);
822}
823
828
830{
831 return fSubfields.empty() ? RConstSchemaIterator(this, -1) : RConstSchemaIterator(fSubfields[0].get(), 0);
832}
833
838
840{
841 if (fColumnRepresentatives.empty()) {
842 return {GetColumnRepresentations().GetSerializationDefault()};
843 }
844
846 result.reserve(fColumnRepresentatives.size());
847 for (const auto &r : fColumnRepresentatives) {
848 result.emplace_back(r.get());
849 }
850 return result;
851}
852
854{
855 if (fState != EState::kUnconnected)
856 throw RException(R__FAIL("cannot set column representative once field is connected"));
857 const auto &validTypes = GetColumnRepresentations().GetSerializationTypes();
858 fColumnRepresentatives.clear();
859 fColumnRepresentatives.reserve(representatives.size());
860 for (const auto &r : representatives) {
861 auto itRepresentative = std::find(validTypes.begin(), validTypes.end(), r);
862 if (itRepresentative == std::end(validTypes))
863 throw RException(R__FAIL("invalid column representative"));
864
865 fColumnRepresentatives.emplace_back(*itRepresentative);
866 }
867}
868
871 std::uint16_t representationIndex) const
872{
873 static const ColumnRepresentation_t kEmpty;
874
875 if (fOnDiskId == ROOT::kInvalidDescriptorId)
876 throw RException(R__FAIL("No on-disk field information for `" + GetQualifiedFieldName() + "`"));
877
878 ColumnRepresentation_t onDiskTypes;
879 for (const auto &c : desc.GetColumnIterable(fOnDiskId)) {
880 if (c.GetRepresentationIndex() == representationIndex)
881 onDiskTypes.emplace_back(c.GetType());
882 }
883 if (onDiskTypes.empty()) {
884 if (representationIndex == 0) {
885 throw RException(R__FAIL("No on-disk column information for field `" + GetQualifiedFieldName() + "`"));
886 }
887 return kEmpty;
888 }
889
890 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
891 if (t == onDiskTypes)
892 return t;
893 }
894
895 std::string columnTypeNames;
896 for (const auto &t : onDiskTypes) {
897 if (!columnTypeNames.empty())
898 columnTypeNames += ", ";
899 columnTypeNames += std::string("`") + ROOT::Internal::RColumnElementBase::GetColumnTypeName(t) + "`";
900 }
901 throw RException(R__FAIL("On-disk column types {" + columnTypeNames + "} for field `" + GetQualifiedFieldName() +
902 "` cannot be matched to its in-memory type `" + GetTypeName() + "` " +
903 "(representation index: " + std::to_string(representationIndex) + ")"));
904}
905
907{
908 fReadCallbacks.push_back(func);
909 fIsSimple = false;
910 return fReadCallbacks.size() - 1;
911}
912
914{
915 fReadCallbacks.erase(fReadCallbacks.begin() + idx);
916 fIsSimple = (fTraits & kTraitMappable) && !fIsArtificial && fReadCallbacks.empty();
917}
918
920{
921 // Sampled upfront: the block below sets representatives, which would clear the "default" state.
922 const bool hadDefaultRepresentative = HasDefaultColumnRepresentative();
923 if ((options.GetCompression() == 0) && hadDefaultRepresentative) {
924 ColumnRepresentation_t rep = GetColumnRepresentations().GetSerializationDefault();
925 for (auto &colType : rep) {
926 switch (colType) {
937 default: break;
938 }
939 }
940 SetColumnRepresentatives({rep});
941 }
942
943 // Only adjust Double32_t when the user did not pin a representation: an explicit representative must
944 // survive (see RNTupleMerger::ExtendDestinationModel), otherwise merging would silently reinterpret the
945 // raw copies of the source pages under a different encoding.
946 if ((fTypeAlias == "Double32_t") && hadDefaultRepresentative) {
947 if (options.GetCompression() != 0)
948 SetColumnRepresentatives({{ROOT::ENTupleColumnType::kSplitReal32}});
949 else
950 SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal32}});
951 }
952
953 // An explicit representation pinned on a Double32_t field must contain a reduced-precision encoding:
954 // a 64-bit-only selection would store full doubles while the field promises Double32_t precision.
955 // A multi-column selection that also includes a reduced-precision representative stays legal.
956 if ((fTypeAlias == "Double32_t") && !hadDefaultRepresentative) {
957 bool hasSubDoubleRep = false;
958 for (const auto &rep : GetColumnRepresentatives()) {
959 for (const auto colType : rep) {
961 hasSubDoubleRep = true;
962 break;
963 }
964 }
965 if (hasSubDoubleRep)
966 break;
967 }
968 if (!hasSubDoubleRep) {
969 throw RException(R__FAIL("explicit column representations of Double32_t field `" + GetFieldName() +
970 "` must include a reduced-precision representation"));
971 }
972 }
973}
974
976{
977 if (dynamic_cast<ROOT::RFieldZero *>(this))
978 throw RException(R__FAIL("invalid attempt to connect zero field to page sink"));
979 if (fState != EState::kUnconnected)
980 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page sink"));
981
982 AutoAdjustColumnTypes(pageSink.GetWriteOptions());
983
984 GenerateColumns();
985 for (auto &column : fAvailableColumns) {
986 // Only the first column of every representation can be a deferred column. In all column representations,
987 // larger column indexes are data columns of collections (string, streamer) and thus
988 // they have no elements on late model extension
989 auto firstElementIndex = (column->GetIndex() == 0) ? EntryToColumnElementIndex(firstEntry) : 0;
990 column->ConnectPageSink(fOnDiskId, pageSink, firstElementIndex);
991 }
992
993 if (HasExtraTypeInfo()) {
995 [this](ROOT::Internal::RPageSink &sink) { sink.UpdateExtraTypeInfo(GetExtraTypeInfo()); });
996 }
997
998 fState = EState::kConnectedToSink;
999}
1000
1002{
1003 if (dynamic_cast<ROOT::RFieldZero *>(this)) {
1004 for (auto &f : fSubfields)
1005 f->ConnectPageSource(pageSource);
1006 return;
1007 }
1008
1009 if (fState != EState::kUnconnected)
1010 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page source"));
1011
1012 if (!fColumnRepresentatives.empty())
1013 throw RException(R__FAIL("fixed column representative only valid when connecting to a page sink"));
1014 if (!fDescription.empty())
1015 throw RException(R__FAIL("setting description only valid when connecting to a page sink"));
1016
1017 if (!fIsArtificial) {
1018 R__ASSERT(fOnDiskId != kInvalidDescriptorId);
1019 // Handle moving from on-disk std::atomic<T> to (compatible of) T in memory centrally because otherwise
1020 // we would need to handle it in each and every ReconcileOnDiskField()
1021 // Note that we have to do this before calling BeforeConnectPageSource(), which already may compare the field
1022 // to its on-disk description.
1023 auto descGuard = pageSource.GetSharedDescriptorGuard();
1024 if (!dynamic_cast<RAtomicField *>(this) &&
1025 Internal::IsStdAtomicFieldDesc(descGuard->GetFieldDescriptor(GetOnDiskId()))) {
1026 SetOnDiskId(descGuard->GetFieldDescriptor(GetOnDiskId()).GetLinkIds()[0]);
1027 }
1028 }
1029
1030 auto substitute = BeforeConnectPageSource(pageSource);
1031 if (substitute) {
1032 const RFieldBase *itr = this;
1033 while (itr->GetParent()) {
1034 itr = itr->GetParent();
1035 }
1036 if (typeid(*itr) == typeid(RFieldZero) && static_cast<const RFieldZero *>(itr)->GetAllowFieldSubstitutions()) {
1037 for (auto &f : fParent->fSubfields) {
1038 if (f.get() != this)
1039 continue;
1040
1041 f = std::move(substitute);
1042 f->ConnectPageSource(pageSource);
1043 return;
1044 }
1045 R__ASSERT(false); // never here
1046 } else {
1047 throw RException(R__FAIL("invalid attempt to substitute field " + GetQualifiedFieldName()));
1048 }
1049 }
1050
1051 if (!fIsArtificial) {
1052 auto descGuard = pageSource.GetSharedDescriptorGuard();
1053 ReconcileOnDiskField(descGuard.GetConstRef());
1054 }
1055
1056 for (auto &f : fSubfields) {
1057 if (f->GetOnDiskId() == ROOT::kInvalidDescriptorId) {
1058 f->SetOnDiskId(pageSource.GetSharedDescriptorGuard()->FindFieldId(f->GetFieldName(), GetOnDiskId()));
1059 }
1060 f->ConnectPageSource(pageSource);
1061 }
1062
1063 // Do not generate columns nor set fColumnRepresentatives for artificial fields.
1064 if (!fIsArtificial) {
1065 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
1066 const ROOT::RNTupleDescriptor &desc = descriptorGuard.GetConstRef();
1067 GenerateColumns(desc);
1068 if (fColumnRepresentatives.empty()) {
1069 // If we didn't get columns from the descriptor, ensure that we actually expect a field without columns
1070 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
1071 if (t.empty()) {
1072 fColumnRepresentatives = {t};
1073 break;
1074 }
1075 }
1076 }
1077 R__ASSERT(!fColumnRepresentatives.empty());
1078 if (fOnDiskId != ROOT::kInvalidDescriptorId) {
1079 const auto &fieldDesc = desc.GetFieldDescriptor(fOnDiskId);
1080 fOnDiskTypeVersion = fieldDesc.GetTypeVersion();
1081 if (fieldDesc.GetTypeChecksum().has_value())
1082 fOnDiskTypeChecksum = *fieldDesc.GetTypeChecksum();
1083 }
1084 }
1085 for (auto &column : fAvailableColumns)
1086 column->ConnectPageSource(fOnDiskId, pageSource);
1087
1088 fState = EState::kConnectedToSource;
1089}
1090
1092{
1093 // The default implementation throws an exception if there are any meaningful differences to the on-disk field.
1094 // Derived classes may overwrite this and relax the checks to support automatic schema evolution.
1095 EnsureMatchingOnDiskField(desc).ThrowOnError();
1096}
1097
1099ROOT::RFieldBase::EnsureMatchingOnDiskField(const RNTupleDescriptor &desc, std::uint32_t ignoreBits) const
1100{
1101 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1102 const std::uint32_t diffBits = CompareOnDiskField(fieldDesc, ignoreBits);
1103 if (diffBits == 0)
1104 return RResult<void>::Success();
1105
1106 std::ostringstream errMsg;
1107 errMsg << "in-memory field " << GetQualifiedFieldName() << " of type " << GetTypeName() << " is incompatible "
1108 << "with on-disk field " << fieldDesc.GetFieldName() << ":";
1109 if (diffBits & kDiffFieldVersion) {
1110 errMsg << " field version " << GetFieldVersion() << " vs. " << fieldDesc.GetFieldVersion() << ";";
1111 }
1112 if (diffBits & kDiffTypeVersion) {
1113 errMsg << " type version " << GetTypeVersion() << " vs. " << fieldDesc.GetTypeVersion() << ";";
1114 }
1115 if (diffBits & kDiffStructure) {
1116 errMsg << " structural role " << GetStructure() << " vs. " << fieldDesc.GetStructure() << ";";
1117 }
1118 if (diffBits & kDiffTypeName) {
1119 errMsg << " incompatible on-disk type name " << fieldDesc.GetTypeName() << ";";
1120 }
1121 if (diffBits & kDiffNRepetitions) {
1122 errMsg << " repetition count " << GetNRepetitions() << " vs. " << fieldDesc.GetNRepetitions() << ";";
1123 }
1124 return R__FAIL(errMsg.str() + "\n" + Internal::GetTypeTraceReport(*this, desc));
1125}
1126
1128{
1129 std::uint32_t ignoreBits = kDiffTypeName;
1130 if (desc.GetFieldDescriptor(GetOnDiskId()).IsSoACollection())
1131 ignoreBits |= kDiffTypeVersion;
1132 return EnsureMatchingOnDiskField(desc, ignoreBits);
1133}
1134
1136 const std::vector<std::string> &prefixes) const
1137{
1138 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1139 for (const auto &p : prefixes) {
1140 if (fieldDesc.GetTypeName().rfind(p, 0) == 0)
1141 return RResult<void>::Success();
1142 }
1143 return R__FAIL("incompatible type " + fieldDesc.GetTypeName() + " for field " + GetQualifiedFieldName() + "\n" +
1144 Internal::GetTypeTraceReport(*this, desc));
1145}
1146
1147std::uint32_t ROOT::RFieldBase::CompareOnDiskField(const RFieldDescriptor &fieldDesc, std::uint32_t ignoreBits) const
1148{
1149 std::uint32_t diffBits = 0;
1150 if ((~ignoreBits & kDiffFieldVersion) && (GetFieldVersion() != fieldDesc.GetFieldVersion()))
1151 diffBits |= kDiffFieldVersion;
1152 if ((~ignoreBits & kDiffTypeVersion) && (GetTypeVersion() != fieldDesc.GetTypeVersion()))
1153 diffBits |= kDiffTypeVersion;
1154 if ((~ignoreBits & kDiffStructure) && (GetStructure() != fieldDesc.GetStructure()))
1155 diffBits |= kDiffStructure;
1156 if ((~ignoreBits & kDiffTypeName) && (GetTypeName() != fieldDesc.GetTypeName()))
1157 diffBits |= kDiffTypeName;
1158 if ((~ignoreBits & kDiffNRepetitions) && (GetNRepetitions() != fieldDesc.GetNRepetitions()))
1159 diffBits |= kDiffNRepetitions;
1160
1161 return diffBits;
1162}
1163
1165{
1166 visitor.VisitField(*this);
1167}
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:324
#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:322
#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
std::size_t capacity
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:139
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:142
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.
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.
void RegisterOnCommitDatasetCallback(const Callback_t &cb)
The registered callback is executed at the beginning of CommitDataset();.
Abstract interface to read data from an ntuple.
RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
Template specializations for C++ std::atomic.
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 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.
void DeleteAligned(void *objPtr) const
Iterates over the subtree of fields in depth-first search order.
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 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.
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)
size_t AddReadCallback(const ReadCallback_t &func)
Set a user-defined function to be called after reading a value, giving a chance to inspect and/or mod...
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()
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.
@ 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.
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 > 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)
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),...
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 > EnsureMatchingTypePrefix(const RNTupleDescriptor &desc, const std::vector< std::string > &prefixes) const
Many fields accept a range of type prefixes for schema evolution, e.g.
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.
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:342
Used in RFieldBase::Check() to record field creation failures.
Definition RField.hxx:96
@ 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
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:222
The field for a class using ROOT standard streaming.
Definition RField.hxx:245
@ 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:2999
static TEnum * GetEnum(const std::type_info &ti, ESearchAction sa=kALoadAndInterpLookup)
Definition TEnum.cxx:181
std::unique_ptr< RFieldBase > CreateEmulatedVectorField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, const RFieldDescriptor &emulatedFrom)
Definition RField.cxx:598
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....
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::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::unique_ptr< RFieldBase > CreateEmulatedRecordField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields, const RFieldDescriptor &emulatedFrom)
Definition RField.cxx:590
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 &)
void CallSetArtificialOnField(RFieldBase &)
std::unique_ptr< RFieldBase > CreateEmulatedEnumField(std::string_view fieldName, std::string_view emulatedFromType, std::string_view underlyingIntType)
bool IsCustomEnumFieldDesc(const RNTupleDescriptor &desc, const RFieldDescriptor &fieldDesc)
Tells if the field describes a user-defined enum type.
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().
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.