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