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