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 if (!itemField->GetTypeAlias().empty()) {
128 fTypeAlias = "std::array<" + itemField->GetTypeAlias() + "," +
129 Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">";
130 }
131 Attach(std::move(itemField));
132}
133
134std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayField::CloneImpl(std::string_view newName) const
135{
136 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
137 return std::make_unique<RArrayField>(newName, std::move(newItemField), fArrayLength);
138}
139
140std::size_t ROOT::RArrayField::AppendImpl(const void *from)
141{
142 std::size_t nbytes = 0;
143 if (fSubfields[0]->IsSimple()) {
144 GetPrincipalColumnOf(*fSubfields[0])->AppendV(from, fArrayLength);
145 nbytes += fArrayLength * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
146 } else {
147 auto arrayPtr = static_cast<const unsigned char *>(from);
148 for (unsigned i = 0; i < fArrayLength; ++i) {
149 nbytes += CallAppendOn(*fSubfields[0], arrayPtr + (i * fItemSize));
150 }
151 }
152 return nbytes;
153}
154
156{
157 if (fSubfields[0]->IsSimple()) {
158 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, to);
159 } else {
160 auto arrayPtr = static_cast<unsigned char *>(to);
161 for (unsigned i = 0; i < fArrayLength; ++i) {
162 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
163 }
164 }
165}
166
168{
169 if (fSubfields[0]->IsSimple()) {
170 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, to);
171 } else {
172 auto arrayPtr = static_cast<unsigned char *>(to);
173 for (unsigned i = 0; i < fArrayLength; ++i) {
174 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
175 }
176 }
177}
178
180{
181 if (!fSubfields[0]->IsSimple())
183
184 GetPrincipalColumnOf(*fSubfields[0])
185 ->ReadV(bulkSpec.fFirstIndex * fArrayLength, bulkSpec.fCount * fArrayLength, bulkSpec.fValues);
186 return RBulkSpec::kAllSet;
187}
188
190{
191 static const std::vector<std::string> prefixes = {"std::array<"};
192
193 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
194 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
195}
196
198{
199 if (fSubfields[0]->GetTraits() & kTraitTriviallyConstructible)
200 return;
201
202 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
203 for (unsigned i = 0; i < fArrayLength; ++i) {
204 CallConstructValueOn(*fSubfields[0], arrayPtr + (i * fItemSize));
205 }
206}
207
209{
210 if (fItemDeleter) {
211 for (unsigned i = 0; i < fArrayLength; ++i) {
212 fItemDeleter->operator()(reinterpret_cast<unsigned char *>(objPtr) + i * fItemSize, true /* dtorOnly */);
213 }
214 }
215 RDeleter::operator()(objPtr, dtorOnly);
216}
217
218std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayField::GetDeleter() const
219{
220 if (!(fSubfields[0]->GetTraits() & kTraitTriviallyDestructible))
221 return std::make_unique<RArrayDeleter>(fItemSize, fArrayLength, GetDeleterOf(*fSubfields[0]));
222 return std::make_unique<RDeleter>();
223}
224
225std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayField::SplitValue(const RValue &value) const
226{
227 auto valuePtr = value.GetPtr<void>();
228 auto arrayPtr = static_cast<unsigned char *>(valuePtr.get());
229 std::vector<RValue> result;
230 result.reserve(fArrayLength);
231 for (unsigned i = 0; i < fArrayLength; ++i) {
232 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(valuePtr, arrayPtr + (i * fItemSize))));
233 }
234 return result;
235}
236
238{
239 visitor.VisitArrayField(*this);
240}
241
242//------------------------------------------------------------------------------
243
244ROOT::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
245 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
246 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
247 fItemSize(itemField->GetValueSize()),
248 fNWritten(0)
249{
250 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
252 if (!itemField->GetTypeAlias().empty())
253 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
254 Attach(std::move(itemField));
256
257 // Determine if we can optimimize bulk reading
258 if (fSubfields[0]->IsSimple()) {
259 fBulkSubfield = fSubfields[0].get();
260 } else {
261 if (auto f = dynamic_cast<RArrayField *>(fSubfields[0].get())) {
262 auto grandChildFields = fSubfields[0]->GetMutableSubfields();
263 if (grandChildFields[0]->IsSimple()) {
265 fBulkNRepetition = f->GetLength();
266 }
267 }
268 }
269}
270
271std::unique_ptr<ROOT::RFieldBase> ROOT::RRVecField::CloneImpl(std::string_view newName) const
272{
273 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
274 return std::make_unique<RRVecField>(newName, std::move(newItemField));
275}
276
277std::size_t ROOT::RRVecField::AppendImpl(const void *from)
278{
279 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(from);
280
281 std::size_t nbytes = 0;
282 if (fSubfields[0]->IsSimple() && *sizePtr) {
283 GetPrincipalColumnOf(*fSubfields[0])->AppendV(*beginPtr, *sizePtr);
284 nbytes += *sizePtr * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
285 } else {
286 for (std::int32_t i = 0; i < *sizePtr; ++i) {
287 nbytes += CallAppendOn(*fSubfields[0], *beginPtr + i * fItemSize);
288 }
289 }
290
291 fNWritten += *sizePtr;
292 fPrincipalColumn->Append(&fNWritten);
293 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
294}
295
296unsigned char *ROOT::RRVecField::ResizeRVec(void *rvec, std::size_t nItems, std::size_t itemSize,
298
299{
300 if (nItems > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) {
301 throw RException(R__FAIL("RVec too large: " + std::to_string(nItems)));
302 }
303
305 const std::size_t oldSize = *sizePtr;
306
307 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md for details
308 // on the element construction/destrution.
309 const bool owns = (*capacityPtr != -1);
310 const bool needsConstruct = !(itemField->GetTraits() & kTraitTriviallyConstructible);
311 const bool needsDestruct = owns && itemDeleter;
312
313 // Destroy excess elements, if any
314 if (needsDestruct) {
315 for (std::size_t i = nItems; i < oldSize; ++i) {
316 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
317 }
318 }
319
320 // Resize RVec (capacity and size)
321 if (std::int32_t(nItems) > *capacityPtr) { // must reallocate
322 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
323 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
324 if (needsDestruct) {
325 for (std::size_t i = 0u; i < oldSize; ++i) {
326 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
327 }
328 }
329
330 // TODO Increment capacity by a factor rather than just enough to fit the elements.
331 if (owns) {
332 // *beginPtr points to the array of item values (allocated in an earlier call by the following malloc())
333 free(*beginPtr);
334 }
335 // We trust that malloc returns a buffer with large enough alignment.
336 // This might not be the case if T in RVec<T> is over-aligned.
337 *beginPtr = static_cast<unsigned char *>(malloc(nItems * itemSize));
338 R__ASSERT(*beginPtr != nullptr);
340
341 // Placement new for elements that were already there before the resize
342 if (needsConstruct) {
343 for (std::size_t i = 0u; i < oldSize; ++i)
344 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
345 }
346 }
347 *sizePtr = nItems;
348
349 // Placement new for new elements, if any
350 if (needsConstruct) {
351 for (std::size_t i = oldSize; i < nItems; ++i)
352 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
353 }
354
355 return *beginPtr;
356}
357
359{
360 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
361 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
362
363 // Read collection info for this entry
366 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
367
368 auto begin = ResizeRVec(to, nItems, fItemSize, fSubfields[0].get(), fItemDeleter.get());
369
370 if (fSubfields[0]->IsSimple() && nItems) {
371 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, begin);
372 return;
373 }
374
375 // Read the new values into the collection elements
376 for (std::size_t i = 0; i < nItems; ++i) {
377 CallReadOn(*fSubfields[0], collectionStart + i, begin + (i * fItemSize));
378 }
379}
380
382{
383 if (!fBulkSubfield)
385
386 if (bulkSpec.fAuxData->empty()) {
387 /// Initialize auxiliary memory: the first sizeof(size_t) bytes store the value size of the item field.
388 /// The following bytes store the item values, consecutively.
389 bulkSpec.fAuxData->resize(sizeof(std::size_t));
390 *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data()) = fBulkNRepetition * fBulkSubfield->GetValueSize();
391 }
392 const auto itemValueSize = *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data());
393 unsigned char *itemValueArray = bulkSpec.fAuxData->data() + sizeof(std::size_t);
395
396 // Get size of the first RVec of the bulk
399 fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &firstItemIndex, &collectionSize);
402 *capacityPtr = -1;
403
404 // Set the size of the remaining RVecs of the bulk, going page by page through the RNTuple offset column.
405 // We optimistically assume that bulkSpec.fAuxData is already large enough to hold all the item values in the
406 // given range. If not, we'll fix up the pointers afterwards.
407 auto lastOffset = firstItemIndex.GetIndexInCluster() + collectionSize;
409 std::size_t nValues = 1;
410 std::size_t nItems = collectionSize;
411 while (nRemainingValues > 0) {
413 const auto offsets =
414 fPrincipalColumn->MapV<ROOT::Internal::RColumnIndex>(bulkSpec.fFirstIndex + nValues, nElementsUntilPageEnd);
415 const std::size_t nBatch = std::min(nRemainingValues, nElementsUntilPageEnd);
416 for (std::size_t i = 0; i < nBatch; ++i) {
417 const auto size = offsets[i] - lastOffset;
418 std::tie(beginPtr, sizePtr, capacityPtr) =
419 GetRVecDataMembers(reinterpret_cast<unsigned char *>(bulkSpec.fValues) + (nValues + i) * fValueSize);
421 *sizePtr = size;
422 *capacityPtr = -1;
423
424 nItems += size;
425 lastOffset = offsets[i];
426 }
428 nValues += nBatch;
429 }
430
431 bulkSpec.fAuxData->resize(sizeof(std::size_t) + nItems * itemValueSize);
432 // If the vector got reallocated, we need to fix-up the RVecs begin pointers.
433 const auto delta = itemValueArray - (bulkSpec.fAuxData->data() + sizeof(std::size_t));
434 if (delta != 0) {
435 auto beginPtrAsUChar = reinterpret_cast<unsigned char *>(bulkSpec.fValues);
436 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
437 *reinterpret_cast<unsigned char **>(beginPtrAsUChar) -= delta;
439 }
440 }
441
442 GetPrincipalColumnOf(*fBulkSubfield)
443 ->ReadV(firstItemIndex * fBulkNRepetition, nItems * fBulkNRepetition, itemValueArray - delta);
444 return RBulkSpec::kAllSet;
445}
446
456
461
466
468{
469 if (GetOnDiskId() == kInvalidDescriptorId)
470 return nullptr;
471
472 const auto descGuard = pageSource.GetSharedDescriptorGuard();
473 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
474 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
475 auto substitute = std::make_unique<RArrayAsRVecField>(
476 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
477 substitute->SetOnDiskId(GetOnDiskId());
478 return substitute;
479 }
480 return nullptr;
481}
482
484{
485 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
486}
487
489{
490 // initialize data members fBegin, fSize, fCapacity
491 // currently the inline buffer is left uninitialized
492 void **beginPtr = new (where)(void *)(nullptr);
493 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
494 new (sizePtr + 1) std::int32_t(-1);
495}
496
498{
500
501 if (fItemDeleter) {
502 for (std::int32_t i = 0; i < *sizePtr; ++i) {
503 fItemDeleter->operator()(*beginPtr + i * fItemSize, true /* dtorOnly */);
504 }
505 }
506
508 RDeleter::operator()(objPtr, dtorOnly);
509}
510
511std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RRVecField::GetDeleter() const
512{
513 if (fItemDeleter)
514 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize, GetDeleterOf(*fSubfields[0]));
515 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment());
516}
517
518std::vector<ROOT::RFieldBase::RValue> ROOT::RRVecField::SplitValue(const RValue &value) const
519{
520 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(value.GetPtr<void>().get());
521
522 std::vector<RValue> result;
523 result.reserve(*sizePtr);
524 for (std::int32_t i = 0; i < *sizePtr; ++i) {
525 result.emplace_back(
526 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), *beginPtr + i * fItemSize)));
527 }
528 return result;
529}
530
532{
533 return fValueSize;
534}
535
537{
538 return EvalRVecAlignment(fSubfields[0]->GetAlignment());
539}
540
542{
543 visitor.VisitRVecField(*this);
544}
545
546//------------------------------------------------------------------------------
547
548ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
549 std::optional<std::string_view> emulatedFromType)
550 : ROOT::RFieldBase(fieldName, emulatedFromType ? *emulatedFromType : "std::vector<" + itemField->GetTypeName() + ">",
551 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
552 fItemSize(itemField->GetValueSize()),
553 fNWritten(0)
554{
555 if (emulatedFromType && !emulatedFromType->empty())
557
558 if (!itemField->GetTypeAlias().empty())
559 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
560
561 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
563 Attach(std::move(itemField));
564}
565
566ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
568{
569}
570
571std::unique_ptr<ROOT::RVectorField>
572ROOT::RVectorField::CreateUntyped(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
573{
574 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(fieldName, itemField->Clone("_0"), ""));
575}
576
577std::unique_ptr<ROOT::RFieldBase> ROOT::RVectorField::CloneImpl(std::string_view newName) const
578{
579 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
580 auto isUntyped = GetTypeName().empty() || ((fTraits & kTraitEmulatedField) != 0);
581 auto emulatedFromType = isUntyped ? std::make_optional(GetTypeName()) : std::nullopt;
582 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(newName, std::move(newItemField), emulatedFromType));
583}
584
585std::size_t ROOT::RVectorField::AppendImpl(const void *from)
586{
587 auto typedValue = static_cast<const std::vector<char> *>(from);
588 // The order is important here: Profiling showed that the integer division is on the critical path. By moving the
589 // computation of count before R__ASSERT, the compiler can use the result of a single instruction (on x86) also for
590 // the modulo operation. Otherwise, it must perform the division twice because R__ASSERT expands to an external call
591 // of Fatal() in case of failure, which could have side effects that the compiler cannot analyze.
592 auto count = typedValue->size() / fItemSize;
593 R__ASSERT((typedValue->size() % fItemSize) == 0);
594 std::size_t nbytes = 0;
595
596 if (fSubfields[0]->IsSimple() && count) {
597 GetPrincipalColumnOf(*fSubfields[0])->AppendV(typedValue->data(), count);
598 nbytes += count * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
599 } else {
600 for (unsigned i = 0; i < count; ++i) {
601 nbytes += CallAppendOn(*fSubfields[0], typedValue->data() + (i * fItemSize));
602 }
603 }
604
605 fNWritten += count;
606 fPrincipalColumn->Append(&fNWritten);
607 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
608}
609
610void ROOT::RVectorField::ResizeVector(void *vec, std::size_t nItems, std::size_t itemSize, const RFieldBase &itemField,
612{
613 auto typedValue = static_cast<std::vector<char> *>(vec);
614
615 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md
616 R__ASSERT(itemSize > 0);
617 const auto oldNItems = typedValue->size() / itemSize;
618 const bool canRealloc = oldNItems < nItems;
619 bool allDeallocated = false;
620 if (itemDeleter) {
622 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
623 itemDeleter->operator()(typedValue->data() + (i * itemSize), true /* dtorOnly */);
624 }
625 }
626 typedValue->resize(nItems * itemSize);
627 if (!(itemField.GetTraits() & kTraitTriviallyConstructible)) {
628 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
629 CallConstructValueOn(itemField, typedValue->data() + (i * itemSize));
630 }
631 }
632}
633
635{
636 auto typedValue = static_cast<std::vector<char> *>(to);
637
640 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
641
642 if (fSubfields[0]->IsSimple()) {
643 typedValue->resize(nItems * fItemSize);
644 if (nItems)
645 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, typedValue->data());
646 return;
647 }
648
649 ResizeVector(to, nItems, fItemSize, *fSubfields[0], fItemDeleter.get());
650
651 for (std::size_t i = 0; i < nItems; ++i) {
652 CallReadOn(*fSubfields[0], collectionStart + i, typedValue->data() + (i * fItemSize));
653 }
654}
655
665
670
675
677{
678 if (GetOnDiskId() == kInvalidDescriptorId)
679 return nullptr;
680
681 const auto descGuard = pageSource.GetSharedDescriptorGuard();
682 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
683 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
684 auto substitute = std::make_unique<RArrayAsVectorField>(
685 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
686 substitute->SetOnDiskId(GetOnDiskId());
687 return substitute;
688 }
689 return nullptr;
690}
691
693{
694 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
695}
696
698{
699 auto vecPtr = static_cast<std::vector<char> *>(objPtr);
700 if (fItemDeleter) {
701 R__ASSERT(fItemSize > 0);
702 R__ASSERT((vecPtr->size() % fItemSize) == 0);
703 auto nItems = vecPtr->size() / fItemSize;
704 for (std::size_t i = 0; i < nItems; ++i) {
705 fItemDeleter->operator()(vecPtr->data() + (i * fItemSize), true /* dtorOnly */);
706 }
707 }
708 std::destroy_at(vecPtr);
709 RDeleter::operator()(objPtr, dtorOnly);
710}
711
712std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVectorField::GetDeleter() const
713{
714 if (fItemDeleter)
715 return std::make_unique<RVectorDeleter>(fItemSize, GetDeleterOf(*fSubfields[0]));
716 return std::make_unique<RVectorDeleter>();
717}
718
719std::vector<ROOT::RFieldBase::RValue> ROOT::RVectorField::SplitValue(const RValue &value) const
720{
721 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
722}
723
725{
726 visitor.VisitVectorField(*this);
727}
728
729//------------------------------------------------------------------------------
730
731ROOT::RField<std::vector<bool>>::RField(std::string_view name)
732 : ROOT::RFieldBase(name, "std::vector<bool>", ROOT::ENTupleStructure::kCollection, false /* isSimple */)
733{
734 Attach(std::make_unique<RField<bool>>("_0"));
735}
736
737std::size_t ROOT::RField<std::vector<bool>>::AppendImpl(const void *from)
738{
739 auto typedValue = static_cast<const std::vector<bool> *>(from);
740 auto count = typedValue->size();
741 for (unsigned i = 0; i < count; ++i) {
742 bool bval = (*typedValue)[i];
743 CallAppendOn(*fSubfields[0], &bval);
744 }
745 fNWritten += count;
746 fPrincipalColumn->Append(&fNWritten);
747 return count + fPrincipalColumn->GetElement()->GetPackedSize();
748}
749
751{
752 auto typedValue = static_cast<std::vector<bool> *>(to);
753
754 if (fOnDiskNRepetitions == 0) {
756 RNTupleLocalIndex collectionStart;
757 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
758 typedValue->resize(nItems);
759 for (std::size_t i = 0; i < nItems; ++i) {
760 bool bval;
761 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
762 (*typedValue)[i] = bval;
763 }
764 } else {
765 typedValue->resize(fOnDiskNRepetitions);
766 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
767 bool bval;
768 CallReadOn(*fSubfields[0], globalIndex * fOnDiskNRepetitions + i, &bval);
769 (*typedValue)[i] = bval;
770 }
771 }
772}
773
774void ROOT::RField<std::vector<bool>>::ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to)
775{
776 auto typedValue = static_cast<std::vector<bool> *>(to);
777
778 if (fOnDiskNRepetitions == 0) {
780 RNTupleLocalIndex collectionStart;
781 fPrincipalColumn->GetCollectionInfo(localIndex, &collectionStart, &nItems);
782 typedValue->resize(nItems);
783 for (std::size_t i = 0; i < nItems; ++i) {
784 bool bval;
785 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
786 (*typedValue)[i] = bval;
787 }
788 } else {
789 typedValue->resize(fOnDiskNRepetitions);
790 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
791 bool bval;
792 CallReadOn(*fSubfields[0], localIndex * fOnDiskNRepetitions + i, &bval);
793 (*typedValue)[i] = bval;
794 }
795 }
796}
797
798const ROOT::RFieldBase::RColumnRepresentations &ROOT::RField<std::vector<bool>>::GetColumnRepresentations() const
799{
800 static RColumnRepresentations representations({{ENTupleColumnType::kSplitIndex64},
804 {{}});
805 return representations;
806}
807
808void ROOT::RField<std::vector<bool>>::GenerateColumns()
809{
810 R__ASSERT(fOnDiskNRepetitions == 0); // fOnDiskNRepetitions must only be used for reading
812}
813
814void ROOT::RField<std::vector<bool>>::GenerateColumns(const ROOT::RNTupleDescriptor &desc)
815{
816 if (fOnDiskNRepetitions == 0)
818}
819
820void ROOT::RField<std::vector<bool>>::ReconcileOnDiskField(const RNTupleDescriptor &desc)
821{
822 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
823
824 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
825 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions).ThrowOnError();
826
827 if (fieldDesc.GetNRepetitions() == 0) {
828 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected repetition count > 0\n" +
829 Internal::GetTypeTraceReport(*this, desc)));
830 }
831 if (fieldDesc.GetStructure() != ENTupleStructure::kPlain) {
832 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected plain on-disk field\n" +
833 Internal::GetTypeTraceReport(*this, desc)));
834 }
835 fOnDiskNRepetitions = fieldDesc.GetNRepetitions();
836 } else {
837 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
838 }
839}
840
841std::vector<ROOT::RFieldBase::RValue> ROOT::RField<std::vector<bool>>::SplitValue(const RValue &value) const
842{
843 const auto &typedValue = value.GetRef<std::vector<bool>>();
844 auto count = typedValue.size();
845 std::vector<RValue> result;
846 result.reserve(count);
847 for (unsigned i = 0; i < count; ++i) {
848 if (typedValue[i]) {
849 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(true))));
850 } else {
851 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(false))));
852 }
853 }
854 return result;
855}
856
858{
859 visitor.VisitVectorBoolField(*this);
860}
861
862//------------------------------------------------------------------------------
863
864ROOT::RArrayAsRVecField::RArrayAsRVecField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
865 std::size_t arrayLength)
866 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
867 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
868 fItemSize(itemField->GetValueSize()),
869 fArrayLength(arrayLength)
870{
871 if (!itemField->GetTypeAlias().empty())
872 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
873 Attach(std::move(itemField));
877}
878
879std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsRVecField::CloneImpl(std::string_view newName) const
880{
881 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
882 return std::make_unique<RArrayAsRVecField>(newName, std::move(newItemField), fArrayLength);
883}
884
886{
887 // initialize data members fBegin, fSize, fCapacity
888 // currently the inline buffer is left uninitialized
889 void **beginPtr = new (where)(void *)(nullptr);
890 std::int32_t *sizePtr = new (static_cast<void *>(beginPtr + 1)) std::int32_t(0);
891 new (sizePtr + 1) std::int32_t(-1);
892}
893
894std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsRVecField::GetDeleter() const
895{
896 if (fItemDeleter) {
897 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize,
898 GetDeleterOf(*fSubfields[0]));
899 }
900 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment());
901}
902
904{
905 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
906
907 if (fSubfields[0]->IsSimple()) {
908 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, begin);
909 return;
910 }
911
912 // Read the new values into the collection elements
913 for (std::size_t i = 0; i < fArrayLength; ++i) {
914 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, begin + (i * fItemSize));
915 }
916}
917
919{
920 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
921
922 if (fSubfields[0]->IsSimple()) {
923 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, begin);
924 return;
925 }
926
927 // Read the new values into the collection elements
928 for (std::size_t i = 0; i < fArrayLength; ++i) {
929 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, begin + (i * fItemSize));
930 }
931}
932
934{
935 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffTypeVersion | kDiffStructure | kDiffNRepetitions)
936 .ThrowOnError();
937 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
938 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
939 throw RException(R__FAIL("RArrayAsRVecField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
940 Internal::GetTypeTraceReport(*this, desc)));
941 }
942}
943
945{
946 return EvalRVecAlignment(fSubfields[0]->GetAlignment());
947}
948
949std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsRVecField::SplitValue(const ROOT::RFieldBase::RValue &value) const
950{
951 auto arrayPtr = value.GetPtr<unsigned char>().get();
952 std::vector<ROOT::RFieldBase::RValue> result;
953 result.reserve(fArrayLength);
954 for (unsigned i = 0; i < fArrayLength; ++i) {
955 result.emplace_back(
956 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), arrayPtr + (i * fItemSize))));
957 }
958 return result;
959}
960
962{
963 visitor.VisitArrayAsRVecField(*this);
964}
965
966//------------------------------------------------------------------------------
967
968ROOT::RArrayAsVectorField::RArrayAsVectorField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
969 std::size_t arrayLength)
970 : ROOT::RFieldBase(fieldName, "std::vector<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kCollection,
971 false /* isSimple */),
972 fItemSize(itemField->GetValueSize()),
973 fArrayLength(arrayLength)
974{
975 if (!itemField->GetTypeAlias().empty())
976 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
977 Attach(std::move(itemField));
980}
981
982std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsVectorField::CloneImpl(std::string_view newName) const
983{
984 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
985 return std::make_unique<RArrayAsVectorField>(newName, std::move(newItemField), fArrayLength);
986}
987
989{
990 throw RException(R__FAIL("RArrayAsVectorField fields must only be used for reading"));
991}
992
993std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsVectorField::GetDeleter() const
994{
995 if (fItemDeleter)
996 return std::make_unique<RVectorField::RVectorDeleter>(fItemSize, GetDeleterOf(*fSubfields[0]));
997 return std::make_unique<RVectorField::RVectorDeleter>();
998}
999
1001{
1002 auto typedValue = static_cast<std::vector<char> *>(to);
1003
1004 if (fSubfields[0]->IsSimple()) {
1005 typedValue->resize(fArrayLength * fItemSize);
1006 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, typedValue->data());
1007 return;
1008 }
1009
1010 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
1011
1012 for (std::size_t i = 0; i < fArrayLength; ++i) {
1013 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
1014 }
1015}
1016
1018{
1019 auto typedValue = static_cast<std::vector<char> *>(to);
1020
1021 if (fSubfields[0]->IsSimple()) {
1022 typedValue->resize(fArrayLength * fItemSize);
1023 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, typedValue->data());
1024 return;
1025 }
1026
1027 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
1028
1029 for (std::size_t i = 0; i < fArrayLength; ++i) {
1030 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
1031 }
1032}
1033
1035{
1036 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffTypeVersion | kDiffStructure | kDiffNRepetitions);
1037
1038 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1039 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
1040 throw RException(R__FAIL("RArrayAsVectorField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
1041 Internal::GetTypeTraceReport(*this, desc)));
1042 }
1043}
1044
1045std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsVectorField::SplitValue(const ROOT::RFieldBase::RValue &value) const
1046{
1047 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
1048}
1049
1051{
1052 visitor.VisitArrayAsVectorField(*this);
1053}
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.
std::string fTypeAlias
A typedef or using name that was used when creating the field.
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:319
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().