Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldSequenceContainer.cxx
Go to the documentation of this file.
1/// \file RFieldSequenceContainer.cxx
2/// \ingroup NTuple
3/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
4/// \date 2024-11-19
5
6#include <ROOT/RField.hxx>
7#include <ROOT/RFieldBase.hxx>
10
11#include <cstdlib> // for malloc, free
12#include <limits>
13#include <memory>
14#include <new> // hardware_destructive_interference_size
15
16namespace {
17
18std::vector<ROOT::RFieldBase::RValue> SplitVector(std::shared_ptr<void> valuePtr, ROOT::RFieldBase &itemField)
19{
20 auto *vec = static_cast<std::vector<char> *>(valuePtr.get());
21 const auto itemSize = itemField.GetValueSize();
23 R__ASSERT((vec->size() % itemSize) == 0);
24 const auto nItems = vec->size() / itemSize;
25 std::vector<ROOT::RFieldBase::RValue> result;
26 result.reserve(nItems);
27 for (unsigned i = 0; i < nItems; ++i) {
28 result.emplace_back(itemField.BindValue(std::shared_ptr<void>(valuePtr, vec->data() + (i * itemSize))));
29 }
30 return result;
31}
32
33} // anonymous namespace
34
35ROOT::RArrayField::RArrayField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
36 std::size_t arrayLength)
38 "std::array<" + itemField->GetTypeName() + "," +
39 Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">",
40 ROOT::ENTupleStructure::kPlain, false /* isSimple */, arrayLength),
41 fItemSize(itemField->GetValueSize()),
42 fArrayLength(arrayLength)
43{
44 fTraits |= itemField->GetTraits() & ~kTraitMappable;
45 if (!itemField->GetTypeAlias().empty()) {
46 fTypeAlias = "std::array<" + itemField->GetTypeAlias() + "," +
47 Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">";
48 }
49 Attach(std::move(itemField), "_0");
50}
51
52std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayField::CloneImpl(std::string_view newName) const
53{
54 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
55 return std::make_unique<RArrayField>(newName, std::move(newItemField), fArrayLength);
56}
57
58std::size_t ROOT::RArrayField::AppendImpl(const void *from)
59{
60 std::size_t nbytes = 0;
61 if (fSubfields[0]->IsSimple()) {
62 GetPrincipalColumnOf(*fSubfields[0])->AppendV(from, fArrayLength);
63 nbytes += fArrayLength * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
64 } else {
65 auto arrayPtr = static_cast<const unsigned char *>(from);
66 for (unsigned i = 0; i < fArrayLength; ++i) {
67 nbytes += CallAppendOn(*fSubfields[0], arrayPtr + (i * fItemSize));
68 }
69 }
70 return nbytes;
71}
72
74{
75 if (fSubfields[0]->IsSimple()) {
76 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, to);
77 } else {
78 auto arrayPtr = static_cast<unsigned char *>(to);
79 for (unsigned i = 0; i < fArrayLength; ++i) {
80 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
81 }
82 }
83}
84
86{
87 if (fSubfields[0]->IsSimple()) {
88 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, to);
89 } else {
90 auto arrayPtr = static_cast<unsigned char *>(to);
91 for (unsigned i = 0; i < fArrayLength; ++i) {
92 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
93 }
94 }
95}
96
98{
99 if (!fSubfields[0]->IsSimple())
101
102 GetPrincipalColumnOf(*fSubfields[0])
103 ->ReadV(bulkSpec.fFirstIndex * fArrayLength, bulkSpec.fCount * fArrayLength, bulkSpec.fValues);
104 return RBulkSpec::kAllSet;
105}
106
108{
109 static const std::vector<std::string> prefixes = {"std::array<"};
110
111 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
112 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
113}
114
116{
117 if (fSubfields[0]->GetTraits() & kTraitTriviallyConstructible)
118 return;
119
120 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
121 for (unsigned i = 0; i < fArrayLength; ++i) {
122 CallConstructValueOn(*fSubfields[0], arrayPtr + (i * fItemSize));
123 }
124}
125
127{
128 if (fItemDeleter) {
129 for (unsigned i = 0; i < fArrayLength; ++i) {
130 fItemDeleter->operator()(reinterpret_cast<unsigned char *>(objPtr) + i * fItemSize, true /* dtorOnly */);
131 }
132 }
133 RDeleter::operator()(objPtr, dtorOnly);
134}
135
136std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayField::GetDeleter() const
137{
138 if (!(fSubfields[0]->GetTraits() & kTraitTriviallyDestructible))
139 return std::make_unique<RArrayDeleter>(fItemSize, fArrayLength, GetDeleterOf(*fSubfields[0]));
140 return std::make_unique<RDeleter>();
141}
142
143std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayField::SplitValue(const RValue &value) const
144{
145 auto valuePtr = value.GetPtr<void>();
146 auto arrayPtr = static_cast<unsigned char *>(valuePtr.get());
147 std::vector<RValue> result;
148 result.reserve(fArrayLength);
149 for (unsigned i = 0; i < fArrayLength; ++i) {
150 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(valuePtr, arrayPtr + (i * fItemSize))));
151 }
152 return result;
153}
154
156{
157 visitor.VisitArrayField(*this);
158}
159
160//------------------------------------------------------------------------------
161
162ROOT::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
163 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
164 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
165 fItemSize(itemField->GetValueSize()),
166 fNWritten(0)
167{
168 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
170 if (!itemField->GetTypeAlias().empty())
171 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
172 Attach(std::move(itemField), "_0");
173 fValueSize =
175
176 // Determine if we can optimimize bulk reading
177 if (fSubfields[0]->IsSimple()) {
178 fBulkSubfield = fSubfields[0].get();
179 } else {
180 if (auto f = dynamic_cast<RArrayField *>(fSubfields[0].get())) {
181 auto grandChildFields = fSubfields[0]->GetMutableSubfields();
182 if (grandChildFields[0]->IsSimple()) {
184 fBulkNRepetition = f->GetLength();
185 }
186 }
187 }
188}
189
190std::unique_ptr<ROOT::RFieldBase> ROOT::RRVecField::CloneImpl(std::string_view newName) const
191{
192 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
193 return std::make_unique<RRVecField>(newName, std::move(newItemField));
194}
195
196std::size_t ROOT::RRVecField::AppendImpl(const void *from)
197{
199
200 std::size_t nbytes = 0;
201 if (fSubfields[0]->IsSimple() && *sizePtr) {
202 GetPrincipalColumnOf(*fSubfields[0])->AppendV(*beginPtr, *sizePtr);
203 nbytes += *sizePtr * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
204 } else {
205 for (std::int32_t i = 0; i < *sizePtr; ++i) {
206 nbytes += CallAppendOn(*fSubfields[0], *beginPtr + i * fItemSize);
207 }
208 }
209
210 fNWritten += *sizePtr;
211 fPrincipalColumn->Append(&fNWritten);
212 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
213}
214
215unsigned char *ROOT::RRVecField::ResizeRVec(void *rvec, std::size_t nItems, std::size_t itemSize,
217
218{
219 if (nItems > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) {
220 throw RException(R__FAIL("RVec too large: " + std::to_string(nItems)));
221 }
222
224 const std::size_t oldSize = *sizePtr;
225
226 if (oldSize == nItems) {
227 // If neither shrink nor grow is necessary, do nothing.
228 // Note that this case preserves a memory adopting RVec as such. All real resizes in either direction
229 // transform a memory adopting RVec into an owning RVec.
230 return *beginPtr;
231 }
232
233 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md for details
234 // on the element construction/destrution.
235 const bool owns = (*capacityPtr != -1);
236 const bool needsConstruct = !(itemField->GetTraits() & kTraitTriviallyConstructible);
237 const bool needsDestruct = owns && itemDeleter;
238
239 // Destroy excess elements, if any
240 if (needsDestruct) {
241 for (std::size_t i = nItems; i < oldSize; ++i) {
242 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
243 }
244 }
245
246 // Resize RVec (capacity and size)
247 if (std::int32_t(nItems) > *capacityPtr) { // must reallocate
248 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
249 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
250 if (needsDestruct) {
251 for (std::size_t i = 0u; i < oldSize; ++i) {
252 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
253 }
254 }
255
256 // TODO Increment capacity by a factor rather than just enough to fit the elements.
257 if (owns) {
258 // *beginPtr points to the array of item values (allocated in an earlier call by the following malloc())
259 free(*beginPtr);
260 }
261 // We trust that malloc returns a buffer with large enough alignment.
262 // This might not be the case if T in RVec<T> is over-aligned.
263 *beginPtr = static_cast<unsigned char *>(malloc(nItems * itemSize));
264 R__ASSERT(*beginPtr != nullptr);
266
267 // Placement new for elements that were already there before the resize
268 if (needsConstruct) {
269 for (std::size_t i = 0u; i < oldSize; ++i)
270 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
271 }
272 }
273 *sizePtr = nItems;
274
275 // Placement new for new elements, if any
276 if (needsConstruct) {
277 for (std::size_t i = oldSize; i < nItems; ++i)
278 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
279 }
280
281 return *beginPtr;
282}
283
285{
286 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
287 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
288
289 // Read collection info for this entry
292 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
293
294 auto begin = ResizeRVec(to, nItems, fItemSize, fSubfields[0].get(), fItemDeleter.get());
295
296 if (fSubfields[0]->IsSimple() && nItems) {
297 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, begin);
298 return;
299 }
300
301 // Read the new values into the collection elements
302 for (std::size_t i = 0; i < nItems; ++i) {
303 CallReadOn(*fSubfields[0], collectionStart + i, begin + (i * fItemSize));
304 }
305}
306
308{
309 if (!fBulkSubfield)
311
312 if (bulkSpec.fAuxData->empty()) {
313 /// Initialize auxiliary memory: the first sizeof(size_t) bytes store the value size of the item field.
314 /// The following bytes store the item values, consecutively.
315 bulkSpec.fAuxData->resize(sizeof(std::size_t));
316 *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data()) = fBulkNRepetition * fBulkSubfield->GetValueSize();
317 }
318 const auto itemValueSize = *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data());
319 unsigned char *itemValueArray = bulkSpec.fAuxData->data() + sizeof(std::size_t);
321
322 // Get size of the first RVec of the bulk
325 fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &firstItemIndex, &collectionSize);
328 *capacityPtr = -1;
329
330 // Set the size of the remaining RVecs of the bulk, going page by page through the RNTuple offset column.
331 // We optimistically assume that bulkSpec.fAuxData is already large enough to hold all the item values in the
332 // given range. If not, we'll fix up the pointers afterwards.
333 auto lastOffset = firstItemIndex.GetIndexInCluster() + collectionSize;
335 std::size_t nValues = 1;
336 std::size_t nItems = collectionSize;
337 while (nRemainingValues > 0) {
339 const auto offsets =
340 fPrincipalColumn->MapV<ROOT::Internal::RColumnIndex>(bulkSpec.fFirstIndex + nValues, nElementsUntilPageEnd);
341 const std::size_t nBatch = std::min(nRemainingValues, nElementsUntilPageEnd);
342 for (std::size_t i = 0; i < nBatch; ++i) {
343 const auto size = offsets[i] - lastOffset;
345 reinterpret_cast<unsigned char *>(bulkSpec.fValues) + (nValues + i) * fValueSize);
347 *sizePtr = size;
348 *capacityPtr = -1;
349
350 nItems += size;
351 lastOffset = offsets[i];
352 }
354 nValues += nBatch;
355 }
356
357 bulkSpec.fAuxData->resize(sizeof(std::size_t) + nItems * itemValueSize);
358 // If the vector got reallocated, we need to fix-up the RVecs begin pointers.
359 const auto delta = itemValueArray - (bulkSpec.fAuxData->data() + sizeof(std::size_t));
360 if (delta != 0) {
361 auto beginPtrAsUChar = reinterpret_cast<unsigned char *>(bulkSpec.fValues);
362 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
363 *reinterpret_cast<unsigned char **>(beginPtrAsUChar) -= delta;
365 }
366 }
367
368 GetPrincipalColumnOf(*fBulkSubfield)
369 ->ReadV(firstItemIndex * fBulkNRepetition, nItems * fBulkNRepetition, itemValueArray - delta);
370 return RBulkSpec::kAllSet;
371}
372
382
387
392
394{
395 if (GetOnDiskId() == kInvalidDescriptorId)
396 return nullptr;
397
398 const auto descGuard = pageSource.GetSharedDescriptorGuard();
399 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
400 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
401 auto substitute = std::make_unique<RArrayAsRVecField>(
402 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
403 substitute->SetOnDiskId(GetOnDiskId());
404 return substitute;
405 }
406 return nullptr;
407}
408
410{
411 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
412}
413
415{
416 // initialize data members fBegin, fSize, fCapacity
417 // currently the inline buffer is left uninitialized
418 void **beginPtr = new (where)(void *)(nullptr);
419 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
420 new (sizePtr + 1) std::int32_t(-1);
421}
422
424{
426
427 if (fItemDeleter) {
428 for (std::int32_t i = 0; i < *sizePtr; ++i) {
429 fItemDeleter->operator()(*beginPtr + i * fItemSize, true /* dtorOnly */);
430 }
431 }
432
434 RDeleter::operator()(objPtr, dtorOnly);
435}
436
437std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RRVecField::GetDeleter() const
438{
439 if (fItemDeleter)
440 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize, GetDeleterOf(*fSubfields[0]));
441 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment());
442}
443
444std::vector<ROOT::RFieldBase::RValue> ROOT::RRVecField::SplitValue(const RValue &value) const
445{
446 auto [beginPtr, sizePtr, _] = Internal::GetRVecDataMembers(value.GetPtr<void>().get());
447
448 std::vector<RValue> result;
449 result.reserve(*sizePtr);
450 for (std::int32_t i = 0; i < *sizePtr; ++i) {
451 result.emplace_back(
452 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), *beginPtr + i * fItemSize)));
453 }
454 return result;
455}
456
458{
459 return fValueSize;
460}
461
463{
464 return Internal::EvalRVecAlignment(fSubfields[0]->GetAlignment());
465}
466
468{
469 visitor.VisitRVecField(*this);
470}
471
472//------------------------------------------------------------------------------
473
474ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
475 std::optional<std::string_view> emulatedFromType)
476 : ROOT::RFieldBase(fieldName, emulatedFromType ? *emulatedFromType : "std::vector<" + itemField->GetTypeName() + ">",
477 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
478 fItemSize(itemField->GetValueSize()),
479 fNWritten(0)
480{
481 if (emulatedFromType && !emulatedFromType->empty())
483
484 if (!itemField->GetTypeAlias().empty())
485 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
486
487 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
489 Attach(std::move(itemField), "_0");
490}
491
492ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
494{
495}
496
497std::unique_ptr<ROOT::RVectorField>
498ROOT::RVectorField::CreateUntyped(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
499{
500 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(fieldName, itemField->Clone("_0"), ""));
501}
502
503std::unique_ptr<ROOT::RFieldBase> ROOT::RVectorField::CloneImpl(std::string_view newName) const
504{
505 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
506 auto isUntyped = GetTypeName().empty() || ((fTraits & kTraitEmulatedField) != 0);
507 auto emulatedFromType = isUntyped ? std::make_optional(GetTypeName()) : std::nullopt;
508 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(newName, std::move(newItemField), emulatedFromType));
509}
510
511std::size_t ROOT::RVectorField::AppendImpl(const void *from)
512{
513 auto typedValue = static_cast<const std::vector<char> *>(from);
514 // The order is important here: Profiling showed that the integer division is on the critical path. By moving the
515 // computation of count before R__ASSERT, the compiler can use the result of a single instruction (on x86) also for
516 // the modulo operation. Otherwise, it must perform the division twice because R__ASSERT expands to an external call
517 // of Fatal() in case of failure, which could have side effects that the compiler cannot analyze.
518 auto count = typedValue->size() / fItemSize;
519 R__ASSERT((typedValue->size() % fItemSize) == 0);
520 std::size_t nbytes = 0;
521
522 if (fSubfields[0]->IsSimple() && count) {
523 GetPrincipalColumnOf(*fSubfields[0])->AppendV(typedValue->data(), count);
524 nbytes += count * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
525 } else {
526 for (unsigned i = 0; i < count; ++i) {
527 nbytes += CallAppendOn(*fSubfields[0], typedValue->data() + (i * fItemSize));
528 }
529 }
530
531 fNWritten += count;
532 fPrincipalColumn->Append(&fNWritten);
533 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
534}
535
536void ROOT::RVectorField::ResizeVector(void *vec, std::size_t nItems, std::size_t itemSize, const RFieldBase &itemField,
538{
539 auto typedValue = static_cast<std::vector<char> *>(vec);
540
541 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md
542 R__ASSERT(itemSize > 0);
543 const auto oldNItems = typedValue->size() / itemSize;
544 const auto availNItems = typedValue->capacity() / itemSize;
545 const bool canRealloc = availNItems < nItems;
546 bool allDeallocated = false;
547 if (itemDeleter) {
549 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
550 itemDeleter->operator()(typedValue->data() + (i * itemSize), true /* dtorOnly */);
551 }
552 }
553 typedValue->resize(nItems * itemSize);
554 if (!(itemField.GetTraits() & kTraitTriviallyConstructible)) {
555 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
556 CallConstructValueOn(itemField, typedValue->data() + (i * itemSize));
557 }
558 }
559}
560
562{
563 auto typedValue = static_cast<std::vector<char> *>(to);
564
567 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
568
569 if (fSubfields[0]->IsSimple()) {
570 typedValue->resize(nItems * fItemSize);
571 if (nItems)
572 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, typedValue->data());
573 return;
574 }
575
576 ResizeVector(to, nItems, fItemSize, *fSubfields[0], fItemDeleter.get());
577
578 for (std::size_t i = 0; i < nItems; ++i) {
579 CallReadOn(*fSubfields[0], collectionStart + i, typedValue->data() + (i * fItemSize));
580 }
581}
582
592
597
602
604{
605 if (GetOnDiskId() == kInvalidDescriptorId)
606 return nullptr;
607
608 const auto descGuard = pageSource.GetSharedDescriptorGuard();
609 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
610 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
611 auto substitute = std::make_unique<RArrayAsVectorField>(
612 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
613 substitute->SetOnDiskId(GetOnDiskId());
614 return substitute;
615 }
616 return nullptr;
617}
618
620{
621 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
622}
623
625{
626 auto vecPtr = static_cast<std::vector<char> *>(objPtr);
627 if (fItemDeleter) {
628 R__ASSERT(fItemSize > 0);
629 R__ASSERT((vecPtr->size() % fItemSize) == 0);
630 auto nItems = vecPtr->size() / fItemSize;
631 for (std::size_t i = 0; i < nItems; ++i) {
632 fItemDeleter->operator()(vecPtr->data() + (i * fItemSize), true /* dtorOnly */);
633 }
634 }
635 std::destroy_at(vecPtr);
636 RDeleter::operator()(objPtr, dtorOnly);
637}
638
639std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVectorField::GetDeleter() const
640{
641 if (fItemDeleter)
642 return std::make_unique<RVectorDeleter>(fItemSize, GetDeleterOf(*fSubfields[0]));
643 return std::make_unique<RVectorDeleter>();
644}
645
646std::vector<ROOT::RFieldBase::RValue> ROOT::RVectorField::SplitValue(const RValue &value) const
647{
648 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
649}
650
652{
653 visitor.VisitVectorField(*this);
654}
655
656//------------------------------------------------------------------------------
657
658ROOT::RField<std::vector<bool>>::RField(std::string_view name)
659 : ROOT::RFieldBase(name, "std::vector<bool>", ROOT::ENTupleStructure::kCollection, false /* isSimple */)
660{
661 Attach(std::make_unique<RField<bool>>("_0"));
662}
663
664std::size_t ROOT::RField<std::vector<bool>>::AppendImpl(const void *from)
665{
666 auto typedValue = static_cast<const std::vector<bool> *>(from);
667 auto count = typedValue->size();
668 for (unsigned i = 0; i < count; ++i) {
669 bool bval = (*typedValue)[i];
670 CallAppendOn(*fSubfields[0], &bval);
671 }
672 fNWritten += count;
673 fPrincipalColumn->Append(&fNWritten);
674 return count + fPrincipalColumn->GetElement()->GetPackedSize();
675}
676
678{
679 auto typedValue = static_cast<std::vector<bool> *>(to);
680
681 if (fOnDiskNRepetitions == 0) {
683 RNTupleLocalIndex collectionStart;
684 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
685 typedValue->resize(nItems);
686 for (std::size_t i = 0; i < nItems; ++i) {
687 bool bval;
688 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
689 (*typedValue)[i] = bval;
690 }
691 } else {
692 typedValue->resize(fOnDiskNRepetitions);
693 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
694 bool bval;
695 CallReadOn(*fSubfields[0], globalIndex * fOnDiskNRepetitions + i, &bval);
696 (*typedValue)[i] = bval;
697 }
698 }
699}
700
701void ROOT::RField<std::vector<bool>>::ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to)
702{
703 auto typedValue = static_cast<std::vector<bool> *>(to);
704
705 if (fOnDiskNRepetitions == 0) {
707 RNTupleLocalIndex collectionStart;
708 fPrincipalColumn->GetCollectionInfo(localIndex, &collectionStart, &nItems);
709 typedValue->resize(nItems);
710 for (std::size_t i = 0; i < nItems; ++i) {
711 bool bval;
712 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
713 (*typedValue)[i] = bval;
714 }
715 } else {
716 typedValue->resize(fOnDiskNRepetitions);
717 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
718 bool bval;
719 CallReadOn(*fSubfields[0], localIndex * fOnDiskNRepetitions + i, &bval);
720 (*typedValue)[i] = bval;
721 }
722 }
723}
724
725const ROOT::RFieldBase::RColumnRepresentations &ROOT::RField<std::vector<bool>>::GetColumnRepresentations() const
726{
727 static RColumnRepresentations representations({{ENTupleColumnType::kSplitIndex64},
731 {{}});
732 return representations;
733}
734
735void ROOT::RField<std::vector<bool>>::GenerateColumns()
736{
737 R__ASSERT(fOnDiskNRepetitions == 0); // fOnDiskNRepetitions must only be used for reading
739}
740
741void ROOT::RField<std::vector<bool>>::GenerateColumns(const ROOT::RNTupleDescriptor &desc)
742{
743 if (fOnDiskNRepetitions == 0)
745}
746
747void ROOT::RField<std::vector<bool>>::ReconcileOnDiskField(const RNTupleDescriptor &desc)
748{
749 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
750
751 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
752 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions).ThrowOnError();
753
754 if (fieldDesc.GetNRepetitions() == 0) {
755 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected repetition count > 0\n" +
756 Internal::GetTypeTraceReport(*this, desc)));
757 }
758 if (fieldDesc.GetStructure() != ENTupleStructure::kPlain) {
759 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected plain on-disk field\n" +
760 Internal::GetTypeTraceReport(*this, desc)));
761 }
762 fOnDiskNRepetitions = fieldDesc.GetNRepetitions();
763 } else {
764 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
765 }
766}
767
768std::vector<ROOT::RFieldBase::RValue> ROOT::RField<std::vector<bool>>::SplitValue(const RValue &value) const
769{
770 const auto &typedValue = value.GetRef<std::vector<bool>>();
771 auto count = typedValue.size();
772 std::vector<RValue> result;
773 result.reserve(count);
774 for (unsigned i = 0; i < count; ++i) {
775 if (typedValue[i]) {
776 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(true))));
777 } else {
778 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(false))));
779 }
780 }
781 return result;
782}
783
785{
786 visitor.VisitVectorBoolField(*this);
787}
788
789//------------------------------------------------------------------------------
790
791ROOT::RArrayAsRVecField::RArrayAsRVecField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
792 std::size_t arrayLength)
793 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
794 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
795 fItemSize(itemField->GetValueSize()),
796 fArrayLength(arrayLength)
797{
798 if (!itemField->GetTypeAlias().empty())
799 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
800 Attach(std::move(itemField), "_0");
801 fValueSize =
805}
806
807std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsRVecField::CloneImpl(std::string_view newName) const
808{
809 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
810 return std::make_unique<RArrayAsRVecField>(newName, std::move(newItemField), fArrayLength);
811}
812
814{
815 // initialize data members fBegin, fSize, fCapacity
816 // currently the inline buffer is left uninitialized
817 void **beginPtr = new (where)(void *)(nullptr);
818 std::int32_t *sizePtr = new (static_cast<void *>(beginPtr + 1)) std::int32_t(0);
819 new (sizePtr + 1) std::int32_t(-1);
820}
821
822std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsRVecField::GetDeleter() const
823{
824 if (fItemDeleter) {
825 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize,
826 GetDeleterOf(*fSubfields[0]));
827 }
828 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment());
829}
830
832{
833 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
834
835 if (fSubfields[0]->IsSimple()) {
836 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, begin);
837 return;
838 }
839
840 // Read the new values into the collection elements
841 for (std::size_t i = 0; i < fArrayLength; ++i) {
842 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, begin + (i * fItemSize));
843 }
844}
845
847{
848 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
849
850 if (fSubfields[0]->IsSimple()) {
851 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, begin);
852 return;
853 }
854
855 // Read the new values into the collection elements
856 for (std::size_t i = 0; i < fArrayLength; ++i) {
857 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, begin + (i * fItemSize));
858 }
859}
860
862{
863 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffTypeVersion | kDiffStructure | kDiffNRepetitions)
864 .ThrowOnError();
865 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
866 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
867 throw RException(R__FAIL("RArrayAsRVecField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
868 Internal::GetTypeTraceReport(*this, desc)));
869 }
870}
871
873{
874 return Internal::EvalRVecAlignment(fSubfields[0]->GetAlignment());
875}
876
877std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsRVecField::SplitValue(const ROOT::RFieldBase::RValue &value) const
878{
879 auto arrayPtr = value.GetPtr<unsigned char>().get();
880 std::vector<ROOT::RFieldBase::RValue> result;
881 result.reserve(fArrayLength);
882 for (unsigned i = 0; i < fArrayLength; ++i) {
883 result.emplace_back(
884 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), arrayPtr + (i * fItemSize))));
885 }
886 return result;
887}
888
890{
891 visitor.VisitArrayAsRVecField(*this);
892}
893
894//------------------------------------------------------------------------------
895
896ROOT::RArrayAsVectorField::RArrayAsVectorField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
897 std::size_t arrayLength)
898 : ROOT::RFieldBase(fieldName, "std::vector<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kCollection,
899 false /* isSimple */),
900 fItemSize(itemField->GetValueSize()),
901 fArrayLength(arrayLength)
902{
903 if (!itemField->GetTypeAlias().empty())
904 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
905 Attach(std::move(itemField), "_0");
908}
909
910std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsVectorField::CloneImpl(std::string_view newName) const
911{
912 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
913 return std::make_unique<RArrayAsVectorField>(newName, std::move(newItemField), fArrayLength);
914}
915
917{
918 throw RException(R__FAIL("RArrayAsVectorField fields must only be used for reading"));
919}
920
921std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsVectorField::GetDeleter() const
922{
923 if (fItemDeleter)
924 return std::make_unique<RVectorField::RVectorDeleter>(fItemSize, GetDeleterOf(*fSubfields[0]));
925 return std::make_unique<RVectorField::RVectorDeleter>();
926}
927
929{
930 auto typedValue = static_cast<std::vector<char> *>(to);
931
932 if (fSubfields[0]->IsSimple()) {
933 typedValue->resize(fArrayLength * fItemSize);
934 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, typedValue->data());
935 return;
936 }
937
938 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
939
940 for (std::size_t i = 0; i < fArrayLength; ++i) {
941 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
942 }
943}
944
946{
947 auto typedValue = static_cast<std::vector<char> *>(to);
948
949 if (fSubfields[0]->IsSimple()) {
950 typedValue->resize(fArrayLength * fItemSize);
951 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, typedValue->data());
952 return;
953 }
954
955 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
956
957 for (std::size_t i = 0; i < fArrayLength; ++i) {
958 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
959 }
960}
961
963{
964 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffTypeVersion | kDiffStructure | kDiffNRepetitions);
965
966 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
967 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
968 throw RException(R__FAIL("RArrayAsVectorField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
969 Internal::GetTypeTraceReport(*this, desc)));
970 }
971}
972
973std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsVectorField::SplitValue(const ROOT::RFieldBase::RValue &value) const
974{
975 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
976}
977
979{
980 visitor.VisitArrayAsVectorField(*this);
981}
size_t fValueSize
#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 f(i)
Definition RSha256.hxx:104
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
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:157
#define _(A, B)
Definition cfortran.h:108
#define free
Definition civetweb.c:1578
#define malloc
Definition civetweb.c:1575
Abstract base class for classes implementing the visitor design pattern.
The in-memory representation of a 32bit or 64bit on-disk index column.
Abstract interface to read data from an ntuple.
std::unique_ptr< RDeleter > fItemDeleter
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
RArrayAsRVecField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::size_t arrayLength)
Constructor of the field.
std::size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
std::unique_ptr< RDeleter > GetDeleter() const final
Returns an RRVecField::RRVecDeleter.
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
The size of a value of this field, i.e. an RVec.
std::vector< RFieldBase::RValue > SplitValue(const RFieldBase::RValue &value) const final
Creates the list of direct child values given an existing value for this field.
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
std::size_t fValueSize
The length of the arrays in this field.
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
std::unique_ptr< RDeleter > GetDeleter() const final
Returns an RVectorField::RVectorDeleter.
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
std::unique_ptr< RDeleter > fItemDeleter
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
RArrayAsVectorField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::size_t arrayLength)
The itemField argument represents the inner item of the on-disk array, i.e.
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
std::vector< RFieldBase::RValue > SplitValue(const RFieldBase::RValue &value) const final
Creates the list of direct child values given an existing value for this field.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
The length of the arrays in this field.
void operator()(void *objPtr, bool dtorOnly) final
Template specializations for C++ std::array and C-style arrays.
std::unique_ptr< RDeleter > GetDeleter() const final
RArrayField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::size_t arrayLength)
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec) final
General implementation of bulk read.
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
The list of column representations a field can have.
A functor to release the memory acquired by CreateValue() (memory and constructor).
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
A field translates read and write calls from/to underlying columns to/from tree values.
void Attach(std::unique_ptr< RFieldBase > child, std::string_view expectedChildName="")
Add a new subfield to the list of nested fields.
std::vector< std::unique_ptr< RFieldBase > > fSubfields
Collections and classes own subfields.
static std::unique_ptr< RDeleter > GetDeleterOf(const RFieldBase &other)
@ kTraitEmulatedField
This field is a user defined type that was missing dictionaries and was reconstructed from the on-dis...
@ kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
std::string fTypeAlias
A typedef or using name that was used when creating the field.
bool IsSimple() const
std::uint32_t GetTraits() const
virtual std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec)
General implementation of bulk read.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:323
The on-storage metadata of an RNTuple.
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
void operator()(void *objPtr, bool dtorOnly) final
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec) final
General implementation of bulk read.
RRVecField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::unique_ptr< RFieldBase > BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final
Called by ConnectPageSource() before connecting; derived classes may override this as appropriate,...
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
static unsigned char * ResizeRVec(void *rvec, std::size_t nItems, std::size_t itemSize, const RFieldBase *itemField, RDeleter *itemDeleter)
std::unique_ptr< RDeleter > fItemDeleter
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
RFieldBase * fBulkSubfield
May be a direct PoD subfield or a sub-subfield of a fixed-size array of PoD.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
std::unique_ptr< RDeleter > GetDeleter() const final
void operator()(void *objPtr, bool dtorOnly) final
Template specializations for C++ std::vector.
static std::unique_ptr< RVectorField > CreateUntyped(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
std::unique_ptr< RFieldBase > BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final
Called by ConnectPageSource() before connecting; derived classes may override this as appropriate,...
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
static void ResizeVector(void *vec, std::size_t nItems, std::size_t itemSize, const RFieldBase &itemField, RDeleter *itemDeleter)
RVectorField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::optional< std::string_view > emulatedFromType)
Creates a possibly-untyped VectorField.
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
std::unique_ptr< RDeleter > fItemDeleter
std::unique_ptr< RDeleter > GetDeleter() const final
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
std::tuple< unsigned char **, std::int32_t *, std::int32_t * > GetRVecDataMembers(void *rvecPtr)
Retrieve the addresses of the data members of a generic RVec from a pointer to the beginning of the R...
void DestroyRVecWithChecks(std::size_t alignOfT, unsigned char **beginPtr, std::int32_t *capacityPtr)
std::string GetNormalizedInteger(const std::string &intTemplateArg)
Appends 'll' or 'ull' to the where necessary and strips the suffix if not needed.
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 ...
std::size_t EvalRVecAlignment(std::size_t alignOfSubfield)
std::size_t EvalRVecValueSize(std::size_t alignOfT, std::size_t sizeOfT, std::size_t alignOfRVecT)
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...
Input parameter to RFieldBase::ReadBulk() and RFieldBase::ReadBulkImpl().