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
18/// Retrieve the addresses of the data members of a generic RVec from a pointer to the beginning of the RVec object.
19/// Returns pointers to fBegin, fSize and fCapacity in a std::tuple.
20std::tuple<unsigned char **, std::int32_t *, std::int32_t *> GetRVecDataMembers(void *rvecPtr)
21{
22 unsigned char **beginPtr = reinterpret_cast<unsigned char **>(rvecPtr);
23 // int32_t fSize is the second data member (after 1 void*)
24 std::int32_t *size = reinterpret_cast<std::int32_t *>(beginPtr + 1);
25 R__ASSERT(*size >= 0);
26 // int32_t fCapacity is the third data member (1 int32_t after fSize)
27 std::int32_t *capacity = size + 1;
28 R__ASSERT(*capacity >= -1);
29 return {beginPtr, size, capacity};
30}
31
32std::tuple<const unsigned char *const *, const std::int32_t *, const std::int32_t *>
33GetRVecDataMembers(const void *rvecPtr)
34{
35 return {GetRVecDataMembers(const_cast<void *>(rvecPtr))};
36}
37
38std::size_t EvalRVecValueSize(std::size_t alignOfT, std::size_t sizeOfT, std::size_t alignOfRVecT)
39{
40 // the size of an RVec<T> is the size of its 4 data-members + optional padding:
41 //
42 // data members:
43 // - void *fBegin
44 // - int32_t fSize
45 // - int32_t fCapacity
46 // - the char[] inline storage, which is aligned like T
47 //
48 // padding might be present:
49 // - between fCapacity and the char[] buffer aligned like T
50 // - after the char[] buffer
51
52 constexpr auto dataMemberSz = sizeof(void *) + 2 * sizeof(std::int32_t);
53
54 // mimic the logic of RVecInlineStorageSize, but at runtime
55 const auto inlineStorageSz = [&] {
56 constexpr unsigned cacheLineSize = R__HARDWARE_INTERFERENCE_SIZE;
57 const unsigned elementsPerCacheLine = (cacheLineSize - dataMemberSz) / sizeOfT;
58 constexpr unsigned maxInlineByteSize = 1024;
59 const unsigned nElements =
60 elementsPerCacheLine >= 8 ? elementsPerCacheLine : (sizeOfT * 8 > maxInlineByteSize ? 0 : 8);
61 return nElements * sizeOfT;
62 }();
63
64 // compute padding between first 3 datamembers and inline buffer
65 // (there should be no padding between the first 3 data members)
67 if (paddingMiddle != 0)
69
70 // padding at the end of the object
72 if (paddingEnd != 0)
74
76}
77
78std::size_t EvalRVecAlignment(std::size_t alignOfSubfield)
79{
80 // the alignment of an RVec<T> is the largest among the alignments of its data members
81 // (including the inline buffer which has the same alignment as the RVec::value_type)
82 return std::max({alignof(void *), alignof(std::int32_t), alignOfSubfield});
83}
84
85void DestroyRVecWithChecks(std::size_t alignOfT, unsigned char **beginPtr, std::int32_t *capacityPtr)
86{
87 // figure out if we are in the small state, i.e. begin == &inlineBuffer
88 // there might be padding between fCapacity and the inline buffer, so we compute it here
89 constexpr auto dataMemberSz = sizeof(void *) + 2 * sizeof(std::int32_t);
91 if (paddingMiddle != 0)
93 const bool isSmall = (*beginPtr == (reinterpret_cast<unsigned char *>(beginPtr) + dataMemberSz + paddingMiddle));
94
95 const bool owns = (*capacityPtr != -1);
96 if (!isSmall && owns)
97 free(*beginPtr);
98}
99
100std::vector<ROOT::RFieldBase::RValue> SplitVector(std::shared_ptr<void> valuePtr, ROOT::RFieldBase &itemField)
101{
102 auto *vec = static_cast<std::vector<char> *>(valuePtr.get());
103 const auto itemSize = itemField.GetValueSize();
104 R__ASSERT(itemSize > 0);
105 R__ASSERT((vec->size() % itemSize) == 0);
106 const auto nItems = vec->size() / itemSize;
107 std::vector<ROOT::RFieldBase::RValue> result;
108 result.reserve(nItems);
109 for (unsigned i = 0; i < nItems; ++i) {
110 result.emplace_back(itemField.BindValue(std::shared_ptr<void>(valuePtr, vec->data() + (i * itemSize))));
111 }
112 return result;
113}
114
115} // anonymous namespace
116
117ROOT::RArrayField::RArrayField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
118 std::size_t arrayLength)
120 "std::array<" + itemField->GetTypeName() + "," +
121 Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">",
122 ROOT::ENTupleStructure::kPlain, false /* isSimple */, arrayLength),
123 fItemSize(itemField->GetValueSize()),
124 fArrayLength(arrayLength)
125{
126 fTraits |= itemField->GetTraits() & ~kTraitMappable;
127 Attach(std::move(itemField));
128}
129
130std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayField::CloneImpl(std::string_view newName) const
131{
132 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
133 return std::make_unique<RArrayField>(newName, std::move(newItemField), fArrayLength);
134}
135
136std::size_t ROOT::RArrayField::AppendImpl(const void *from)
137{
138 std::size_t nbytes = 0;
139 if (fSubfields[0]->IsSimple()) {
140 GetPrincipalColumnOf(*fSubfields[0])->AppendV(from, fArrayLength);
141 nbytes += fArrayLength * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
142 } else {
143 auto arrayPtr = static_cast<const unsigned char *>(from);
144 for (unsigned i = 0; i < fArrayLength; ++i) {
145 nbytes += CallAppendOn(*fSubfields[0], arrayPtr + (i * fItemSize));
146 }
147 }
148 return nbytes;
149}
150
152{
153 if (fSubfields[0]->IsSimple()) {
154 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, to);
155 } else {
156 auto arrayPtr = static_cast<unsigned char *>(to);
157 for (unsigned i = 0; i < fArrayLength; ++i) {
158 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
159 }
160 }
161}
162
164{
165 if (fSubfields[0]->IsSimple()) {
166 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, to);
167 } else {
168 auto arrayPtr = static_cast<unsigned char *>(to);
169 for (unsigned i = 0; i < fArrayLength; ++i) {
170 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
171 }
172 }
173}
174
176{
177 if (!fSubfields[0]->IsSimple())
179
180 GetPrincipalColumnOf(*fSubfields[0])
181 ->ReadV(bulkSpec.fFirstIndex * fArrayLength, bulkSpec.fCount * fArrayLength, bulkSpec.fValues);
182 return RBulkSpec::kAllSet;
183}
184
186{
187 static const std::vector<std::string> prefixes = {"std::array<"};
188
189 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
190 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
191}
192
194{
195 if (fSubfields[0]->GetTraits() & kTraitTriviallyConstructible)
196 return;
197
198 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
199 for (unsigned i = 0; i < fArrayLength; ++i) {
200 CallConstructValueOn(*fSubfields[0], arrayPtr + (i * fItemSize));
201 }
202}
203
205{
206 if (fItemDeleter) {
207 for (unsigned i = 0; i < fArrayLength; ++i) {
208 fItemDeleter->operator()(reinterpret_cast<unsigned char *>(objPtr) + i * fItemSize, true /* dtorOnly */);
209 }
210 }
211 RDeleter::operator()(objPtr, dtorOnly);
212}
213
214std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayField::GetDeleter() const
215{
216 if (!(fSubfields[0]->GetTraits() & kTraitTriviallyDestructible))
217 return std::make_unique<RArrayDeleter>(fItemSize, fArrayLength, GetDeleterOf(*fSubfields[0]));
218 return std::make_unique<RDeleter>();
219}
220
221std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayField::SplitValue(const RValue &value) const
222{
223 auto valuePtr = value.GetPtr<void>();
224 auto arrayPtr = static_cast<unsigned char *>(valuePtr.get());
225 std::vector<RValue> result;
226 result.reserve(fArrayLength);
227 for (unsigned i = 0; i < fArrayLength; ++i) {
228 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(valuePtr, arrayPtr + (i * fItemSize))));
229 }
230 return result;
231}
232
234{
235 visitor.VisitArrayField(*this);
236}
237
238//------------------------------------------------------------------------------
239
240ROOT::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
241 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
242 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
243 fItemSize(itemField->GetValueSize()),
244 fNWritten(0)
245{
246 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
248 Attach(std::move(itemField));
250
251 // Determine if we can optimimize bulk reading
252 if (fSubfields[0]->IsSimple()) {
253 fBulkSubfield = fSubfields[0].get();
254 } else {
255 if (auto f = dynamic_cast<RArrayField *>(fSubfields[0].get())) {
256 auto grandChildFields = fSubfields[0]->GetMutableSubfields();
257 if (grandChildFields[0]->IsSimple()) {
259 fBulkNRepetition = f->GetLength();
260 }
261 }
262 }
263}
264
265std::unique_ptr<ROOT::RFieldBase> ROOT::RRVecField::CloneImpl(std::string_view newName) const
266{
267 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
268 return std::make_unique<RRVecField>(newName, std::move(newItemField));
269}
270
271std::size_t ROOT::RRVecField::AppendImpl(const void *from)
272{
273 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(from);
274
275 std::size_t nbytes = 0;
276 if (fSubfields[0]->IsSimple() && *sizePtr) {
277 GetPrincipalColumnOf(*fSubfields[0])->AppendV(*beginPtr, *sizePtr);
278 nbytes += *sizePtr * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
279 } else {
280 for (std::int32_t i = 0; i < *sizePtr; ++i) {
281 nbytes += CallAppendOn(*fSubfields[0], *beginPtr + i * fItemSize);
282 }
283 }
284
285 fNWritten += *sizePtr;
286 fPrincipalColumn->Append(&fNWritten);
287 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
288}
289
290unsigned char *ROOT::RRVecField::ResizeRVec(void *rvec, std::size_t nItems, std::size_t itemSize,
292
293{
294 if (nItems > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) {
295 throw RException(R__FAIL("RVec too large: " + std::to_string(nItems)));
296 }
297
299 const std::size_t oldSize = *sizePtr;
300
301 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md for details
302 // on the element construction/destrution.
303 const bool owns = (*capacityPtr != -1);
304 const bool needsConstruct = !(itemField->GetTraits() & kTraitTriviallyConstructible);
305 const bool needsDestruct = owns && itemDeleter;
306
307 // Destroy excess elements, if any
308 if (needsDestruct) {
309 for (std::size_t i = nItems; i < oldSize; ++i) {
310 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
311 }
312 }
313
314 // Resize RVec (capacity and size)
315 if (std::int32_t(nItems) > *capacityPtr) { // must reallocate
316 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
317 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
318 if (needsDestruct) {
319 for (std::size_t i = 0u; i < oldSize; ++i) {
320 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
321 }
322 }
323
324 // TODO Increment capacity by a factor rather than just enough to fit the elements.
325 if (owns) {
326 // *beginPtr points to the array of item values (allocated in an earlier call by the following malloc())
327 free(*beginPtr);
328 }
329 // We trust that malloc returns a buffer with large enough alignment.
330 // This might not be the case if T in RVec<T> is over-aligned.
331 *beginPtr = static_cast<unsigned char *>(malloc(nItems * itemSize));
332 R__ASSERT(*beginPtr != nullptr);
334
335 // Placement new for elements that were already there before the resize
336 if (needsConstruct) {
337 for (std::size_t i = 0u; i < oldSize; ++i)
338 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
339 }
340 }
341 *sizePtr = nItems;
342
343 // Placement new for new elements, if any
344 if (needsConstruct) {
345 for (std::size_t i = oldSize; i < nItems; ++i)
346 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
347 }
348
349 return *beginPtr;
350}
351
353{
354 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
355 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
356
357 // Read collection info for this entry
360 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
361
362 auto begin = ResizeRVec(to, nItems, fItemSize, fSubfields[0].get(), fItemDeleter.get());
363
364 if (fSubfields[0]->IsSimple() && nItems) {
365 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, begin);
366 return;
367 }
368
369 // Read the new values into the collection elements
370 for (std::size_t i = 0; i < nItems; ++i) {
371 CallReadOn(*fSubfields[0], collectionStart + i, begin + (i * fItemSize));
372 }
373}
374
376{
377 if (!fBulkSubfield)
379
380 if (bulkSpec.fAuxData->empty()) {
381 /// Initialize auxiliary memory: the first sizeof(size_t) bytes store the value size of the item field.
382 /// The following bytes store the item values, consecutively.
383 bulkSpec.fAuxData->resize(sizeof(std::size_t));
384 *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data()) = fBulkNRepetition * fBulkSubfield->GetValueSize();
385 }
386 const auto itemValueSize = *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data());
387 unsigned char *itemValueArray = bulkSpec.fAuxData->data() + sizeof(std::size_t);
389
390 // Get size of the first RVec of the bulk
393 fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &firstItemIndex, &collectionSize);
396 *capacityPtr = -1;
397
398 // Set the size of the remaining RVecs of the bulk, going page by page through the RNTuple offset column.
399 // We optimistically assume that bulkSpec.fAuxData is already large enough to hold all the item values in the
400 // given range. If not, we'll fix up the pointers afterwards.
401 auto lastOffset = firstItemIndex.GetIndexInCluster() + collectionSize;
403 std::size_t nValues = 1;
404 std::size_t nItems = collectionSize;
405 while (nRemainingValues > 0) {
407 const auto offsets =
408 fPrincipalColumn->MapV<ROOT::Internal::RColumnIndex>(bulkSpec.fFirstIndex + nValues, nElementsUntilPageEnd);
409 const std::size_t nBatch = std::min(nRemainingValues, nElementsUntilPageEnd);
410 for (std::size_t i = 0; i < nBatch; ++i) {
411 const auto size = offsets[i] - lastOffset;
412 std::tie(beginPtr, sizePtr, capacityPtr) =
413 GetRVecDataMembers(reinterpret_cast<unsigned char *>(bulkSpec.fValues) + (nValues + i) * fValueSize);
415 *sizePtr = size;
416 *capacityPtr = -1;
417
418 nItems += size;
419 lastOffset = offsets[i];
420 }
422 nValues += nBatch;
423 }
424
425 bulkSpec.fAuxData->resize(sizeof(std::size_t) + nItems * itemValueSize);
426 // If the vector got reallocated, we need to fix-up the RVecs begin pointers.
427 const auto delta = itemValueArray - (bulkSpec.fAuxData->data() + sizeof(std::size_t));
428 if (delta != 0) {
429 auto beginPtrAsUChar = reinterpret_cast<unsigned char *>(bulkSpec.fValues);
430 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
431 *reinterpret_cast<unsigned char **>(beginPtrAsUChar) -= delta;
433 }
434 }
435
436 GetPrincipalColumnOf(*fBulkSubfield)
437 ->ReadV(firstItemIndex * fBulkNRepetition, nItems * fBulkNRepetition, itemValueArray - delta);
438 return RBulkSpec::kAllSet;
439}
440
450
455
460
462{
463 if (GetOnDiskId() == kInvalidDescriptorId)
464 return nullptr;
465
466 const auto descGuard = pageSource.GetSharedDescriptorGuard();
467 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
468 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
469 auto substitute = std::make_unique<RArrayAsRVecField>(
470 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
471 substitute->SetOnDiskId(GetOnDiskId());
472 return substitute;
473 }
474 return nullptr;
475}
476
478{
479 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
480}
481
483{
484 // initialize data members fBegin, fSize, fCapacity
485 // currently the inline buffer is left uninitialized
486 void **beginPtr = new (where)(void *)(nullptr);
487 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
488 new (sizePtr + 1) std::int32_t(-1);
489}
490
492{
494
495 if (fItemDeleter) {
496 for (std::int32_t i = 0; i < *sizePtr; ++i) {
497 fItemDeleter->operator()(*beginPtr + i * fItemSize, true /* dtorOnly */);
498 }
499 }
500
502 RDeleter::operator()(objPtr, dtorOnly);
503}
504
505std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RRVecField::GetDeleter() const
506{
507 if (fItemDeleter)
508 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize, GetDeleterOf(*fSubfields[0]));
509 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment());
510}
511
512std::vector<ROOT::RFieldBase::RValue> ROOT::RRVecField::SplitValue(const RValue &value) const
513{
514 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(value.GetPtr<void>().get());
515
516 std::vector<RValue> result;
517 result.reserve(*sizePtr);
518 for (std::int32_t i = 0; i < *sizePtr; ++i) {
519 result.emplace_back(
520 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), *beginPtr + i * fItemSize)));
521 }
522 return result;
523}
524
526{
527 return fValueSize;
528}
529
531{
532 return EvalRVecAlignment(fSubfields[0]->GetAlignment());
533}
534
536{
537 visitor.VisitRVecField(*this);
538}
539
540//------------------------------------------------------------------------------
541
542ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
543 std::optional<std::string_view> emulatedFromType)
544 : ROOT::RFieldBase(fieldName, emulatedFromType ? *emulatedFromType : "std::vector<" + itemField->GetTypeName() + ">",
545 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
546 fItemSize(itemField->GetValueSize()),
547 fNWritten(0)
548{
549 if (emulatedFromType && !emulatedFromType->empty())
551
552 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
554 Attach(std::move(itemField));
555}
556
557ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
559{
560}
561
562std::unique_ptr<ROOT::RVectorField>
563ROOT::RVectorField::CreateUntyped(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
564{
565 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(fieldName, itemField->Clone("_0"), ""));
566}
567
568std::unique_ptr<ROOT::RFieldBase> ROOT::RVectorField::CloneImpl(std::string_view newName) const
569{
570 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
571 auto isUntyped = GetTypeName().empty() || ((fTraits & kTraitEmulatedField) != 0);
572 auto emulatedFromType = isUntyped ? std::make_optional(GetTypeName()) : std::nullopt;
573 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(newName, std::move(newItemField), emulatedFromType));
574}
575
576std::size_t ROOT::RVectorField::AppendImpl(const void *from)
577{
578 auto typedValue = static_cast<const std::vector<char> *>(from);
579 // The order is important here: Profiling showed that the integer division is on the critical path. By moving the
580 // computation of count before R__ASSERT, the compiler can use the result of a single instruction (on x86) also for
581 // the modulo operation. Otherwise, it must perform the division twice because R__ASSERT expands to an external call
582 // of Fatal() in case of failure, which could have side effects that the compiler cannot analyze.
583 auto count = typedValue->size() / fItemSize;
584 R__ASSERT((typedValue->size() % fItemSize) == 0);
585 std::size_t nbytes = 0;
586
587 if (fSubfields[0]->IsSimple() && count) {
588 GetPrincipalColumnOf(*fSubfields[0])->AppendV(typedValue->data(), count);
589 nbytes += count * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
590 } else {
591 for (unsigned i = 0; i < count; ++i) {
592 nbytes += CallAppendOn(*fSubfields[0], typedValue->data() + (i * fItemSize));
593 }
594 }
595
596 fNWritten += count;
597 fPrincipalColumn->Append(&fNWritten);
598 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
599}
600
601void ROOT::RVectorField::ResizeVector(void *vec, std::size_t nItems, std::size_t itemSize, const RFieldBase &itemField,
603{
604 auto typedValue = static_cast<std::vector<char> *>(vec);
605
606 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md
607 R__ASSERT(itemSize > 0);
608 const auto oldNItems = typedValue->size() / itemSize;
609 const bool canRealloc = oldNItems < nItems;
610 bool allDeallocated = false;
611 if (itemDeleter) {
613 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
614 itemDeleter->operator()(typedValue->data() + (i * itemSize), true /* dtorOnly */);
615 }
616 }
617 typedValue->resize(nItems * itemSize);
618 if (!(itemField.GetTraits() & kTraitTriviallyConstructible)) {
619 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
620 CallConstructValueOn(itemField, typedValue->data() + (i * itemSize));
621 }
622 }
623}
624
626{
627 auto typedValue = static_cast<std::vector<char> *>(to);
628
631 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
632
633 if (fSubfields[0]->IsSimple()) {
634 typedValue->resize(nItems * fItemSize);
635 if (nItems)
636 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, typedValue->data());
637 return;
638 }
639
640 ResizeVector(to, nItems, fItemSize, *fSubfields[0], fItemDeleter.get());
641
642 for (std::size_t i = 0; i < nItems; ++i) {
643 CallReadOn(*fSubfields[0], collectionStart + i, typedValue->data() + (i * fItemSize));
644 }
645}
646
656
661
666
668{
669 if (GetOnDiskId() == kInvalidDescriptorId)
670 return nullptr;
671
672 const auto descGuard = pageSource.GetSharedDescriptorGuard();
673 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
674 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
675 auto substitute = std::make_unique<RArrayAsVectorField>(
676 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
677 substitute->SetOnDiskId(GetOnDiskId());
678 return substitute;
679 }
680 return nullptr;
681}
682
684{
685 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
686}
687
689{
690 auto vecPtr = static_cast<std::vector<char> *>(objPtr);
691 if (fItemDeleter) {
692 R__ASSERT(fItemSize > 0);
693 R__ASSERT((vecPtr->size() % fItemSize) == 0);
694 auto nItems = vecPtr->size() / fItemSize;
695 for (std::size_t i = 0; i < nItems; ++i) {
696 fItemDeleter->operator()(vecPtr->data() + (i * fItemSize), true /* dtorOnly */);
697 }
698 }
699 std::destroy_at(vecPtr);
700 RDeleter::operator()(objPtr, dtorOnly);
701}
702
703std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVectorField::GetDeleter() const
704{
705 if (fItemDeleter)
706 return std::make_unique<RVectorDeleter>(fItemSize, GetDeleterOf(*fSubfields[0]));
707 return std::make_unique<RVectorDeleter>();
708}
709
710std::vector<ROOT::RFieldBase::RValue> ROOT::RVectorField::SplitValue(const RValue &value) const
711{
712 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
713}
714
716{
717 visitor.VisitVectorField(*this);
718}
719
720//------------------------------------------------------------------------------
721
722ROOT::RField<std::vector<bool>>::RField(std::string_view name)
723 : ROOT::RFieldBase(name, "std::vector<bool>", ROOT::ENTupleStructure::kCollection, false /* isSimple */)
724{
725 Attach(std::make_unique<RField<bool>>("_0"));
726}
727
728std::size_t ROOT::RField<std::vector<bool>>::AppendImpl(const void *from)
729{
730 auto typedValue = static_cast<const std::vector<bool> *>(from);
731 auto count = typedValue->size();
732 for (unsigned i = 0; i < count; ++i) {
733 bool bval = (*typedValue)[i];
734 CallAppendOn(*fSubfields[0], &bval);
735 }
736 fNWritten += count;
737 fPrincipalColumn->Append(&fNWritten);
738 return count + fPrincipalColumn->GetElement()->GetPackedSize();
739}
740
742{
743 auto typedValue = static_cast<std::vector<bool> *>(to);
744
745 if (fOnDiskNRepetitions == 0) {
747 RNTupleLocalIndex collectionStart;
748 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
749 typedValue->resize(nItems);
750 for (std::size_t i = 0; i < nItems; ++i) {
751 bool bval;
752 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
753 (*typedValue)[i] = bval;
754 }
755 } else {
756 typedValue->resize(fOnDiskNRepetitions);
757 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
758 bool bval;
759 CallReadOn(*fSubfields[0], globalIndex * fOnDiskNRepetitions + i, &bval);
760 (*typedValue)[i] = bval;
761 }
762 }
763}
764
765void ROOT::RField<std::vector<bool>>::ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to)
766{
767 auto typedValue = static_cast<std::vector<bool> *>(to);
768
769 if (fOnDiskNRepetitions == 0) {
771 RNTupleLocalIndex collectionStart;
772 fPrincipalColumn->GetCollectionInfo(localIndex, &collectionStart, &nItems);
773 typedValue->resize(nItems);
774 for (std::size_t i = 0; i < nItems; ++i) {
775 bool bval;
776 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
777 (*typedValue)[i] = bval;
778 }
779 } else {
780 typedValue->resize(fOnDiskNRepetitions);
781 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
782 bool bval;
783 CallReadOn(*fSubfields[0], localIndex * fOnDiskNRepetitions + i, &bval);
784 (*typedValue)[i] = bval;
785 }
786 }
787}
788
789const ROOT::RFieldBase::RColumnRepresentations &ROOT::RField<std::vector<bool>>::GetColumnRepresentations() const
790{
791 static RColumnRepresentations representations({{ENTupleColumnType::kSplitIndex64},
795 {{}});
796 return representations;
797}
798
799void ROOT::RField<std::vector<bool>>::GenerateColumns()
800{
801 R__ASSERT(fOnDiskNRepetitions == 0); // fOnDiskNRepetitions must only be used for reading
803}
804
805void ROOT::RField<std::vector<bool>>::GenerateColumns(const ROOT::RNTupleDescriptor &desc)
806{
807 if (fOnDiskNRepetitions == 0)
809}
810
811void ROOT::RField<std::vector<bool>>::ReconcileOnDiskField(const RNTupleDescriptor &desc)
812{
813 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
814
815 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
816 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions).ThrowOnError();
817
818 if (fieldDesc.GetNRepetitions() == 0) {
819 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected repetition count > 0\n" +
820 Internal::GetTypeTraceReport(*this, desc)));
821 }
822 if (fieldDesc.GetStructure() != ENTupleStructure::kPlain) {
823 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected plain on-disk field\n" +
824 Internal::GetTypeTraceReport(*this, desc)));
825 }
826 fOnDiskNRepetitions = fieldDesc.GetNRepetitions();
827 } else {
828 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
829 }
830}
831
832std::vector<ROOT::RFieldBase::RValue> ROOT::RField<std::vector<bool>>::SplitValue(const RValue &value) const
833{
834 const auto &typedValue = value.GetRef<std::vector<bool>>();
835 auto count = typedValue.size();
836 std::vector<RValue> result;
837 result.reserve(count);
838 for (unsigned i = 0; i < count; ++i) {
839 if (typedValue[i]) {
840 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(true))));
841 } else {
842 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(false))));
843 }
844 }
845 return result;
846}
847
849{
850 visitor.VisitVectorBoolField(*this);
851}
852
853//------------------------------------------------------------------------------
854
855ROOT::RArrayAsRVecField::RArrayAsRVecField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
856 std::size_t arrayLength)
857 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
858 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
859 fItemSize(itemField->GetValueSize()),
860 fArrayLength(arrayLength)
861{
862 Attach(std::move(itemField));
866}
867
868std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsRVecField::CloneImpl(std::string_view newName) const
869{
870 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
871 return std::make_unique<RArrayAsRVecField>(newName, std::move(newItemField), fArrayLength);
872}
873
875{
876 // initialize data members fBegin, fSize, fCapacity
877 // currently the inline buffer is left uninitialized
878 void **beginPtr = new (where)(void *)(nullptr);
879 std::int32_t *sizePtr = new (static_cast<void *>(beginPtr + 1)) std::int32_t(0);
880 new (sizePtr + 1) std::int32_t(-1);
881}
882
883std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsRVecField::GetDeleter() const
884{
885 if (fItemDeleter) {
886 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize,
887 GetDeleterOf(*fSubfields[0]));
888 }
889 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment());
890}
891
893{
894 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
895
896 if (fSubfields[0]->IsSimple()) {
897 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, begin);
898 return;
899 }
900
901 // Read the new values into the collection elements
902 for (std::size_t i = 0; i < fArrayLength; ++i) {
903 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, begin + (i * fItemSize));
904 }
905}
906
908{
909 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
910
911 if (fSubfields[0]->IsSimple()) {
912 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, begin);
913 return;
914 }
915
916 // Read the new values into the collection elements
917 for (std::size_t i = 0; i < fArrayLength; ++i) {
918 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, begin + (i * fItemSize));
919 }
920}
921
923{
924 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffTypeVersion | kDiffStructure | kDiffNRepetitions)
925 .ThrowOnError();
926 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
927 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
928 throw RException(R__FAIL("RArrayAsRVecField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
929 Internal::GetTypeTraceReport(*this, desc)));
930 }
931}
932
934{
935 return EvalRVecAlignment(fSubfields[0]->GetAlignment());
936}
937
938std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsRVecField::SplitValue(const ROOT::RFieldBase::RValue &value) const
939{
940 auto arrayPtr = value.GetPtr<unsigned char>().get();
941 std::vector<ROOT::RFieldBase::RValue> result;
942 result.reserve(fArrayLength);
943 for (unsigned i = 0; i < fArrayLength; ++i) {
944 result.emplace_back(
945 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), arrayPtr + (i * fItemSize))));
946 }
947 return result;
948}
949
951{
952 visitor.VisitArrayAsRVecField(*this);
953}
954
955//------------------------------------------------------------------------------
956
957ROOT::RArrayAsVectorField::RArrayAsVectorField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
958 std::size_t arrayLength)
959 : ROOT::RFieldBase(fieldName, "std::vector<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kCollection,
960 false /* isSimple */),
961 fItemSize(itemField->GetValueSize()),
962 fArrayLength(arrayLength)
963{
964 Attach(std::move(itemField));
967}
968
969std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsVectorField::CloneImpl(std::string_view newName) const
970{
971 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
972 return std::make_unique<RArrayAsVectorField>(newName, std::move(newItemField), fArrayLength);
973}
974
976{
977 throw RException(R__FAIL("RArrayAsVectorField fields must only be used for reading"));
978}
979
980std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsVectorField::GetDeleter() const
981{
982 if (fItemDeleter)
983 return std::make_unique<RVectorField::RVectorDeleter>(fItemSize, GetDeleterOf(*fSubfields[0]));
984 return std::make_unique<RVectorField::RVectorDeleter>();
985}
986
988{
989 auto typedValue = static_cast<std::vector<char> *>(to);
990
991 if (fSubfields[0]->IsSimple()) {
992 typedValue->resize(fArrayLength * fItemSize);
993 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, typedValue->data());
994 return;
995 }
996
997 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
998
999 for (std::size_t i = 0; i < fArrayLength; ++i) {
1000 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
1001 }
1002}
1003
1005{
1006 auto typedValue = static_cast<std::vector<char> *>(to);
1007
1008 if (fSubfields[0]->IsSimple()) {
1009 typedValue->resize(fArrayLength * fItemSize);
1010 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, typedValue->data());
1011 return;
1012 }
1013
1014 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
1015
1016 for (std::size_t i = 0; i < fArrayLength; ++i) {
1017 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
1018 }
1019}
1020
1022{
1023 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffTypeVersion | kDiffStructure | kDiffNRepetitions);
1024
1025 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1026 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
1027 throw RException(R__FAIL("RArrayAsVectorField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
1028 Internal::GetTypeTraceReport(*this, desc)));
1029 }
1030}
1031
1032std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsVectorField::SplitValue(const ROOT::RFieldBase::RValue &value) const
1033{
1034 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
1035}
1036
1038{
1039 visitor.VisitArrayAsVectorField(*this);
1040}
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:110
#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)
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)
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
bool IsSimple() const
std::uint32_t GetTraits() const
@ 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.
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:313
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::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::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().