Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RFieldSequenceContainer.cxx
Go to the documentation of this file.
1/// \file RFieldSequenceContainer.cxx
2/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
3/// \date 2024-11-19
4
5#include <ROOT/RField.hxx>
6#include <ROOT/RFieldBase.hxx>
9
10#include <cstdlib> // for malloc, free
11#include <limits>
12#include <memory>
13#include <new> // hardware_destructive_interference_size
14
15namespace {
16
17std::vector<ROOT::RFieldBase::RValue> SplitVector(std::shared_ptr<void> valuePtr, ROOT::RFieldBase &itemField)
18{
19 auto *vec = static_cast<std::vector<char> *>(valuePtr.get());
20 const auto itemSize = itemField.GetValueSize();
21 R__ASSERT(itemSize > 0);
22 R__ASSERT((vec->size() % itemSize) == 0);
23 const auto nItems = vec->size() / itemSize;
24 std::vector<ROOT::RFieldBase::RValue> result;
25 result.reserve(nItems);
26 for (unsigned i = 0; i < nItems; ++i) {
27 result.emplace_back(itemField.BindValue(std::shared_ptr<void>(valuePtr, vec->data() + (i * itemSize))));
28 }
29 return result;
30}
31
32} // anonymous namespace
33
34ROOT::RArrayField::RArrayField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
35 std::size_t arrayLength)
36 : ROOT::RFieldBase(fieldName,
37 "std::array<" + itemField->GetTypeName() + "," +
38 Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">",
39 ROOT::ENTupleStructure::kPlain, false /* isSimple */, arrayLength),
40 fItemSize(itemField->GetValueSize()),
41 fArrayLength(arrayLength)
42{
43 fTraits |= itemField->GetTraits() & ~kTraitMappable;
44 if (!itemField->GetTypeAlias().empty()) {
45 fTypeAlias = "std::array<" + itemField->GetTypeAlias() + "," +
46 Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">";
47 }
48 Attach(std::move(itemField), "_0");
49}
50
51std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayField::CloneImpl(std::string_view newName) const
52{
53 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
54 return std::make_unique<RArrayField>(newName, std::move(newItemField), fArrayLength);
55}
56
57std::size_t ROOT::RArrayField::AppendImpl(const void *from)
58{
59 std::size_t nbytes = 0;
60 if (fSubfields[0]->IsSimple()) {
61 GetPrincipalColumnOf(*fSubfields[0])->AppendV(from, fArrayLength);
62 nbytes += fArrayLength * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
63 } else {
64 auto arrayPtr = static_cast<const unsigned char *>(from);
65 for (unsigned i = 0; i < fArrayLength; ++i) {
66 nbytes += CallAppendOn(*fSubfields[0], arrayPtr + (i * fItemSize));
67 }
68 }
69 return nbytes;
70}
71
73{
74 if (fSubfields[0]->IsSimple()) {
75 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, to);
76 } else {
77 auto arrayPtr = static_cast<unsigned char *>(to);
78 for (unsigned i = 0; i < fArrayLength; ++i) {
79 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
80 }
81 }
82}
83
85{
86 if (fSubfields[0]->IsSimple()) {
87 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, to);
88 } else {
89 auto arrayPtr = static_cast<unsigned char *>(to);
90 for (unsigned i = 0; i < fArrayLength; ++i) {
91 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
92 }
93 }
94}
95
96std::size_t ROOT::RArrayField::ReadBulkImpl(const RBulkSpec &bulkSpec)
97{
98 if (!fSubfields[0]->IsSimple())
99 return RFieldBase::ReadBulkImpl(bulkSpec);
100
102 ->ReadV(bulkSpec.fFirstIndex * fArrayLength, bulkSpec.fCount * fArrayLength, bulkSpec.fValues);
103 return RBulkSpec::kAllSet;
104}
105
107{
108 static const std::vector<std::string> prefixes = {"std::array<"};
109
110 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
111 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
112}
113
115{
117 return;
118
119 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
120 for (unsigned i = 0; i < fArrayLength; ++i) {
121 CallConstructValueOn(*fSubfields[0], arrayPtr + (i * fItemSize));
122 }
123}
124
125void ROOT::RArrayField::RArrayDeleter::operator()(void *objPtr, bool dtorOnly)
126{
127 if (fItemDeleter) {
128 for (unsigned i = 0; i < fArrayLength; ++i) {
129 fItemDeleter->operator()(reinterpret_cast<unsigned char *>(objPtr) + i * fItemSize, true /* dtorOnly */);
130 }
131 }
132 RDeleter::operator()(objPtr, dtorOnly);
133}
134
135std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayField::GetDeleter() const
136{
138 return std::make_unique<RArrayDeleter>(fItemSize, fArrayLength, GetDeleterOf(*fSubfields[0]));
139 return std::make_unique<RDeleter>();
140}
141
142std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayField::SplitValue(const RValue &value) const
143{
144 auto valuePtr = value.GetPtr<void>();
145 auto arrayPtr = static_cast<unsigned char *>(valuePtr.get());
146 std::vector<RValue> result;
147 result.reserve(fArrayLength);
148 for (unsigned i = 0; i < fArrayLength; ++i) {
149 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(valuePtr, arrayPtr + (i * fItemSize))));
150 }
151 return result;
152}
153
155{
156 visitor.VisitArrayField(*this);
157}
158
159//------------------------------------------------------------------------------
160
161ROOT::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
162 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
163 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
164 fItemSize(itemField->GetValueSize()),
165 fNWritten(0)
166{
167 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
168 fItemDeleter = GetDeleterOf(*itemField);
169 if (!itemField->GetTypeAlias().empty())
170 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
171 Attach(std::move(itemField), "_0");
172 fValueSize =
174
175 // Determine if we can optimimize bulk reading
176 if (fSubfields[0]->IsSimple()) {
177 fBulkSubfield = fSubfields[0].get();
178 } else {
179 if (auto f = dynamic_cast<RArrayField *>(fSubfields[0].get())) {
180 auto grandChildFields = fSubfields[0]->GetMutableSubfields();
181 if (grandChildFields[0]->IsSimple()) {
182 fBulkSubfield = grandChildFields[0];
183 fBulkNRepetition = f->GetLength();
184 }
185 }
186 }
187}
188
189std::unique_ptr<ROOT::RFieldBase> ROOT::RRVecField::CloneImpl(std::string_view newName) const
190{
191 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
192 return std::make_unique<RRVecField>(newName, std::move(newItemField));
193}
194
195std::size_t ROOT::RRVecField::AppendImpl(const void *from)
196{
197 auto [beginPtr, sizePtr, _] = Internal::GetRVecDataMembers(from);
198
199 std::size_t nbytes = 0;
200 if (fSubfields[0]->IsSimple() && *sizePtr) {
201 GetPrincipalColumnOf(*fSubfields[0])->AppendV(*beginPtr, *sizePtr);
202 nbytes += *sizePtr * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
203 } else {
204 for (std::int32_t i = 0; i < *sizePtr; ++i) {
205 nbytes += CallAppendOn(*fSubfields[0], *beginPtr + i * fItemSize);
206 }
207 }
208
209 fNWritten += *sizePtr;
210 fPrincipalColumn->Append(&fNWritten);
211 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
212}
213
214unsigned char *ROOT::RRVecField::ResizeRVec(void *rvec, std::size_t nItems, std::size_t itemSize,
215 const RFieldBase *itemField, RDeleter *itemDeleter)
216
217{
218 if (nItems > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) {
219 throw RException(R__FAIL("RVec too large: " + std::to_string(nItems)));
220 }
221
222 auto [beginPtr, sizePtr, capacityPtr] = Internal::GetRVecDataMembers(rvec);
223 const std::size_t oldSize = *sizePtr;
224
225 if (oldSize == nItems) {
226 // If neither shrink nor grow is necessary, do nothing.
227 // Note that this case preserves a memory adopting RVec as such. All real resizes in either direction
228 // transform a memory adopting RVec into an owning RVec.
229 return *beginPtr;
230 }
231
232 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md for details
233 // on the element construction/destrution.
234 const bool owns = (*capacityPtr != -1);
235 const bool needsConstruct = !(itemField->GetTraits() & kTraitTriviallyConstructible);
236 const bool needsDestruct = owns && itemDeleter;
237
238 // Destroy excess elements, if any
239 if (needsDestruct) {
240 for (std::size_t i = nItems; i < oldSize; ++i) {
241 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
242 }
243 }
244
245 // Resize RVec (capacity and size)
246 if (std::int32_t(nItems) > *capacityPtr) { // must reallocate
247 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
248 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
249 if (needsDestruct) {
250 for (std::size_t i = 0u; i < oldSize; ++i) {
251 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
252 }
253 }
254
255 // TODO Increment capacity by a factor rather than just enough to fit the elements.
256 if (owns) {
257 // *beginPtr points to the array of item values (allocated in an earlier call by the following malloc())
258 free(*beginPtr);
259 }
260 // We trust that malloc returns a buffer with large enough alignment.
261 // This might not be the case if T in RVec<T> is over-aligned.
262 *beginPtr = static_cast<unsigned char *>(malloc(nItems * itemSize));
263 R__ASSERT(*beginPtr != nullptr);
264 *capacityPtr = nItems;
265
266 // Placement new for elements that were already there before the resize
267 if (needsConstruct) {
268 for (std::size_t i = 0u; i < oldSize; ++i)
269 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
270 }
271 }
272 *sizePtr = nItems;
273
274 // Placement new for new elements, if any
275 if (needsConstruct) {
276 for (std::size_t i = oldSize; i < nItems; ++i)
277 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
278 }
279
280 return *beginPtr;
281}
282
284{
285 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
286 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
287
288 // Read collection info for this entry
289 ROOT::NTupleSize_t nItems;
290 RNTupleLocalIndex collectionStart;
291 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
292
293 auto begin = ResizeRVec(to, nItems, fItemSize, fSubfields[0].get(), fItemDeleter.get());
294
295 if (fSubfields[0]->IsSimple() && nItems) {
296 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, begin);
297 return;
298 }
299
300 // Read the new values into the collection elements
301 for (std::size_t i = 0; i < nItems; ++i) {
302 CallReadOn(*fSubfields[0], collectionStart + i, begin + (i * fItemSize));
303 }
304}
305
306std::size_t ROOT::RRVecField::ReadBulkImpl(const RBulkSpec &bulkSpec)
307{
308 if (!fBulkSubfield)
309 return RFieldBase::ReadBulkImpl(bulkSpec);
310
311 if (bulkSpec.fAuxData->empty()) {
312 /// Initialize auxiliary memory: the first sizeof(size_t) bytes store the value size of the item field.
313 /// The following bytes store the item values, consecutively.
314 bulkSpec.fAuxData->resize(sizeof(std::size_t));
315 *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data()) = fBulkNRepetition * fBulkSubfield->GetValueSize();
316 }
317 const auto itemValueSize = *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data());
318 unsigned char *itemValueArray = bulkSpec.fAuxData->data() + sizeof(std::size_t);
319 auto [beginPtr, sizePtr, capacityPtr] = Internal::GetRVecDataMembers(bulkSpec.fValues);
320
321 // Get size of the first RVec of the bulk
322 RNTupleLocalIndex firstItemIndex;
323 ROOT::NTupleSize_t collectionSize;
324 fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &firstItemIndex, &collectionSize);
325 *beginPtr = itemValueArray;
326 *sizePtr = collectionSize;
327 *capacityPtr = -1;
328
329 // Set the size of the remaining RVecs of the bulk, going page by page through the RNTuple offset column.
330 // We optimistically assume that bulkSpec.fAuxData is already large enough to hold all the item values in the
331 // given range. If not, we'll fix up the pointers afterwards.
332 auto lastOffset = firstItemIndex.GetIndexInCluster() + collectionSize;
333 ROOT::NTupleSize_t nRemainingValues = bulkSpec.fCount - 1;
334 std::size_t nValues = 1;
335 std::size_t nItems = collectionSize;
336 while (nRemainingValues > 0) {
337 ROOT::NTupleSize_t nElementsUntilPageEnd;
338 const auto offsets =
339 fPrincipalColumn->MapV<ROOT::Internal::RColumnIndex>(bulkSpec.fFirstIndex + nValues, nElementsUntilPageEnd);
340 const std::size_t nBatch = std::min(nRemainingValues, nElementsUntilPageEnd);
341 for (std::size_t i = 0; i < nBatch; ++i) {
342 const auto size = offsets[i] - lastOffset;
343 std::tie(beginPtr, sizePtr, capacityPtr) = Internal::GetRVecDataMembers(
344 reinterpret_cast<unsigned char *>(bulkSpec.fValues) + (nValues + i) * fValueSize);
345 *beginPtr = itemValueArray + nItems * itemValueSize;
346 *sizePtr = size;
347 *capacityPtr = -1;
348
349 nItems += size;
350 lastOffset = offsets[i];
351 }
352 nRemainingValues -= nBatch;
353 nValues += nBatch;
354 }
355
356 bulkSpec.fAuxData->resize(sizeof(std::size_t) + nItems * itemValueSize);
357 // If the vector got reallocated, we need to fix-up the RVecs begin pointers.
358 const auto delta = itemValueArray - (bulkSpec.fAuxData->data() + sizeof(std::size_t));
359 if (delta != 0) {
360 auto beginPtrAsUChar = reinterpret_cast<unsigned char *>(bulkSpec.fValues);
361 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
362 *reinterpret_cast<unsigned char **>(beginPtrAsUChar) -= delta;
363 beginPtrAsUChar += fValueSize;
364 }
365 }
366
368 ->ReadV(firstItemIndex * fBulkNRepetition, nItems * fBulkNRepetition, itemValueArray - delta);
369 return RBulkSpec::kAllSet;
370}
371
381
386
391
392std::unique_ptr<ROOT::RFieldBase> ROOT::RRVecField::BeforeConnectPageSource(Internal::RPageSource &pageSource)
393{
395 return nullptr;
396
397 const auto descGuard = pageSource.GetSharedDescriptorGuard();
398 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
399 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
400 auto substitute = std::make_unique<RArrayAsRVecField>(
401 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
402 substitute->SetOnDiskId(GetOnDiskId());
403 return substitute;
404 }
405 return nullptr;
406}
407
412
413void ROOT::RRVecField::ConstructValue(void *where) const
414{
415 // initialize data members fBegin, fSize, fCapacity
416 // currently the inline buffer is left uninitialized
417 void **beginPtr = new (where)(void *)(nullptr);
418 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
419 new (sizePtr + 1) std::int32_t(-1);
420}
421
422void ROOT::RRVecField::RRVecDeleter::operator()(void *objPtr, bool dtorOnly)
423{
424 auto [beginPtr, sizePtr, capacityPtr] = Internal::GetRVecDataMembers(objPtr);
425
426 if (fItemDeleter) {
427 for (std::int32_t i = 0; i < *sizePtr; ++i) {
428 fItemDeleter->operator()(*beginPtr + i * fItemSize, true /* dtorOnly */);
429 }
430 }
431
432 Internal::DestroyRVecWithChecks(fItemAlignment, beginPtr, capacityPtr);
433 RDeleter::operator()(objPtr, dtorOnly);
434}
435
436std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RRVecField::GetDeleter() const
437{
438 if (fItemDeleter)
439 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize, GetDeleterOf(*fSubfields[0]));
440 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment());
441}
442
443std::vector<ROOT::RFieldBase::RValue> ROOT::RRVecField::SplitValue(const RValue &value) const
444{
445 auto [beginPtr, sizePtr, _] = Internal::GetRVecDataMembers(value.GetPtr<void>().get());
446
447 std::vector<RValue> result;
448 result.reserve(*sizePtr);
449 for (std::int32_t i = 0; i < *sizePtr; ++i) {
450 result.emplace_back(
451 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), *beginPtr + i * fItemSize)));
452 }
453 return result;
454}
455
457{
458 return fValueSize;
459}
460
465
467{
468 visitor.VisitRVecField(*this);
469}
470
471//------------------------------------------------------------------------------
472
473ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
474 std::optional<std::string_view> emulatedFromType)
475 : ROOT::RFieldBase(fieldName, emulatedFromType ? *emulatedFromType : "std::vector<" + itemField->GetTypeName() + ">",
476 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
477 fItemSize(itemField->GetValueSize()),
478 fNWritten(0)
479{
480 if (emulatedFromType && !emulatedFromType->empty())
482
483 if (!itemField->GetTypeAlias().empty())
484 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
485
486 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
487 fItemDeleter = GetDeleterOf(*itemField);
488 Attach(std::move(itemField), "_0");
489}
490
491ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
492 : RVectorField(fieldName, std::move(itemField), {})
493{
494}
495
496std::unique_ptr<ROOT::RVectorField>
497ROOT::RVectorField::CreateUntyped(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
498{
499 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(fieldName, itemField->Clone("_0"), ""));
500}
501
502std::unique_ptr<ROOT::RFieldBase> ROOT::RVectorField::CloneImpl(std::string_view newName) const
503{
504 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
505 auto isUntyped = GetTypeName().empty() || ((fTraits & kTraitEmulatedField) != 0);
506 auto emulatedFromType = isUntyped ? std::make_optional(GetTypeName()) : std::nullopt;
507 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(newName, std::move(newItemField), emulatedFromType));
508}
509
510std::size_t ROOT::RVectorField::AppendImpl(const void *from)
511{
512 auto typedValue = static_cast<const std::vector<char> *>(from);
513 // The order is important here: Profiling showed that the integer division is on the critical path. By moving the
514 // computation of count before R__ASSERT, the compiler can use the result of a single instruction (on x86) also for
515 // the modulo operation. Otherwise, it must perform the division twice because R__ASSERT expands to an external call
516 // of Fatal() in case of failure, which could have side effects that the compiler cannot analyze.
517 auto count = typedValue->size() / fItemSize;
518 R__ASSERT((typedValue->size() % fItemSize) == 0);
519 std::size_t nbytes = 0;
520
521 if (fSubfields[0]->IsSimple() && count) {
522 GetPrincipalColumnOf(*fSubfields[0])->AppendV(typedValue->data(), count);
523 nbytes += count * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
524 } else {
525 for (unsigned i = 0; i < count; ++i) {
526 nbytes += CallAppendOn(*fSubfields[0], typedValue->data() + (i * fItemSize));
527 }
528 }
529
530 fNWritten += count;
531 fPrincipalColumn->Append(&fNWritten);
532 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
533}
534
535void ROOT::RVectorField::ResizeVector(void *vec, std::size_t nItems, std::size_t itemSize, const RFieldBase &itemField,
536 RDeleter *itemDeleter)
537{
538 auto typedValue = static_cast<std::vector<char> *>(vec);
539
540 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md
541 R__ASSERT(itemSize > 0);
542 const auto oldNItems = typedValue->size() / itemSize;
543 const auto availNItems = typedValue->capacity() / itemSize;
544 const bool canRealloc = availNItems < nItems;
545 bool allDeallocated = false;
546 if (itemDeleter) {
547 allDeallocated = canRealloc;
548 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
549 itemDeleter->operator()(typedValue->data() + (i * itemSize), true /* dtorOnly */);
550 }
551 }
552 typedValue->resize(nItems * itemSize);
553 if (!(itemField.GetTraits() & kTraitTriviallyConstructible)) {
554 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
555 CallConstructValueOn(itemField, typedValue->data() + (i * itemSize));
556 }
557 }
558}
559
561{
562 auto typedValue = static_cast<std::vector<char> *>(to);
563
564 ROOT::NTupleSize_t nItems;
565 RNTupleLocalIndex collectionStart;
566 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
567
568 if (fSubfields[0]->IsSimple()) {
569 typedValue->resize(nItems * fItemSize);
570 if (nItems)
571 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, typedValue->data());
572 return;
573 }
574
575 ResizeVector(to, nItems, fItemSize, *fSubfields[0], fItemDeleter.get());
576
577 for (std::size_t i = 0; i < nItems; ++i) {
578 CallReadOn(*fSubfields[0], collectionStart + i, typedValue->data() + (i * fItemSize));
579 }
580}
581
591
596
601
602std::unique_ptr<ROOT::RFieldBase> ROOT::RVectorField::BeforeConnectPageSource(Internal::RPageSource &pageSource)
603{
605 return nullptr;
606
607 const auto descGuard = pageSource.GetSharedDescriptorGuard();
608 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
609 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
610 auto substitute = std::make_unique<RArrayAsVectorField>(
611 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
612 substitute->SetOnDiskId(GetOnDiskId());
613 return substitute;
614 }
615 return nullptr;
616}
617
622
623void ROOT::RVectorField::RVectorDeleter::operator()(void *objPtr, bool dtorOnly)
624{
625 auto vecPtr = static_cast<std::vector<char> *>(objPtr);
626 if (fItemDeleter) {
627 R__ASSERT(fItemSize > 0);
628 R__ASSERT((vecPtr->size() % fItemSize) == 0);
629 auto nItems = vecPtr->size() / fItemSize;
630 for (std::size_t i = 0; i < nItems; ++i) {
631 fItemDeleter->operator()(vecPtr->data() + (i * fItemSize), true /* dtorOnly */);
632 }
633 }
634 std::destroy_at(vecPtr);
635 RDeleter::operator()(objPtr, dtorOnly);
636}
637
638std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVectorField::GetDeleter() const
639{
640 if (fItemDeleter)
641 return std::make_unique<RVectorDeleter>(fItemSize, GetDeleterOf(*fSubfields[0]));
642 return std::make_unique<RVectorDeleter>();
643}
644
645std::vector<ROOT::RFieldBase::RValue> ROOT::RVectorField::SplitValue(const RValue &value) const
646{
647 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
648}
649
651{
652 visitor.VisitVectorField(*this);
653}
654
655//------------------------------------------------------------------------------
656
658 : ROOT::RFieldBase(name, "std::vector<bool>", ROOT::ENTupleStructure::kCollection, false /* isSimple */)
659{
660 Attach(std::make_unique<RField<bool>>("_0"));
661}
662
663std::size_t ROOT::RField<std::vector<bool>>::AppendImpl(const void *from)
664{
665 auto typedValue = static_cast<const std::vector<bool> *>(from);
666 auto count = typedValue->size();
667 for (unsigned i = 0; i < count; ++i) {
668 bool bval = (*typedValue)[i];
669 CallAppendOn(*fSubfields[0], &bval);
670 }
671 fNWritten += count;
672 fPrincipalColumn->Append(&fNWritten);
673 return count + fPrincipalColumn->GetElement()->GetPackedSize();
674}
675
676void ROOT::RField<std::vector<bool>>::ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to)
677{
678 auto typedValue = static_cast<std::vector<bool> *>(to);
679
680 if (fOnDiskNRepetitions == 0) {
681 ROOT::NTupleSize_t nItems;
682 RNTupleLocalIndex collectionStart;
683 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
684 typedValue->resize(nItems);
685 for (std::size_t i = 0; i < nItems; ++i) {
686 bool bval;
687 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
688 (*typedValue)[i] = bval;
689 }
690 } else {
691 typedValue->resize(fOnDiskNRepetitions);
692 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
693 bool bval;
694 CallReadOn(*fSubfields[0], globalIndex * fOnDiskNRepetitions + i, &bval);
695 (*typedValue)[i] = bval;
696 }
697 }
698}
699
700void ROOT::RField<std::vector<bool>>::ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to)
701{
702 auto typedValue = static_cast<std::vector<bool> *>(to);
703
704 if (fOnDiskNRepetitions == 0) {
705 ROOT::NTupleSize_t nItems;
706 RNTupleLocalIndex collectionStart;
707 fPrincipalColumn->GetCollectionInfo(localIndex, &collectionStart, &nItems);
708 typedValue->resize(nItems);
709 for (std::size_t i = 0; i < nItems; ++i) {
710 bool bval;
711 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
712 (*typedValue)[i] = bval;
713 }
714 } else {
715 typedValue->resize(fOnDiskNRepetitions);
716 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
717 bool bval;
718 CallReadOn(*fSubfields[0], localIndex * fOnDiskNRepetitions + i, &bval);
719 (*typedValue)[i] = bval;
720 }
721 }
722}
723
724const ROOT::RFieldBase::RColumnRepresentations &ROOT::RField<std::vector<bool>>::GetColumnRepresentations() const
725{
726 static RColumnRepresentations representations({{ENTupleColumnType::kSplitIndex64},
730 {{}});
731 return representations;
732}
733
734void ROOT::RField<std::vector<bool>>::GenerateColumns()
735{
736 R__ASSERT(fOnDiskNRepetitions == 0); // fOnDiskNRepetitions must only be used for reading
737 GenerateColumnsImpl<ROOT::Internal::RColumnIndex>();
738}
739
740void ROOT::RField<std::vector<bool>>::GenerateColumns(const ROOT::RNTupleDescriptor &desc)
741{
742 if (fOnDiskNRepetitions == 0)
743 GenerateColumnsImpl<ROOT::Internal::RColumnIndex>(desc);
744}
745
746void ROOT::RField<std::vector<bool>>::ReconcileOnDiskField(const RNTupleDescriptor &desc)
747{
748 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
749
750 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
751 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions).ThrowOnError();
752
753 if (fieldDesc.GetNRepetitions() == 0) {
754 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected repetition count > 0\n" +
755 Internal::GetTypeTraceReport(*this, desc)));
756 }
757 if (fieldDesc.GetStructure() != ENTupleStructure::kPlain) {
758 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected plain on-disk field\n" +
759 Internal::GetTypeTraceReport(*this, desc)));
760 }
761 fOnDiskNRepetitions = fieldDesc.GetNRepetitions();
762 } else {
763 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
764 }
765}
766
767std::vector<ROOT::RFieldBase::RValue> ROOT::RField<std::vector<bool>>::SplitValue(const RValue &value) const
768{
769 const auto &typedValue = value.GetRef<std::vector<bool>>();
770 auto count = typedValue.size();
771 std::vector<RValue> result;
772 result.reserve(count);
773 for (unsigned i = 0; i < count; ++i) {
774 if (typedValue[i]) {
775 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(true))));
776 } else {
777 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(false))));
778 }
779 }
780 return result;
781}
782
783void ROOT::RField<std::vector<bool>>::AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const
784{
785 visitor.VisitVectorBoolField(*this);
786}
787
788//------------------------------------------------------------------------------
789
790ROOT::RArrayAsRVecField::RArrayAsRVecField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
791 std::size_t arrayLength)
792 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
793 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
794 fItemSize(itemField->GetValueSize()),
795 fArrayLength(arrayLength)
796{
797 if (!itemField->GetTypeAlias().empty())
798 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
799 Attach(std::move(itemField), "_0");
800 fValueSize =
804}
805
806std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsRVecField::CloneImpl(std::string_view newName) const
807{
808 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
809 return std::make_unique<RArrayAsRVecField>(newName, std::move(newItemField), fArrayLength);
810}
811
813{
814 // initialize data members fBegin, fSize, fCapacity
815 // currently the inline buffer is left uninitialized
816 void **beginPtr = new (where)(void *)(nullptr);
817 std::int32_t *sizePtr = new (static_cast<void *>(beginPtr + 1)) std::int32_t(0);
818 new (sizePtr + 1) std::int32_t(-1);
819}
820
821std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsRVecField::GetDeleter() const
822{
823 if (fItemDeleter) {
824 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize,
826 }
827 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment());
828}
829
831{
833
834 if (fSubfields[0]->IsSimple()) {
836 return;
837 }
838
839 // Read the new values into the collection elements
840 for (std::size_t i = 0; i < fArrayLength; ++i) {
841 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, begin + (i * fItemSize));
842 }
843}
844
846{
848
849 if (fSubfields[0]->IsSimple()) {
851 return;
852 }
853
854 // Read the new values into the collection elements
855 for (std::size_t i = 0; i < fArrayLength; ++i) {
856 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, begin + (i * fItemSize));
857 }
858}
859
861{
863 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
864 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
865 throw RException(R__FAIL("RArrayAsRVecField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
866 Internal::GetTypeTraceReport(*this, desc)));
867 }
868}
869
874
875std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsRVecField::SplitValue(const ROOT::RFieldBase::RValue &value) const
876{
877 auto arrayPtr = value.GetPtr<unsigned char>().get();
878 std::vector<ROOT::RFieldBase::RValue> result;
879 result.reserve(fArrayLength);
880 for (unsigned i = 0; i < fArrayLength; ++i) {
881 result.emplace_back(
882 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), arrayPtr + (i * fItemSize))));
883 }
884 return result;
885}
886
891
892//------------------------------------------------------------------------------
893
894ROOT::RArrayAsVectorField::RArrayAsVectorField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
895 std::size_t arrayLength)
896 : ROOT::RFieldBase(fieldName, "std::vector<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kCollection,
897 false /* isSimple */),
898 fItemSize(itemField->GetValueSize()),
899 fArrayLength(arrayLength)
900{
901 if (!itemField->GetTypeAlias().empty())
902 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
903 Attach(std::move(itemField), "_0");
906}
907
908std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsVectorField::CloneImpl(std::string_view newName) const
909{
910 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
911 return std::make_unique<RArrayAsVectorField>(newName, std::move(newItemField), fArrayLength);
912}
913
915{
916 throw RException(R__FAIL("RArrayAsVectorField fields must only be used for reading"));
917}
918
919std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsVectorField::GetDeleter() const
920{
921 if (fItemDeleter)
922 return std::make_unique<RVectorField::RVectorDeleter>(fItemSize, GetDeleterOf(*fSubfields[0]));
923 return std::make_unique<RVectorField::RVectorDeleter>();
924}
925
927{
928 auto typedValue = static_cast<std::vector<char> *>(to);
929
930 if (fSubfields[0]->IsSimple()) {
931 typedValue->resize(fArrayLength * fItemSize);
932 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, typedValue->data());
933 return;
934 }
935
937
938 for (std::size_t i = 0; i < fArrayLength; ++i) {
939 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
940 }
941}
942
944{
945 auto typedValue = static_cast<std::vector<char> *>(to);
946
947 if (fSubfields[0]->IsSimple()) {
948 typedValue->resize(fArrayLength * fItemSize);
949 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, typedValue->data());
950 return;
951 }
952
954
955 for (std::size_t i = 0; i < fArrayLength; ++i) {
956 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
957 }
958}
959
961{
963
964 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
965 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
966 throw RException(R__FAIL("RArrayAsVectorField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
967 Internal::GetTypeTraceReport(*this, desc)));
968 }
969}
970
971std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsVectorField::SplitValue(const ROOT::RFieldBase::RValue &value) const
972{
973 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
974}
975
#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:299
#define f(i)
Definition RSha256.hxx:104
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
char name[80]
Definition TGX11.cxx:148
@ kCollection
Definition TStructNode.h:21
#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.
virtual void VisitVectorField(const ROOT::RVectorField &field)
virtual void VisitVectorBoolField(const ROOT::RField< std::vector< bool > > &field)
virtual void VisitRVecField(const ROOT::RRVecField &field)
virtual void VisitArrayAsRVecField(const ROOT::RArrayAsRVecField &field)
virtual void VisitArrayAsVectorField(const ROOT::RArrayAsVectorField &field)
virtual void VisitArrayField(const ROOT::RArrayField &field)
The in-memory representation of a 32bit or 64bit on-disk index column.
Abstract interface to read data from an ntuple.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
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.
std::size_t fArrayLength
The size of a child field's item.
std::size_t fItemSize
Sub field deleter or nullptr for simple fields.
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
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
std::size_t fArrayLength
The size of a child field's item.
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.
std::size_t fItemSize
Sub field deleter or nullptr for simple fields.
std::unique_ptr< RDeleter > fItemDeleter
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
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.
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:78
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.
std::shared_ptr< T > GetPtr() const
A field translates read and write calls from/to underlying columns to/from tree values.
virtual size_t GetValueSize() const =0
The number of bytes taken by a value of the appropriate type.
void Attach(std::unique_ptr< RFieldBase > child, std::string_view expectedChildName="")
Add a new subfield to the list of nested fields.
ROOT::Internal::RColumn * fPrincipalColumn
All fields that have columns have a distinct main column.
std::vector< std::unique_ptr< RFieldBase > > fSubfields
Collections and classes own subfields.
@ 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.
@ kTraitTriviallyConstructible
No constructor needs to be called, i.e.
@ kTraitMappable
A field of a fundamental type that can be directly mapped via RField<T>::Map(), i....
static std::unique_ptr< RDeleter > GetDeleterOf(const RFieldBase &other)
static ROOT::Internal::RColumn * GetPrincipalColumnOf(const RFieldBase &other)
Fields may need direct access to the principal column of their subfields, e.g. in RRVecField::ReadBul...
RSchemaIterator begin()
RResult< void > EnsureMatchingOnDiskCollection(const RNTupleDescriptor &desc) const
Convenience wrapper for the common case of calling EnsureMatchinOnDiskField() for collections.
std::size_t Append(const void *from)
Write the given value into columns.
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots (grandparent.parent....
const std::string & GetFieldName() const
RResult< void > EnsureMatchingOnDiskField(const RNTupleDescriptor &desc, std::uint32_t ignoreBits=0) const
Compares the field to the corresponding on-disk field information in the provided descriptor.
static std::size_t CallAppendOn(RFieldBase &other, const void *from)
Allow derived classes to call Append() and Read() on other (sub)fields.
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
RFieldBase(std::string_view name, std::string_view type, ROOT::ENTupleStructure structure, bool isSimple, std::size_t nRepetitions=0)
The constructor creates the underlying column objects and connects them to either a sink or a source.
std::string fTypeAlias
A typedef or using name that was used when creating the field.
bool IsSimple() const
std::uint32_t GetTraits() const
const std::string & GetTypeName() const
void GenerateColumnsImpl(const ColumnRepresentation_t &representation, std::uint16_t representationIndex)
Helpers for generating columns.
RValue BindValue(std::shared_ptr< void > objPtr)
Creates a value from a memory location with an already constructed object.
static void CallReadOn(RFieldBase &other, RNTupleLocalIndex localIndex, void *to)
ROOT::DescriptorId_t GetOnDiskId() const
std::unique_ptr< RFieldBase > Clone(std::string_view newName) const
Copies the field and its subfields using a possibly new name and a new, unconnected set of columns.
static void CallConstructValueOn(const RFieldBase &other, void *where)
Allow derived classes to call ConstructValue(void *) and GetDeleter() on other (sub)fields.
RResult< void > EnsureMatchingTypePrefix(const RNTupleDescriptor &desc, const std::vector< std::string > &prefixes) const
Many fields accept a range of type prefixes for schema evolution, e.g.
virtual std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec)
General implementation of bulk read.
@ kDiffStructure
The in-memory field and the on-disk field differ in their structural roles.
@ kDiffTypeName
The in-memory field and the on-disk field have different type names.
@ kDiffNRepetitions
The in-memory field and the on-disk field have different repetition counts.
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:320
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...
ROOT::NTupleSize_t GetIndexInCluster() const
void operator()(void *objPtr, bool dtorOnly) final
std::unique_ptr< RDeleter > fItemDeleter
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.
ROOT::Internal::RColumnIndex fNWritten
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
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
ROOT::Internal::RColumnIndex fNWritten
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
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...
if(pos!=-1) leafTypeName.Remove(pos)
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().
RNTupleLocalIndex fFirstIndex
Start of the bulk range.
void * fValues
The destination area, which has to be an array of valid objects of the correct type large enough to h...
std::size_t fCount
Size of the bulk range.
std::vector< unsigned char > * fAuxData
Reference to memory owned by the RBulkValues class.