Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RField.cxx
Go to the documentation of this file.
1/// \file RField.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-15
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#include <ROOT/RColumn.hxx>
17#include <ROOT/RColumnModel.hxx>
18#include <ROOT/REntry.hxx>
19#include <ROOT/RError.hxx>
20#include <ROOT/RField.hxx>
22#include <ROOT/RLogger.hxx>
24#include <ROOT/RNTupleModel.hxx>
25
26#include <TBaseClass.h>
27#include <TClass.h>
28#include <TClassEdit.h>
29#include <TCollection.h>
30#include <TDataMember.h>
31#include <TEnum.h>
32#include <TError.h>
33#include <TList.h>
34#include <TObjArray.h>
35#include <TObjString.h>
36#include <TRealData.h>
37#include <TSchemaRule.h>
38#include <TSchemaRuleSet.h>
39#include <TVirtualObject.h>
40
41#include <algorithm>
42#include <cctype> // for isspace
43#include <charconv>
44#include <cstdint>
45#include <cstdlib> // for malloc, free
46#include <cstring> // for memset
47#include <exception>
48#include <iostream>
49#include <memory>
50#include <new> // hardware_destructive_interference_size
51#include <type_traits>
52#include <unordered_map>
53
54namespace {
55
56const std::unordered_map<std::string_view, std::string_view> typeTranslationMap{
57 {"Bool_t", "bool"},
58 {"Float_t", "float"},
59 {"Double_t", "double"},
60 {"string", "std::string"},
61
62 {"byte", "std::byte"},
63 {"Char_t", "char"},
64 {"int8_t", "std::int8_t"},
65 {"signed char", "char"},
66 {"UChar_t", "std::uint8_t"},
67 {"unsigned char", "std::uint8_t"},
68 {"uint8_t", "std::uint8_t"},
69
70 {"Short_t", "std::int16_t"},
71 {"int16_t", "std::int16_t"},
72 {"short", "std::int16_t"},
73 {"UShort_t", "std::uint16_t"},
74 {"unsigned short", "std::uint16_t"},
75 {"uint16_t", "std::uint16_t"},
76
77 {"Int_t", "std::int32_t"},
78 {"int32_t", "std::int32_t"},
79 {"int", "std::int32_t"},
80 {"UInt_t", "std::uint32_t"},
81 {"unsigned", "std::uint32_t"},
82 {"unsigned int", "std::uint32_t"},
83 {"uint32_t", "std::uint32_t"},
84
85 // FIXME: Long_t and ULong_t are 32-bit on 64-bit Windows.
86 {"Long_t", "std::int64_t"},
87 {"Long64_t", "std::int64_t"},
88 {"int64_t", "std::int64_t"},
89 {"long", "std::int64_t"},
90 {"ULong_t", "std::uint64_t"},
91 {"ULong64_t", "std::uint64_t"},
92 {"unsigned long", "std::uint64_t"},
93 {"uint64_t", "std::uint64_t"}
94};
95
96/// Used in CreateField() in order to get the comma-separated list of template types
97/// E.g., gets {"int", "std::variant<double,int>"} from "int,std::variant<double,int>"
98std::vector<std::string> TokenizeTypeList(std::string templateType) {
99 std::vector<std::string> result;
100 if (templateType.empty())
101 return result;
102
103 const char *eol = templateType.data() + templateType.length();
104 const char *typeBegin = templateType.data();
105 const char *typeCursor = templateType.data();
106 unsigned int nestingLevel = 0;
107 while (typeCursor != eol) {
108 switch (*typeCursor) {
109 case '<':
110 ++nestingLevel;
111 break;
112 case '>':
113 --nestingLevel;
114 break;
115 case ',':
116 if (nestingLevel == 0) {
117 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
118 typeBegin = typeCursor + 1;
119 }
120 break;
121 }
122 typeCursor++;
123 }
124 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
125 return result;
126}
127
128/// Parse a type name of the form `T[n][m]...` and return the base type `T` and a vector that contains,
129/// in order, the declared size for each dimension, e.g. for `unsigned char[1][2][3]` it returns the tuple
130/// `{"unsigned char", {1, 2, 3}}`. Extra whitespace in `typeName` should be removed before calling this function.
131///
132/// If `typeName` is not an array type, it returns a tuple `{T, {}}`. On error, it returns a default-constructed tuple.
133std::tuple<std::string, std::vector<size_t>> ParseArrayType(std::string_view typeName)
134{
135 std::vector<size_t> sizeVec;
136
137 // Only parse outer array definition, i.e. the right `]` should be at the end of the type name
138 while (typeName.back() == ']') {
139 auto posRBrace = typeName.size() - 1;
140 auto posLBrace = typeName.find_last_of('[', posRBrace);
141 if (posLBrace == std::string_view::npos)
142 return {};
143
144 size_t size;
145 if (std::from_chars(typeName.data() + posLBrace + 1, typeName.data() + posRBrace, size).ec != std::errc{})
146 return {};
147 sizeVec.insert(sizeVec.begin(), size);
148 typeName.remove_suffix(typeName.size() - posLBrace);
149 }
150 return std::make_tuple(std::string{typeName}, sizeVec);
151}
152
153/// Return the canonical name of a type, resolving typedefs to their underlying types if needed. A canonical type has
154/// typedefs stripped out from the type name.
155std::string GetCanonicalTypeName(const std::string &typeName)
156{
157 // The following types are asummed to be canonical names; thus, do not perform `typedef` resolution on those
158 if (typeName == "ROOT::Experimental::ClusterSize_t" || typeName.substr(0, 5) == "std::" ||
159 typeName.substr(0, 39) == "ROOT::Experimental::RNTupleCardinality<")
160 return typeName;
161
162 return TClassEdit::ResolveTypedef(typeName.c_str());
163}
164
165/// Applies type name normalization rules that lead to the final name used to create a RField, e.g. transforms
166/// `unsigned int` to `std::uint32_t` or `const vector<T>` to `std::vector<T>`. Specifically, `const` / `volatile`
167/// qualifiers are removed, integral types such as `unsigned int` or `long` are translated to fixed-length integer types
168/// (e.g. `std::uint32_t`), and `std::` is added to fully qualify known types in the `std` namespace. The same happens
169/// to `ROOT::RVec` which is normalized to `ROOT::VecOps::RVec`.
170std::string GetNormalizedTypeName(const std::string &typeName)
171{
172 std::string normalizedType{TClassEdit::CleanType(typeName.c_str(), /*mode=*/2)};
173
174 if (auto it = typeTranslationMap.find(normalizedType); it != typeTranslationMap.end())
175 normalizedType = it->second;
176
177 if (normalizedType.substr(0, 7) == "vector<")
178 normalizedType = "std::" + normalizedType;
179 if (normalizedType.substr(0, 6) == "array<")
180 normalizedType = "std::" + normalizedType;
181 if (normalizedType.substr(0, 8) == "variant<")
182 normalizedType = "std::" + normalizedType;
183 if (normalizedType.substr(0, 5) == "pair<")
184 normalizedType = "std::" + normalizedType;
185 if (normalizedType.substr(0, 6) == "tuple<")
186 normalizedType = "std::" + normalizedType;
187 if (normalizedType.substr(0, 7) == "bitset<")
188 normalizedType = "std::" + normalizedType;
189 if (normalizedType.substr(0, 11) == "unique_ptr<")
190 normalizedType = "std::" + normalizedType;
191 if (normalizedType.substr(0, 4) == "set<")
192 normalizedType = "std::" + normalizedType;
193 if (normalizedType.substr(0, 14) == "unordered_set<")
194 normalizedType = "std::" + normalizedType;
195 if (normalizedType.substr(0, 4) == "map<")
196 normalizedType = "std::" + normalizedType;
197 if (normalizedType.substr(0, 14) == "unordered_map<")
198 normalizedType = "std::" + normalizedType;
199 if (normalizedType.substr(0, 7) == "atomic<")
200 normalizedType = "std::" + normalizedType;
201
202 if (normalizedType.substr(0, 11) == "ROOT::RVec<")
203 normalizedType = "ROOT::VecOps::RVec<" + normalizedType.substr(11);
204
205 return normalizedType;
206}
207
208/// Used as a thread local context storage for Create(); steers the behavior of the Create() call stack
209class CreateContextGuard;
210class CreateContext {
211 friend class CreateContextGuard;
212 /// All classes that were defined by Create() calls higher up in the stack. Finds cyclic type definitions.
213 std::vector<std::string> fClassesOnStack;
214 /// If set to true, Create() will create an RInvalidField on error instead of throwing an exception.
215 /// This is used in RFieldBase::Check() to identify unsupported sub fields.
216 bool fContinueOnError = false;
217
218public:
219 CreateContext() = default;
220 bool GetContinueOnError() const { return fContinueOnError; }
221};
222
223/// RAII for modifications of CreateContext
224class CreateContextGuard {
225 CreateContext &fCreateContext;
226 std::size_t fNOriginalClassesOnStack;
227 bool fOriginalContinueOnError;
228
229public:
230 CreateContextGuard(CreateContext &ctx)
231 : fCreateContext(ctx),
232 fNOriginalClassesOnStack(ctx.fClassesOnStack.size()),
233 fOriginalContinueOnError(ctx.fContinueOnError)
234 {
235 }
236 ~CreateContextGuard()
237 {
238 fCreateContext.fClassesOnStack.resize(fNOriginalClassesOnStack);
239 fCreateContext.fContinueOnError = fOriginalContinueOnError;
240 }
241
242 void AddClassToStack(const std::string &cl)
243 {
244 if (std::find(fCreateContext.fClassesOnStack.begin(), fCreateContext.fClassesOnStack.end(), cl) !=
245 fCreateContext.fClassesOnStack.end()) {
246 throw ROOT::Experimental::RException(R__FAIL("cyclic class definition: " + cl));
247 }
248 fCreateContext.fClassesOnStack.emplace_back(cl);
249 }
250
251 void SetContinueOnError(bool value) { fCreateContext.fContinueOnError = value; }
252};
253
254/// Retrieve the addresses of the data members of a generic RVec from a pointer to the beginning of the RVec object.
255/// Returns pointers to fBegin, fSize and fCapacity in a std::tuple.
256std::tuple<void **, std::int32_t *, std::int32_t *> GetRVecDataMembers(void *rvecPtr)
257{
258 void **begin = reinterpret_cast<void **>(rvecPtr);
259 // int32_t fSize is the second data member (after 1 void*)
260 std::int32_t *size = reinterpret_cast<std::int32_t *>(begin + 1);
261 R__ASSERT(*size >= 0);
262 // int32_t fCapacity is the third data member (1 int32_t after fSize)
263 std::int32_t *capacity = size + 1;
264 R__ASSERT(*capacity >= -1);
265 return {begin, size, capacity};
266}
267
268std::tuple<const void *const *, const std::int32_t *, const std::int32_t *> GetRVecDataMembers(const void *rvecPtr)
269{
270 return {GetRVecDataMembers(const_cast<void *>(rvecPtr))};
271}
272
273/// Applies the field IDs from 'from' to 'to', where from and to are expected to be each other's clones.
274/// Used in RClassField and RCollectionClassField cloning. In these classes, we don't clone the subfields
275/// but we recreate them. Therefore, the on-disk IDs need to be fixed up.
276void SyncFieldIDs(const ROOT::Experimental::RFieldBase &from, ROOT::Experimental::RFieldBase &to)
277{
278 auto iFrom = from.cbegin();
279 auto iTo = to.begin();
280 for (; iFrom != from.cend(); ++iFrom, ++iTo) {
281 iTo->SetOnDiskId(iFrom->GetOnDiskId());
282 }
283}
284
285std::size_t EvalRVecValueSize(std::size_t alignOfT, std::size_t sizeOfT, std::size_t alignOfRVecT)
286{
287 // the size of an RVec<T> is the size of its 4 data-members + optional padding:
288 //
289 // data members:
290 // - void *fBegin
291 // - int32_t fSize
292 // - int32_t fCapacity
293 // - the char[] inline storage, which is aligned like T
294 //
295 // padding might be present:
296 // - between fCapacity and the char[] buffer aligned like T
297 // - after the char[] buffer
298
299 constexpr auto dataMemberSz = sizeof(void *) + 2 * sizeof(std::int32_t);
300
301 // mimic the logic of RVecInlineStorageSize, but at runtime
302 const auto inlineStorageSz = [&] {
303#ifdef R__HAS_HARDWARE_INTERFERENCE_SIZE
304 // hardware_destructive_interference_size is a C++17 feature but many compilers do not implement it yet
305 constexpr unsigned cacheLineSize = std::hardware_destructive_interference_size;
306#else
307 constexpr unsigned cacheLineSize = 64u;
308#endif
309 const unsigned elementsPerCacheLine = (cacheLineSize - dataMemberSz) / sizeOfT;
310 constexpr unsigned maxInlineByteSize = 1024;
311 const unsigned nElements =
312 elementsPerCacheLine >= 8 ? elementsPerCacheLine : (sizeOfT * 8 > maxInlineByteSize ? 0 : 8);
313 return nElements * sizeOfT;
314 }();
315
316 // compute padding between first 3 datamembers and inline buffer
317 // (there should be no padding between the first 3 data members)
318 auto paddingMiddle = dataMemberSz % alignOfT;
319 if (paddingMiddle != 0)
320 paddingMiddle = alignOfT - paddingMiddle;
321
322 // padding at the end of the object
323 auto paddingEnd = (dataMemberSz + paddingMiddle + inlineStorageSz) % alignOfRVecT;
324 if (paddingEnd != 0)
325 paddingEnd = alignOfRVecT - paddingEnd;
326
327 return dataMemberSz + inlineStorageSz + paddingMiddle + paddingEnd;
328}
329
330std::size_t EvalRVecAlignment(std::size_t alignOfSubField)
331{
332 // the alignment of an RVec<T> is the largest among the alignments of its data members
333 // (including the inline buffer which has the same alignment as the RVec::value_type)
334 return std::max({alignof(void *), alignof(std::int32_t), alignOfSubField});
335}
336
337void DestroyRVecWithChecks(std::size_t alignOfT, void **beginPtr, char *begin, std::int32_t *capacityPtr)
338{
339 // figure out if we are in the small state, i.e. begin == &inlineBuffer
340 // there might be padding between fCapacity and the inline buffer, so we compute it here
341 constexpr auto dataMemberSz = sizeof(void *) + 2 * sizeof(std::int32_t);
342 auto paddingMiddle = dataMemberSz % alignOfT;
343 if (paddingMiddle != 0)
344 paddingMiddle = alignOfT - paddingMiddle;
345 const bool isSmall = (reinterpret_cast<void *>(begin) == (beginPtr + dataMemberSz + paddingMiddle));
346
347 const bool owns = (*capacityPtr != -1);
348 if (!isSmall && owns)
349 free(begin);
350}
351
352} // anonymous namespace
353
355{
356 field.CommitCluster();
357}
359 NTupleSize_t firstEntry)
360{
361 field.ConnectPageSink(sink, firstEntry);
362}
364{
365 field.ConnectPageSource(source);
366}
367
368//------------------------------------------------------------------------------
369
371{
372 // A single representations with an empty set of columns
375}
376
378 const TypesList_t &serializationTypes, const TypesList_t &deserializationExtraTypes)
379 : fSerializationTypes(serializationTypes), fDeserializationTypes(serializationTypes)
380{
382 deserializationExtraTypes.begin(), deserializationExtraTypes.end());
383}
384
385//------------------------------------------------------------------------------
386
388{
389 // Set fObjPtr to an aliased shared_ptr of the input raw pointer. Note that
390 // fObjPtr will be non-empty but have use count zero.
392}
393
394//------------------------------------------------------------------------------
395
397 : fField(other.fField),
398 fValueSize(other.fValueSize),
399 fCapacity(other.fCapacity),
400 fSize(other.fSize),
401 fIsAdopted(other.fIsAdopted),
402 fNValidValues(other.fNValidValues),
403 fFirstIndex(other.fFirstIndex)
404{
405 std::swap(fDeleter, other.fDeleter);
406 std::swap(fValues, other.fValues);
407 std::swap(fMaskAvail, other.fMaskAvail);
408}
409
411{
412 std::swap(fField, other.fField);
413 std::swap(fDeleter, other.fDeleter);
414 std::swap(fValues, other.fValues);
415 std::swap(fValueSize, other.fValueSize);
416 std::swap(fCapacity, other.fCapacity);
417 std::swap(fSize, other.fSize);
418 std::swap(fIsAdopted, other.fIsAdopted);
419 std::swap(fMaskAvail, other.fMaskAvail);
420 std::swap(fNValidValues, other.fNValidValues);
421 std::swap(fFirstIndex, other.fFirstIndex);
422 return *this;
423}
424
426{
427 if (fValues)
428 ReleaseValues();
429}
430
432{
433 if (fIsAdopted)
434 return;
435
436 if (fField->GetTraits() & RFieldBase::kTraitTriviallyDestructible) {
437 free(fValues);
438 return;
439 }
440
441 for (std::size_t i = 0; i < fCapacity; ++i) {
442 fDeleter->operator()(GetValuePtrAt(i), true /* dtorOnly */);
443 }
444 free(fValues);
445}
446
448{
449 if (fCapacity < size) {
450 if (fIsAdopted) {
451 throw RException(R__FAIL("invalid attempt to bulk read beyond the adopted buffer"));
452 }
453 ReleaseValues();
454 fValues = malloc(size * fValueSize);
455
456 if (!(fField->GetTraits() & RFieldBase::kTraitTriviallyConstructible)) {
457 for (std::size_t i = 0; i < size; ++i) {
458 fField->ConstructValue(GetValuePtrAt(i));
459 }
460 }
461
462 fMaskAvail = std::make_unique<bool[]>(size);
463 fCapacity = size;
464 }
465
466 std::fill(fMaskAvail.get(), fMaskAvail.get() + size, false);
467 fNValidValues = 0;
468
469 fFirstIndex = firstIndex;
470 fSize = size;
471}
472
474{
475 fNValidValues = 0;
476 for (std::size_t i = 0; i < fSize; ++i)
477 fNValidValues += static_cast<std::size_t>(fMaskAvail[i]);
478}
479
480void ROOT::Experimental::RFieldBase::RBulk::AdoptBuffer(void *buf, std::size_t capacity)
481{
482 ReleaseValues();
483 fValues = buf;
484 fCapacity = capacity;
485 fSize = capacity;
486
487 fMaskAvail = std::make_unique<bool[]>(capacity);
488
489 fFirstIndex = RClusterIndex();
490
491 fIsAdopted = true;
492}
493
494//------------------------------------------------------------------------------
495
497{
498 R__LOG_WARNING(NTupleLog()) << "possibly leaking object from RField<T>::CreateObject<void>";
499}
500
501template <>
502std::unique_ptr<void, typename ROOT::Experimental::RFieldBase::RCreateObjectDeleter<void>::deleter>
503ROOT::Experimental::RFieldBase::CreateObject<void>() const
504{
506 return std::unique_ptr<void, RCreateObjectDeleter<void>::deleter>(CreateObjectRawPtr(), gDeleter);
507}
508
509//------------------------------------------------------------------------------
510
511ROOT::Experimental::RFieldBase::RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure,
512 bool isSimple, std::size_t nRepetitions)
513 : fName(name),
514 fType(type),
515 fStructure(structure),
516 fNRepetitions(nRepetitions),
517 fIsSimple(isSimple),
518 fParent(nullptr),
519 fPrincipalColumn(nullptr),
520 fTraits(isSimple ? kTraitMappable : 0)
521{
522}
523
525{
526 std::string result = GetFieldName();
527 auto parent = GetParent();
528 while (parent && !parent->GetFieldName().empty()) {
529 result = parent->GetFieldName() + "." + result;
530 parent = parent->GetParent();
531 }
532 return result;
533}
534
536ROOT::Experimental::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
537{
538 auto typeAlias = GetNormalizedTypeName(typeName);
539 auto canonicalType = GetNormalizedTypeName(GetCanonicalTypeName(typeAlias));
540 return R__FORWARD_RESULT(RFieldBase::Create(fieldName, canonicalType, typeAlias));
541}
542
543std::vector<ROOT::Experimental::RFieldBase::RCheckResult>
544ROOT::Experimental::RFieldBase::Check(const std::string &fieldName, const std::string &typeName)
545{
546 auto typeAlias = GetNormalizedTypeName(typeName);
547 auto canonicalType = GetNormalizedTypeName(GetCanonicalTypeName(typeAlias));
548
549 RFieldZero fieldZero;
550 fieldZero.Attach(RFieldBase::Create(fieldName, canonicalType, typeAlias, true /* continueOnError */).Unwrap());
551
552 std::vector<RCheckResult> result;
553 for (const auto &f : fieldZero) {
554 auto invalidField = dynamic_cast<const RInvalidField *>(&f);
555 if (!invalidField)
556 continue;
557
558 result.emplace_back(
559 RCheckResult{invalidField->GetQualifiedFieldName(), invalidField->GetTypeName(), invalidField->GetError()});
560 }
561 return result;
562}
563
565ROOT::Experimental::RFieldBase::Create(const std::string &fieldName, const std::string &canonicalType,
566 const std::string &typeAlias, bool continueOnError)
567{
568 thread_local CreateContext createContext;
569 CreateContextGuard createContextGuard(createContext);
570 if (continueOnError)
571 createContextGuard.SetContinueOnError(true);
572
573 auto fnFail = [&fieldName, &canonicalType](const std::string &errMsg) -> RResult<std::unique_ptr<RFieldBase>> {
574 if (createContext.GetContinueOnError()) {
575 return std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, canonicalType, errMsg));
576 } else {
577 return R__FAIL(errMsg);
578 }
579 };
580
581 if (canonicalType.empty())
582 return R__FORWARD_RESULT(fnFail("no type name specified for field '" + fieldName + "'"));
583
584 if (auto [arrayBaseType, arraySizes] = ParseArrayType(canonicalType); !arraySizes.empty()) {
585 std::unique_ptr<RFieldBase> arrayField = Create("_0", arrayBaseType).Unwrap();
586 for (int i = arraySizes.size() - 1; i >= 0; --i) {
587 arrayField = std::make_unique<RArrayField>((i == 0) ? fieldName : "_0", std::move(arrayField), arraySizes[i]);
588 }
589 return arrayField;
590 }
591
592 std::unique_ptr<ROOT::Experimental::RFieldBase> result;
593
594 if (canonicalType == "ROOT::Experimental::ClusterSize_t") {
595 result = std::make_unique<RField<ClusterSize_t>>(fieldName);
596 } else if (canonicalType == "bool") {
597 result = std::make_unique<RField<bool>>(fieldName);
598 } else if (canonicalType == "char") {
599 result = std::make_unique<RField<char>>(fieldName);
600 } else if (canonicalType == "std::byte") {
601 result = std::make_unique<RField<std::byte>>(fieldName);
602 } else if (canonicalType == "std::int8_t") {
603 result = std::make_unique<RField<std::int8_t>>(fieldName);
604 } else if (canonicalType == "std::uint8_t") {
605 result = std::make_unique<RField<std::uint8_t>>(fieldName);
606 } else if (canonicalType == "std::int16_t") {
607 result = std::make_unique<RField<std::int16_t>>(fieldName);
608 } else if (canonicalType == "std::uint16_t") {
609 result = std::make_unique<RField<std::uint16_t>>(fieldName);
610 } else if (canonicalType == "std::int32_t") {
611 result = std::make_unique<RField<std::int32_t>>(fieldName);
612 } else if (canonicalType == "std::uint32_t") {
613 result = std::make_unique<RField<std::uint32_t>>(fieldName);
614 } else if (canonicalType == "std::int64_t") {
615 result = std::make_unique<RField<std::int64_t>>(fieldName);
616 } else if (canonicalType == "std::uint64_t") {
617 result = std::make_unique<RField<std::uint64_t>>(fieldName);
618 } else if (canonicalType == "float") {
619 result = std::make_unique<RField<float>>(fieldName);
620 } else if (canonicalType == "double") {
621 result = std::make_unique<RField<double>>(fieldName);
622 } else if (canonicalType == "Double32_t") {
623 result = std::make_unique<RField<double>>(fieldName);
624 static_cast<RField<double> *>(result.get())->SetDouble32();
625 // Prevent the type alias from being reset by returning early
626 return result;
627 } else if (canonicalType == "std::string") {
628 result = std::make_unique<RField<std::string>>(fieldName);
629 } else if (canonicalType == "std::vector<bool>") {
630 result = std::make_unique<RField<std::vector<bool>>>(fieldName);
631 } else if (canonicalType.substr(0, 12) == "std::vector<") {
632 std::string itemTypeName = canonicalType.substr(12, canonicalType.length() - 13);
633 auto itemField = Create("_0", itemTypeName);
634 result = std::make_unique<RVectorField>(fieldName, itemField.Unwrap());
635 } else if (canonicalType.substr(0, 19) == "ROOT::VecOps::RVec<") {
636 std::string itemTypeName = canonicalType.substr(19, canonicalType.length() - 20);
637 auto itemField = Create("_0", itemTypeName);
638 result = std::make_unique<RRVecField>(fieldName, itemField.Unwrap());
639 } else if (canonicalType.substr(0, 11) == "std::array<") {
640 auto arrayDef = TokenizeTypeList(canonicalType.substr(11, canonicalType.length() - 12));
641 if (arrayDef.size() != 2) {
642 return R__FORWARD_RESULT(fnFail("the template list for std::array must have exactly two elements"));
643 }
644 auto arrayLength = std::stoi(arrayDef[1]);
645 auto itemField = Create("_0", arrayDef[0]);
646 result = std::make_unique<RArrayField>(fieldName, itemField.Unwrap(), arrayLength);
647 } else if (canonicalType.substr(0, 13) == "std::variant<") {
648 auto innerTypes = TokenizeTypeList(canonicalType.substr(13, canonicalType.length() - 14));
649 std::vector<RFieldBase *> items;
650 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
651 items.emplace_back(Create("_" + std::to_string(i), innerTypes[i]).Unwrap().release());
652 }
653 result = std::make_unique<RVariantField>(fieldName, items);
654 } else if (canonicalType.substr(0, 10) == "std::pair<") {
655 auto innerTypes = TokenizeTypeList(canonicalType.substr(10, canonicalType.length() - 11));
656 if (innerTypes.size() != 2) {
657 return R__FORWARD_RESULT(fnFail("the type list for std::pair must have exactly two elements"));
658 }
659 std::array<std::unique_ptr<RFieldBase>, 2> items{Create("_0", innerTypes[0]).Unwrap(),
660 Create("_1", innerTypes[1]).Unwrap()};
661 result = std::make_unique<RPairField>(fieldName, items);
662 } else if (canonicalType.substr(0, 11) == "std::tuple<") {
663 auto innerTypes = TokenizeTypeList(canonicalType.substr(11, canonicalType.length() - 12));
664 std::vector<std::unique_ptr<RFieldBase>> items;
665 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
666 items.emplace_back(Create("_" + std::to_string(i), innerTypes[i]).Unwrap());
667 }
668 result = std::make_unique<RTupleField>(fieldName, items);
669 } else if (canonicalType.substr(0, 12) == "std::bitset<") {
670 auto size = std::stoull(canonicalType.substr(12, canonicalType.length() - 13));
671 result = std::make_unique<RBitsetField>(fieldName, size);
672 } else if (canonicalType.substr(0, 16) == "std::unique_ptr<") {
673 std::string itemTypeName = canonicalType.substr(16, canonicalType.length() - 17);
674 auto itemField = Create("_0", itemTypeName).Unwrap();
675 auto normalizedInnerTypeName = itemField->GetTypeName();
676 result = std::make_unique<RUniquePtrField>(fieldName, "std::unique_ptr<" + normalizedInnerTypeName + ">",
677 std::move(itemField));
678 } else if (canonicalType.substr(0, 9) == "std::set<") {
679 std::string itemTypeName = canonicalType.substr(9, canonicalType.length() - 10);
680 auto itemField = Create("_0", itemTypeName).Unwrap();
681 auto normalizedInnerTypeName = itemField->GetTypeName();
682 result =
683 std::make_unique<RSetField>(fieldName, "std::set<" + normalizedInnerTypeName + ">", std::move(itemField));
684 } else if (canonicalType.substr(0, 19) == "std::unordered_set<") {
685 std::string itemTypeName = canonicalType.substr(19, canonicalType.length() - 20);
686 auto itemField = Create("_0", itemTypeName).Unwrap();
687 auto normalizedInnerTypeName = itemField->GetTypeName();
688 result = std::make_unique<RSetField>(fieldName, "std::unordered_set<" + normalizedInnerTypeName + ">",
689 std::move(itemField));
690 } else if (canonicalType.substr(0, 9) == "std::map<") {
691 auto innerTypes = TokenizeTypeList(canonicalType.substr(9, canonicalType.length() - 10));
692 if (innerTypes.size() != 2) {
693 return R__FORWARD_RESULT(fnFail("the type list for std::map must have exactly two elements"));
694 }
695
696 auto normalizedKeyTypeName = GetNormalizedTypeName(innerTypes[0]);
697 auto normalizedValueTypeName = GetNormalizedTypeName(innerTypes[1]);
698
699 auto itemField =
700 Create("_0", "std::pair<" + normalizedKeyTypeName + "," + normalizedValueTypeName + ">").Unwrap();
701 result = std::make_unique<RMapField>(
702 fieldName, "std::map<" + normalizedKeyTypeName + "," + normalizedValueTypeName + ">", std::move(itemField));
703 } else if (canonicalType.substr(0, 19) == "std::unordered_map<") {
704 auto innerTypes = TokenizeTypeList(canonicalType.substr(19, canonicalType.length() - 20));
705 if (innerTypes.size() != 2)
706 return R__FORWARD_RESULT(fnFail("the type list for std::unordered_map must have exactly two elements"));
707
708 auto normalizedKeyTypeName = GetNormalizedTypeName(innerTypes[0]);
709 auto normalizedValueTypeName = GetNormalizedTypeName(innerTypes[1]);
710
711 auto itemField =
712 Create("_0", "std::pair<" + normalizedKeyTypeName + "," + normalizedValueTypeName + ">").Unwrap();
713 result = std::make_unique<RMapField>(
714 fieldName, "std::unordered_map<" + normalizedKeyTypeName + "," + normalizedValueTypeName + ">",
715 std::move(itemField));
716 } else if (canonicalType.substr(0, 12) == "std::atomic<") {
717 std::string itemTypeName = canonicalType.substr(12, canonicalType.length() - 13);
718 auto itemField = Create("_0", itemTypeName).Unwrap();
719 auto normalizedInnerTypeName = itemField->GetTypeName();
720 result = std::make_unique<RAtomicField>(fieldName, "std::atomic<" + normalizedInnerTypeName + ">",
721 std::move(itemField));
722 } else if (canonicalType.substr(0, 39) == "ROOT::Experimental::RNTupleCardinality<") {
723 auto innerTypes = TokenizeTypeList(canonicalType.substr(39, canonicalType.length() - 40));
724 if (innerTypes.size() != 1)
725 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + canonicalType));
726 if (innerTypes[0] == "std::uint32_t") {
727 result = std::make_unique<RField<RNTupleCardinality<std::uint32_t>>>(fieldName);
728 } else if (innerTypes[0] == "std::uint64_t") {
729 result = std::make_unique<RField<RNTupleCardinality<std::uint64_t>>>(fieldName);
730 } else {
731 return R__FORWARD_RESULT(fnFail("invalid cardinality template: " + canonicalType));
732 }
733 }
734
735 try {
736 if (!result) {
737 auto e = TEnum::GetEnum(canonicalType.c_str());
738 if (e != nullptr) {
739 result = std::make_unique<REnumField>(fieldName, canonicalType);
740 }
741 }
742
743 if (!result) {
744 auto cl = TClass::GetClass(canonicalType.c_str());
745 if (cl != nullptr) {
746 createContextGuard.AddClassToStack(canonicalType);
747 if (cl->GetCollectionProxy()) {
748 result = std::make_unique<RProxiedCollectionField>(fieldName, canonicalType);
749 } else {
750 result = std::make_unique<RClassField>(fieldName, canonicalType);
751 }
752 }
753 }
754 } catch (RException &e) {
755 auto error = e.GetError();
756 if (createContext.GetContinueOnError()) {
757 std::unique_ptr<RFieldBase>(std::make_unique<RInvalidField>(fieldName, canonicalType, error.GetReport()));
758 } else {
759 return error;
760 }
761 }
762
763 if (result) {
764 if (typeAlias != canonicalType)
765 result->fTypeAlias = typeAlias;
766 return result;
767 }
768 return R__FORWARD_RESULT(fnFail("unknown type: " + canonicalType));
769}
770
772{
773 if (fieldName.empty()) {
774 return R__FAIL("name cannot be empty string \"\"");
775 } else if (fieldName.find('.') != std::string::npos) {
776 return R__FAIL("name '" + std::string(fieldName) + "' cannot contain dot characters '.'");
777 }
778 return RResult<void>::Success();
779}
780
783{
784 static RColumnRepresentations representations;
785 return representations;
786}
787
788std::unique_ptr<ROOT::Experimental::RFieldBase> ROOT::Experimental::RFieldBase::Clone(std::string_view newName) const
789{
790 auto clone = CloneImpl(newName);
791 clone->fTypeAlias = fTypeAlias;
792 clone->fOnDiskId = fOnDiskId;
793 clone->fDescription = fDescription;
794 // We can just copy the pointer because fColumnRepresentative points into a static structure
795 clone->fColumnRepresentative = fColumnRepresentative;
796 return clone;
797}
798
799std::size_t ROOT::Experimental::RFieldBase::AppendImpl(const void * /* from */)
800{
801 R__ASSERT(false && "A non-simple RField must implement its own AppendImpl");
802 return 0;
803}
804
806{
807 R__ASSERT(false);
808}
809
811{
812 const auto valueSize = GetValueSize();
813 std::size_t nRead = 0;
814 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
815 // Value not needed
816 if (!bulkSpec.fMaskReq[i])
817 continue;
818
819 // Value already present
820 if (bulkSpec.fMaskAvail[i])
821 continue;
822
823 Read(bulkSpec.fFirstIndex + i, reinterpret_cast<unsigned char *>(bulkSpec.fValues) + i * valueSize);
824 bulkSpec.fMaskAvail[i] = true;
825 nRead++;
826 }
827 return nRead;
828}
829
831{
832 void *where = operator new(GetValueSize());
833 R__ASSERT(where != nullptr);
834 ConstructValue(where);
835 return where;
836}
837
839{
840 void *obj = CreateObjectRawPtr();
841 return RValue(this, std::shared_ptr<void>(obj, RSharedPtrDeleter(GetDeleter())));
842}
843
844std::vector<ROOT::Experimental::RFieldBase::RValue>
846{
847 return std::vector<RValue>();
848}
849
850void ROOT::Experimental::RFieldBase::Attach(std::unique_ptr<ROOT::Experimental::RFieldBase> child)
851{
852 // Note that during a model update, new fields will be attached to the zero field. The zero field, however,
853 // does not change its inital state because only its sub fields get connected by RPageSink::UpdateSchema.
854 if (fState != EState::kUnconnected)
855 throw RException(R__FAIL("invalid attempt to attach subfield to already connected field"));
856 child->fParent = this;
857 fSubFields.emplace_back(std::move(child));
858}
859
862{
863 std::size_t result = globalIndex;
864 for (auto f = this; f != nullptr; f = f->GetParent()) {
865 auto parent = f->GetParent();
866 if (parent && (parent->GetStructure() == kCollection || parent->GetStructure() == kVariant))
867 return 0U;
868 result *= std::max(f->GetNRepetitions(), std::size_t{1U});
869 }
870 return result;
871}
872
873std::vector<ROOT::Experimental::RFieldBase *> ROOT::Experimental::RFieldBase::GetSubFields()
874{
875 std::vector<RFieldBase *> result;
876 result.reserve(fSubFields.size());
877 for (const auto &f : fSubFields) {
878 result.emplace_back(f.get());
879 }
880 return result;
881}
882
883std::vector<const ROOT::Experimental::RFieldBase *> ROOT::Experimental::RFieldBase::GetSubFields() const
884{
885 std::vector<const RFieldBase *> result;
886 result.reserve(fSubFields.size());
887 for (const auto &f : fSubFields) {
888 result.emplace_back(f.get());
889 }
890 return result;
891}
892
894{
895 for (auto& column : fColumns) {
896 column->Flush();
897 }
898 CommitClusterImpl();
899}
900
901void ROOT::Experimental::RFieldBase::SetDescription(std::string_view description)
902{
903 if (fState != EState::kUnconnected)
904 throw RException(R__FAIL("cannot set field description once field is connected"));
905 fDescription = std::string(description);
906}
907
909{
910 if (fState != EState::kUnconnected)
911 throw RException(R__FAIL("cannot set field ID once field is connected"));
912 fOnDiskId = id;
913}
914
917{
918 if (fColumnRepresentative)
919 return *fColumnRepresentative;
920 return GetColumnRepresentations().GetSerializationDefault();
921}
922
924{
925 if (fState != EState::kUnconnected)
926 throw RException(R__FAIL("cannot set column representative once field is connected"));
927 const auto &validTypes = GetColumnRepresentations().GetSerializationTypes();
928 auto itRepresentative = std::find(validTypes.begin(), validTypes.end(), representative);
929 if (itRepresentative == std::end(validTypes))
930 throw RException(R__FAIL("invalid column representative"));
931 fColumnRepresentative = &(*itRepresentative);
932}
933
936{
937 if (fOnDiskId == kInvalidDescriptorId)
938 throw RException(R__FAIL("No on-disk column information for field `" + GetQualifiedFieldName() + "`"));
939
940 ColumnRepresentation_t onDiskTypes;
941 for (const auto &c : desc.GetColumnIterable(fOnDiskId)) {
942 onDiskTypes.emplace_back(c.GetModel().GetType());
943 }
944 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
945 if (t == onDiskTypes)
946 return t;
947 }
948
949 std::string columnTypeNames;
950 for (const auto &t : onDiskTypes) {
951 if (!columnTypeNames.empty())
952 columnTypeNames += ", ";
953 columnTypeNames += Internal::RColumnElementBase::GetTypeName(t);
954 }
955 throw RException(R__FAIL("On-disk column types `" + columnTypeNames + "` for field `" + GetQualifiedFieldName() +
956 "` cannot be matched."));
957}
958
960{
961 fReadCallbacks.push_back(func);
962 fIsSimple = false;
963 return fReadCallbacks.size() - 1;
964}
965
967{
968 fReadCallbacks.erase(fReadCallbacks.begin() + idx);
969 fIsSimple = (fTraits & kTraitMappable) && fReadCallbacks.empty();
970}
971
973{
974 if ((options.GetCompression() == 0) && HasDefaultColumnRepresentative()) {
975 ColumnRepresentation_t rep = GetColumnRepresentative();
976 for (auto &colType : rep) {
977 switch (colType) {
980 case EColumnType::kSplitReal64: colType = EColumnType::kReal64; break;
981 case EColumnType::kSplitReal32: colType = EColumnType::kReal32; break;
982 case EColumnType::kSplitInt64: colType = EColumnType::kInt64; break;
983 case EColumnType::kSplitInt32: colType = EColumnType::kInt32; break;
984 case EColumnType::kSplitInt16: colType = EColumnType::kInt16; break;
985 default: break;
986 }
987 }
988 SetColumnRepresentative(rep);
989 }
990
991 if (options.GetHasSmallClusters()) {
992 ColumnRepresentation_t rep = GetColumnRepresentative();
993 for (auto &colType : rep) {
994 switch (colType) {
996 case EColumnType::kIndex64: colType = EColumnType::kIndex32; break;
997 default: break;
998 }
999 }
1000 SetColumnRepresentative(rep);
1001 }
1002
1003 if (fTypeAlias == "Double32_t")
1004 SetColumnRepresentative({EColumnType::kSplitReal32});
1005}
1006
1008{
1009 if (dynamic_cast<ROOT::Experimental::RFieldZero *>(this))
1010 throw RException(R__FAIL("invalid attempt to connect zero field to page sink"));
1011 if (fState != EState::kUnconnected)
1012 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page sink"));
1013
1014 AutoAdjustColumnTypes(pageSink.GetWriteOptions());
1015
1016 GenerateColumnsImpl();
1017 if (!fColumns.empty())
1018 fPrincipalColumn = fColumns[0].get();
1019 for (auto &column : fColumns) {
1020 auto firstElementIndex = (column.get() == fPrincipalColumn) ? EntryToColumnElementIndex(firstEntry) : 0;
1021 column->ConnectPageSink(fOnDiskId, pageSink, firstElementIndex);
1022 }
1023
1024 fState = EState::kConnectedToSink;
1025}
1026
1028{
1029 if (dynamic_cast<ROOT::Experimental::RFieldZero *>(this))
1030 throw RException(R__FAIL("invalid attempt to connect zero field to page source"));
1031 if (fState != EState::kUnconnected)
1032 throw RException(R__FAIL("invalid attempt to connect an already connected field to a page source"));
1033
1034 if (fColumnRepresentative)
1035 throw RException(R__FAIL("fixed column representative only valid when connecting to a page sink"));
1036 if (!fDescription.empty())
1037 throw RException(R__FAIL("setting description only valid when connecting to a page sink"));
1038
1039 for (auto &f : fSubFields) {
1040 if (f->GetOnDiskId() == kInvalidDescriptorId) {
1041 f->SetOnDiskId(pageSource.GetSharedDescriptorGuard()->FindFieldId(f->GetFieldName(), GetOnDiskId()));
1042 }
1043 f->ConnectPageSource(pageSource);
1044 }
1045
1046 {
1047 const auto descriptorGuard = pageSource.GetSharedDescriptorGuard();
1048 const RNTupleDescriptor &desc = descriptorGuard.GetRef();
1049 GenerateColumnsImpl(desc);
1050 ColumnRepresentation_t onDiskColumnTypes;
1051 for (const auto &c : fColumns) {
1052 onDiskColumnTypes.emplace_back(c->GetModel().GetType());
1053 }
1054 for (const auto &t : GetColumnRepresentations().GetDeserializationTypes()) {
1055 if (t == onDiskColumnTypes)
1056 fColumnRepresentative = &t;
1057 }
1058 R__ASSERT(fColumnRepresentative);
1059 if (fOnDiskId != kInvalidDescriptorId)
1060 fOnDiskTypeVersion = desc.GetFieldDescriptor(fOnDiskId).GetTypeVersion();
1061 }
1062 if (!fColumns.empty())
1063 fPrincipalColumn = fColumns[0].get();
1064 for (auto& column : fColumns)
1065 column->ConnectPageSource(fOnDiskId, pageSource);
1066 OnConnectPageSource();
1067
1068 fState = EState::kConnectedToSource;
1069}
1070
1072{
1073 visitor.VisitField(*this);
1074}
1075
1076//-----------------------------------------------------------------------------
1077
1078std::unique_ptr<ROOT::Experimental::RFieldBase>
1079ROOT::Experimental::RFieldZero::CloneImpl(std::string_view /*newName*/) const
1080{
1081 auto result = std::make_unique<RFieldZero>();
1082 for (auto &f : fSubFields)
1083 result->Attach(f->Clone(f->GetFieldName()));
1084 return result;
1085}
1086
1087
1089{
1090 visitor.VisitFieldZero(*this);
1091}
1092
1093
1094//------------------------------------------------------------------------------
1095
1098{
1099 static RColumnRepresentations representations(
1101 {});
1102 return representations;
1103}
1104
1106{
1107 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1108}
1109
1111{
1112 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1113 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
1114}
1115
1117{
1118 visitor.VisitClusterSizeField(*this);
1119}
1120
1121//------------------------------------------------------------------------------
1122
1125{
1126 static RColumnRepresentations representations(
1128 {});
1129 return representations;
1130}
1131
1133{
1134 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1135 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
1136}
1137
1139{
1140 visitor.VisitCardinalityField(*this);
1141}
1142
1145{
1146 return dynamic_cast<const RField<RNTupleCardinality<std::uint32_t>> *>(this);
1147}
1148
1151{
1152 return dynamic_cast<const RField<RNTupleCardinality<std::uint64_t>> *>(this);
1153}
1154
1155//------------------------------------------------------------------------------
1156
1159{
1160 static RColumnRepresentations representations({{EColumnType::kChar}}, {{}});
1161 return representations;
1162}
1163
1165{
1166 fColumns.emplace_back(Internal::RColumn::Create<char>(RColumnModel(GetColumnRepresentative()[0]), 0));
1167}
1168
1170{
1171 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1172 fColumns.emplace_back(Internal::RColumn::Create<char>(RColumnModel(onDiskTypes[0]), 0));
1173}
1174
1176{
1177 visitor.VisitCharField(*this);
1178}
1179
1180//------------------------------------------------------------------------------
1181
1184{
1185 static RColumnRepresentations representations({{EColumnType::kByte}}, {{}});
1186 return representations;
1187}
1188
1190{
1191 fColumns.emplace_back(Internal::RColumn::Create<char>(RColumnModel(GetColumnRepresentative()[0]), 0));
1192}
1193
1194void ROOT::Experimental::RField<std::byte>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1195{
1196 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1197 fColumns.emplace_back(Internal::RColumn::Create<char>(RColumnModel(onDiskTypes[0]), 0));
1198}
1199
1200void ROOT::Experimental::RField<std::byte>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1201{
1202 visitor.VisitByteField(*this);
1203}
1204
1205//------------------------------------------------------------------------------
1206
1209{
1210 static RColumnRepresentations representations({{EColumnType::kInt8}}, {{EColumnType::kUInt8}});
1211 return representations;
1212}
1213
1215{
1216 fColumns.emplace_back(Internal::RColumn::Create<std::int8_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1217}
1218
1219void ROOT::Experimental::RField<std::int8_t>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1220{
1221 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1222 fColumns.emplace_back(Internal::RColumn::Create<std::int8_t>(RColumnModel(onDiskTypes[0]), 0));
1223}
1224
1225void ROOT::Experimental::RField<std::int8_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1226{
1227 visitor.VisitInt8Field(*this);
1228}
1229
1230//------------------------------------------------------------------------------
1231
1234{
1235 static RColumnRepresentations representations({{EColumnType::kUInt8}}, {{EColumnType::kInt8}});
1236 return representations;
1237}
1238
1240{
1241 fColumns.emplace_back(Internal::RColumn::Create<std::uint8_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1242}
1243
1244void ROOT::Experimental::RField<std::uint8_t>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1245{
1246 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1247 fColumns.emplace_back(Internal::RColumn::Create<std::uint8_t>(RColumnModel(onDiskTypes[0]), 0));
1248}
1249
1250void ROOT::Experimental::RField<std::uint8_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1251{
1252 visitor.VisitUInt8Field(*this);
1253}
1254
1255//------------------------------------------------------------------------------
1256
1259{
1260 static RColumnRepresentations representations({{EColumnType::kBit}}, {});
1261 return representations;
1262}
1263
1265{
1266 fColumns.emplace_back(Internal::RColumn::Create<bool>(RColumnModel(GetColumnRepresentative()[0]), 0));
1267}
1268
1270{
1271 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1272 fColumns.emplace_back(Internal::RColumn::Create<bool>(RColumnModel(onDiskTypes[0]), 0));
1273}
1274
1276{
1277 visitor.VisitBoolField(*this);
1278}
1279
1280//------------------------------------------------------------------------------
1281
1284{
1285 static RColumnRepresentations representations(
1287 return representations;
1288}
1289
1291{
1292 fColumns.emplace_back(Internal::RColumn::Create<float>(RColumnModel(GetColumnRepresentative()[0]), 0));
1293}
1294
1296{
1297 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1298 fColumns.emplace_back(Internal::RColumn::Create<float>(RColumnModel(onDiskTypes[0]), 0));
1299}
1300
1302{
1303 visitor.VisitFloatField(*this);
1304}
1305
1307{
1308 SetColumnRepresentative({EColumnType::kReal16});
1309}
1310
1311//------------------------------------------------------------------------------
1312
1315{
1316 static RColumnRepresentations representations(
1318 return representations;
1319}
1320
1322{
1323 fColumns.emplace_back(Internal::RColumn::Create<double>(RColumnModel(GetColumnRepresentative()[0]), 0));
1324}
1325
1327{
1328 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1329 fColumns.emplace_back(Internal::RColumn::Create<double>(RColumnModel(onDiskTypes[0]), 0));
1330}
1331
1333{
1334 visitor.VisitDoubleField(*this);
1335}
1336
1338{
1339 fTypeAlias = "Double32_t";
1340}
1341
1342//------------------------------------------------------------------------------
1343
1346{
1347 static RColumnRepresentations representations({{EColumnType::kSplitInt16}, {EColumnType::kInt16}},
1349 return representations;
1350}
1351
1353{
1354 fColumns.emplace_back(Internal::RColumn::Create<std::int16_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1355}
1356
1357void ROOT::Experimental::RField<std::int16_t>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1358{
1359 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1360 fColumns.emplace_back(Internal::RColumn::Create<std::int16_t>(RColumnModel(onDiskTypes[0]), 0));
1361}
1362
1363void ROOT::Experimental::RField<std::int16_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1364{
1365 visitor.VisitInt16Field(*this);
1366}
1367
1368//------------------------------------------------------------------------------
1369
1372{
1373 static RColumnRepresentations representations({{EColumnType::kSplitUInt16}, {EColumnType::kUInt16}},
1375 return representations;
1376}
1377
1379{
1380 fColumns.emplace_back(Internal::RColumn::Create<std::uint16_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1381}
1382
1384{
1385 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1386 fColumns.emplace_back(Internal::RColumn::Create<std::uint16_t>(RColumnModel(onDiskTypes[0]), 0));
1387}
1388
1389void ROOT::Experimental::RField<std::uint16_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1390{
1391 visitor.VisitUInt16Field(*this);
1392}
1393
1394//------------------------------------------------------------------------------
1395
1398{
1399 static RColumnRepresentations representations({{EColumnType::kSplitInt32}, {EColumnType::kInt32}},
1401 return representations;
1402}
1403
1405{
1406 fColumns.emplace_back(Internal::RColumn::Create<std::int32_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1407}
1408
1409void ROOT::Experimental::RField<std::int32_t>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1410{
1411 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1412 fColumns.emplace_back(Internal::RColumn::Create<std::int32_t>(RColumnModel(onDiskTypes[0]), 0));
1413}
1414
1415void ROOT::Experimental::RField<std::int32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1416{
1417 visitor.VisitIntField(*this);
1418}
1419
1420//------------------------------------------------------------------------------
1421
1424{
1425 static RColumnRepresentations representations({{EColumnType::kSplitUInt32}, {EColumnType::kUInt32}},
1427 return representations;
1428}
1429
1431{
1432 fColumns.emplace_back(Internal::RColumn::Create<std::uint32_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1433}
1434
1436{
1437 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1438 fColumns.emplace_back(Internal::RColumn::Create<std::uint32_t>(RColumnModel(onDiskTypes[0]), 0));
1439}
1440
1441void ROOT::Experimental::RField<std::uint32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1442{
1443 visitor.VisitUInt32Field(*this);
1444}
1445
1446//------------------------------------------------------------------------------
1447
1450{
1451 static RColumnRepresentations representations({{EColumnType::kSplitUInt64}, {EColumnType::kUInt64}},
1453 return representations;
1454}
1455
1457{
1458 fColumns.emplace_back(Internal::RColumn::Create<std::uint64_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1459}
1460
1462{
1463 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1464 fColumns.emplace_back(Internal::RColumn::Create<std::uint64_t>(RColumnModel(onDiskTypes[0]), 0));
1465}
1466
1467void ROOT::Experimental::RField<std::uint64_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1468{
1469 visitor.VisitUInt64Field(*this);
1470}
1471
1472//------------------------------------------------------------------------------
1473
1476{
1477 static RColumnRepresentations representations({{EColumnType::kSplitInt64}, {EColumnType::kInt64}},
1484 return representations;
1485}
1486
1488{
1489 fColumns.emplace_back(Internal::RColumn::Create<std::int64_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1490}
1491
1492void ROOT::Experimental::RField<std::int64_t>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1493{
1494 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1495 fColumns.emplace_back(Internal::RColumn::Create<std::int64_t>(RColumnModel(onDiskTypes[0]), 0));
1496}
1497
1498void ROOT::Experimental::RField<std::int64_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1499{
1500 visitor.VisitInt64Field(*this);
1501}
1502
1503//------------------------------------------------------------------------------
1504
1507{
1508 static RColumnRepresentations representations({{EColumnType::kSplitIndex64, EColumnType::kChar},
1512 {});
1513 return representations;
1514}
1515
1517{
1518 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1519 fColumns.emplace_back(Internal::RColumn::Create<char>(RColumnModel(GetColumnRepresentative()[1]), 1));
1520}
1521
1522void ROOT::Experimental::RField<std::string>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
1523{
1524 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1525 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
1526 fColumns.emplace_back(Internal::RColumn::Create<char>(RColumnModel(onDiskTypes[1]), 1));
1527}
1528
1529std::size_t ROOT::Experimental::RField<std::string>::AppendImpl(const void *from)
1530{
1531 auto typedValue = static_cast<const std::string *>(from);
1532 auto length = typedValue->length();
1533 fColumns[1]->AppendV(typedValue->data(), length);
1534 fIndex += length;
1535 fColumns[0]->Append(&fIndex);
1536 return length + fColumns[0]->GetElement()->GetPackedSize();
1537}
1538
1540{
1541 auto typedValue = static_cast<std::string *>(to);
1542 RClusterIndex collectionStart;
1543 ClusterSize_t nChars;
1544 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nChars);
1545 if (nChars == 0) {
1546 typedValue->clear();
1547 } else {
1548 typedValue->resize(nChars);
1549 fColumns[1]->ReadV(collectionStart, nChars, const_cast<char *>(typedValue->data()));
1550 }
1551}
1552
1553void ROOT::Experimental::RField<std::string>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
1554{
1555 visitor.VisitStringField(*this);
1556}
1557
1558//------------------------------------------------------------------------------
1559
1560ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className)
1561 : RClassField(fieldName, className, TClass::GetClass(std::string(className).c_str()))
1562{
1563}
1564
1565ROOT::Experimental::RClassField::RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
1566 : ROOT::Experimental::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */),
1567 fClass(classp)
1568{
1569 if (fClass == nullptr) {
1570 throw RException(R__FAIL("RField: no I/O support for type " + std::string(className)));
1571 }
1572 // Avoid accidentally supporting std types through TClass.
1573 if (fClass->Property() & kIsDefinedInStd) {
1574 throw RException(R__FAIL(std::string(className) + " is not supported"));
1575 }
1576 if (fClass->GetCollectionProxy()) {
1577 throw RException(
1578 R__FAIL(std::string(className) + " has an associated collection proxy; use RProxiedCollectionField instead"));
1579 }
1580 // Classes with, e.g., custom streamers are not supported through this field. Empty classes, however, are.
1581 if (!fClass->CanSplit() && fClass->Size() > 1) {
1582 throw RException(R__FAIL(std::string(className) + " cannot be split"));
1583 }
1584
1589
1590 int i = 0;
1592 if (baseClass->GetDelta() < 0) {
1593 throw RException(R__FAIL(std::string("virtual inheritance is not supported: ") + std::string(className) +
1594 " virtually inherits from " + baseClass->GetName()));
1595 }
1596 TClass *c = baseClass->GetClassPointer();
1597 auto subField =
1598 RFieldBase::Create(std::string(kPrefixInherited) + "_" + std::to_string(i), c->GetName()).Unwrap();
1599 fTraits &= subField->GetTraits();
1600 Attach(std::move(subField),
1601 RSubFieldInfo{kBaseClass, static_cast<std::size_t>(baseClass->GetDelta())});
1602 i++;
1603 }
1605 // Skip, for instance, unscoped enum constants defined in the class
1606 if (dataMember->Property() & kIsStatic)
1607 continue;
1608 // Skip members explicitly marked as transient by user comment
1609 if (!dataMember->IsPersistent()) {
1610 // TODO(jblomer): we could do better
1612 continue;
1613 }
1614
1615 std::string typeName{GetNormalizedTypeName(dataMember->GetTrueTypeName())};
1616 std::string typeAlias{GetNormalizedTypeName(dataMember->GetFullTypeName())};
1617 // For C-style arrays, complete the type name with the size for each dimension, e.g. `int[4][2]`
1618 if (dataMember->Property() & kIsArray) {
1619 for (int dim = 0, n = dataMember->GetArrayDim(); dim < n; ++dim)
1620 typeName += "[" + std::to_string(dataMember->GetMaxIndex(dim)) + "]";
1621 }
1622 auto subField = RFieldBase::Create(dataMember->GetName(), typeName, typeAlias).Unwrap();
1623 fTraits &= subField->GetTraits();
1624 Attach(std::move(subField),
1625 RSubFieldInfo{kDataMember, static_cast<std::size_t>(dataMember->GetOffset())});
1626 }
1627}
1628
1629void ROOT::Experimental::RClassField::Attach(std::unique_ptr<RFieldBase> child, RSubFieldInfo info)
1630{
1631 fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
1632 fSubFieldsInfo.push_back(info);
1633 RFieldBase::Attach(std::move(child));
1634}
1635
1636void ROOT::Experimental::RClassField::AddReadCallbacksFromIORules(const std::span<const ROOT::TSchemaRule *> rules,
1637 TClass *classp)
1638{
1639 for (const auto rule : rules) {
1640 if (rule->GetRuleType() != ROOT::TSchemaRule::kReadRule) {
1641 R__LOG_WARNING(NTupleLog()) << "ignoring I/O customization rule with unsupported type";
1642 continue;
1643 }
1644 auto func = rule->GetReadFunctionPointer();
1645 R__ASSERT(func != nullptr);
1646 fReadCallbacks.emplace_back([func, classp](void *target) {
1647 TVirtualObject oldObj{nullptr};
1648 oldObj.fClass = classp;
1649 oldObj.fObject = target;
1650 func(static_cast<char *>(target), &oldObj);
1651 oldObj.fClass = nullptr; // TVirtualObject does not own the value
1652 });
1653 }
1654}
1655
1656std::unique_ptr<ROOT::Experimental::RFieldBase>
1657ROOT::Experimental::RClassField::CloneImpl(std::string_view newName) const
1658{
1659 auto result = std::unique_ptr<RClassField>(new RClassField(newName, GetTypeName(), fClass));
1660 SyncFieldIDs(*this, *result);
1661 return result;
1662}
1663
1665{
1666 std::size_t nbytes = 0;
1667 for (unsigned i = 0; i < fSubFields.size(); i++) {
1668 nbytes += CallAppendOn(*fSubFields[i], static_cast<const unsigned char *>(from) + fSubFieldsInfo[i].fOffset);
1669 }
1670 return nbytes;
1671}
1672
1674{
1675 for (unsigned i = 0; i < fSubFields.size(); i++) {
1676 CallReadOn(*fSubFields[i], globalIndex, static_cast<unsigned char *>(to) + fSubFieldsInfo[i].fOffset);
1677 }
1678}
1679
1681{
1682 for (unsigned i = 0; i < fSubFields.size(); i++) {
1683 CallReadOn(*fSubFields[i], clusterIndex, static_cast<unsigned char *>(to) + fSubFieldsInfo[i].fOffset);
1684 }
1685}
1686
1688{
1689 // Add post-read callbacks for I/O customization rules; only rules that target transient members are allowed for now
1690 // TODO(jalopezg): revise after supporting schema evolution
1691 const auto ruleset = fClass->GetSchemaRules();
1692 if (!ruleset)
1693 return;
1694 auto referencesNonTransientMembers = [klass = fClass](const ROOT::TSchemaRule *rule) {
1695 if (rule->GetTarget() == nullptr)
1696 return false;
1697 for (auto target : ROOT::Detail::TRangeStaticCast<TObjString>(*rule->GetTarget())) {
1698 const auto dataMember = klass->GetDataMember(target->GetString());
1699 if (!dataMember || dataMember->IsPersistent()) {
1700 R__LOG_WARNING(NTupleLog()) << "ignoring I/O customization rule with non-transient member: "
1701 << dataMember->GetName();
1702 return true;
1703 }
1704 }
1705 return false;
1706 };
1707
1708 auto rules = ruleset->FindRules(fClass->GetName(), static_cast<Int_t>(GetOnDiskTypeVersion()));
1709 rules.erase(std::remove_if(rules.begin(), rules.end(), referencesNonTransientMembers), rules.end());
1710 AddReadCallbacksFromIORules(rules, fClass);
1711}
1712
1714{
1715 fClass->New(where);
1716}
1717
1719{
1720 fClass->Destructor(objPtr, true /* dtorOnly */);
1721 RDeleter::operator()(objPtr, dtorOnly);
1722}
1723
1724std::vector<ROOT::Experimental::RFieldBase::RValue>
1726{
1727 std::vector<RValue> result;
1728 auto basePtr = value.GetPtr<unsigned char>().get();
1729 for (unsigned i = 0; i < fSubFields.size(); i++) {
1730 result.emplace_back(
1731 fSubFields[i]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + fSubFieldsInfo[i].fOffset)));
1732 }
1733 return result;
1734}
1735
1736
1738{
1739 return fClass->GetClassSize();
1740}
1741
1743{
1744 return fClass->GetClassVersion();
1745}
1746
1748{
1749 visitor.VisitClassField(*this);
1750}
1751
1752//------------------------------------------------------------------------------
1753
1754ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName)
1755 : REnumField(fieldName, enumName, TEnum::GetEnum(std::string(enumName).c_str()))
1756{
1757}
1758
1759ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName, TEnum *enump)
1760 : ROOT::Experimental::RFieldBase(fieldName, enumName, ENTupleStructure::kLeaf, false /* isSimple */)
1761{
1762 if (enump == nullptr) {
1763 throw RException(R__FAIL("RField: no I/O support for enum type " + std::string(enumName)));
1764 }
1765 // Avoid accidentally supporting std types through TEnum.
1766 if (enump->Property() & kIsDefinedInStd) {
1767 throw RException(R__FAIL(std::string(enumName) + " is not supported"));
1768 }
1769
1770 switch (enump->GetUnderlyingType()) {
1771 case kChar_t: Attach(std::make_unique<RField<int8_t>>("_0")); break;
1772 case kUChar_t: Attach(std::make_unique<RField<uint8_t>>("_0")); break;
1773 case kShort_t: Attach(std::make_unique<RField<int16_t>>("_0")); break;
1774 case kUShort_t: Attach(std::make_unique<RField<uint16_t>>("_0")); break;
1775 case kInt_t: Attach(std::make_unique<RField<int32_t>>("_0")); break;
1776 case kUInt_t: Attach(std::make_unique<RField<uint32_t>>("_0")); break;
1777 case kLong_t:
1778 case kLong64_t: Attach(std::make_unique<RField<int64_t>>("_0")); break;
1779 case kULong_t:
1780 case kULong64_t: Attach(std::make_unique<RField<uint64_t>>("_0")); break;
1781 default: throw RException(R__FAIL("Unsupported underlying integral type for enum type " + std::string(enumName)));
1782 }
1783
1785}
1786
1787ROOT::Experimental::REnumField::REnumField(std::string_view fieldName, std::string_view enumName,
1788 std::unique_ptr<RFieldBase> intField)
1789 : ROOT::Experimental::RFieldBase(fieldName, enumName, ENTupleStructure::kLeaf, false /* isSimple */)
1790{
1791 Attach(std::move(intField));
1793}
1794
1795std::unique_ptr<ROOT::Experimental::RFieldBase>
1796ROOT::Experimental::REnumField::CloneImpl(std::string_view newName) const
1797{
1798 auto newIntField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
1799 return std::unique_ptr<REnumField>(new REnumField(newName, GetTypeName(), std::move(newIntField)));
1800}
1801
1802std::vector<ROOT::Experimental::RFieldBase::RValue>
1804{
1805 std::vector<RValue> result;
1806 result.emplace_back(fSubFields[0]->BindValue(value.GetPtr<void>()));
1807 return result;
1808}
1809
1811{
1812 visitor.VisitEnumField(*this);
1813}
1814
1815//------------------------------------------------------------------------------
1816
1819 bool readFromDisk)
1820{
1821 RIteratorFuncs ifuncs;
1822 ifuncs.fCreateIterators = proxy->GetFunctionCreateIterators(readFromDisk);
1823 ifuncs.fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators(readFromDisk);
1824 ifuncs.fNext = proxy->GetFunctionNext(readFromDisk);
1825 R__ASSERT((ifuncs.fCreateIterators != nullptr) && (ifuncs.fDeleteTwoIterators != nullptr) &&
1826 (ifuncs.fNext != nullptr));
1827 return ifuncs;
1828}
1829
1831 std::string_view typeName, TClass *classp)
1832 : RFieldBase(fieldName, typeName, ENTupleStructure::kCollection, false /* isSimple */), fNWritten(0)
1833{
1834 if (classp == nullptr)
1835 throw RException(R__FAIL("RField: no I/O support for collection proxy type " + std::string(typeName)));
1836 if (!classp->GetCollectionProxy())
1837 throw RException(R__FAIL(std::string(typeName) + " has no associated collection proxy"));
1838
1839 fProxy.reset(classp->GetCollectionProxy()->Generate());
1840 fProperties = fProxy->GetProperties();
1841 fCollectionType = fProxy->GetCollectionType();
1842 if (fProxy->HasPointers())
1843 throw RException(R__FAIL("collection proxies whose value type is a pointer are not supported"));
1844 if (!fProxy->GetCollectionClass()->HasDictionary()) {
1845 throw RException(R__FAIL("dictionary not available for type " +
1846 GetNormalizedTypeName(fProxy->GetCollectionClass()->GetName())));
1847 }
1848
1849 fIFuncsRead = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), true /* readFromDisk */);
1850 fIFuncsWrite = RCollectionIterableOnce::GetIteratorFuncs(fProxy.get(), false /* readFromDisk */);
1851}
1852
1854 std::string_view typeName,
1855 std::unique_ptr<RFieldBase> itemField)
1856 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
1857{
1858 fItemSize = itemField->GetValueSize();
1859 Attach(std::move(itemField));
1860}
1861
1863 std::string_view typeName)
1864 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
1865{
1866 // NOTE (fdegeus): std::map is supported, custom associative might be supported in the future if the need arises.
1868 throw RException(R__FAIL("custom associative collection proxies not supported"));
1869
1870 std::unique_ptr<ROOT::Experimental::RFieldBase> itemField;
1871
1872 if (auto valueClass = fProxy->GetValueClass()) {
1873 // Element type is a class
1874 itemField = RFieldBase::Create("_0", valueClass->GetName()).Unwrap();
1875 } else {
1876 switch (fProxy->GetType()) {
1877 case EDataType::kChar_t: itemField = std::make_unique<RField<char>>("_0"); break;
1878 case EDataType::kUChar_t: itemField = std::make_unique<RField<std::uint8_t>>("_0"); break;
1879 case EDataType::kShort_t: itemField = std::make_unique<RField<std::int16_t>>("_0"); break;
1880 case EDataType::kUShort_t: itemField = std::make_unique<RField<std::uint16_t>>("_0"); break;
1881 case EDataType::kInt_t: itemField = std::make_unique<RField<std::int32_t>>("_0"); break;
1882 case EDataType::kUInt_t: itemField = std::make_unique<RField<std::uint32_t>>("_0"); break;
1883 case EDataType::kLong_t:
1885 itemField = std::make_unique<RField<std::int64_t>>("_0");
1886 break;
1889 itemField = std::make_unique<RField<std::uint64_t>>("_0");
1890 break;
1891 case EDataType::kFloat_t: itemField = std::make_unique<RField<float>>("_0"); break;
1892 case EDataType::kDouble_t: itemField = std::make_unique<RField<double>>("_0"); break;
1893 case EDataType::kBool_t: itemField = std::make_unique<RField<bool>>("_0"); break;
1894 default:
1895 throw RException(R__FAIL("unsupported value type"));
1896 }
1897 }
1898
1899 fItemSize = itemField->GetValueSize();
1900 Attach(std::move(itemField));
1901}
1902
1903std::unique_ptr<ROOT::Experimental::RFieldBase>
1905{
1906 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
1907 return std::unique_ptr<RProxiedCollectionField>(
1908 new RProxiedCollectionField(newName, GetTypeName(), std::move(newItemField)));
1909}
1910
1912{
1913 std::size_t nbytes = 0;
1914 unsigned count = 0;
1915 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), const_cast<void *>(from));
1916 for (auto ptr : RCollectionIterableOnce{const_cast<void *>(from), fIFuncsWrite, fProxy.get(),
1917 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
1918 nbytes += CallAppendOn(*fSubFields[0], ptr);
1919 count++;
1920 }
1921
1922 fNWritten += count;
1923 fColumns[0]->Append(&fNWritten);
1924 return nbytes + fColumns[0]->GetElement()->GetPackedSize();
1925}
1926
1928{
1929 ClusterSize_t nItems;
1930 RClusterIndex collectionStart;
1931 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
1932
1933 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), to);
1934 void *obj =
1935 fProxy->Allocate(static_cast<std::uint32_t>(nItems), (fProperties & TVirtualCollectionProxy::kNeedDelete));
1936
1937 unsigned i = 0;
1938 for (auto elementPtr : RCollectionIterableOnce{obj, fIFuncsRead, fProxy.get(),
1939 (fCollectionType == kSTLvector || obj != to ? fItemSize : 0U)}) {
1940 CallReadOn(*fSubFields[0], collectionStart + (i++), elementPtr);
1941 }
1942 if (obj != to)
1943 fProxy->Commit(obj);
1944}
1945
1948{
1949 static RColumnRepresentations representations(
1951 {});
1952 return representations;
1953}
1954
1956{
1957 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
1958}
1959
1961{
1962 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
1963 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
1964}
1965
1967{
1968 fProxy->New(where);
1969}
1970
1971std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter>
1973{
1974 if (fProperties & TVirtualCollectionProxy::kNeedDelete) {
1975 std::size_t itemSize = fCollectionType == kSTLvector ? fItemSize : 0U;
1976 return std::make_unique<RProxiedCollectionDeleter>(fProxy, GetDeleterOf(*fSubFields[0]), itemSize);
1977 }
1978 return std::make_unique<RProxiedCollectionDeleter>(fProxy);
1979}
1980
1982{
1983 if (fItemDeleter) {
1984 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), objPtr);
1985 for (auto ptr : RCollectionIterableOnce{objPtr, fIFuncsWrite, fProxy.get(), fItemSize}) {
1986 fItemDeleter->operator()(ptr, true /* dtorOnly */);
1987 }
1988 }
1989 fProxy->Destructor(objPtr, true /* dtorOnly */);
1990 RDeleter::operator()(objPtr, dtorOnly);
1991}
1992
1993std::vector<ROOT::Experimental::RFieldBase::RValue>
1995{
1996 std::vector<RValue> result;
1997 auto valueRawPtr = value.GetPtr<void>().get();
1998 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), valueRawPtr);
1999 for (auto ptr : RCollectionIterableOnce{valueRawPtr, fIFuncsWrite, fProxy.get(),
2000 (fCollectionType == kSTLvector ? fItemSize : 0U)}) {
2001 result.emplace_back(fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), ptr)));
2002 }
2003 return result;
2004}
2005
2007{
2008 visitor.VisitProxiedCollectionField(*this);
2009}
2010
2011//------------------------------------------------------------------------------
2012
2014 std::vector<std::unique_ptr<RFieldBase>> &&itemFields,
2015 const std::vector<std::size_t> &offsets, std::string_view typeName)
2016 : ROOT::Experimental::RFieldBase(fieldName, typeName, ENTupleStructure::kRecord, false /* isSimple */),
2017 fOffsets(offsets)
2018{
2020 for (auto &item : itemFields) {
2021 fMaxAlignment = std::max(fMaxAlignment, item->GetAlignment());
2022 fSize += GetItemPadding(fSize, item->GetAlignment()) + item->GetValueSize();
2023 fTraits &= item->GetTraits();
2024 Attach(std::move(item));
2025 }
2026}
2027
2029 std::vector<std::unique_ptr<RFieldBase>> &&itemFields)
2030 : ROOT::Experimental::RFieldBase(fieldName, "", ENTupleStructure::kRecord, false /* isSimple */)
2031{
2033 for (auto &item : itemFields) {
2034 fSize += GetItemPadding(fSize, item->GetAlignment());
2035 fOffsets.push_back(fSize);
2036 fMaxAlignment = std::max(fMaxAlignment, item->GetAlignment());
2037 fSize += item->GetValueSize();
2038 fTraits &= item->GetTraits();
2039 Attach(std::move(item));
2040 }
2041 // Trailing padding: although this is implementation-dependent, most add enough padding to comply with the
2042 // requirements of the type with strictest alignment
2044}
2045
2047 std::vector<std::unique_ptr<RFieldBase>> &itemFields)
2048 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields))
2049{
2050}
2051
2052std::size_t ROOT::Experimental::RRecordField::GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
2053{
2054 if (itemAlignment > 1) {
2055 auto remainder = baseOffset % itemAlignment;
2056 if (remainder != 0)
2057 return itemAlignment - remainder;
2058 }
2059 return 0;
2060}
2061
2062std::unique_ptr<ROOT::Experimental::RFieldBase>
2063ROOT::Experimental::RRecordField::CloneImpl(std::string_view newName) const
2064{
2065 std::vector<std::unique_ptr<RFieldBase>> cloneItems;
2066 cloneItems.reserve(fSubFields.size());
2067 for (auto &item : fSubFields)
2068 cloneItems.emplace_back(item->Clone(item->GetFieldName()));
2069 return std::unique_ptr<RRecordField>(new RRecordField(newName, std::move(cloneItems), fOffsets, GetTypeName()));
2070}
2071
2073{
2074 std::size_t nbytes = 0;
2075 for (unsigned i = 0; i < fSubFields.size(); ++i) {
2076 nbytes += CallAppendOn(*fSubFields[i], static_cast<const unsigned char *>(from) + fOffsets[i]);
2077 }
2078 return nbytes;
2079}
2080
2082{
2083 for (unsigned i = 0; i < fSubFields.size(); ++i) {
2084 CallReadOn(*fSubFields[i], globalIndex, static_cast<unsigned char *>(to) + fOffsets[i]);
2085 }
2086}
2087
2089{
2090 for (unsigned i = 0; i < fSubFields.size(); ++i) {
2091 CallReadOn(*fSubFields[i], clusterIndex, static_cast<unsigned char *>(to) + fOffsets[i]);
2092 }
2093}
2094
2096{
2097 for (unsigned i = 0; i < fSubFields.size(); ++i) {
2098 CallConstructValueOn(*fSubFields[i], static_cast<unsigned char *>(where) + fOffsets[i]);
2099 }
2100}
2101
2103{
2104 for (unsigned i = 0; i < fItemDeleters.size(); ++i) {
2105 fItemDeleters[i]->operator()(reinterpret_cast<unsigned char *>(objPtr) + fOffsets[i], true /* dtorOnly */);
2106 }
2107 RDeleter::operator()(objPtr, dtorOnly);
2108}
2109
2110std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RRecordField::GetDeleter() const
2111{
2112 std::vector<std::unique_ptr<RDeleter>> itemDeleters;
2113 itemDeleters.reserve(fOffsets.size());
2114 for (const auto &f : fSubFields) {
2115 itemDeleters.emplace_back(GetDeleterOf(*f));
2116 }
2117 return std::make_unique<RRecordDeleter>(itemDeleters, fOffsets);
2118}
2119
2120std::vector<ROOT::Experimental::RFieldBase::RValue>
2122{
2123 auto basePtr = value.GetPtr<unsigned char>().get();
2124 std::vector<RValue> result;
2125 for (unsigned i = 0; i < fSubFields.size(); ++i) {
2126 result.emplace_back(fSubFields[i]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), basePtr + fOffsets[i])));
2127 }
2128 return result;
2129}
2130
2131
2133{
2134 visitor.VisitRecordField(*this);
2135}
2136
2137//------------------------------------------------------------------------------
2138
2139ROOT::Experimental::RVectorField::RVectorField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
2140 : ROOT::Experimental::RFieldBase(fieldName, "std::vector<" + itemField->GetTypeName() + ">",
2141 ENTupleStructure::kCollection, false /* isSimple */),
2142 fItemSize(itemField->GetValueSize()),
2143 fNWritten(0)
2144{
2145 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
2146 fItemDeleter = GetDeleterOf(*itemField);
2147 Attach(std::move(itemField));
2148}
2149
2150std::unique_ptr<ROOT::Experimental::RFieldBase>
2151ROOT::Experimental::RVectorField::CloneImpl(std::string_view newName) const
2152{
2153 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
2154 return std::make_unique<RVectorField>(newName, std::move(newItemField));
2155}
2156
2158{
2159 auto typedValue = static_cast<const std::vector<char> *>(from);
2160 R__ASSERT((typedValue->size() % fItemSize) == 0);
2161 std::size_t nbytes = 0;
2162 auto count = typedValue->size() / fItemSize;
2163
2164 if (fSubFields[0]->IsSimple() && count) {
2165 GetPrincipalColumnOf(*fSubFields[0])->AppendV(typedValue->data(), count);
2166 nbytes += count * GetPrincipalColumnOf(*fSubFields[0])->GetElement()->GetPackedSize();
2167 } else {
2168 for (unsigned i = 0; i < count; ++i) {
2169 nbytes += CallAppendOn(*fSubFields[0], typedValue->data() + (i * fItemSize));
2170 }
2171 }
2172
2173 fNWritten += count;
2174 fColumns[0]->Append(&fNWritten);
2175 return nbytes + fColumns[0]->GetElement()->GetPackedSize();
2176}
2177
2179{
2180 auto typedValue = static_cast<std::vector<char> *>(to);
2181
2182 ClusterSize_t nItems;
2183 RClusterIndex collectionStart;
2184 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
2185
2186 if (fSubFields[0]->IsSimple()) {
2187 typedValue->resize(nItems * fItemSize);
2188 if (nItems)
2189 GetPrincipalColumnOf(*fSubFields[0])->ReadV(collectionStart, nItems, typedValue->data());
2190 return;
2191 }
2192
2193 // See "semantics of reading non-trivial objects" in RNTuple's architecture.md
2194 const auto oldNItems = typedValue->size() / fItemSize;
2195 const bool canRealloc = oldNItems < nItems;
2196 bool allDeallocated = false;
2197 if (fItemDeleter) {
2198 allDeallocated = canRealloc;
2199 for (std::size_t i = allDeallocated ? 0 : nItems; i < oldNItems; ++i) {
2200 fItemDeleter->operator()(typedValue->data() + (i * fItemSize), true /* dtorOnly */);
2201 }
2202 }
2203 typedValue->resize(nItems * fItemSize);
2204 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyConstructible)) {
2205 for (std::size_t i = allDeallocated ? 0 : oldNItems; i < nItems; ++i) {
2206 CallConstructValueOn(*fSubFields[0], typedValue->data() + (i * fItemSize));
2207 }
2208 }
2209
2210 for (std::size_t i = 0; i < nItems; ++i) {
2211 CallReadOn(*fSubFields[0], collectionStart + i, typedValue->data() + (i * fItemSize));
2212 }
2213}
2214
2217{
2218 static RColumnRepresentations representations(
2220 {});
2221 return representations;
2222}
2223
2225{
2226 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
2227}
2228
2230{
2231 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
2232 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
2233}
2234
2236{
2237 auto vecPtr = static_cast<std::vector<char> *>(objPtr);
2238 if (fItemDeleter) {
2239 R__ASSERT((vecPtr->size() % fItemSize) == 0);
2240 auto nItems = vecPtr->size() / fItemSize;
2241 for (std::size_t i = 0; i < nItems; ++i) {
2242 fItemDeleter->operator()(vecPtr->data() + (i * fItemSize), true /* dtorOnly */);
2243 }
2244 }
2245 std::destroy_at(vecPtr);
2246 RDeleter::operator()(objPtr, dtorOnly);
2247}
2248
2249std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RVectorField::GetDeleter() const
2250{
2251 if (fItemDeleter)
2252 return std::make_unique<RVectorDeleter>(fItemSize, GetDeleterOf(*fSubFields[0]));
2253 return std::make_unique<RVectorDeleter>();
2254}
2255
2256std::vector<ROOT::Experimental::RFieldBase::RValue>
2258{
2259 auto vec = value.GetPtr<std::vector<char>>();
2260 R__ASSERT((vec->size() % fItemSize) == 0);
2261 auto nItems = vec->size() / fItemSize;
2262 std::vector<RValue> result;
2263 for (unsigned i = 0; i < nItems; ++i) {
2264 result.emplace_back(
2265 fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), vec->data() + (i * fItemSize))));
2266 }
2267 return result;
2268}
2269
2271{
2272 visitor.VisitVectorField(*this);
2273}
2274
2275
2276//------------------------------------------------------------------------------
2277
2278ROOT::Experimental::RRVecField::RRVecField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
2279 : ROOT::Experimental::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
2280 ENTupleStructure::kCollection, false /* isSimple */),
2281 fItemSize(itemField->GetValueSize()),
2282 fNWritten(0)
2283{
2284 if (!(itemField->GetTraits() & kTraitTriviallyDestructible))
2285 fItemDeleter = GetDeleterOf(*itemField);
2286 Attach(std::move(itemField));
2287 fValueSize = EvalRVecValueSize(fSubFields[0]->GetAlignment(), fSubFields[0]->GetValueSize(), GetAlignment());
2288}
2289
2290std::unique_ptr<ROOT::Experimental::RFieldBase>
2291ROOT::Experimental::RRVecField::CloneImpl(std::string_view newName) const
2292{
2293 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
2294 return std::make_unique<RRVecField>(newName, std::move(newItemField));
2295}
2296
2298{
2299 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(from);
2300
2301 std::size_t nbytes = 0;
2302 if (fSubFields[0]->IsSimple() && *sizePtr) {
2303 GetPrincipalColumnOf(*fSubFields[0])->AppendV(*beginPtr, *sizePtr);
2304 nbytes += *sizePtr * GetPrincipalColumnOf(*fSubFields[0])->GetElement()->GetPackedSize();
2305 } else {
2306 auto begin = reinterpret_cast<const char *>(*beginPtr); // for pointer arithmetics
2307 for (std::int32_t i = 0; i < *sizePtr; ++i) {
2308 nbytes += CallAppendOn(*fSubFields[0], begin + i * fItemSize);
2309 }
2310 }
2311
2312 fNWritten += *sizePtr;
2313 fColumns[0]->Append(&fNWritten);
2314 return nbytes + fColumns[0]->GetElement()->GetPackedSize();
2315}
2316
2318{
2319 // TODO as a performance optimization, we could assign values to elements of the inline buffer:
2320 // if size < inline buffer size: we save one allocation here and usage of the RVec skips a pointer indirection
2321
2322 auto [beginPtr, sizePtr, capacityPtr] = GetRVecDataMembers(to);
2323
2324 // Read collection info for this entry
2325 ClusterSize_t nItems;
2326 RClusterIndex collectionStart;
2327 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
2328 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
2329 const std::size_t oldSize = *sizePtr;
2330
2331 // See "semantics of reading non-trivial objects" in RNTuple's architecture.md for details
2332 // on the element construction/destrution.
2333 const bool owns = (*capacityPtr != -1);
2334 const bool needsConstruct = !(fSubFields[0]->GetTraits() & kTraitTriviallyConstructible);
2335 const bool needsDestruct = owns && fItemDeleter;
2336
2337 // Destroy excess elements, if any
2338 if (needsDestruct) {
2339 for (std::size_t i = nItems; i < oldSize; ++i) {
2340 fItemDeleter->operator()(begin + (i * fItemSize), true /* dtorOnly */);
2341 }
2342 }
2343
2344 // Resize RVec (capacity and size)
2345 if (std::int32_t(nItems) > *capacityPtr) { // must reallocate
2346 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
2347 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
2348 if (needsDestruct) {
2349 for (std::size_t i = 0u; i < oldSize; ++i) {
2350 fItemDeleter->operator()(begin + (i * fItemSize), true /* dtorOnly */);
2351 }
2352 }
2353
2354 // TODO Increment capacity by a factor rather than just enough to fit the elements.
2355 if (owns) {
2356 // *beginPtr points to the array of item values (allocated in an earlier call by the following malloc())
2357 free(*beginPtr);
2358 }
2359 // We trust that malloc returns a buffer with large enough alignment.
2360 // This might not be the case if T in RVec<T> is over-aligned.
2361 *beginPtr = malloc(nItems * fItemSize);
2362 R__ASSERT(*beginPtr != nullptr);
2363 begin = reinterpret_cast<char *>(*beginPtr);
2364 *capacityPtr = nItems;
2365
2366 // Placement new for elements that were already there before the resize
2367 if (needsConstruct) {
2368 for (std::size_t i = 0u; i < oldSize; ++i)
2369 CallConstructValueOn(*fSubFields[0], begin + (i * fItemSize));
2370 }
2371 }
2372 *sizePtr = nItems;
2373
2374 // Placement new for new elements, if any
2375 if (needsConstruct) {
2376 for (std::size_t i = oldSize; i < nItems; ++i)
2377 CallConstructValueOn(*fSubFields[0], begin + (i * fItemSize));
2378 }
2379
2380 if (fSubFields[0]->IsSimple() && nItems) {
2381 GetPrincipalColumnOf(*fSubFields[0])->ReadV(collectionStart, nItems, begin);
2382 return;
2383 }
2384
2385 // Read the new values into the collection elements
2386 for (std::size_t i = 0; i < nItems; ++i) {
2387 CallReadOn(*fSubFields[0], collectionStart + i, begin + (i * fItemSize));
2388 }
2389}
2390
2392{
2393 if (!fSubFields[0]->IsSimple())
2394 return RFieldBase::ReadBulkImpl(bulkSpec);
2395
2396 if (bulkSpec.fAuxData->empty()) {
2397 /// Initialize auxiliary memory: the first sizeof(size_t) bytes store the value size of the item field.
2398 /// The following bytes store the item values, consecutively.
2399 bulkSpec.fAuxData->resize(sizeof(std::size_t));
2400 *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data()) = fSubFields[0]->GetValueSize();
2401 }
2402 const auto itemValueSize = *reinterpret_cast<std::size_t *>(bulkSpec.fAuxData->data());
2403 unsigned char *itemValueArray = bulkSpec.fAuxData->data() + sizeof(std::size_t);
2404 auto [beginPtr, sizePtr, capacityPtr] = GetRVecDataMembers(bulkSpec.fValues);
2405
2406 // Get size of the first RVec of the bulk
2407 RClusterIndex firstItemIndex;
2408 RClusterIndex collectionStart;
2409 ClusterSize_t collectionSize;
2410 this->GetCollectionInfo(bulkSpec.fFirstIndex, &firstItemIndex, &collectionSize);
2411 *beginPtr = itemValueArray;
2412 *sizePtr = collectionSize;
2413 *capacityPtr = -1;
2414
2415 // Set the size of the remaining RVecs of the bulk, going page by page through the RNTuple offset column.
2416 // We optimistically assume that bulkSpec.fAuxData is already large enough to hold all the item values in the
2417 // given range. If not, we'll fix up the pointers afterwards.
2418 auto lastOffset = firstItemIndex.GetIndex() + collectionSize;
2419 ClusterSize_t::ValueType nRemainingValues = bulkSpec.fCount - 1;
2420 std::size_t nValues = 1;
2421 std::size_t nItems = collectionSize;
2422 while (nRemainingValues > 0) {
2423 NTupleSize_t nElementsUntilPageEnd;
2424 const auto offsets = fPrincipalColumn->MapV<ClusterSize_t>(bulkSpec.fFirstIndex + nValues, nElementsUntilPageEnd);
2425 const std::size_t nBatch = std::min(nRemainingValues, nElementsUntilPageEnd);
2426 for (std::size_t i = 0; i < nBatch; ++i) {
2427 const auto size = offsets[i] - lastOffset;
2428 std::tie(beginPtr, sizePtr, capacityPtr) =
2429 GetRVecDataMembers(reinterpret_cast<unsigned char *>(bulkSpec.fValues) + (nValues + i) * fValueSize);
2430 *beginPtr = itemValueArray + nItems * itemValueSize;
2431 *sizePtr = size;
2432 *capacityPtr = -1;
2433
2434 nItems += size;
2435 lastOffset = offsets[i];
2436 }
2437 nRemainingValues -= nBatch;
2438 nValues += nBatch;
2439 }
2440
2441 bulkSpec.fAuxData->resize(sizeof(std::size_t) + nItems * itemValueSize);
2442 // If the vector got reallocated, we need to fix-up the RVecs begin pointers.
2443 const auto delta = itemValueArray - (bulkSpec.fAuxData->data() + sizeof(std::size_t));
2444 if (delta != 0) {
2445 auto beginPtrAsUChar = reinterpret_cast<unsigned char *>(bulkSpec.fValues);
2446 for (std::size_t i = 0; i < bulkSpec.fCount; ++i) {
2447 *reinterpret_cast<unsigned char **>(beginPtrAsUChar) -= delta;
2448 beginPtrAsUChar += fValueSize;
2449 }
2450 }
2451
2452 GetPrincipalColumnOf(*fSubFields[0])->ReadV(firstItemIndex, nItems, itemValueArray - delta);
2453 return RBulkSpec::kAllSet;
2454}
2455
2458{
2459 static RColumnRepresentations representations(
2461 {});
2462 return representations;
2463}
2464
2466{
2467 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
2468}
2469
2471{
2472 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
2473 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
2474}
2475
2477{
2478 // initialize data members fBegin, fSize, fCapacity
2479 // currently the inline buffer is left uninitialized
2480 void **beginPtr = new (where)(void *)(nullptr);
2481 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
2482 new (sizePtr + 1) std::int32_t(-1);
2483}
2484
2486{
2487 auto [beginPtr, sizePtr, capacityPtr] = GetRVecDataMembers(objPtr);
2488
2489 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
2490 if (fItemDeleter) {
2491 for (std::int32_t i = 0; i < *sizePtr; ++i) {
2492 fItemDeleter->operator()(begin + i * fItemSize, true /* dtorOnly */);
2493 }
2494 }
2495
2496 DestroyRVecWithChecks(fItemAlignment, beginPtr, begin, capacityPtr);
2497 RDeleter::operator()(objPtr, dtorOnly);
2498}
2499
2500std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RRVecField::GetDeleter() const
2501{
2502 if (fItemDeleter)
2503 return std::make_unique<RRVecDeleter>(fSubFields[0]->GetAlignment(), fItemSize, GetDeleterOf(*fSubFields[0]));
2504 return std::make_unique<RRVecDeleter>(fSubFields[0]->GetAlignment());
2505}
2506
2507std::vector<ROOT::Experimental::RFieldBase::RValue>
2509{
2510 auto [beginPtr, sizePtr, _] = GetRVecDataMembers(value.GetPtr<void>().get());
2511
2512 std::vector<RValue> result;
2513 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
2514 result.reserve(*sizePtr);
2515 for (std::int32_t i = 0; i < *sizePtr; ++i) {
2516 result.emplace_back(fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), begin + i * fItemSize)));
2517 }
2518 return result;
2519}
2520
2522{
2523 return fValueSize;
2524}
2525
2527{
2528 return EvalRVecAlignment(fSubFields[0]->GetAlignment());
2529}
2530
2532{
2533 visitor.VisitRVecField(*this);
2534}
2535
2536//------------------------------------------------------------------------------
2537
2539 : ROOT::Experimental::RFieldBase(name, "std::vector<bool>", ENTupleStructure::kCollection, false /* isSimple */)
2540{
2541 Attach(std::make_unique<RField<bool>>("_0"));
2542}
2543
2544std::size_t ROOT::Experimental::RField<std::vector<bool>>::AppendImpl(const void *from)
2545{
2546 auto typedValue = static_cast<const std::vector<bool> *>(from);
2547 auto count = typedValue->size();
2548 for (unsigned i = 0; i < count; ++i) {
2549 bool bval = (*typedValue)[i];
2550 CallAppendOn(*fSubFields[0], &bval);
2551 }
2552 fNWritten += count;
2553 fColumns[0]->Append(&fNWritten);
2554 return count + fColumns[0]->GetElement()->GetPackedSize();
2555}
2556
2557void ROOT::Experimental::RField<std::vector<bool>>::ReadGlobalImpl(NTupleSize_t globalIndex, void *to)
2558{
2559 auto typedValue = static_cast<std::vector<bool> *>(to);
2560
2561 ClusterSize_t nItems;
2562 RClusterIndex collectionStart;
2563 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
2564
2565 typedValue->resize(nItems);
2566 for (unsigned i = 0; i < nItems; ++i) {
2567 bool bval;
2568 CallReadOn(*fSubFields[0], collectionStart + i, &bval);
2569 (*typedValue)[i] = bval;
2570 }
2571}
2572
2574ROOT::Experimental::RField<std::vector<bool>>::GetColumnRepresentations() const
2575{
2576 static RColumnRepresentations representations(
2578 {});
2579 return representations;
2580}
2581
2582void ROOT::Experimental::RField<std::vector<bool>>::GenerateColumnsImpl()
2583{
2584 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
2585}
2586
2587void ROOT::Experimental::RField<std::vector<bool>>::GenerateColumnsImpl(const RNTupleDescriptor &desc)
2588{
2589 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
2590 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
2591}
2592
2593std::vector<ROOT::Experimental::RFieldBase::RValue>
2594ROOT::Experimental::RField<std::vector<bool>>::SplitValue(const RValue &value) const
2595{
2596 const auto &typedValue = value.GetRef<std::vector<bool>>();
2597 auto count = typedValue.size();
2598 std::vector<RValue> result;
2599 for (unsigned i = 0; i < count; ++i) {
2600 if (typedValue[i])
2601 result.emplace_back(fSubFields[0]->BindValue(std::shared_ptr<bool>(new bool(true))));
2602 else
2603 result.emplace_back(fSubFields[0]->BindValue(std::shared_ptr<bool>(new bool(false))));
2604 }
2605 return result;
2606}
2607
2608void ROOT::Experimental::RField<std::vector<bool>>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
2609{
2610 visitor.VisitVectorBoolField(*this);
2611}
2612
2613
2614//------------------------------------------------------------------------------
2615
2616ROOT::Experimental::RArrayField::RArrayField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
2617 std::size_t arrayLength)
2618 : ROOT::Experimental::RFieldBase(fieldName,
2619 "std::array<" + itemField->GetTypeName() + "," + std::to_string(arrayLength) + ">",
2620 ENTupleStructure::kLeaf, false /* isSimple */, arrayLength),
2621 fItemSize(itemField->GetValueSize()),
2622 fArrayLength(arrayLength)
2623{
2624 fTraits |= itemField->GetTraits() & ~kTraitMappable;
2625 Attach(std::move(itemField));
2626}
2627
2628std::unique_ptr<ROOT::Experimental::RFieldBase>
2629ROOT::Experimental::RArrayField::CloneImpl(std::string_view newName) const
2630{
2631 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
2632 return std::make_unique<RArrayField>(newName, std::move(newItemField), fArrayLength);
2633}
2634
2636{
2637 std::size_t nbytes = 0;
2638 auto arrayPtr = static_cast<const unsigned char *>(from);
2639 for (unsigned i = 0; i < fArrayLength; ++i) {
2640 nbytes += CallAppendOn(*fSubFields[0], arrayPtr + (i * fItemSize));
2641 }
2642 return nbytes;
2643}
2644
2646{
2647 auto arrayPtr = static_cast<unsigned char *>(to);
2648 for (unsigned i = 0; i < fArrayLength; ++i) {
2649 CallReadOn(*fSubFields[0], globalIndex * fArrayLength + i, arrayPtr + (i * fItemSize));
2650 }
2651}
2652
2654{
2655 auto arrayPtr = static_cast<unsigned char *>(to);
2656 for (unsigned i = 0; i < fArrayLength; ++i) {
2657 CallReadOn(*fSubFields[0], RClusterIndex(clusterIndex.GetClusterId(), clusterIndex.GetIndex() * fArrayLength + i),
2658 arrayPtr + (i * fItemSize));
2659 }
2660}
2661
2663{
2664 if (fSubFields[0]->GetTraits() & kTraitTriviallyConstructible)
2665 return;
2666
2667 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
2668 for (unsigned i = 0; i < fArrayLength; ++i) {
2669 CallConstructValueOn(*fSubFields[0], arrayPtr + (i * fItemSize));
2670 }
2671}
2672
2674{
2675 if (fItemDeleter) {
2676 for (unsigned i = 0; i < fArrayLength; ++i) {
2677 fItemDeleter->operator()(reinterpret_cast<unsigned char *>(objPtr) + i * fItemSize, true /* dtorOnly */);
2678 }
2679 }
2680 RDeleter::operator()(objPtr, dtorOnly);
2681}
2682
2683std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RArrayField::GetDeleter() const
2684{
2685 if (!(fSubFields[0]->GetTraits() & kTraitTriviallyDestructible))
2686 return std::make_unique<RArrayDeleter>(fItemSize, fArrayLength, GetDeleterOf(*fSubFields[0]));
2687 return std::make_unique<RDeleter>();
2688}
2689
2690std::vector<ROOT::Experimental::RFieldBase::RValue>
2692{
2693 auto arrayPtr = value.GetPtr<unsigned char>().get();
2694 std::vector<RValue> result;
2695 for (unsigned i = 0; i < fArrayLength; ++i) {
2696 result.emplace_back(
2697 fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), arrayPtr + (i * fItemSize))));
2698 }
2699 return result;
2700}
2701
2703{
2704 visitor.VisitArrayField(*this);
2705}
2706
2707//------------------------------------------------------------------------------
2708// RArrayAsRVecField
2709
2711 std::unique_ptr<ROOT::Experimental::RFieldBase> itemField,
2712 std::size_t arrayLength)
2713 : ROOT::Experimental::RFieldBase(fieldName, "ROOT::VecOps::RVec<" + itemField->GetTypeName() + ">",
2714 ENTupleStructure::kCollection, false /* isSimple */),
2715 fItemSize(itemField->GetValueSize()),
2716 fArrayLength(arrayLength)
2717{
2718 Attach(std::move(itemField));
2719 fValueSize = EvalRVecValueSize(fSubFields[0]->GetAlignment(), fSubFields[0]->GetValueSize(), GetAlignment());
2722}
2723
2724std::unique_ptr<ROOT::Experimental::RFieldBase>
2726{
2727 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
2728 return std::make_unique<RArrayAsRVecField>(newName, std::move(newItemField), fArrayLength);
2729}
2730
2732{
2733 // initialize data members fBegin, fSize, fCapacity
2734 void **beginPtr = new (where)(void *)(nullptr);
2735 std::int32_t *sizePtr = new (reinterpret_cast<void *>(beginPtr + 1)) std::int32_t(0);
2736 std::int32_t *capacityPtr = new (sizePtr + 1) std::int32_t(0);
2737
2738 // Create the RVec with the known fixed size, do it once here instead of
2739 // every time the value is read in `Read*Impl` functions
2740 char *begin = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
2741
2742 // Early return if the RVec has already been allocated.
2743 if (*sizePtr == std::int32_t(fArrayLength))
2744 return;
2745
2746 // Need to allocate the RVec if it is the first time the value is being created.
2747 // See "semantics of reading non-trivial objects" in RNTuple's architecture.md for details
2748 // on the element construction.
2749 const bool owns = (*capacityPtr != -1); // RVec is adopting the memory
2750 const bool needsConstruct = !(fSubFields[0]->GetTraits() & kTraitTriviallyConstructible);
2751 const bool needsDestruct = owns && fItemDeleter;
2752
2753 // Destroy old elements: useless work for trivial types, but in case the element type's constructor
2754 // allocates memory we need to release it here to avoid memleaks (e.g. if this is an RVec<RVec<int>>)
2755 if (needsDestruct) {
2756 for (std::int32_t i = 0; i < *sizePtr; ++i) {
2757 fItemDeleter->operator()(begin + (i * fItemSize), true /* dtorOnly */);
2758 }
2759 }
2760
2761 // TODO: Isn't the RVec always owning in this case?
2762 if (owns) {
2763 // *beginPtr points to the array of item values (allocated in an earlier call by the following malloc())
2764 free(*beginPtr);
2765 }
2766
2767 *beginPtr = malloc(fArrayLength * fItemSize);
2768 R__ASSERT(*beginPtr != nullptr);
2769 // Re-assign begin pointer after allocation
2770 begin = reinterpret_cast<char *>(*beginPtr);
2771 // Size and capacity are equal since the field data type is std::array
2772 *sizePtr = fArrayLength;
2773 *capacityPtr = fArrayLength;
2774
2775 // Placement new for the array elements
2776 if (needsConstruct) {
2777 for (std::size_t i = 0; i < fArrayLength; ++i)
2778 CallConstructValueOn(*fSubFields[0], begin + (i * fItemSize));
2779 }
2780}
2781
2782std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RArrayAsRVecField::GetDeleter() const
2783{
2784 if (fItemDeleter) {
2785 return std::make_unique<RRVecField::RRVecDeleter>(fSubFields[0]->GetAlignment(), fItemSize,
2786 GetDeleterOf(*fSubFields[0]));
2787 }
2788 return std::make_unique<RRVecField::RRVecDeleter>(fSubFields[0]->GetAlignment());
2789}
2790
2792{
2793
2794 auto [beginPtr, _, __] = GetRVecDataMembers(to);
2795 auto rvecBeginPtr = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
2796
2797 if (fSubFields[0]->IsSimple()) {
2798 GetPrincipalColumnOf(*fSubFields[0])->ReadV(globalIndex*fArrayLength, fArrayLength, rvecBeginPtr);
2799 return;
2800 }
2801
2802 // Read the new values into the collection elements
2803 for (std::size_t i = 0; i < fArrayLength; ++i) {
2804 CallReadOn(*fSubFields[0], globalIndex * fArrayLength + i, rvecBeginPtr + (i * fItemSize));
2805 }
2806}
2807
2809{
2810 auto [beginPtr, _, __] = GetRVecDataMembers(to);
2811 auto rvecBeginPtr = reinterpret_cast<char *>(*beginPtr); // for pointer arithmetics
2812
2813 const auto &clusterId = clusterIndex.GetClusterId();
2814 const auto &clusterIndexIndex = clusterIndex.GetIndex();
2815
2816 if (fSubFields[0]->IsSimple()) {
2817 GetPrincipalColumnOf(*fSubFields[0])
2818 ->ReadV(RClusterIndex(clusterId, clusterIndexIndex * fArrayLength), fArrayLength, rvecBeginPtr);
2819 return;
2820 }
2821
2822 // Read the new values into the collection elements
2823 for (std::size_t i = 0; i < fArrayLength; ++i) {
2824 CallReadOn(*fSubFields[0], RClusterIndex(clusterId, clusterIndexIndex * fArrayLength + i),
2825 rvecBeginPtr + (i * fItemSize));
2826 }
2827}
2828
2830{
2831 return EvalRVecAlignment(fSubFields[0]->GetAlignment());
2832}
2833
2834std::vector<ROOT::Experimental::RFieldBase::RValue>
2836{
2837 auto arrayPtr = value.GetPtr<unsigned char>().get();
2838 std::vector<ROOT::Experimental::RFieldBase::RValue> result;
2839 for (unsigned i = 0; i < fArrayLength; ++i) {
2840 result.emplace_back(
2841 fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), arrayPtr + (i * fItemSize))));
2842 }
2843 return result;
2844}
2845
2847{
2848 visitor.VisitArrayAsRVecField(*this);
2849}
2850
2851// RArrayAsRVecField
2852//------------------------------------------------------------------------------
2853
2854//------------------------------------------------------------------------------
2855
2856ROOT::Experimental::RBitsetField::RBitsetField(std::string_view fieldName, std::size_t N)
2857 : ROOT::Experimental::RFieldBase(fieldName, "std::bitset<" + std::to_string(N) + ">", ENTupleStructure::kLeaf,
2858 false /* isSimple */, N),
2859 fN(N)
2860{
2862}
2863
2866{
2867 static RColumnRepresentations representations({{EColumnType::kBit}}, {});
2868 return representations;
2869}
2870
2872{
2873 fColumns.emplace_back(Internal::RColumn::Create<bool>(RColumnModel(GetColumnRepresentative()[0]), 0));
2874}
2875
2877{
2878 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
2879 fColumns.emplace_back(Internal::RColumn::Create<bool>(RColumnModel(onDiskTypes[0]), 0));
2880}
2881
2883{
2884 const auto *asULongArray = static_cast<const Word_t *>(from);
2885 bool elementValue;
2886 std::size_t i = 0;
2887 for (std::size_t word = 0; word < (fN + kBitsPerWord - 1) / kBitsPerWord; ++word) {
2888 for (std::size_t mask = 0; (mask < kBitsPerWord) && (i < fN); ++mask, ++i) {
2889 elementValue = (asULongArray[word] & (static_cast<Word_t>(1) << mask)) != 0;
2890 fColumns[0]->Append(&elementValue);
2891 }
2892 }
2893 return fN;
2894}
2895
2897{
2898 auto *asULongArray = static_cast<Word_t *>(to);
2899 bool elementValue;
2900 for (std::size_t i = 0; i < fN; ++i) {
2901 fColumns[0]->Read(globalIndex * fN + i, &elementValue);
2902 Word_t mask = static_cast<Word_t>(1) << (i % kBitsPerWord);
2903 Word_t bit = static_cast<Word_t>(elementValue) << (i % kBitsPerWord);
2904 asULongArray[i / kBitsPerWord] = (asULongArray[i / kBitsPerWord] & ~mask) | bit;
2905 }
2906}
2907
2909{
2910 visitor.VisitBitsetField(*this);
2911}
2912
2913//------------------------------------------------------------------------------
2914
2915std::string ROOT::Experimental::RVariantField::GetTypeList(const std::vector<RFieldBase *> &itemFields)
2916{
2917 std::string result;
2918 for (size_t i = 0; i < itemFields.size(); ++i) {
2919 result += itemFields[i]->GetTypeName() + ",";
2920 }
2921 R__ASSERT(!result.empty()); // there is always at least one variant
2922 result.pop_back(); // remove trailing comma
2923 return result;
2924}
2925
2927 const std::vector<RFieldBase *> &itemFields)
2928 : ROOT::Experimental::RFieldBase(fieldName, "std::variant<" + GetTypeList(itemFields) + ">",
2929 ENTupleStructure::kVariant, false /* isSimple */)
2930{
2931 // The variant needs to initialize its own tag member
2932 fTraits |= kTraitTriviallyDestructible & ~kTraitTriviallyConstructible;
2933
2934 auto nFields = itemFields.size();
2935 R__ASSERT(nFields > 0);
2936 fNWritten.resize(nFields, 0);
2937 for (unsigned int i = 0; i < nFields; ++i) {
2938 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
2939 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
2940 fTraits &= itemFields[i]->GetTraits();
2941 Attach(std::unique_ptr<RFieldBase>(itemFields[i]));
2942 }
2944}
2945
2946std::unique_ptr<ROOT::Experimental::RFieldBase>
2948{
2949 auto nFields = fSubFields.size();
2950 std::vector<RFieldBase *> itemFields;
2951 for (unsigned i = 0; i < nFields; ++i) {
2952 // TODO(jblomer): use unique_ptr in RVariantField constructor
2953 itemFields.emplace_back(fSubFields[i]->Clone(fSubFields[i]->GetFieldName()).release());
2954 }
2955 return std::make_unique<RVariantField>(newName, itemFields);
2956}
2957
2958std::uint32_t ROOT::Experimental::RVariantField::GetTag(const void *variantPtr, std::size_t tagOffset)
2959{
2960 auto index = *(reinterpret_cast<const char *>(variantPtr) + tagOffset);
2961 return (index < 0) ? 0 : index + 1;
2962}
2963
2964void ROOT::Experimental::RVariantField::SetTag(void *variantPtr, std::size_t tagOffset, std::uint32_t tag)
2965{
2966 auto index = reinterpret_cast<char *>(variantPtr) + tagOffset;
2967 *index = static_cast<char>(tag - 1);
2968}
2969
2971{
2972 auto tag = GetTag(from, fTagOffset);
2973 std::size_t nbytes = 0;
2974 auto index = 0;
2975 if (tag > 0) {
2976 nbytes += CallAppendOn(*fSubFields[tag - 1], from);
2977 index = fNWritten[tag - 1]++;
2978 }
2979 RColumnSwitch varSwitch(ClusterSize_t(index), tag);
2980 fColumns[0]->Append(&varSwitch);
2981 return nbytes + sizeof(RColumnSwitch);
2982}
2983
2985{
2986 RClusterIndex variantIndex;
2987 std::uint32_t tag;
2988 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
2989
2990 // If `tag` equals 0, the variant is in the invalid state, i.e, it does not hold any of the valid alternatives in
2991 // the type list. This happens, e.g., if the field was late added; in this case, keep the invalid tag, which makes
2992 // any `std::holds_alternative<T>` check fail later.
2993 if (R__likely(tag > 0)) {
2994 CallConstructValueOn(*fSubFields[tag - 1], to);
2995 CallReadOn(*fSubFields[tag - 1], variantIndex, to);
2996 }
2997 SetTag(to, fTagOffset, tag);
2998}
2999
3002{
3003 static RColumnRepresentations representations({{EColumnType::kSwitch}}, {{}});
3004 return representations;
3005}
3006
3008{
3009 fColumns.emplace_back(Internal::RColumn::Create<RColumnSwitch>(RColumnModel(GetColumnRepresentative()[0]), 0));
3010}
3011
3013{
3014 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
3015 fColumns.emplace_back(Internal::RColumn::Create<RColumnSwitch>(RColumnModel(onDiskTypes[0]), 0));
3016}
3017
3019{
3020 memset(where, 0, GetValueSize());
3021 CallConstructValueOn(*fSubFields[0], where);
3022 SetTag(where, fTagOffset, 1);
3023}
3024
3026{
3027 auto tag = GetTag(objPtr, fTagOffset);
3028 if (tag > 0) {
3029 fItemDeleters[tag - 1]->operator()(objPtr, true /* dtorOnly */);
3030 }
3031 RDeleter::operator()(objPtr, dtorOnly);
3032}
3033
3034std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RVariantField::GetDeleter() const
3035{
3036 std::vector<std::unique_ptr<RDeleter>> itemDeleters;
3037 itemDeleters.reserve(fSubFields.size());
3038 for (const auto &f : fSubFields) {
3039 itemDeleters.emplace_back(GetDeleterOf(*f));
3040 }
3041 return std::make_unique<RVariantDeleter>(fTagOffset, itemDeleters);
3042}
3043
3045{
3046 return fMaxItemSize + fMaxAlignment; // TODO: fix for more than 255 items
3047}
3048
3050{
3051 std::fill(fNWritten.begin(), fNWritten.end(), 0);
3052}
3053
3054//------------------------------------------------------------------------------
3055
3056ROOT::Experimental::RSetField::RSetField(std::string_view fieldName, std::string_view typeName,
3057 std::unique_ptr<RFieldBase> itemField)
3058 : ROOT::Experimental::RProxiedCollectionField(fieldName, typeName, std::move(itemField))
3059{
3060}
3061
3062std::unique_ptr<ROOT::Experimental::RFieldBase> ROOT::Experimental::RSetField::CloneImpl(std::string_view newName) const
3063{
3064 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
3065 return std::make_unique<RSetField>(newName, GetTypeName(), std::move(newItemField));
3066}
3067
3068//------------------------------------------------------------------------------
3069
3070ROOT::Experimental::RMapField::RMapField(std::string_view fieldName, std::string_view typeName,
3071 std::unique_ptr<RFieldBase> itemField)
3072 : RProxiedCollectionField(fieldName, typeName, TClass::GetClass(std::string(typeName).c_str()))
3073{
3074 if (!dynamic_cast<RPairField *>(itemField.get()))
3075 throw RException(R__FAIL("RMapField inner field type must be of RPairField"));
3076
3077 fItemClass = fProxy->GetValueClass();
3079
3080 Attach(std::move(itemField));
3081}
3082
3084{
3085 std::size_t nbytes = 0;
3086 unsigned count = 0;
3087 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), const_cast<void *>(from));
3088 for (auto ptr : RCollectionIterableOnce{const_cast<void *>(from), fIFuncsWrite, fProxy.get(), 0U}) {
3089 nbytes += CallAppendOn(*fSubFields[0], ptr);
3090 count++;
3091 }
3092 fNWritten += count;
3093 fColumns[0]->Append(&fNWritten);
3094 return nbytes + fColumns[0]->GetElement()->GetPackedSize();
3095}
3096
3098{
3099 ClusterSize_t nItems;
3100 RClusterIndex collectionStart;
3101 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
3102
3103 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), to);
3104 void *obj =
3105 fProxy->Allocate(static_cast<std::uint32_t>(nItems), (fProperties & TVirtualCollectionProxy::kNeedDelete));
3106
3107 unsigned i = 0;
3108 for (auto ptr : RCollectionIterableOnce{obj, fIFuncsRead, fProxy.get(), fItemSize}) {
3109 CallReadOn(*fSubFields[0], collectionStart + i, ptr);
3110 i++;
3111 }
3112
3113 if (obj != to)
3114 fProxy->Commit(obj);
3115}
3116
3117std::vector<ROOT::Experimental::RFieldBase::RValue> ROOT::Experimental::RMapField::SplitValue(const RValue &value) const
3118{
3119 std::vector<RValue> result;
3120 auto valueRawPtr = value.GetPtr<void>().get();
3121 TVirtualCollectionProxy::TPushPop RAII(fProxy.get(), valueRawPtr);
3122 for (auto ptr : RCollectionIterableOnce{valueRawPtr, fIFuncsWrite, fProxy.get(), 0U}) {
3123 result.emplace_back(fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), ptr)));
3124 }
3125 return result;
3126}
3127
3128std::unique_ptr<ROOT::Experimental::RFieldBase> ROOT::Experimental::RMapField::CloneImpl(std::string_view newName) const
3129{
3130 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
3131 return std::unique_ptr<RMapField>(new RMapField(newName, GetTypeName(), std::move(newItemField)));
3132}
3133
3134//------------------------------------------------------------------------------
3135
3136ROOT::Experimental::RNullableField::RNullableField(std::string_view fieldName, std::string_view typeName,
3137 std::unique_ptr<RFieldBase> itemField)
3138 : ROOT::Experimental::RFieldBase(fieldName, typeName, ENTupleStructure::kCollection, false /* isSimple */)
3139{
3140 Attach(std::move(itemField));
3141}
3142
3145{
3146 static RColumnRepresentations representations(
3148 {EColumnType::kBit}}, {});
3149 return representations;
3150}
3151
3153{
3154 if (HasDefaultColumnRepresentative()) {
3155 if (fSubFields[0]->GetValueSize() < 4) {
3156 SetColumnRepresentative({EColumnType::kBit});
3157 }
3158 }
3159 if (IsDense()) {
3160 fDefaultItemValue = std::make_unique<RValue>(fSubFields[0]->CreateValue());
3161 fColumns.emplace_back(Internal::RColumn::Create<bool>(RColumnModel(EColumnType::kBit), 0));
3162 } else {
3163 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
3164 }
3165}
3166
3168{
3169 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
3170 if (onDiskTypes[0] == EColumnType::kBit) {
3171 fColumns.emplace_back(Internal::RColumn::Create<bool>(RColumnModel(EColumnType::kBit), 0));
3172 } else {
3173 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
3174 }
3175}
3176
3178{
3179 if (IsDense()) {
3180 bool mask = false;
3181 fPrincipalColumn->Append(&mask);
3182 return 1 + CallAppendOn(*fSubFields[0], fDefaultItemValue->GetPtr<void>().get());
3183 } else {
3184 fPrincipalColumn->Append(&fNWritten);
3185 return sizeof(ClusterSize_t);
3186 }
3187}
3188
3190{
3191 auto nbytesItem = CallAppendOn(*fSubFields[0], from);
3192 if (IsDense()) {
3193 bool mask = true;
3194 fPrincipalColumn->Append(&mask);
3195 return 1 + nbytesItem;
3196 } else {
3197 fNWritten++;
3198 fPrincipalColumn->Append(&fNWritten);
3199 return sizeof(ClusterSize_t) + nbytesItem;
3200 }
3201}
3202
3204{
3205 RClusterIndex nullIndex;
3206 if (IsDense()) {
3207 const bool isValidItem = *fPrincipalColumn->Map<bool>(globalIndex);
3208 return isValidItem ? fPrincipalColumn->GetClusterIndex(globalIndex) : nullIndex;
3209 } else {
3210 RClusterIndex collectionStart;
3211 ClusterSize_t collectionSize;
3212 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &collectionSize);
3213 return (collectionSize == 0) ? nullIndex : collectionStart;
3214 }
3215}
3216
3218{
3219 visitor.VisitNullableField(*this);
3220}
3221
3222//------------------------------------------------------------------------------
3223
3224ROOT::Experimental::RUniquePtrField::RUniquePtrField(std::string_view fieldName, std::string_view typeName,
3225 std::unique_ptr<RFieldBase> itemField)
3226 : RNullableField(fieldName, typeName, std::move(itemField)), fItemDeleter(GetDeleterOf(*fSubFields[0]))
3227{
3228}
3229
3230std::unique_ptr<ROOT::Experimental::RFieldBase>
3232{
3233 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
3234 return std::make_unique<RUniquePtrField>(newName, GetTypeName(), std::move(newItemField));
3235}
3236
3238{
3239 auto typedValue = static_cast<const std::unique_ptr<char> *>(from);
3240 if (*typedValue) {
3241 return AppendValue(typedValue->get());
3242 } else {
3243 return AppendNull();
3244 }
3245}
3246
3248{
3249 auto ptr = static_cast<std::unique_ptr<char> *>(to);
3250 bool isValidValue = static_cast<bool>(*ptr);
3251
3252 auto itemIndex = GetItemIndex(globalIndex);
3253 bool isValidItem = itemIndex.GetIndex() != kInvalidClusterIndex;
3254
3255 void *valuePtr = nullptr;
3256 if (isValidValue)
3257 valuePtr = ptr->get();
3258
3259 if (isValidValue && !isValidItem) {
3260 ptr->release();
3261 fItemDeleter->operator()(valuePtr, false /* dtorOnly */);
3262 return;
3263 }
3264
3265 if (!isValidItem) // On-disk value missing; nothing else to do
3266 return;
3267
3268 if (!isValidValue) {
3269 valuePtr = malloc(fSubFields[0]->GetValueSize());
3270 CallConstructValueOn(*fSubFields[0], valuePtr);
3271 ptr->reset(reinterpret_cast<char *>(valuePtr));
3272 }
3273
3274 CallReadOn(*fSubFields[0], itemIndex, valuePtr);
3275}
3276
3278{
3279 auto typedPtr = static_cast<std::unique_ptr<char> *>(objPtr);
3280 if (*typedPtr) {
3281 fItemDeleter->operator()(typedPtr->get(), false /* dtorOnly */);
3282 typedPtr->release();
3283 }
3284 RDeleter::operator()(objPtr, dtorOnly);
3285}
3286
3287std::unique_ptr<ROOT::Experimental::RFieldBase::RDeleter> ROOT::Experimental::RUniquePtrField::GetDeleter() const
3288{
3289 return std::make_unique<RUniquePtrDeleter>(GetDeleterOf(*fSubFields[0]));
3290}
3291
3292std::vector<ROOT::Experimental::RFieldBase::RValue>
3294{
3295 std::vector<RValue> result;
3296 const auto &ptr = value.GetRef<std::unique_ptr<char>>();
3297 if (ptr) {
3298 result.emplace_back(fSubFields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), ptr.get())));
3299 }
3300 return result;
3301}
3302
3303//------------------------------------------------------------------------------
3304
3305std::string
3306ROOT::Experimental::RPairField::RPairField::GetTypeList(const std::array<std::unique_ptr<RFieldBase>, 2> &itemFields)
3307{
3308 return itemFields[0]->GetTypeName() + "," + itemFields[1]->GetTypeName();
3309}
3310
3312 std::array<std::unique_ptr<RFieldBase>, 2> &&itemFields,
3313 const std::array<std::size_t, 2> &offsets)
3314 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), offsets,
3315 "std::pair<" + GetTypeList(itemFields) + ">")
3316{
3317}
3318
3320 std::array<std::unique_ptr<RFieldBase>, 2> &itemFields)
3321 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), {},
3322 "std::pair<" + GetTypeList(itemFields) + ">")
3323{
3324 // ISO C++ does not guarantee any specific layout for `std::pair`; query TClass for the member offsets
3325 fClass = TClass::GetClass(GetTypeName().c_str());
3326 if (!fClass)
3327 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
3328 fSize = fClass->Size();
3329
3330 auto firstElem = fClass->GetRealData("first");
3331 if (!firstElem)
3332 throw RException(R__FAIL("first: no such member"));
3333 fOffsets[0] = firstElem->GetThisOffset();
3334
3335 auto secondElem = fClass->GetRealData("second");
3336 if (!secondElem)
3337 throw RException(R__FAIL("second: no such member"));
3338 fOffsets[1] = secondElem->GetThisOffset();
3339}
3340
3341std::unique_ptr<ROOT::Experimental::RFieldBase>
3342ROOT::Experimental::RPairField::CloneImpl(std::string_view newName) const
3343{
3344 std::array<std::unique_ptr<RFieldBase>, 2> items{fSubFields[0]->Clone(fSubFields[0]->GetFieldName()),
3345 fSubFields[1]->Clone(fSubFields[1]->GetFieldName())};
3346
3347 std::unique_ptr<RPairField> result(new RPairField(newName, std::move(items), {fOffsets[0], fOffsets[1]}));
3348 result->fClass = fClass;
3349 return result;
3350}
3351
3353{
3354 fClass->New(where);
3355}
3356
3358{
3359 fClass->Destructor(objPtr, true /* dtorOnly */);
3360 RDeleter::operator()(objPtr, dtorOnly);
3361}
3362
3363//------------------------------------------------------------------------------
3364
3365std::string
3366ROOT::Experimental::RTupleField::RTupleField::GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields)
3367{
3368 std::string result;
3369 if (itemFields.empty())
3370 throw RException(R__FAIL("the type list for std::tuple must have at least one element"));
3371 for (size_t i = 0; i < itemFields.size(); ++i) {
3372 result += itemFields[i]->GetTypeName() + ",";
3373 }
3374 result.pop_back(); // remove trailing comma
3375 return result;
3376}
3377
3379 std::vector<std::unique_ptr<RFieldBase>> &&itemFields,
3380 const std::vector<std::size_t> &offsets)
3381 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), offsets,
3382 "std::tuple<" + GetTypeList(itemFields) + ">")
3383{
3384}
3385
3387 std::vector<std::unique_ptr<RFieldBase>> &itemFields)
3388 : ROOT::Experimental::RRecordField(fieldName, std::move(itemFields), {},
3389 "std::tuple<" + GetTypeList(itemFields) + ">")
3390{
3391 fClass = TClass::GetClass(GetTypeName().c_str());
3392 if (!fClass)
3393 throw RException(R__FAIL("cannot get type information for " + GetTypeName()));
3394 fSize = fClass->Size();
3395
3396 // ISO C++ does not guarantee neither specific layout nor member names for `std::tuple`. However, most
3397 // implementations including libstdc++ (gcc), libc++ (llvm), and MSVC name members as `_0`, `_1`, ..., `_N-1`,
3398 // following the order of the type list.
3399 // Use TClass to get their offsets; in case a particular `std::tuple` implementation does not define such
3400 // members, the assertion below will fail.
3401 for (unsigned i = 0; i < fSubFields.size(); ++i) {
3402 std::string memberName("_" + std::to_string(i));
3403 auto member = fClass->GetRealData(memberName.c_str());
3404 if (!member)
3405 throw RException(R__FAIL(memberName + ": no such member"));
3406 fOffsets.push_back(member->GetThisOffset());
3407 }
3408}
3409
3410std::unique_ptr<ROOT::Experimental::RFieldBase>
3411ROOT::Experimental::RTupleField::CloneImpl(std::string_view newName) const
3412{
3413 std::vector<std::unique_ptr<RFieldBase>> items;
3414 items.reserve(fSubFields.size());
3415 for (const auto &item : fSubFields)
3416 items.push_back(item->Clone(item->GetFieldName()));
3417
3418 std::unique_ptr<RTupleField> result(new RTupleField(newName, std::move(items), fOffsets));
3419 result->fClass = fClass;
3420 return result;
3421}
3422
3424{
3425 fClass->New(where);
3426}
3427
3429{
3430 fClass->Destructor(objPtr, true /* dtorOnly */);
3431 RDeleter::operator()(objPtr, dtorOnly);
3432}
3433
3434//------------------------------------------------------------------------------
3435
3437 std::shared_ptr<RNTupleCollectionWriter> collectionWriter,
3438 std::unique_ptr<RFieldZero> collectionParent)
3439 : RFieldBase(name, "", ENTupleStructure::kCollection, false /* isSimple */), fCollectionWriter(collectionWriter)
3440{
3441 const std::size_t N = collectionParent->fSubFields.size();
3442 for (std::size_t i = 0; i < N; ++i) {
3443 Attach(std::move(collectionParent->fSubFields[i]));
3444 }
3445}
3446
3449{
3450 static RColumnRepresentations representations(
3452 {});
3453 return representations;
3454}
3455
3457{
3458 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(GetColumnRepresentative()[0]), 0));
3459}
3460
3462{
3463 auto onDiskTypes = EnsureCompatibleColumnTypes(desc);
3464 fColumns.emplace_back(Internal::RColumn::Create<ClusterSize_t>(RColumnModel(onDiskTypes[0]), 0));
3465}
3466
3467std::unique_ptr<ROOT::Experimental::RFieldBase>
3469{
3470 auto parent = std::make_unique<RFieldZero>();
3471 for (auto& f : fSubFields) {
3472 parent->Attach(f->Clone(f->GetFieldName()));
3473 }
3474 return std::make_unique<RCollectionField>(newName, fCollectionWriter, std::move(parent));
3475}
3476
3478{
3479 // RCollectionFields are almost simple, but they return the bytes written by their subfields as accumulated by the
3480 // RNTupleCollectionWriter.
3481 std::size_t bytesWritten = fCollectionWriter->fBytesWritten;
3482 fCollectionWriter->fBytesWritten = 0;
3483
3484 fColumns[0]->Append(from);
3485 return bytesWritten + fColumns[0]->GetElement()->GetPackedSize();
3486}
3487
3489{
3490 R__ASSERT(false && "should never read an RCollectionField");
3491}
3492
3494{
3495 *fCollectionWriter->GetOffsetPtr() = 0;
3496}
3497
3498//------------------------------------------------------------------------------
3499
3500ROOT::Experimental::RAtomicField::RAtomicField(std::string_view fieldName, std::string_view typeName,
3501 std::unique_ptr<RFieldBase> itemField)
3502 : RFieldBase(fieldName, typeName, ENTupleStructure::kLeaf, false /* isSimple */)
3503{
3504 if (itemField->GetTraits() & kTraitTriviallyConstructible)
3506 if (itemField->GetTraits() & kTraitTriviallyDestructible)
3508 Attach(std::move(itemField));
3509}
3510
3511std::unique_ptr<ROOT::Experimental::RFieldBase>
3512ROOT::Experimental::RAtomicField::CloneImpl(std::string_view newName) const
3513{
3514 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetFieldName());
3515 return std::make_unique<RAtomicField>(newName, GetTypeName(), std::move(newItemField));
3516}
3517
3518std::vector<ROOT::Experimental::RFieldBase::RValue>
3520{
3521 std::vector<RValue> result;
3522 result.emplace_back(fSubFields[0]->BindValue(value.GetPtr<void>()));
3523 return result;
3524}
3525
3527{
3528 visitor.VisitAtomicField(*this);
3529}
size_t fValueSize
Cppyy::TCppType_t fClass
dim_t fSize
#define R__likely(expr)
Definition RConfig.hxx:579
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:292
#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:290
#define R__LOG_WARNING(...)
Definition RLogger.hxx:363
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define e(i)
Definition RSha256.hxx:103
TObject * clone(const char *newname) const override
Definition RooChi2Var.h:9
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kLong_t
Definition TDataType.h:30
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kUInt_t
Definition TDataType.h:30
@ kClassHasExplicitCtor
@ kClassHasExplicitDtor
@ kIsArray
Definition TDictionary.h:79
@ kIsStatic
Definition TDictionary.h:80
@ kIsDefinedInStd
Definition TDictionary.h:98
#define R__ASSERT(e)
Definition TError.h:118
#define N
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 mask
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
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 char Point_t Rectangle_t WindowAttributes_t index
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
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 Int_t Int_t Window_t child
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
#define _(A, B)
Definition cfortran.h:108
#define free
Definition civetweb.c:1539
#define malloc
Definition civetweb.c:1536
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitProxiedCollectionField(const RProxiedCollectionField &field)
virtual void VisitBoolField(const RField< bool > &field)
virtual void VisitBitsetField(const RBitsetField &field)
virtual void VisitNullableField(const RNullableField &field)
virtual void VisitFieldZero(const RFieldZero &field)
virtual void VisitRVecField(const RRVecField &field)
virtual void VisitCardinalityField(const RCardinalityField &field)
virtual void VisitEnumField(const REnumField &field)
virtual void VisitArrayAsRVecField(const RArrayAsRVecField &field)
virtual void VisitDoubleField(const RField< double > &field)
virtual void VisitField(const RFieldBase &field)=0
virtual void VisitCharField(const RField< char > &field)
virtual void VisitArrayField(const RArrayField &field)
virtual void VisitClassField(const RClassField &field)
virtual void VisitRecordField(const RRecordField &field)
virtual void VisitVectorField(const RVectorField &field)
virtual void VisitFloatField(const RField< float > &field)
virtual void VisitAtomicField(const RAtomicField &field)
static std::string GetTypeName(EColumnType type)
Abstract interface to write data into an ntuple.
const RNTupleWriteOptions & GetWriteOptions() const
Returns the sink's write options.
Abstract interface to read data from an ntuple.
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
The size of a value of this field, i.e. an RVec.
Definition RField.cxx:2725
std::size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.cxx:2829
std::size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:1269
std::size_t fValueSize
The length of the arrays in this field.
Definition RField.hxx:1241
std::unique_ptr< RDeleter > GetDeleter() const final
Returns an RRVecField::RRVecDeleter.
Definition RField.cxx:2782
RArrayAsRVecField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::size_t arrayLength)
Constructor of the field.
Definition RField.cxx:2710
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:2731
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2846
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:2791
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Definition RField.cxx:2808
std::vector< RFieldBase::RValue > SplitValue(const RFieldBase::RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:2835
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1238
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:2673
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:2691
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:2635
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2702
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Definition RField.cxx:2653
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:2683
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2629
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:2645
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:2662
RArrayField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::size_t arrayLength)
Definition RField.cxx:2616
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:3512
RAtomicField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:3500
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:3519
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:3526
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:2871
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:2882
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:2896
RBitsetField(std::string_view fieldName, std::size_t N)
Definition RField.cxx:2856
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:2865
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2908
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:1124
const RField< RNTupleCardinality< std::uint32_t > > * As32Bit() const
Definition RField.cxx:1144
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.hxx:1723
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1138
const RField< RNTupleCardinality< std::uint64_t > > * As64Bit() const
Definition RField.cxx:1150
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:1718
The field for a class with dictionary.
Definition RField.hxx:759
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Definition RField.cxx:1680
static constexpr const char * kPrefixInherited
Prefix used in the subfield names generated for base classes.
Definition RField.hxx:770
void Attach(std::unique_ptr< RFieldBase > child, RSubFieldInfo info)
Definition RField.cxx:1629
void OnConnectPageSource() final
Called by ConnectPageSource() only once connected; derived classes may override this as appropriate.
Definition RField.cxx:1687
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:1737
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:1713
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:1664
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:1673
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1657
void AddReadCallbacksFromIORules(const std::span< const TSchemaRule * > rules, TClass *classp=nullptr)
Register post-read callbacks corresponding to a list of ROOT I/O customization rules.
Definition RField.cxx:1636
void AcceptVisitor(Detail::RFieldVisitor &visitor) const override
Definition RField.cxx:1747
std::uint32_t GetTypeVersion() const final
Indicates an evolution of the C++ type itself.
Definition RField.cxx:1742
RClassField(std::string_view fieldName, std::string_view className, TClass *classp)
Definition RField.cxx:1565
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:1725
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
DescriptorId_t GetClusterId() const
ClusterSize_t::ValueType GetIndex() const
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:3477
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:3456
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:3468
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:3488
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:3448
Holds the static meta-data of an RNTuple column.
Holds the index and the tag of a kSwitch column.
The field for an unscoped or scoped enum with dictionary.
Definition RField.hxx:820
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1810
REnumField(std::string_view fieldName, std::string_view enumName, TEnum *enump)
Definition RField.cxx:1759
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:1803
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1796
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Similar to RValue but manages an array of consecutive values.
Definition RField.hxx:230
std::unique_ptr< bool[]> fMaskAvail
Masks invalid values in the array.
Definition RField.hxx:241
void AdoptBuffer(void *buf, std::size_t capacity)
Definition RField.cxx:480
RBulk & operator=(const RBulk &)=delete
void Reset(RClusterIndex firstIndex, std::size_t size)
Sets a new range for the bulk.
Definition RField.cxx:447
void * fValues
Cached deleter of fField.
Definition RField.hxx:236
std::unique_ptr< RFieldBase::RDeleter > fDeleter
Definition RField.hxx:235
Some fields have multiple possible column representations, e.g.
Definition RField.hxx:166
std::vector< ColumnRepresentation_t > TypesList_t
Definition RField.hxx:168
TypesList_t fDeserializationTypes
The union of the serialization types and the deserialization extra types.
Definition RField.hxx:181
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
Definition RField.hxx:186
A field translates read and write calls from/to underlying columns to/from tree values.
Definition RField.hxx:94
virtual void GenerateColumnsImpl()=0
Creates the backing columns corresponsing to the field type for writing.
static constexpr int kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
Definition RField.hxx:142
void Attach(std::unique_ptr< RFieldBase > child)
Add a new subfield to the list of nested fields.
Definition RField.cxx:850
void AutoAdjustColumnTypes(const RNTupleWriteOptions &options)
When connecting a field to a page sink, the field's default column representation is subject to adjus...
Definition RField.cxx:972
const ColumnRepresentation_t & EnsureCompatibleColumnTypes(const RNTupleDescriptor &desc) const
Returns the on-disk column types found in the provided descriptor for fOnDiskId.
Definition RField.cxx:935
ENTupleStructure fStructure
The role of this field in the data model structure.
Definition RField.hxx:326
std::vector< RFieldBase * > GetSubFields()
Definition RField.cxx:873
static std::vector< RCheckResult > Check(const std::string &fieldName, const std::string &typeName)
Checks if the given type is supported by RNTuple.
Definition RField.cxx:544
static constexpr int kTraitMappable
A field of a fundamental type that can be directly mapped via RField<T>::Map(), i....
Definition RField.hxx:145
std::function< void(void *)> ReadCallback_t
Definition RField.hxx:100
static constexpr int kTraitTriviallyConstructible
No constructor needs to be called, i.e.
Definition RField.hxx:140
RSchemaIterator begin()
Definition RField.hxx:700
RConstSchemaIterator cbegin() const
Definition RField.hxx:705
virtual void AcceptVisitor(Detail::RFieldVisitor &visitor) const
Definition RField.cxx:1071
std::size_t fNRepetitions
For fixed sized arrays, the array length.
Definition RField.hxx:328
friend class ROOT::Experimental::RCollectionField
Definition RField.hxx:95
RFieldBase * fParent
Sub fields point to their mother field.
Definition RField.hxx:393
int fTraits
Properties of the type that allow for optimizations of collections of that type.
Definition RField.hxx:401
static std::unique_ptr< RDeleter > GetDeleterOf(const RFieldBase &other)
Definition RField.hxx:437
void ConnectPageSink(Internal::RPageSink &pageSink, NTupleSize_t firstEntry=0)
Fields and their columns live in the void until connected to a physical page storage.
Definition RField.cxx:1007
virtual std::size_t AppendImpl(const void *from)
Operations on values of complex types, e.g.
Definition RField.cxx:799
RConstSchemaIterator cend() const
Definition RField.hxx:709
bool fIsSimple
A field qualifies as simple if it is both mappable and has no post-read callback.
Definition RField.hxx:330
std::string GetQualifiedFieldName() const
Returns the field name and parent field names separated by dots ("grandparent.parent....
Definition RField.cxx:524
std::vector< EColumnType > ColumnRepresentation_t
Definition RField.hxx:149
virtual std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec)
General implementation of bulk read.
Definition RField.cxx:810
void RemoveReadCallback(size_t idx)
Definition RField.cxx:966
void * CreateObjectRawPtr() const
Factory method for the field's type. The caller owns the returned pointer.
Definition RField.cxx:830
void CommitCluster()
Flushes data from active columns to disk and calls CommitClusterImpl.
Definition RField.cxx:893
void ConnectPageSource(Internal::RPageSource &pageSource)
Connects the field and its sub field tree to the given page source.
Definition RField.cxx:1027
RValue CreateValue()
Generates an object of the field type and wraps the created object in a shared pointer and returns it...
Definition RField.cxx:838
std::unique_ptr< RFieldBase > Clone(std::string_view newName) const
Copies the field and its sub fields using a possibly new name and a new, unconnected set of columns.
Definition RField.cxx:788
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &canonicalType, const std::string &typeAlias, bool fContinueOnError=false)
Factory method to resurrect a field from the stored on-disk type information.
Definition RField.cxx:565
size_t AddReadCallback(ReadCallback_t func)
Set a user-defined function to be called after reading a value, giving a chance to inspect and/or mod...
Definition RField.cxx:959
virtual std::vector< RValue > SplitValue(const RValue &value) const
Creates the list of direct child values given a value for this field.
Definition RField.cxx:845
void SetOnDiskId(DescriptorId_t id)
Definition RField.cxx:908
std::string fName
The field name relative to its parent field.
Definition RField.hxx:322
void SetColumnRepresentative(const ColumnRepresentation_t &representative)
Fixes a column representative.
Definition RField.cxx:923
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Definition RField.hxx:391
std::string fType
The C++ type captured by this field.
Definition RField.hxx:324
Internal::RColumn * fPrincipalColumn
Points into fColumns.
Definition RField.hxx:397
static constexpr int kTraitTrivialType
Shorthand for types that are both trivially constructible and destructible.
Definition RField.hxx:147
const ColumnRepresentation_t & GetColumnRepresentative() const
Returns the fColumnRepresentative pointee or, if unset, the field's default representative.
Definition RField.cxx:916
void SetDescription(std::string_view description)
Definition RField.cxx:901
static RResult< void > EnsureValidFieldName(std::string_view fieldName)
Check whether a given string is a valid field name.
Definition RField.cxx:771
NTupleSize_t EntryToColumnElementIndex(NTupleSize_t globalIndex) const
Translate an entry index to a column element index of the principal column and viceversa.
Definition RField.cxx:861
virtual void ReadGlobalImpl(NTupleSize_t globalIndex, void *to)
Definition RField.cxx:805
RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple, std::size_t nRepetitions=0)
The constructor creates the underlying column objects and connects them to either a sink or a source.
Definition RField.cxx:511
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:782
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:716
void Attach(std::unique_ptr< RFieldBase > child)
Add a new subfield to the list of nested fields.
Definition RField.cxx:850
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1088
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1079
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:1505
Used in RFieldBase::Check() to record field creation failures.
Definition RField.hxx:734
The generic field for a std::map<KeyType, ValueType> and std::unordered_map<KeyType,...
Definition RField.hxx:1381
RMapField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:3070
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:3083
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:3097
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:3128
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:3117
The on-storage meta-data of an ntuple.
DescriptorId_t FindFieldId(std::string_view fieldName, DescriptorId_t parentId) const
const RFieldDescriptor & GetFieldDescriptor(DescriptorId_t fieldId) const
RColumnDescriptorIterable GetColumnIterable() const
Common user-tunable settings for storing ntuples.
The field for values that may or may not be present in an entry.
Definition RField.hxx:1410
const RFieldBase::RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:3144
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:3152
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:3217
RClusterIndex GetItemIndex(NTupleSize_t globalIndex)
Given the index of the nullable field, returns the corresponding global index of the subfield or,...
Definition RField.cxx:3203
RNullableField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:3136
std::size_t AppendValue(const void *from)
Definition RField.cxx:3189
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:3357
The generic field for std::pair<T1, T2> types.
Definition RField.hxx:1648
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:3352
RPairField(std::string_view fieldName, std::array< std::unique_ptr< RFieldBase >, 2 > &&itemFields, const std::array< std::size_t, 2 > &offsets)
Definition RField.cxx:3311
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:3342
Allows for iterating over the elements of a proxied collection.
Definition RField.hxx:861
static RIteratorFuncs GetIteratorFuncs(TVirtualCollectionProxy *proxy, bool readFromDisk)
Definition RField.cxx:1818
The field for a class representing a collection of elements via TVirtualCollectionProxy.
Definition RField.hxx:857
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1904
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:1966
std::size_t AppendImpl(const void *from) override
Operations on values of complex types, e.g.
Definition RField.cxx:1911
std::shared_ptr< TVirtualCollectionProxy > fProxy
The collection proxy is needed by the deleters and thus defined as a shared pointer.
Definition RField.hxx:947
RCollectionIterableOnce::RIteratorFuncs fIFuncsRead
Two sets of functions to operate on iterators, to be used depending on the access type.
Definition RField.hxx:952
void AcceptVisitor(Detail::RFieldVisitor &visitor) const override
Definition RField.cxx:2006
std::unique_ptr< RDeleter > GetDeleter() const override
Definition RField.cxx:1972
RProxiedCollectionField(std::string_view fieldName, std::string_view typeName, TClass *classp)
Constructor used when the value type of the collection is not known in advance, i....
Definition RField.cxx:1830
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:1947
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:1955
std::vector< RValue > SplitValue(const RValue &value) const override
Creates the list of direct child values given a value for this field.
Definition RField.cxx:1994
RCollectionIterableOnce::RIteratorFuncs fIFuncsWrite
Definition RField.hxx:953
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) override
Definition RField.cxx:1927
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.hxx:985
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:2485
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2291
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1140
std::unique_ptr< RDeleter > GetDeleter() const override
Definition RField.cxx:2500
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:2476
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2531
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:2508
size_t GetAlignment() const override
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.cxx:2526
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:2521
RRVecField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:2278
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:2457
std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec) final
General implementation of bulk read.
Definition RField.cxx:2391
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:2465
std::size_t AppendImpl(const void *from) override
Operations on values of complex types, e.g.
Definition RField.cxx:2297
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) override
Definition RField.cxx:2317
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:2102
The field for an untyped record.
Definition RField.hxx:1000
RRecordField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > &&itemFields, const std::vector< std::size_t > &offsets, std::string_view typeName="")
Definition RField.cxx:2013
std::vector< std::size_t > fOffsets
Definition RField.hxx:1018
void ReadInClusterImpl(RClusterIndex clusterIndex, void *to) final
Definition RField.cxx:2088
std::unique_ptr< RDeleter > GetDeleter() const override
Definition RField.cxx:2110
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:2081
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:2121
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:2052
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:2072
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2132
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:2095
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2063
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:194
RSetField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:3056
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:3062
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:3428
The generic field for std::tuple<Ts...> types.
Definition RField.hxx:1679
RTupleField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > &&itemFields, const std::vector< std::size_t > &offsets)
Definition RField.cxx:3378
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:3411
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:3423
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:3277
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:3231
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:3247
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:3293
RUniquePtrField(std::string_view fieldName, std::string_view typeName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:3224
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:3287
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:3237
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:3025
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:2984
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:3044
static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint32_t tag)
Definition RField.cxx:2964
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:3001
void ConstructValue(void *where) const override
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:3018
static std::string GetTypeList(const std::vector< RFieldBase * > &itemFields)
Definition RField.cxx:2915
std::vector< ClusterSize_t::ValueType > fNWritten
Definition RField.hxx:1333
size_t fTagOffset
In the std::variant memory layout, at which byte number is the index stored.
Definition RField.hxx:1332
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2947
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:3007
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:3034
static std::uint32_t GetTag(const void *variantPtr, std::size_t tagOffset)
Extracts the index from an std::variant and transforms it into the 1-based index used for the switch ...
Definition RField.cxx:2958
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:2970
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.hxx:1363
RVariantField(std::string_view fieldName, const std::vector< RFieldBase * > &itemFields)
Definition RField.cxx:2926
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:2235
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given a value for this field.
Definition RField.cxx:2257
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:2270
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:2157
std::unique_ptr< RDeleter > fItemDeleter
Definition RField.hxx:1085
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:2249
RVectorField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:2139
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:2216
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:2151
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type for writing.
Definition RField.cxx:2224
void ReadGlobalImpl(NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:2178
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2319
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3770
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5704
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3636
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2897
Int_t GetClassSize() const
Definition TClass.h:425
Long_t ClassProperty() const
Return the C++ property of this class, eg.
Definition TClass.cxx:2396
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6086
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2968
The TEnum class implements the enum type.
Definition TEnum.h:33
EDataType GetUnderlyingType() const
Get the underlying integer type of the enum: enum E { kOne }; // ==> int enum F: long; // ==> long Re...
Definition TEnum.h:71
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Definition TEnum.cxx:139
static TEnum * GetEnum(const std::type_info &ti, ESearchAction sa=kALoadAndInterpLookup)
Definition TEnum.cxx:175
RAII helper class that ensures that PushProxy() / PopProxy() are called when entering / leaving a C++...
Defines a common interface to inspect/change the contents of an object that represents a collection.
@ kNeedDelete
The collection contains directly or indirectly (via other collection) some pointers that need explici...
virtual Next_t GetFunctionNext(Bool_t read=kTRUE)=0
Return a pointer to a function that can advance an iterator (see Next_t).
virtual DeleteTwoIterators_t GetFunctionDeleteTwoIterators(Bool_t read=kTRUE)=0
virtual TVirtualCollectionProxy * Generate() const =0
Returns a clean object of the actual class that derives from TVirtualCollectionProxy.
virtual CreateIterators_t GetFunctionCreateIterators(Bool_t read=kTRUE)=0
Return a pointer to a function that can create an iterator pair, where each iterator points to the be...
Wrapper around an object and giving indirect access to its content even if the object is not of a cla...
const Int_t n
Definition legend1.C:16
auto MakeAliasedSharedPtr(T *rawPtr)
void CallConnectPageSinkOnField(RFieldBase &, RPageSink &, NTupleSize_t firstEntry=0)
Definition RField.cxx:358
void CallConnectPageSourceOnField(RFieldBase &, RPageSource &)
Definition RField.cxx:363
void CallCommitClusterOnField(RFieldBase &)
Definition RField.cxx:354
RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
RClusterSize ClusterSize_t
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
constexpr ClusterSize_t kInvalidClusterIndex(std::uint64_t(-1))
constexpr DescriptorId_t kInvalidDescriptorId
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
TClass * GetClass(T *)
Definition TClass.h:663
@ kSTLvector
Definition ESTLType.h:30
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
std::string CleanType(const char *typeDesc, int mode=0, const char **tail=nullptr)
Cleanup type description, redundant blanks removed and redundant tail ignored return *tail = pointer ...
Wrap the integer in a struct in order to avoid template specialization clash with std::uint64_t.
Input parameter to ReadBulk() and ReadBulkImpl(). See RBulk class for more information.
Definition RField.hxx:373
void * fValues
The destination area, which has to be a big enough array of valid objects of the correct type.
Definition RField.hxx:384
const bool * fMaskReq
A bool array of size fCount, indicating the required values in the requested range.
Definition RField.hxx:381
bool * fMaskAvail
A bool array of size fCount, indicating the valid values in fValues.
Definition RField.hxx:382
std::size_t fCount
Size of the bulk range.
Definition RField.hxx:379
RClusterIndex fFirstIndex
Start of the bulk range.
Definition RField.hxx:378
std::vector< unsigned char > * fAuxData
Reference to memory owned by the RBulk class.
Definition RField.hxx:387
Used in the return value of the Check() method.
Definition RField.hxx:605