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(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.
295 if (owns) {
296 // *beginPtr points to the array of item values (allocated in an earlier call by the following malloc())
297 free(*beginPtr);
298 }
299 // We trust that malloc returns a buffer with large enough alignment.
300 // This might not be the case if T in RVec<T> is over-aligned.
301 *beginPtr = static_cast<unsigned char *>(malloc(nItems * itemSize));
302 R__ASSERT(*beginPtr != nullptr);
304
305 // Placement new for elements that were already there before the resize
306 if (needsConstruct) {
307 for (std::size_t i = 0u; i < oldSize; ++i)
308 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
309 }
310 }
311 *sizePtr = nItems;
312
313 // Placement new for new elements, if any
314 if (needsConstruct) {
315 for (std::size_t i = oldSize; i < nItems; ++i)
316 CallConstructValueOn(*itemField, *beginPtr + (i * itemSize));
317 }
318
319 return *beginPtr;
320}
321
323{
324 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
325 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
326
327 // Read collection info for this entry
330 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
331
332 auto begin = ResizeRVec(to, nItems, fItemSize, fSubfields[0].get(), fItemDeleter.get());
333
334 if (fSubfields[0]->IsSimple() && nItems) {
335 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, begin);
336 return;
337 }
338
339 // Read the new values into the collection elements
340 for (std::size_t i = 0; i < nItems; ++i) {
341 CallReadOn(*fSubfields[0], collectionStart + i, begin + (i * fItemSize));
342 }
343}
344
346{
347 if (!fBulkSubfield)
349
350 if (bulkSpec.fAuxData->empty()) {
351 /// Initialize auxiliary memory: the first sizeof(size_t) bytes store the value size of the item field.
352 /// The following bytes store the item values, consecutively.
353 bulkSpec.fAuxData->resize(sizeof(std::size_t));
354 *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data()) = fBulkNRepetition * fBulkSubfield->GetValueSize();
355 }
356 const auto itemValueSize = *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data());
357 unsigned char *itemValueArray = bulkSpec.fAuxData->data() + sizeof(std::size_t);
359
360 // Get size of the first RVec of the bulk
363 fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &firstItemIndex, &collectionSize);
366 *capacityPtr = -1;
367
368 // Set the size of the remaining RVecs of the bulk, going page by page through the RNTuple offset column.
369 // We optimistically assume that bulkSpec.fAuxData is already large enough to hold all the item values in the
370 // given range. If not, we'll fix up the pointers afterwards.
371 auto lastOffset = firstItemIndex.GetIndexInCluster() + collectionSize;
373 std::size_t nValues = 1;
374 std::size_t nItems = collectionSize;
375 while (nRemainingValues > 0) {
377 const auto offsets =
378 fPrincipalColumn->MapV<ROOT::Internal::RColumnIndex>(bulkSpec.fFirstIndex + nValues, nElementsUntilPageEnd);
379 const std::size_t nBatch = std::min(nRemainingValues, nElementsUntilPageEnd);
380 for (std::size_t i = 0; i < nBatch; ++i) {
381 const auto size = offsets[i] - lastOffset;
383 reinterpret_cast<unsigned char *>(bulkSpec.fValues) + (nValues + i) * fValueSize);
385 *sizePtr = size;
386 *capacityPtr = -1;
387
388 nItems += size;
389 lastOffset = offsets[i];
390 }
392 nValues += nBatch;
393 }
394
395 bulkSpec.fAuxData->resize(sizeof(std::size_t) + nItems * itemValueSize);
396 // If the vector got reallocated, we need to fix-up the RVecs begin pointers.
397 const auto delta = itemValueArray - (bulkSpec.fAuxData->data() + sizeof(std::size_t));
398 if (delta != 0) {
399 auto beginPtrAsUChar = reinterpret_cast<unsigned char *>(bulkSpec.fValues);
400 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
401 *reinterpret_cast<unsigned char **>(beginPtrAsUChar) -= delta;
403 }
404 }
405
406 GetPrincipalColumnOf(*fBulkSubfield)
407 ->ReadV(firstItemIndex * fBulkNRepetition, nItems * fBulkNRepetition, itemValueArray - delta);
408 return RBulkSpec::kAllSet;
409}
410
420
425
430
432{
433 if (GetOnDiskId() == kInvalidDescriptorId)
434 return nullptr;
435
436 const auto descGuard = pageSource.GetSharedDescriptorGuard();
437 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
438 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
439 auto substitute = std::make_unique<RArrayAsRVecField>(
440 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
441 substitute->SetOnDiskId(GetOnDiskId());
442 return substitute;
443 }
444 return nullptr;
445}
446
448{
449 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
450}
451
453{
454 // initialize data members fBegin, fSize, fCapacity
455 // currently the inline buffer is left uninitialized
456 void **beginPtr = new (where)(void *)(nullptr);
457 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
458 new (sizePtr + 1) std::int32_t(-1);
459}
460
462{
464
465 if (fItemDeleter) {
466 for (std::int32_t i = 0; i < *sizePtr; ++i) {
467 fItemDeleter->operator()(*beginPtr + i * fItemSize, true /* dtorOnly */);
468 }
469 }
470
472 RDeleter::operator()(objPtr, dtorOnly);
473}
474
475std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RRVecField::GetDeleter() const
476{
477 if (fItemDeleter)
478 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize, GetDeleterOf(*fSubfields[0]));
479 return std::make_unique<RRVecDeleter>(fSubfields[0]->GetAlignment());
480}
481
482std::vector<ROOT::RFieldBase::RValue> ROOT::RRVecField::SplitValue(const RValue &value) const
483{
484 auto [beginPtr, sizePtr, _] = Internal::GetRVecDataMembers(value.GetPtr<void>().get());
485
486 std::vector<RValue> result;
487 result.reserve(*sizePtr);
488 for (std::int32_t i = 0; i < *sizePtr; ++i) {
489 result.emplace_back(
490 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), *beginPtr + i * fItemSize)));
491 }
492 return result;
493}
494
496{
497 return fValueSize;
498}
499
501{
502 return Internal::EvalRVecAlignment(fSubfields[0]->GetAlignment());
503}
504
506{
507 visitor.VisitRVecField(*this);
508}
509
510//------------------------------------------------------------------------------
511
512ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
513 std::optional<std::string_view> emulatedFromType)
514 : ROOT::RFieldBase(fieldName, emulatedFromType ? *emulatedFromType : "std::vector<" + itemField->GetTypeName() + ">",
515 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
516 fItemSize(itemField->GetValueSize()),
517 fNWritten(0)
518{
519 if (itemField->GetAlignment() > kMaxItemAlignment) {
520 throw RException(
521 R__FAIL(std::string("Unsupported vector item alignment: ") + std::to_string(itemField->GetAlignment())));
522 }
523
524 if (emulatedFromType && !emulatedFromType->empty())
526
527 if (!itemField->GetTypeAlias().empty())
528 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
529
530 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
532 Attach(std::move(itemField), "_0");
533}
534
535ROOT::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
537{
538}
539
540std::unique_ptr<ROOT::RVectorField>
541ROOT::RVectorField::CreateUntyped(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
542{
543 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(fieldName, itemField->Clone("_0"), ""));
544}
545
546std::unique_ptr<ROOT::RFieldBase> ROOT::RVectorField::CloneImpl(std::string_view newName) const
547{
548 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
549 auto isUntyped = GetTypeName().empty() || ((fTraits & kTraitEmulatedField) != 0);
550 auto emulatedFromType = isUntyped ? std::make_optional(GetTypeName()) : std::nullopt;
551 return std::unique_ptr<ROOT::RVectorField>(new RVectorField(newName, std::move(newItemField), emulatedFromType));
552}
553
554std::size_t ROOT::RVectorField::AppendImpl(const void *from)
555{
556 auto typedValue = static_cast<const std::vector<char> *>(from);
557 // The order is important here: Profiling showed that the integer division is on the critical path. By moving the
558 // computation of count before R__ASSERT, the compiler can use the result of a single instruction (on x86) also for
559 // the modulo operation. Otherwise, it must perform the division twice because R__ASSERT expands to an external call
560 // of Fatal() in case of failure, which could have side effects that the compiler cannot analyze.
561 auto count = typedValue->size() / fItemSize;
562 R__ASSERT((typedValue->size() % fItemSize) == 0);
563 std::size_t nbytes = 0;
564
565 if (fSubfields[0]->IsSimple() && count) {
566 GetPrincipalColumnOf(*fSubfields[0])->AppendV(typedValue->data(), count);
567 nbytes += count * GetPrincipalColumnOf(*fSubfields[0])->GetElement()->GetPackedSize();
568 } else {
569 for (unsigned i = 0; i < count; ++i) {
570 nbytes += CallAppendOn(*fSubfields[0], typedValue->data() + (i * fItemSize));
571 }
572 }
573
574 fNWritten += count;
575 fPrincipalColumn->Append(&fNWritten);
576 return nbytes + fPrincipalColumn->GetElement()->GetPackedSize();
577}
578
579void ROOT::RVectorField::ResizeVector(void *vec, std::size_t nItems, std::size_t itemSize, const RFieldBase &itemField,
581{
582 auto typedValue = static_cast<std::vector<char> *>(vec);
583
584 // See "semantics of reading non-trivial objects" in RNTuple's Architecture.md
585 assert(itemSize > 0);
586 const auto oldNItems = typedValue->size() / itemSize;
587 const auto availNItems = typedValue->capacity() / itemSize;
588 assert((typedValue->size() % itemSize == 0) && (typedValue->capacity() % itemSize == 0));
589
590 const bool canRealloc = availNItems < nItems;
591 bool allDeallocated = false;
592 if (itemDeleter) {
594 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
595 itemDeleter->operator()(typedValue->data() + (i * itemSize), true /* dtorOnly */);
596 }
597 }
598
599 // Resize the vector with correct alignment
600 const auto itemAlignment = itemField.GetAlignment();
601 const auto nbytes = nItems * itemSize;
602
603 auto fnAlignedResize = [](auto &vecOfAlignedStorage, std::size_t targetSize) {
604 constexpr auto valueTypeSize = sizeof(typename std::decay_t<decltype(vecOfAlignedStorage)>::value_type);
605 constexpr auto valueTypeAlignment = alignof(typename std::decay_t<decltype(vecOfAlignedStorage)>::value_type);
606 // Ensure that this function is used with RAlignedStorage as a template argument.
607 // In general, the actual (user-defined) item type may have larger size than alignment.
608 static_assert(valueTypeSize == valueTypeAlignment);
611 };
612
613 static_assert(kMaxItemAlignment == 4096);
614 // clang-format off
615 switch (itemAlignment) {
616 case 1: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 1>> *>(vec), nbytes); break;
617 case 2: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 2>> *>(vec), nbytes); break;
618 case 4: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 4>> *>(vec), nbytes); break;
619 case 8: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 8>> *>(vec), nbytes); break;
620 case 16: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 16>> *>(vec), nbytes); break;
621 case 32: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 32>> *>(vec), nbytes); break;
622 case 64: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 64>> *>(vec), nbytes); break;
623 case 128: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 128>> *>(vec), nbytes); break;
624 case 256: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 256>> *>(vec), nbytes); break;
625 case 512: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage< 512>> *>(vec), nbytes); break;
626 case 1024: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<1024>> *>(vec), nbytes); break;
627 case 2048: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<2048>> *>(vec), nbytes); break;
628 case 4096: fnAlignedResize(*static_cast<std::vector<Internal::RAlignedStorage<4096>> *>(vec), nbytes); break;
629 default: throw RException(R__FAIL(std::string("Unsupported alignment: ") + std::to_string(itemAlignment)));
630 }
631 // clang-format on
632
633 if (!(itemField.GetTraits() & kTraitTriviallyConstructible)) {
634 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
635 CallConstructValueOn(itemField, typedValue->data() + (i * itemSize));
636 }
637 }
638}
639
641{
642 auto typedValue = static_cast<std::vector<char> *>(to);
643
646 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
647
648 if (fSubfields[0]->IsSimple()) {
649 typedValue->resize(nItems * fItemSize);
650 if (nItems)
651 GetPrincipalColumnOf(*fSubfields[0])->ReadV(collectionStart, nItems, typedValue->data());
652 return;
653 }
654
655 ResizeVector(to, nItems, fItemSize, *fSubfields[0], fItemDeleter.get());
656
657 for (std::size_t i = 0; i < nItems; ++i) {
658 CallReadOn(*fSubfields[0], collectionStart + i, typedValue->data() + (i * fItemSize));
659 }
660}
661
671
676
681
683{
684 if (GetOnDiskId() == kInvalidDescriptorId)
685 return nullptr;
686
687 const auto descGuard = pageSource.GetSharedDescriptorGuard();
688 const auto &fieldDesc = descGuard->GetFieldDescriptor(GetOnDiskId());
689 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
690 auto substitute = std::make_unique<RArrayAsVectorField>(
691 GetFieldName(), fSubfields[0]->Clone(fSubfields[0]->GetFieldName()), fieldDesc.GetNRepetitions());
692 substitute->SetOnDiskId(GetOnDiskId());
693 return substitute;
694 }
695 return nullptr;
696}
697
699{
700 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
701}
702
704{
705 ConstructVector(where, fSubfields[0]->GetAlignment());
706}
707
712
714 std::unique_ptr<RDeleter> itemDeleter)
717 fItemAlignment(itemAlignment),
719{
720}
721
723{
724 auto vecPtr = static_cast<std::vector<char> *>(objPtr);
725 if (fItemDeleter) {
726 assert(fItemSize > 0);
727 auto nItems = vecPtr->size() / fItemSize;
728 assert((vecPtr->size() % fItemSize) == 0);
729 for (std::size_t i = 0; i < nItems; ++i) {
730 fItemDeleter->operator()(vecPtr->data() + (i * fItemSize), true /* dtorOnly */);
731 }
732 }
733
734 static_assert(kMaxItemAlignment == 4096);
735 // clang-format off
736 switch (fItemAlignment) {
737 case 1: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 1>> *>(objPtr)); break;
738 case 2: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 2>> *>(objPtr)); break;
739 case 4: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 4>> *>(objPtr)); break;
740 case 8: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 8>> *>(objPtr)); break;
741 case 16: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 16>> *>(objPtr)); break;
742 case 32: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 32>> *>(objPtr)); break;
743 case 64: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 64>> *>(objPtr)); break;
744 case 128: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 128>> *>(objPtr)); break;
745 case 256: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 256>> *>(objPtr)); break;
746 case 512: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage< 512>> *>(objPtr)); break;
747 case 1024: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<1024>> *>(objPtr)); break;
748 case 2048: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<2048>> *>(objPtr)); break;
749 case 4096: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<4096>> *>(objPtr)); break;
750 default: throw ROOT::RException(R__FAIL(std::string("Unsupported alignment: ") + std::to_string(fItemAlignment)));
751 }
752 // clang-format on
753
754 RDeleter::operator()(objPtr, dtorOnly);
755}
756
757std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RVectorField::GetDeleter() const
758{
759 if (fItemDeleter)
760 return std::make_unique<RVectorDeleter>(fItemSize, fSubfields[0]->GetAlignment(), GetDeleterOf(*fSubfields[0]));
761 return std::make_unique<RVectorDeleter>(fSubfields[0]->GetAlignment());
762}
763
764std::vector<ROOT::RFieldBase::RValue> ROOT::RVectorField::SplitValue(const RValue &value) const
765{
766 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
767}
768
770{
771 return GetSizeOfVector();
772}
773
775{
776 return GetAlignOfVector();
777}
778
780{
781 visitor.VisitVectorField(*this);
782}
783
784//------------------------------------------------------------------------------
785
786ROOT::RField<std::vector<bool>>::RField(std::string_view name)
787 : ROOT::RFieldBase(name, "std::vector<bool>", ROOT::ENTupleStructure::kCollection, false /* isSimple */)
788{
789 Attach(std::make_unique<RField<bool>>("_0"));
790}
791
792std::size_t ROOT::RField<std::vector<bool>>::AppendImpl(const void *from)
793{
794 auto typedValue = static_cast<const std::vector<bool> *>(from);
795 auto count = typedValue->size();
796 for (unsigned i = 0; i < count; ++i) {
797 bool bval = (*typedValue)[i];
798 CallAppendOn(*fSubfields[0], &bval);
799 }
800 fNWritten += count;
801 fPrincipalColumn->Append(&fNWritten);
802 return count + fPrincipalColumn->GetElement()->GetPackedSize();
803}
804
806{
807 auto typedValue = static_cast<std::vector<bool> *>(to);
808
809 if (fOnDiskNRepetitions == 0) {
811 RNTupleLocalIndex collectionStart;
812 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
813 typedValue->resize(nItems);
814 for (std::size_t i = 0; i < nItems; ++i) {
815 bool bval;
816 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
817 (*typedValue)[i] = bval;
818 }
819 } else {
820 typedValue->resize(fOnDiskNRepetitions);
821 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
822 bool bval;
823 CallReadOn(*fSubfields[0], globalIndex * fOnDiskNRepetitions + i, &bval);
824 (*typedValue)[i] = bval;
825 }
826 }
827}
828
829void ROOT::RField<std::vector<bool>>::ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to)
830{
831 auto typedValue = static_cast<std::vector<bool> *>(to);
832
833 if (fOnDiskNRepetitions == 0) {
835 RNTupleLocalIndex collectionStart;
836 fPrincipalColumn->GetCollectionInfo(localIndex, &collectionStart, &nItems);
837 typedValue->resize(nItems);
838 for (std::size_t i = 0; i < nItems; ++i) {
839 bool bval;
840 CallReadOn(*fSubfields[0], collectionStart + i, &bval);
841 (*typedValue)[i] = bval;
842 }
843 } else {
844 typedValue->resize(fOnDiskNRepetitions);
845 for (std::size_t i = 0; i < fOnDiskNRepetitions; ++i) {
846 bool bval;
847 CallReadOn(*fSubfields[0], localIndex * fOnDiskNRepetitions + i, &bval);
848 (*typedValue)[i] = bval;
849 }
850 }
851}
852
853const ROOT::RFieldBase::RColumnRepresentations &ROOT::RField<std::vector<bool>>::GetColumnRepresentations() const
854{
855 static RColumnRepresentations representations({{ENTupleColumnType::kSplitIndex64},
859 {{}});
860 return representations;
861}
862
863void ROOT::RField<std::vector<bool>>::GenerateColumns()
864{
865 R__ASSERT(fOnDiskNRepetitions == 0); // fOnDiskNRepetitions must only be used for reading
867}
868
869void ROOT::RField<std::vector<bool>>::GenerateColumns(const ROOT::RNTupleDescriptor &desc)
870{
871 if (fOnDiskNRepetitions == 0)
873}
874
875void ROOT::RField<std::vector<bool>>::ReconcileOnDiskField(const RNTupleDescriptor &desc)
876{
877 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
878
879 if (fieldDesc.GetTypeName().rfind("std::array<", 0) == 0) {
880 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions).ThrowOnError();
881
882 if (fieldDesc.GetNRepetitions() == 0) {
883 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected repetition count > 0\n" +
884 Internal::GetTypeTraceReport(*this, desc)));
885 }
886 if (fieldDesc.GetStructure() != ENTupleStructure::kPlain) {
887 throw RException(R__FAIL("fixed-size array --> std::vector<bool>: expected plain on-disk field\n" +
888 Internal::GetTypeTraceReport(*this, desc)));
889 }
890 fOnDiskNRepetitions = fieldDesc.GetNRepetitions();
891 } else {
892 EnsureMatchingOnDiskCollection(desc).ThrowOnError();
893 }
894}
895
896std::vector<ROOT::RFieldBase::RValue> ROOT::RField<std::vector<bool>>::SplitValue(const RValue &value) const
897{
898 const auto &typedValue = value.GetRef<std::vector<bool>>();
899 auto count = typedValue.size();
900 std::vector<RValue> result;
901 result.reserve(count);
902 for (unsigned i = 0; i < count; ++i) {
903 if (typedValue[i]) {
904 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(true))));
905 } else {
906 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<bool>(new bool(false))));
907 }
908 }
909 return result;
910}
911
913{
914 visitor.VisitVectorBoolField(*this);
915}
916
917//------------------------------------------------------------------------------
918
919ROOT::RArrayAsRVecField::RArrayAsRVecField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
920 std::size_t arrayLength)
921 : ROOT::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
922 ROOT::ENTupleStructure::kCollection, false /* isSimple */),
923 fItemSize(itemField->GetValueSize()),
924 fArrayLength(arrayLength)
925{
926 if (!itemField->GetTypeAlias().empty())
927 fTypeAlias = "ROOT::VecOps::RVec<" + itemField->GetTypeAlias() + ">";
928 Attach(std::move(itemField), "_0");
929 fValueSize =
933}
934
935std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsRVecField::CloneImpl(std::string_view newName) const
936{
937 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
938 return std::make_unique<RArrayAsRVecField>(newName, std::move(newItemField), fArrayLength);
939}
940
942{
943 // initialize data members fBegin, fSize, fCapacity
944 // currently the inline buffer is left uninitialized
945 void **beginPtr = new (where)(void *)(nullptr);
946 std::int32_t *sizePtr = new (static_cast<void *>(beginPtr + 1)) std::int32_t(0);
947 new (sizePtr + 1) std::int32_t(-1);
948}
949
950std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsRVecField::GetDeleter() const
951{
952 if (fItemDeleter) {
953 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment(), fItemSize,
954 GetDeleterOf(*fSubfields[0]));
955 }
956 return std::make_unique<RRVecField::RRVecDeleter>(fSubfields[0]->GetAlignment());
957}
958
960{
961 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
962
963 if (fSubfields[0]->IsSimple()) {
964 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, begin);
965 return;
966 }
967
968 // Read the new values into the collection elements
969 for (std::size_t i = 0; i < fArrayLength; ++i) {
970 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, begin + (i * fItemSize));
971 }
972}
973
975{
976 auto begin = RRVecField::ResizeRVec(to, fArrayLength, fItemSize, fSubfields[0].get(), fItemDeleter.get());
977
978 if (fSubfields[0]->IsSimple()) {
979 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, begin);
980 return;
981 }
982
983 // Read the new values into the collection elements
984 for (std::size_t i = 0; i < fArrayLength; ++i) {
985 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, begin + (i * fItemSize));
986 }
987}
988
990{
991 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions).ThrowOnError();
992 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
993 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
994 throw RException(R__FAIL("RArrayAsRVecField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
995 Internal::GetTypeTraceReport(*this, desc)));
996 }
997}
998
1000{
1001 return Internal::EvalRVecAlignment(fSubfields[0]->GetAlignment());
1002}
1003
1004std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsRVecField::SplitValue(const ROOT::RFieldBase::RValue &value) const
1005{
1006 auto arrayPtr = value.GetPtr<unsigned char>().get();
1007 std::vector<ROOT::RFieldBase::RValue> result;
1008 result.reserve(fArrayLength);
1009 for (unsigned i = 0; i < fArrayLength; ++i) {
1010 result.emplace_back(
1011 fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), arrayPtr + (i * fItemSize))));
1012 }
1013 return result;
1014}
1015
1017{
1018 visitor.VisitArrayAsRVecField(*this);
1019}
1020
1021//------------------------------------------------------------------------------
1022
1023ROOT::RArrayAsVectorField::RArrayAsVectorField(std::string_view fieldName, std::unique_ptr<ROOT::RFieldBase> itemField,
1024 std::size_t arrayLength)
1025 : ROOT::RFieldBase(fieldName, "std::vector<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kCollection,
1026 false /* isSimple */),
1027 fItemSize(itemField->GetValueSize()),
1028 fArrayLength(arrayLength)
1029{
1030 if (!itemField->GetTypeAlias().empty())
1031 fTypeAlias = "std::vector<" + itemField->GetTypeAlias() + ">";
1032 Attach(std::move(itemField), "_0");
1035}
1036
1037std::unique_ptr<ROOT::RFieldBase> ROOT::RArrayAsVectorField::CloneImpl(std::string_view newName) const
1038{
1039 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
1040 return std::make_unique<RArrayAsVectorField>(newName, std::move(newItemField), fArrayLength);
1041}
1042
1044{
1045 throw RException(R__FAIL("RArrayAsVectorField fields must only be used for reading"));
1046}
1047
1049{
1050 ConstructVector(where, fSubfields[0]->GetAlignment());
1051}
1052
1053std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RArrayAsVectorField::GetDeleter() const
1054{
1055 if (fItemDeleter) {
1056 return std::make_unique<RVectorField::RVectorDeleter>(fItemSize, fSubfields[0]->GetAlignment(),
1057 GetDeleterOf(*fSubfields[0]));
1058 }
1059 return std::make_unique<RVectorField::RVectorDeleter>(fSubfields[0]->GetAlignment());
1060}
1061
1063{
1064 auto typedValue = static_cast<std::vector<char> *>(to);
1065
1066 if (fSubfields[0]->IsSimple()) {
1067 typedValue->resize(fArrayLength * fItemSize);
1068 GetPrincipalColumnOf(*fSubfields[0])->ReadV(globalIndex * fArrayLength, fArrayLength, typedValue->data());
1069 return;
1070 }
1071
1072 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
1073
1074 for (std::size_t i = 0; i < fArrayLength; ++i) {
1075 CallReadOn(*fSubfields[0], globalIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
1076 }
1077}
1078
1080{
1081 auto typedValue = static_cast<std::vector<char> *>(to);
1082
1083 if (fSubfields[0]->IsSimple()) {
1084 typedValue->resize(fArrayLength * fItemSize);
1085 GetPrincipalColumnOf(*fSubfields[0])->ReadV(localIndex * fArrayLength, fArrayLength, typedValue->data());
1086 return;
1087 }
1088
1089 RVectorField::ResizeVector(to, fArrayLength, fItemSize, *fSubfields[0], fItemDeleter.get());
1090
1091 for (std::size_t i = 0; i < fArrayLength; ++i) {
1092 CallReadOn(*fSubfields[0], localIndex * fArrayLength + i, typedValue->data() + (i * fItemSize));
1093 }
1094}
1095
1097{
1098 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffStructure | kDiffNRepetitions);
1099
1100 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1101 if (fieldDesc.GetTypeName().rfind("std::array<", 0) != 0) {
1102 throw RException(R__FAIL("RArrayAsVectorField " + GetQualifiedFieldName() + " expects an on-disk array field\n" +
1103 Internal::GetTypeTraceReport(*this, desc)));
1104 }
1105}
1106
1107std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsVectorField::SplitValue(const ROOT::RFieldBase::RValue &value) const
1108{
1109 return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
1110}
1111
1113{
1114 return GetSizeOfVector();
1115}
1116
1118{
1119 return GetAlignOfVector();
1120}
1121
1123{
1124 visitor.VisitArrayAsVectorField(*this);
1125}
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:299
#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 free
Definition civetweb.c:1578
#define malloc
Definition civetweb.c:1575
Abstract base class for classes implementing the visitor design pattern.
The in-memory representation of a 32bit or 64bit on-disk index column.
Abstract interface to read data from an ntuple.
std::unique_ptr< RDeleter > fItemDeleter
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
RArrayAsRVecField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::size_t arrayLength)
Constructor of the field.
std::size_t GetAlignment() const final
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.
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.
@ 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::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().