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/BitUtils.hxx>
6#include <ROOT/RField.hxx>
7#include <ROOT/RFieldBase.hxx>
10
11#include <cstdlib> // for malloc, free
12#include <limits>
13#include <memory>
14#include <new> // hardware_destructive_interference_size
15
16namespace {
17
18std::vector<ROOT::RFieldBase::RValue> SplitVector(const std::shared_ptr<void> &valuePtr, ROOT::RFieldBase &itemField)
19{
20 auto *vec = static_cast<std::vector<char> *>(valuePtr.get());
21 const auto itemSize = itemField.GetValueSize();
23 R__ASSERT((vec->size() % itemSize) == 0);
24 const auto nItems = vec->size() / itemSize;
25 std::vector<ROOT::RFieldBase::RValue> result;
26 result.reserve(nItems);
27 for (unsigned i = 0; i < nItems; ++i) {
28 result.emplace_back(itemField.BindValue(std::shared_ptr<void>(valuePtr, vec->data() + (i * itemSize))));
29 }
30 return result;
31}
32
33std::size_t GetSizeOfVector()
34{
35 return sizeof(std::vector<char>);
36}
37
38std::size_t GetAlignOfVector()
39{
40 return alignof(std::vector<char>);
41}
42
43void ConstructVector(void *where, std::size_t alignOfValue)
44{
45 static_assert(ROOT::RVectorField::kMaxItemAlignment == 4096);
46 // clang-format off
47 switch (alignOfValue) {
48 case 1: new (where) std::vector<ROOT::Internal::RAlignedStorage< 1>>(); break;
49 case 2: new (where) std::vector<ROOT::Internal::RAlignedStorage< 2>>(); break;
50 case 4: new (where) std::vector<ROOT::Internal::RAlignedStorage< 4>>(); break;
51 case 8: new (where) std::vector<ROOT::Internal::RAlignedStorage< 8>>(); break;
52 case 16: new (where) std::vector<ROOT::Internal::RAlignedStorage< 16>>(); break;
53 case 32: new (where) std::vector<ROOT::Internal::RAlignedStorage< 32>>(); break;
54 case 64: new (where) std::vector<ROOT::Internal::RAlignedStorage< 64>>(); break;
55 case 128: new (where) std::vector<ROOT::Internal::RAlignedStorage< 128>>(); break;
56 case 256: new (where) std::vector<ROOT::Internal::RAlignedStorage< 256>>(); break;
57 case 512: new (where) std::vector<ROOT::Internal::RAlignedStorage< 512>>(); break;
58 case 1024: new (where) std::vector<ROOT::Internal::RAlignedStorage<1024>>(); break;
59 case 2048: new (where) std::vector<ROOT::Internal::RAlignedStorage<2048>>(); break;
60 case 4096: new (where) std::vector<ROOT::Internal::RAlignedStorage<4096>>(); break;
61 default: throw ROOT::RException(R__FAIL(std::string("Unsupported alignment: ") + std::to_string(alignOfValue)));
62 }
63 // clang-format on
64}
65
66} // anonymous namespace
67
68ROOT::RArrayField::RArrayField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
69 std::size_t arrayLength)
71 "std::array<" + itemField->GetTypeName() + "," +
72 Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">",
73 ROOT::ENTupleStructure::kPlain, false /* isSimple */, arrayLength),
74 fItemSize(itemField->GetValueSize()),
75 fArrayLength(arrayLength)
76{
77 fTraits |= itemField->GetTraits() & ~kTraitMappable;
78 if (!itemField->GetTypeAlias().empty()) {
79 fTypeAlias = "std::array<" + itemField->GetTypeAlias() + "," +
80 Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">";
81 }
82 Attach(std::move(itemField), "_0");
83}
84
85std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayField::CloneImpl(std::string_view newName) const
86{
87 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
88 return std::make_unique<RArrayField>(newName, std::move(newItemField), fArrayLength);
89}
90
91std::size_t ROOT::RArrayField::AppendImpl(const void *from)
92{
93 std::size_t nbytes = 0;
94 if (fSubfields[0]->IsSimple()) {
95 GetPrincipalColumnOf(*fSubfields[0])->AppendV(from, fArrayLength);
96 nbytes += fArrayLength * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
97 } else {
98 auto arrayPtr = static_cast<const unsigned char *>(from);
99 for (unsigned i = 0; i < fArrayLength; ++i) {
100 nbytes += CallAppendOn(*fSubfields[0], arrayPtr + (i * fItemSize));
101 }
102 }
103 return nbytes;
104}
105
107{
108 if (fSubfields[0]->IsSimple()) {
109 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, to);
110 } else {
111 auto arrayPtr = static_cast<unsigned char *>(to);
112 for (unsigned i = 0; i < fArrayLength; ++i) {
113 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
114 }
115 }
116}
117
119{
120 if (fSubfields[0]->IsSimple()) {
121 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, to);
122 } else {
123 auto arrayPtr = static_cast<unsigned char *>(to);
124 for (unsigned i = 0; i < fArrayLength; ++i) {
125 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
126 }
127 }
128}
129
131{
132 if (!fSubfields[0]->IsSimple())
134
135 GetPrincipalColumnOf(*fSubfields[0])
136 ->ReadV(bulkSpec.fFirstIndex * fArrayLength, bulkSpec.fCount * fArrayLength, bulkSpec.fValues);
137 return RBulkSpec::kAllSet;
138}
139
141{
142 static const std::vector<std::string> prefixes = {"std::array<"};
143
144 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
145 EnsureMatchingTypePrefix(desc, prefixes).ThrowOnError();
146}
147
149{
150 if (fSubfields[0]->GetTraits() & kTraitTriviallyConstructible)
151 return;
152
153 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
154 for (unsigned i = 0; i < fArrayLength; ++i) {
155 CallConstructValueOn(*fSubfields[0], arrayPtr + (i * fItemSize));
156 }
157}
158
160{
161 if (fItemDeleter) {
162 for (unsigned i = 0; i < fArrayLength; ++i) {
163 fItemDeleter->operator()(reinterpret_cast<unsigned char *>(objPtr) + i * fItemSize, true /* dtorOnly */);
164 }
165 }
166 RDeleter::operator()(objPtr, dtorOnly);
167}
168
169std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayField::GetDeleter() const
170{
171 if (!(fSubfields[0]->GetTraits() & kTraitTriviallyDestructible))
172 return std::make_unique<RArrayDeleter>(fItemSize, fArrayLength, GetAlignment(), GetDeleterOf(*fSubfields[0]));
173 return std::make_unique<RDeleter>(GetAlignment());
174}
175
176std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayField::SplitValue(const RValue &value) const
177{
178 auto valuePtr = value.GetPtr<void>();
179 auto arrayPtr = static_cast<unsigned char *>(valuePtr.get());
180 std::vector<RValue> result;
181 result.reserve(fArrayLength);
182 for (unsigned i = 0; i < fArrayLength; ++i) {
183 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(valuePtr, arrayPtr + (i * fItemSize))));
184 }
185 return result;
186}
187
189{
190 visitor.VisitArrayField(*this);
191}
192
193//------------------------------------------------------------------------------
194
195ROOT::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
196 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
197 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
198 fItemSize(itemField->GetValueSize()),
199 fNWritten(0)
200{
201 if (itemField->GetAlignment() > sizeof(std::max_align_t)) {
202 // RVec uses malloc() and free()
203 throw RException(R__FAIL("RVec does not support over-aligned types"));
204 }
205
206 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
208 if (!itemField->GetTypeAlias().empty())
209 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
210 Attach(std::move(itemField), "_0");
211 fValueSize =
213
214 // Determine if we can optimimize bulk reading
215 if (fSubfields[0]->IsSimple()) {
216 fBulkSubfield = fSubfields[0].get();
217 } else {
218 if (auto f = dynamic_cast<RArrayField *>(fSubfields[0].get())) {
219 auto grandChildFields = fSubfields[0]->GetMutableSubfields();
220 if (grandChildFields[0]->IsSimple()) {
222 fBulkNRepetition = f->GetLength();
223 }
224 }
225 }
226}
227
228std::unique_ptr<ROOT::RFieldBase> ROOT::RRVecField::CloneImpl(std::string_view newName) const
229{
230 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
231 return std::make_unique<RRVecField>(newName, std::move(newItemField));
232}
233
234std::size_t ROOT::RRVecField::AppendImpl(const void *from)
235{
237
238 std::size_t nbytes = 0;
239 if (fSubfields[0]->IsSimple() && *sizePtr) {
240 GetPrincipalColumnOf(*fSubfields[0])->AppendV(*beginPtr, *sizePtr);
241 nbytes += *sizePtr * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
242 } else {
243 for (std::int32_t i = 0; i < *sizePtr; ++i) {
244 nbytes += CallAppendOn(*fSubfields[0], *beginPtr + i * fItemSize);
245 }
246 }
247
248 fNWritten += *sizePtr;
249 fPrincipalColumn->Append(&fNWritten);
250 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
251}
252
253unsigned char *ROOT::RRVecField::ResizeRVec(void *rvec, std::size_t nItems, std::size_t itemSize,
255
256{
257 if (nItems > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) {
258 throw RException(R__FAIL("RVec too large: " + std::to_string(nItems)));
259 }
260
262 const std::size_t oldSize = *sizePtr;
263
264 if (oldSize == nItems) {
265 // If neither shrink nor grow is necessary, do nothing.
266 // Note that this case preserves a memory adopting RVec as such. All real resizes in either direction
267 // transform a memory adopting RVec into an owning RVec.
268 return *beginPtr;
269 }
270
271 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md for details
272 // on the element construction/destrution.
273 const bool owns = (*capacityPtr != -1);
274 const bool needsConstruct = !(itemField->GetTraits() & kTraitTriviallyConstructible);
275 const bool needsDestruct = owns && itemDeleter;
276
277 // Destroy excess elements, if any
278 if (needsDestruct) {
279 for (std::size_t i = nItems; i < oldSize; ++i) {
280 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
281 }
282 }
283
284 // Resize RVec (capacity and size)
285 if (std::int32_t(nItems) > *capacityPtr) { // must reallocate
286 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
287 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
288 if (needsDestruct) {
289 for (std::size_t i = 0u; i < oldSize; ++i) {
290 itemDeleter->operator()(*beginPtr + (i * itemSize), true /* dtorOnly */);
291 }
292 }
293
294 // TODO Increment capacity by a factor rather than just enough to fit the elements.
296 // We trust that malloc returns a buffer with large enough alignment.
297 // This might not be the case if T in RVec<T> is over-aligned.
298 *beginPtr = static_cast<unsigned char *>(malloc(nItems * itemSize));
299 R__ASSERT(*beginPtr != nullptr);
301
302 // Placement new for elements that were already there before the resize
303 if (needsConstruct) {
304 for (std::size_t i = 0u; i < oldSize; ++i)
305 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
306 }
307 }
308 *sizePtr = nItems;
309
310 // Placement new for new elements, if any
311 if (needsConstruct) {
312 for (std::size_t i = oldSize; i < nItems; ++i)
313 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
314 }
315
316 return *beginPtr;
317}
318
320{
321 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
322 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
323
324 // Read collection info for this entry
327 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
328
329 auto begin = ResizeRVec(to, nItems, fItemSize, fSubfields[0].get(), fItemDeleter.get());
330
331 if (fSubfields[0]->IsSimple() && nItems) {
332 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, begin);
333 return;
334 }
335
336 // Read the new values into the collection elements
337 for (std::size_t i = 0; i < nItems; ++i) {
338 CallReadOn(*fSubfields[0], collectionStart + i, begin + (i * fItemSize));
339 }
340}
341
343{
344 if (!fBulkSubfield)
346
347 if (bulkSpec.fAuxData->empty()) {
348 /// Initialize auxiliary memory: the first sizeof(size_t) bytes store the value size of the item field.
349 /// The following bytes store the item values, consecutively.
350 bulkSpec.fAuxData->resize(sizeof(std::size_t));
351 *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data()) = fBulkNRepetition * fBulkSubfield->GetValueSize();
352 }
353 const auto itemValueSize = *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data());
354 unsigned char *itemValueArray = bulkSpec.fAuxData->data() + sizeof(std::size_t);
356
357 // Get size of the first RVec of the bulk
360 fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &firstItemIndex, &collectionSize);
363 *capacityPtr = -1;
364
365 // Set the size of the remaining RVecs of the bulk, going page by page through the RNTuple offset column.
366 // We optimistically assume that bulkSpec.fAuxData is already large enough to hold all the item values in the
367 // given range. If not, we'll fix up the pointers afterwards.
368 auto lastOffset = firstItemIndex.GetIndexInCluster() + collectionSize;
370 std::size_t nValues = 1;
371 std::size_t nItems = collectionSize;
372 while (nRemainingValues > 0) {
374 const auto offsets =
375 fPrincipalColumn->MapV<ROOT::Internal::RColumnIndex>(bulkSpec.fFirstIndex + nValues, nElementsUntilPageEnd);
376 const std::size_t nBatch = std::min(nRemainingValues, nElementsUntilPageEnd);
377 for (std::size_t i = 0; i < nBatch; ++i) {
378 const auto size = offsets[i] - lastOffset;
380 reinterpret_cast<unsigned char *>(bulkSpec.fValues) + (nValues + i) * fValueSize);
382 *sizePtr = size;
383 *capacityPtr = -1;
384
385 nItems += size;
386 lastOffset = offsets[i];
387 }
389 nValues += nBatch;
390 }
391
392 bulkSpec.fAuxData->resize(sizeof(std::size_t) + nItems * itemValueSize);
393 // If the vector got reallocated, we need to fix-up the RVecs begin pointers.
394 const auto delta = itemValueArray - (bulkSpec.fAuxData->data() + sizeof(std::size_t));
395 if (delta != 0) {
396 auto beginPtrAsUChar = reinterpret_cast<unsigned char *>(bulkSpec.fValues);
397 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
398 *reinterpret_cast<unsigned char **>(beginPtrAsUChar) -= delta;
400 }
401 }
402
403 GetPrincipalColumnOf(*fBulkSubfield)
404 ->ReadV(firstItemIndex * fBulkNRepetition, nItems * fBulkNRepetition, itemValueArray - delta);
405 return RBulkSpec::kAllSet;
406}
407
417
422
427
429{
430 if (GetOnDiskId() == kInvalidDescriptorId)
431 return nullptr;
432
433 const auto descGuard = pageSource.GetSharedDescriptorGuard();
434 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
435 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
436 auto substitute = std::make_unique<RArrayAsRVecField>(
437 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
438 substitute->SetOnDiskId(GetOnDiskId());
439 return substitute;
440 }
441 return nullptr;
442}
443
445{
446 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
447}
448
450{
451 // initialize data members fBegin, fSize, fCapacity
452 // currently the inline buffer is left uninitialized
453 void **beginPtr = new (where)(void *)(nullptr);
454 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
455 new (sizePtr + 1) std::int32_t(-1);
456}
457
459{
461
462 if (fItemDeleter) {
463 for (std::int32_t i = 0; i < *sizePtr; ++i) {
464 fItemDeleter->operator()(*beginPtr + i * fItemSize, true /* dtorOnly */);
465 }
466 }
467
469 RDeleter::operator()(objPtr, dtorOnly);
470}
471
472std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RRVecField::GetDeleter() const
473{
474 if (fItemDeleter)
475 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize, GetDeleterOf(*fSubfields[0]));
476 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment());
477}
478
479std::vector<ROOT::RFieldBase::RValue> ROOT::RRVecField::SplitValue(const RValue &value) const
480{
481 auto [beginPtr, sizePtr, _] = Internal::GetRVecDataMembers(value.GetPtr<void>().get());
482
483 std::vector<RValue> result;
484 result.reserve(*sizePtr);
485 for (std::int32_t i = 0; i < *sizePtr; ++i) {
486 result.emplace_back(
487 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), *beginPtr + i * fItemSize)));
488 }
489 return result;
490}
491
493{
494 return fValueSize;
495}
496
498{
499 return Internal::EvalRVecAlignment(fSubfields[0]->GetAlignment());
500}
501
503{
504 visitor.VisitRVecField(*this);
505}
506
507//------------------------------------------------------------------------------
508
509ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
510 std::optional<std::string_view> emulatedFromType)
511 : ROOT::RFieldBase(fieldName, emulatedFromType ? *emulatedFromType : "std::vector<" + itemField->GetTypeName() + ">",
512 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
513 fItemSize(itemField->GetValueSize()),
514 fNWritten(0)
515{
516 if (itemField->GetAlignment() > kMaxItemAlignment) {
517 throw RException(
518 R__FAIL(std::string("Unsupported vector item alignment: ") + std::to_string(itemField->GetAlignment())));
519 }
520
521 if (emulatedFromType && !emulatedFromType->empty())
523
524 if (!itemField->GetTypeAlias().empty())
525 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
526
527 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
529 Attach(std::move(itemField), "_0");
530}
531
532ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
534{
535}
536
537std::unique_ptr<ROOT::RVectorField>
538ROOT::RVectorField::CreateUntyped(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
539{
540 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(fieldName, itemField->Clone("_0"), ""));
541}
542
543std::unique_ptr<ROOT::RFieldBase> ROOT::RVectorField::CloneImpl(std::string_view newName) const
544{
545 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
546 auto isUntyped = GetTypeName().empty() || ((fTraits & kTraitEmulatedField) != 0);
547 auto emulatedFromType = isUntyped ? std::make_optional(GetTypeName()) : std::nullopt;
548 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(newName, std::move(newItemField), emulatedFromType));
549}
550
551std::size_t ROOT::RVectorField::AppendImpl(const void *from)
552{
553 auto typedValue = static_cast<const std::vector<char> *>(from);
554 // The order is important here: Profiling showed that the integer division is on the critical path. By moving the
555 // computation of count before R__ASSERT, the compiler can use the result of a single instruction (on x86) also for
556 // the modulo operation. Otherwise, it must perform the division twice because R__ASSERT expands to an external call
557 // of Fatal() in case of failure, which could have side effects that the compiler cannot analyze.
558 auto count = typedValue->size() / fItemSize;
559 R__ASSERT((typedValue->size() % fItemSize) == 0);
560 std::size_t nbytes = 0;
561
562 if (fSubfields[0]->IsSimple() && count) {
563 GetPrincipalColumnOf(*fSubfields[0])->AppendV(typedValue->data(), count);
564 nbytes += count * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
565 } else {
566 for (unsigned i = 0; i < count; ++i) {
567 nbytes += CallAppendOn(*fSubfields[0], typedValue->data() + (i * fItemSize));
568 }
569 }
570
571 fNWritten += count;
572 fPrincipalColumn->Append(&fNWritten);
573 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
574}
575
576void ROOT::RVectorField::ResizeVector(void *vec, std::size_t nItems, std::size_t itemSize, const RFieldBase &itemField,
578{
579 auto typedValue = static_cast<std::vector<char> *>(vec);
580
581 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md
582 assert(itemSize > 0);
583 const auto oldNItems = typedValue->size() / itemSize;
584 const auto availNItems = typedValue->capacity() / itemSize;
585 assert((typedValue->size() % itemSize == 0) && (typedValue->capacity() % itemSize == 0));
586
587 const bool canRealloc = availNItems < nItems;
588 bool allDeallocated = false;
589 if (itemDeleter) {
591 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
592 itemDeleter->operator()(typedValue->data() + (i * itemSize), true /* dtorOnly */);
593 }
594 }
595
596 // Resize the vector with correct alignment
597 const auto itemAlignment = itemField.GetAlignment();
598 const auto nbytes = nItems * itemSize;
599
600 auto fnAlignedResize = [](auto &vecOfAlignedStorage, std::size_t targetSize) {
601 constexpr auto valueTypeSize = sizeof(typename std::decay_t<decltype(vecOfAlignedStorage)>::value_type);
602 constexpr auto valueTypeAlignment = alignof(typename std::decay_t<decltype(vecOfAlignedStorage)>::value_type);
603 // Ensure that this function is used with RAlignedStorage as a template argument.
604 // In general, the actual (user-defined) item type may have larger size than alignment.
605 static_assert(valueTypeSize == valueTypeAlignment);
608 };
609
610 static_assert(kMaxItemAlignment == 4096);
611 // clang-format off
612 switch (itemAlignment) {
613 case 1: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 1>> *>(vec), nbytes); break;
614 case 2: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 2>> *>(vec), nbytes); break;
615 case 4: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 4>> *>(vec), nbytes); break;
616 case 8: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 8>> *>(vec), nbytes); break;
617 case 16: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 16>> *>(vec), nbytes); break;
618 case 32: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 32>> *>(vec), nbytes); break;
619 case 64: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 64>> *>(vec), nbytes); break;
620 case 128: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 128>> *>(vec), nbytes); break;
621 case 256: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 256>> *>(vec), nbytes); break;
622 case 512: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 512>> *>(vec), nbytes); break;
623 case 1024: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<1024>> *>(vec), nbytes); break;
624 case 2048: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<2048>> *>(vec), nbytes); break;
625 case 4096: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<4096>> *>(vec), nbytes); break;
626 default: throw RException(R__FAIL(std::string("Unsupported alignment: ") + std::to_string(itemAlignment)));
627 }
628 // clang-format on
629
630 if (!(itemField.GetTraits() & kTraitTriviallyConstructible)) {
631 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
632 CallConstructValueOn(itemField, typedValue->data() + (i * itemSize));
633 }
634 }
635}
636
638{
639 auto typedValue = static_cast<std::vector<char> *>(to);
640
643 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
644
645 if (fSubfields[0]->IsSimple()) {
646 typedValue->resize(nItems * fItemSize);
647 if (nItems)
648 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, typedValue->data());
649 return;
650 }
651
652 ResizeVector(to, nItems, fItemSize, *fSubfields[0], fItemDeleter.get());
653
654 for (std::size_t i = 0; i < nItems; ++i) {
655 CallReadOn(*fSubfields[0], collectionStart + i, typedValue->data() + (i * fItemSize));
656 }
657}
658
668
673
678
680{
681 if (GetOnDiskId() == kInvalidDescriptorId)
682 return nullptr;
683
684 const auto descGuard = pageSource.GetSharedDescriptorGuard();
685 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
686 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
687 auto substitute = std::make_unique<RArrayAsVectorField>(
688 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
689 substitute->SetOnDiskId(GetOnDiskId());
690 return substitute;
691 }
692 return nullptr;
693}
694
696{
697 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
698}
699
701{
702 ConstructVector(where, fSubfields[0]->GetAlignment());
703}
704
709
711 std::unique_ptr<RDeleter> itemDeleter)
714 fItemAlignment(itemAlignment),
716{
717}
718
720{
721 auto vecPtr = static_cast<std::vector<char> *>(objPtr);
722 if (fItemDeleter) {
723 assert(fItemSize > 0);
724 auto nItems = vecPtr->size() / fItemSize;
725 assert((vecPtr->size() % fItemSize) == 0);
726 for (std::size_t i = 0; i < nItems; ++i) {
727 fItemDeleter->operator()(vecPtr->data() + (i * fItemSize), true /* dtorOnly */);
728 }
729 }
730
731 static_assert(kMaxItemAlignment == 4096);
732 // clang-format off
733 switch (fItemAlignment) {
734 case 1: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 1>> *>(objPtr)); break;
735 case 2: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 2>> *>(objPtr)); break;
736 case 4: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 4>> *>(objPtr)); break;
737 case 8: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 8>> *>(objPtr)); break;
738 case 16: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 16>> *>(objPtr)); break;
739 case 32: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 32>> *>(objPtr)); break;
740 case 64: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 64>> *>(objPtr)); break;
741 case 128: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 128>> *>(objPtr)); break;
742 case 256: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 256>> *>(objPtr)); break;
743 case 512: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 512>> *>(objPtr)); break;
744 case 1024: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<1024>> *>(objPtr)); break;
745 case 2048: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<2048>> *>(objPtr)); break;
746 case 4096: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<4096>> *>(objPtr)); break;
747 default: throw ROOT::RException(R__FAIL(std::string("Unsupported alignment: ") + std::to_string(fItemAlignment)));
748 }
749 // clang-format on
750
751 RDeleter::operator()(objPtr, dtorOnly);
752}
753
754std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVectorField::GetDeleter() const
755{
756 if (fItemDeleter)
757 return std::make_unique<RVectorDeleter>(fItemSize, fSubfields[0]->GetAlignment(), GetDeleterOf(*fSubfields[0]));
758 return std::make_unique<RVectorDeleter>(fSubfields[0]->GetAlignment());
759}
760
761std::vector<ROOT::RFieldBase::RValue> ROOT::RVectorField::SplitValue(const RValue &value) const
762{
763 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
764}
765
767{
768 return GetSizeOfVector();
769}
770
772{
773 return GetAlignOfVector();
774}
775
777{
778 visitor.VisitVectorField(*this);
779}
780
781//------------------------------------------------------------------------------
782
783ROOT::RField<std::vector<bool>>::RField(std::string_view name)
784 : ROOT::RFieldBase(name, "std::vector<bool>", ROOT::ENTupleStructure::kCollection, false /* isSimple */)
785{
786 Attach(std::make_unique<RField<bool>>("_0"));
787}
788
789std::size_t ROOT::RField<std::vector<bool>>::AppendImpl(const void *from)
790{
791 auto typedValue = static_cast<const std::vector<bool> *>(from);
792 auto count = typedValue->size();
793 for (unsigned i = 0; i < count; ++i) {
794 bool bval = (*typedValue)[i];
795 CallAppendOn(*fSubfields[0], &bval);
796 }
797 fNWritten += count;
798 fPrincipalColumn->Append(&fNWritten);
799 return count + fPrincipalColumn->GetElement()->GetPackedSize();
800}
801
803{
804 auto typedValue = static_cast<std::vector<bool> *>(to);
805
806 if (fOnDiskNRepetitions == 0) {
808 RNTupleLocalIndex collectionStart;
809 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
810 typedValue->resize(nItems);
811 for (std::size_t i = 0; i < nItems; ++i) {
812 bool bval;
813 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
814 (*typedValue)[i] = bval;
815 }
816 } else {
817 typedValue->resize(fOnDiskNRepetitions);
818 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
819 bool bval;
820 CallReadOn(*fSubfields[0], globalIndex * fOnDiskNRepetitions + i, &bval);
821 (*typedValue)[i] = bval;
822 }
823 }
824}
825
826void ROOT::RField<std::vector<bool>>::ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to)
827{
828 auto typedValue = static_cast<std::vector<bool> *>(to);
829
830 if (fOnDiskNRepetitions == 0) {
832 RNTupleLocalIndex collectionStart;
833 fPrincipalColumn->GetCollectionInfo(localIndex, &collectionStart, &nItems);
834 typedValue->resize(nItems);
835 for (std::size_t i = 0; i < nItems; ++i) {
836 bool bval;
837 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
838 (*typedValue)[i] = bval;
839 }
840 } else {
841 typedValue->resize(fOnDiskNRepetitions);
842 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
843 bool bval;
844 CallReadOn(*fSubfields[0], localIndex * fOnDiskNRepetitions + i, &bval);
845 (*typedValue)[i] = bval;
846 }
847 }
848}
849
850const ROOT::RFieldBase::RColumnRepresentations &ROOT::RField<std::vector<bool>>::GetColumnRepresentations() const
851{
852 static RColumnRepresentations representations({{ENTupleColumnType::kSplitIndex64},
856 {{}});
857 return representations;
858}
859
860void ROOT::RField<std::vector<bool>>::GenerateColumns()
861{
862 R__ASSERT(fOnDiskNRepetitions == 0); // fOnDiskNRepetitions must only be used for reading
864}
865
866void ROOT::RField<std::vector<bool>>::GenerateColumns(const ROOT::RNTupleDescriptor &desc)
867{
868 if (fOnDiskNRepetitions == 0)
870}
871
872void ROOT::RField<std::vector<bool>>::ReconcileOnDiskField(const RNTupleDescriptor &desc)
873{
874 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
875
876 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
877 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions).ThrowOnError();
878
879 if (fieldDesc.GetNRepetitions() == 0) {
880 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected repetition count > 0\n" +
881 Internal::GetTypeTraceReport(*this, desc)));
882 }
883 if (fieldDesc.GetStructure() != ENTupleStructure::kPlain) {
884 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected plain on-disk field\n" +
885 Internal::GetTypeTraceReport(*this, desc)));
886 }
887 fOnDiskNRepetitions = fieldDesc.GetNRepetitions();
888 } else {
889 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
890 }
891}
892
893std::vector<ROOT::RFieldBase::RValue> ROOT::RField<std::vector<bool>>::SplitValue(const RValue &value) const
894{
895 const auto &typedValue = value.GetRef<std::vector<bool>>();
896 auto count = typedValue.size();
897 std::vector<RValue> result;
898 result.reserve(count);
899 for (unsigned i = 0; i < count; ++i) {
900 if (typedValue[i]) {
901 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(true))));
902 } else {
903 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(false))));
904 }
905 }
906 return result;
907}
908
910{
911 visitor.VisitVectorBoolField(*this);
912}
913
914//------------------------------------------------------------------------------
915
916ROOT::RArrayAsRVecField::RArrayAsRVecField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
917 std::size_t arrayLength)
918 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
919 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
920 fItemSize(itemField->GetValueSize()),
921 fArrayLength(arrayLength)
922{
923 if (!itemField->GetTypeAlias().empty())
924 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
925 Attach(std::move(itemField), "_0");
926 fValueSize =
930}
931
932std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsRVecField::CloneImpl(std::string_view newName) const
933{
934 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
935 return std::make_unique<RArrayAsRVecField>(newName, std::move(newItemField), fArrayLength);
936}
937
939{
940 // initialize data members fBegin, fSize, fCapacity
941 // currently the inline buffer is left uninitialized
942 void **beginPtr = new (where)(void *)(nullptr);
943 std::int32_t *sizePtr = new (static_cast<void *>(beginPtr + 1)) std::int32_t(0);
944 new (sizePtr + 1) std::int32_t(-1);
945}
946
947std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsRVecField::GetDeleter() const
948{
949 if (fItemDeleter) {
950 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize,
951 GetDeleterOf(*fSubfields[0]));
952 }
953 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment());
954}
955
957{
958 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
959
960 if (fSubfields[0]->IsSimple()) {
961 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, begin);
962 return;
963 }
964
965 // Read the new values into the collection elements
966 for (std::size_t i = 0; i < fArrayLength; ++i) {
967 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, begin + (i * fItemSize));
968 }
969}
970
972{
973 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
974
975 if (fSubfields[0]->IsSimple()) {
976 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, begin);
977 return;
978 }
979
980 // Read the new values into the collection elements
981 for (std::size_t i = 0; i < fArrayLength; ++i) {
982 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, begin + (i * fItemSize));
983 }
984}
985
987{
988 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions).ThrowOnError();
989 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
990 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
991 throw RException(R__FAIL("RArrayAsRVecField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
992 Internal::GetTypeTraceReport(*this, desc)));
993 }
994}
995
997{
998 return Internal::EvalRVecAlignment(fSubfields[0]->GetAlignment());
999}
1000
1001std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsRVecField::SplitValue(const ROOT::RFieldBase::RValue &value) const
1002{
1003 auto arrayPtr = value.GetPtr<unsigned char>().get();
1004 std::vector<ROOT::RFieldBase::RValue> result;
1005 result.reserve(fArrayLength);
1006 for (unsigned i = 0; i < fArrayLength; ++i) {
1007 result.emplace_back(
1008 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), arrayPtr + (i * fItemSize))));
1009 }
1010 return result;
1011}
1012
1014{
1015 visitor.VisitArrayAsRVecField(*this);
1016}
1017
1018//------------------------------------------------------------------------------
1019
1020ROOT::RArrayAsVectorField::RArrayAsVectorField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
1021 std::size_t arrayLength)
1022 : ROOT::RFieldBase(fieldName, "std::vector<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kCollection,
1023 false /* isSimple */),
1024 fItemSize(itemField->GetValueSize()),
1025 fArrayLength(arrayLength)
1026{
1027 if (!itemField->GetTypeAlias().empty())
1028 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
1029 Attach(std::move(itemField), "_0");
1032}
1033
1034std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsVectorField::CloneImpl(std::string_view newName) const
1035{
1036 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
1037 return std::make_unique<RArrayAsVectorField>(newName, std::move(newItemField), fArrayLength);
1038}
1039
1041{
1042 throw RException(R__FAIL("RArrayAsVectorField fields must only be used for reading"));
1043}
1044
1046{
1047 ConstructVector(where, fSubfields[0]->GetAlignment());
1048}
1049
1050std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsVectorField::GetDeleter() const
1051{
1052 if (fItemDeleter) {
1053 return std::make_unique<RVectorField::RVectorDeleter>(fItemSize, fSubfields[0]->GetAlignment(),
1054 GetDeleterOf(*fSubfields[0]));
1055 }
1056 return std::make_unique<RVectorField::RVectorDeleter>(fSubfields[0]->GetAlignment());
1057}
1058
1060{
1061 auto typedValue = static_cast<std::vector<char> *>(to);
1062
1063 if (fSubfields[0]->IsSimple()) {
1064 typedValue->resize(fArrayLength * fItemSize);
1065 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, typedValue->data());
1066 return;
1067 }
1068
1069 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
1070
1071 for (std::size_t i = 0; i < fArrayLength; ++i) {
1072 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
1073 }
1074}
1075
1077{
1078 auto typedValue = static_cast<std::vector<char> *>(to);
1079
1080 if (fSubfields[0]->IsSimple()) {
1081 typedValue->resize(fArrayLength * fItemSize);
1082 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, typedValue->data());
1083 return;
1084 }
1085
1086 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
1087
1088 for (std::size_t i = 0; i < fArrayLength; ++i) {
1089 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
1090 }
1091}
1092
1094{
1095 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions);
1096
1097 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1098 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
1099 throw RException(R__FAIL("RArrayAsVectorField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
1100 Internal::GetTypeTraceReport(*this, desc)));
1101 }
1102}
1103
1104std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsVectorField::SplitValue(const ROOT::RFieldBase::RValue &value) const
1105{
1106 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
1107}
1108
1110{
1111 return GetSizeOfVector();
1112}
1113
1115{
1116 return GetAlignOfVector();
1117}
1118
1120{
1121 visitor.VisitArrayAsVectorField(*this);
1122}
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:322
#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:148
#define _(A, B)
Definition cfortran.h:108
#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
What alignof(T) for this type returns.
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
What sizeof(T) for this type returns.
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
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
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 GetAlignment() const final
What alignof(T) for this type returns.
std::size_t GetValueSize() const final
What sizeof(T) for this type returns.
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: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.
A field translates read and write calls from/to underlying columns to/from tree values.
void Attach(std::unique_ptr< RFieldBase > child, std::string_view expectedChildName="")
Add a new subfield to the list of nested fields.
@ kTraitEmulatedField
This field is a user defined type that was missing dictionaries and was reconstructed from the on-dis...
@ kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
std::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
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
What alignof(T) for this type returns.
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
What sizeof(T) for this type returns.
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::size_t GetValueSize() const final
What sizeof(T) for this type returns.
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::size_t GetAlignment() const final
What alignof(T) for this type returns.
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
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
static constexpr std::size_t kMaxItemAlignment
Maximum alignment of the vector's value 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...
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...
Storage type whose alignment matches AlignT bytes.
Definition BitUtils.hxx:53
Input parameter to RFieldBase::ReadBulk() and RFieldBase::ReadBulkImpl().