Logo ROOT  
Reference Guide
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/RField.hxx>
20#include <ROOT/RFieldValue.hxx>
22#include <ROOT/RLogger.hxx>
23#include <ROOT/RNTuple.hxx>
24#include <ROOT/RNTupleModel.hxx>
25
26#include <TClass.h>
27#include <TCollection.h>
28#include <TDataMember.h>
29#include <TError.h>
30#include <TList.h>
31
32#include <algorithm>
33#include <cctype> // for isspace
34#include <cstdlib> // for malloc, free
35#include <cstring> // for memset
36#include <exception>
37#include <iostream>
38#include <type_traits>
39
40namespace {
41
42/// Used in CreateField() in order to get the comma-separated list of template types
43/// E.g., gets {"int", "std::variant<double,int>"} from "int,std::variant<double,int>"
44std::vector<std::string> TokenizeTypeList(std::string templateType) {
45 std::vector<std::string> result;
46 if (templateType.empty())
47 return result;
48
49 const char *eol = templateType.data() + templateType.length();
50 const char *typeBegin = templateType.data();
51 const char *typeCursor = templateType.data();
52 unsigned int nestingLevel = 0;
53 while (typeCursor != eol) {
54 switch (*typeCursor) {
55 case '<':
56 ++nestingLevel;
57 break;
58 case '>':
59 --nestingLevel;
60 break;
61 case ',':
62 if (nestingLevel == 0) {
63 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
64 typeBegin = typeCursor + 1;
65 }
66 break;
67 }
68 typeCursor++;
69 }
70 result.push_back(std::string(typeBegin, typeCursor - typeBegin));
71 return result;
72}
73
74} // anonymous namespace
75
77{
78 if (field.fColumns.empty())
79 field.DoGenerateColumns();
80 for (auto& column : field.fColumns)
81 column->Connect(fieldId, &pageStorage);
82}
83
84
85//------------------------------------------------------------------------------
86
87
89 std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple, std::size_t nRepetitions)
90 : fName(name), fType(type), fStructure(structure), fNRepetitions(nRepetitions), fIsSimple(isSimple),
91 fParent(nullptr), fPrincipalColumn(nullptr)
92{
93}
94
96{
97}
98
100ROOT::Experimental::Detail::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
101{
102 std::string normalizedType(typeName);
103 normalizedType.erase(remove_if(normalizedType.begin(), normalizedType.end(), isspace), normalizedType.end());
104 // TODO(jblomer): use a type translation map
105 if (normalizedType == "Bool_t") normalizedType = "bool";
106 if (normalizedType == "Float_t") normalizedType = "float";
107 if (normalizedType == "Double_t") normalizedType = "double";
108 if (normalizedType == "UChar_t") normalizedType = "std::uint8_t";
109 if (normalizedType == "unsigned char") normalizedType = "std::uint8_t";
110 if (normalizedType == "uint8_t") normalizedType = "std::uint8_t";
111 if (normalizedType == "Int_t") normalizedType = "std::int32_t";
112 if (normalizedType == "int") normalizedType = "std::int32_t";
113 if (normalizedType == "int32_t") normalizedType = "std::int32_t";
114 if (normalizedType == "unsigned") normalizedType = "std::uint32_t";
115 if (normalizedType == "unsigned int") normalizedType = "std::uint32_t";
116 if (normalizedType == "UInt_t") normalizedType = "std::uint32_t";
117 if (normalizedType == "uint32_t") normalizedType = "std::uint32_t";
118 if (normalizedType == "ULong64_t") normalizedType = "std::uint64_t";
119 if (normalizedType == "uint64_t") normalizedType = "std::uint64_t";
120 if (normalizedType == "string") normalizedType = "std::string";
121 if (normalizedType.substr(0, 7) == "vector<") normalizedType = "std::" + normalizedType;
122 if (normalizedType.substr(0, 6) == "array<") normalizedType = "std::" + normalizedType;
123 if (normalizedType.substr(0, 8) == "variant<") normalizedType = "std::" + normalizedType;
124
125 if (normalizedType == "ROOT::Experimental::ClusterSize_t") return new RField<ClusterSize_t>(fieldName);
126 if (normalizedType == "bool") return new RField<bool>(fieldName);
127 if (normalizedType == "std::uint8_t") return new RField<std::uint8_t>(fieldName);
128 if (normalizedType == "std::int32_t") return new RField<std::int32_t>(fieldName);
129 if (normalizedType == "std::uint32_t") return new RField<std::uint32_t>(fieldName);
130 if (normalizedType == "std::uint64_t") return new RField<std::uint64_t>(fieldName);
131 if (normalizedType == "float") return new RField<float>(fieldName);
132 if (normalizedType == "double") return new RField<double>(fieldName);
133 if (normalizedType == "std::string") return new RField<std::string>(fieldName);
134 if (normalizedType == "std::vector<bool>") return new RField<std::vector<bool>>(fieldName);
135 if (normalizedType.substr(0, 12) == "std::vector<") {
136 std::string itemTypeName = normalizedType.substr(12, normalizedType.length() - 13);
137 auto itemField = Create(itemTypeName, itemTypeName);
138 return new RFieldVector(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField));
139 }
140 // For the time being, we silently read RVec fields as std::vector
141 if (normalizedType == "ROOT::VecOps::RVec<bool>") return new RField<ROOT::VecOps::RVec<bool>>(fieldName);
142 if (normalizedType.substr(0, 19) == "ROOT::VecOps::RVec<") {
143 std::string itemTypeName = normalizedType.substr(19, normalizedType.length() - 20);
144 auto itemField = Create(itemTypeName, itemTypeName);
145 return new RFieldVector(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField));
146 }
147 if (normalizedType.substr(0, 11) == "std::array<") {
148 auto arrayDef = TokenizeTypeList(normalizedType.substr(11, normalizedType.length() - 12));
149 R__ASSERT(arrayDef.size() == 2);
150 auto arrayLength = std::stoi(arrayDef[1]);
151 auto itemField = Create(arrayDef[0], arrayDef[0]);
152 return new RFieldArray(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField), arrayLength);
153 }
154#if __cplusplus >= 201703L
155 if (normalizedType.substr(0, 13) == "std::variant<") {
156 auto innerTypes = TokenizeTypeList(normalizedType.substr(13, normalizedType.length() - 14));
157 std::vector<RFieldBase *> items;
158 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
159 items.emplace_back(Create("variant" + std::to_string(i), innerTypes[i]));
160 }
161 return new RFieldVariant(fieldName, items);
162 }
163#endif
164 // TODO: create an RFieldCollection?
165 if (normalizedType == ":Collection:") return new RField<ClusterSize_t>(fieldName);
166 auto cl = TClass::GetClass(normalizedType.c_str());
167 if (cl != nullptr) {
168 return new RFieldClass(fieldName, normalizedType);
169 }
170 R__ERROR_HERE("NTuple") << "Field " << fieldName << " has unknown type " << normalizedType;
171 R__ASSERT(false);
172 return nullptr;
173}
174
176 R__ASSERT(false);
177}
178
181 RFieldValue* /*value*/)
182{
183 R__ASSERT(false);
184}
185
187{
188 void *where = malloc(GetValueSize());
189 R__ASSERT(where != nullptr);
190 return GenerateValue(where);
191}
192
194{
195 if (!dtorOnly)
196 free(value.GetRawPtr());
197}
198
200 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> child)
201{
202 child->fParent = this;
203 child->SetOrder(fSubFields.size()+1);
204 fSubFields.emplace_back(std::move(child));
205}
206
208{
209 for (auto& column : fColumns) {
210 column->Flush();
211 }
212}
213
215{
216 // The level is passed as a parameter so that AcceptVisitor() can access to the relative level of the field instead of the absolute one.
217 this->AcceptVisitor(visitor, level);
218 ++level;
219 for (const auto &fieldPtr: fSubFields) {
220 fieldPtr->TraverseVisitor(visitor, level);
221 }
222}
223
225{
226 visitor.VisitField(*this, level);
227}
228
230{
231 if (fSubFields.empty()) return RIterator(this, -1);
232 return RIterator(this->fSubFields[0].get(), 0);
233}
234
236{
237 return RIterator(this, -1);
238}
239
240
241//-----------------------------------------------------------------------------
242
243
245{
246 auto itr = fStack.rbegin();
247 if (!itr->fFieldPtr->fSubFields.empty()) {
248 fStack.emplace_back(Position(itr->fFieldPtr->fSubFields[0].get(), 0));
249 return;
250 }
251
252 unsigned int nextIdxInParent = ++(itr->fIdxInParent);
253 while (nextIdxInParent >= itr->fFieldPtr->fParent->fSubFields.size()) {
254 if (fStack.size() == 1) {
255 itr->fFieldPtr = itr->fFieldPtr->fParent;
256 itr->fIdxInParent = -1;
257 return;
258 }
259 fStack.pop_back();
260 itr = fStack.rbegin();
261 nextIdxInParent = ++(itr->fIdxInParent);
262 }
263 itr->fFieldPtr = itr->fFieldPtr->fParent->fSubFields[nextIdxInParent].get();
264}
265
266
267//------------------------------------------------------------------------------
268
269
271{
272 Detail::RFieldBase* result = new RFieldRoot();
273 for (auto &f : fSubFields) {
274 auto clone = f->Clone(f->GetName());
275 result->Attach(std::unique_ptr<RFieldBase>(clone));
276 }
277 return result;
278}
279
280
282{
283 auto entry = new REntry();
284 for (auto& f : fSubFields) {
285 entry->AddValue(f->GenerateValue());
286 }
287 return entry;
288}
289
291{
292 visitor.VisitRootField(*this, level);
293}
294
295
296//------------------------------------------------------------------------------
297
298
300{
301 RColumnModel model(EColumnType::kIndex, true /* isSorted*/);
302 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
303 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(model, 0)));
304 fPrincipalColumn = fColumns[0].get();
305}
306
307//------------------------------------------------------------------------------
308
310{
311 RColumnModel model(EColumnType::kByte, false /* isSorted*/);
312 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
313 std::uint8_t, EColumnType::kByte>(model, 0)));
314 fPrincipalColumn = fColumns[0].get();
315}
316
317
318//------------------------------------------------------------------------------
319
320
322{
323 RColumnModel model(EColumnType::kBit, false /* isSorted*/);
324 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
325 Detail::RColumn::Create<bool, EColumnType::kBit>(model, 0)));
326 fPrincipalColumn = fColumns[0].get();
327}
328
329
330//------------------------------------------------------------------------------
331
332
334{
335 RColumnModel model(EColumnType::kReal32, false /* isSorted*/);
336 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
337 Detail::RColumn::Create<float, EColumnType::kReal32>(model, 0)));
338 fPrincipalColumn = fColumns[0].get();
339}
340
341//------------------------------------------------------------------------------
342
344{
345 RColumnModel model(EColumnType::kReal64, false /* isSorted*/);
346 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
347 Detail::RColumn::Create<double, EColumnType::kReal64>(model, 0)));
348 fPrincipalColumn = fColumns[0].get();
349}
350
351
352//------------------------------------------------------------------------------
353
355{
356 RColumnModel model(EColumnType::kInt32, false /* isSorted*/);
357 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
358 std::int32_t, EColumnType::kInt32>(model, 0)));
359 fPrincipalColumn = fColumns[0].get();
360}
361
362//------------------------------------------------------------------------------
363
365{
366 RColumnModel model(EColumnType::kInt32, false /* isSorted*/);
367 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
368 Detail::RColumn::Create<std::uint32_t, EColumnType::kInt32>(model, 0)));
369 fPrincipalColumn = fColumns[0].get();
370}
371
372//------------------------------------------------------------------------------
373
375{
376 RColumnModel model(EColumnType::kInt64, false /* isSorted*/);
377 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
378 Detail::RColumn::Create<std::uint64_t, EColumnType::kInt64>(model, 0)));
379 fPrincipalColumn = fColumns[0].get();
380}
381
382//------------------------------------------------------------------------------
383
384
386{
387 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
388 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
389 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
390
391 RColumnModel modelChars(EColumnType::kByte, false /* isSorted*/);
392 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
393 Detail::RColumn::Create<char, EColumnType::kByte>(modelChars, 1)));
394 fPrincipalColumn = fColumns[0].get();
395}
396
398{
399 auto typedValue = value.Get<std::string>();
400 auto length = typedValue->length();
401 Detail::RColumnElement<char, EColumnType::kByte> elemChars(const_cast<char*>(typedValue->data()));
402 fColumns[1]->AppendV(elemChars, length);
403 fIndex += length;
404 fColumns[0]->Append(fElemIndex);
405}
406
409{
410 auto typedValue = value->Get<std::string>();
411 RClusterIndex collectionStart;
412 ClusterSize_t nChars;
413 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nChars);
414 typedValue->resize(nChars);
415 Detail::RColumnElement<char, EColumnType::kByte> elemChars(const_cast<char*>(typedValue->data()));
416 fColumns[1]->ReadV(collectionStart, nChars, &elemChars);
417}
418
420{
421 fIndex = 0;
422}
423
424
425//------------------------------------------------------------------------------
426
427
429 : ROOT::Experimental::Detail::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */)
430 , fClass(TClass::GetClass(std::string(className).c_str()))
431{
432 if (fClass == nullptr) {
433 throw std::runtime_error("RField: no I/O support for type " + std::string(className));
434 }
436 while (auto dataMember = static_cast<TDataMember *>(next())) {
437 //printf("Now looking at %s %s\n", dataMember->GetName(), dataMember->GetFullTypeName());
438 auto subField = Detail::RFieldBase::Create(dataMember->GetName(), dataMember->GetFullTypeName());
439 fMaxAlignment = std::max(fMaxAlignment, subField->GetAlignment());
440 Attach(std::unique_ptr<Detail::RFieldBase>(subField));
441 }
442}
443
445{
446 return new RFieldClass(newName, GetType());
447}
448
450 TIter next(fClass->GetListOfDataMembers());
451 unsigned i = 0;
452 while (auto dataMember = static_cast<TDataMember *>(next())) {
453 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + dataMember->GetOffset());
454 fSubFields[i]->Append(memberValue);
455 i++;
456 }
457}
458
460{
461 TIter next(fClass->GetListOfDataMembers());
462 unsigned i = 0;
463 while (auto dataMember = static_cast<TDataMember *>(next())) {
464 auto memberValue = fSubFields[i]->GenerateValue(value->Get<unsigned char>() + dataMember->GetOffset());
465 fSubFields[i]->Read(globalIndex, &memberValue);
466 i++;
467 }
468}
469
471{
472 TIter next(fClass->GetListOfDataMembers());
473 unsigned i = 0;
474 while (auto dataMember = static_cast<TDataMember *>(next())) {
475 auto memberValue = fSubFields[i]->GenerateValue(value->Get<unsigned char>() + dataMember->GetOffset());
476 fSubFields[i]->Read(clusterIndex, &memberValue);
477 i++;
478 }
479}
480
482{
483}
484
486{
487 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
488}
489
491{
492 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
493 if (!dtorOnly)
494 free(value.GetRawPtr());
495}
496
498{
499 return Detail::RFieldValue(true /* captureFlat */, this, where);
500}
501
503{
504 return fClass->GetClassSize();
505}
506
507
508//------------------------------------------------------------------------------
509
510
512 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
513 : ROOT::Experimental::Detail::RFieldBase(
514 fieldName, "std::vector<" + itemField->GetType() + ">", ENTupleStructure::kCollection, false /* isSimple */)
515 , fItemSize(itemField->GetValueSize()), fNWritten(0)
516{
517 Attach(std::move(itemField));
518}
519
521{
522 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
523 return new RFieldVector(newName, std::unique_ptr<Detail::RFieldBase>(newItemField));
524}
525
527 auto typedValue = value.Get<std::vector<char>>();
528 R__ASSERT((typedValue->size() % fItemSize) == 0);
529 auto count = typedValue->size() / fItemSize;
530 for (unsigned i = 0; i < count; ++i) {
531 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
532 fSubFields[0]->Append(itemValue);
533 }
535 fNWritten += count;
536 fColumns[0]->Append(elemIndex);
537}
538
540{
541 auto typedValue = value->Get<std::vector<char>>();
542
543 ClusterSize_t nItems;
544 RClusterIndex collectionStart;
545 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
546
547 typedValue->resize(nItems * fItemSize);
548 for (unsigned i = 0; i < nItems; ++i) {
549 auto itemValue = fSubFields[0]->GenerateValue(typedValue->data() + (i * fItemSize));
550 fSubFields[0]->Read(collectionStart + i, &itemValue);
551 }
552}
553
555{
556 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
557 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
558 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
559 fPrincipalColumn = fColumns[0].get();
560}
561
563{
564 return Detail::RFieldValue(this, reinterpret_cast<std::vector<char>*>(where));
565}
566
568{
569 auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
570 R__ASSERT((vec->size() % fItemSize) == 0);
571 auto nItems = vec->size() / fItemSize;
572 for (unsigned i = 0; i < nItems; ++i) {
573 auto itemValue = fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize));
574 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
575 }
576 vec->~vector();
577 if (!dtorOnly)
578 free(vec);
579}
580
582{
583 return Detail::RFieldValue(true /* captureFlag */, this, where);
584}
585
587{
588 fNWritten = 0;
589}
590
591
592//------------------------------------------------------------------------------
593
594
596 : ROOT::Experimental::Detail::RFieldBase(name, "std::vector<bool>", ENTupleStructure::kCollection,
597 false /* isSimple */)
598{
599 Attach(std::make_unique<RField<bool>>("bool"));
600}
601
602void ROOT::Experimental::RField<std::vector<bool>>::DoAppend(const Detail::RFieldValue& value) {
603 auto typedValue = value.Get<std::vector<bool>>();
604 auto count = typedValue->size();
605 for (unsigned i = 0; i < count; ++i) {
606 bool bval = (*typedValue)[i];
607 auto itemValue = fSubFields[0]->CaptureValue(&bval);
608 fSubFields[0]->Append(itemValue);
609 }
610 Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> elemIndex(&fNWritten);
611 fNWritten += count;
612 fColumns[0]->Append(elemIndex);
613}
614
615void ROOT::Experimental::RField<std::vector<bool>>::DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue* value)
616{
617 auto typedValue = value->Get<std::vector<bool>>();
618
619 ClusterSize_t nItems;
620 RClusterIndex collectionStart;
621 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
622
623 typedValue->resize(nItems);
624 for (unsigned i = 0; i < nItems; ++i) {
625 bool bval;
626 auto itemValue = fSubFields[0]->GenerateValue(&bval);
627 fSubFields[0]->Read(collectionStart + i, &itemValue);
628 (*typedValue)[i] = bval;
629 }
630}
631
632void ROOT::Experimental::RField<std::vector<bool>>::DoGenerateColumns()
633{
634 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
635 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
636 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
637 fPrincipalColumn = fColumns[0].get();
638}
639
640void ROOT::Experimental::RField<std::vector<bool>>::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
641{
642 auto vec = static_cast<std::vector<bool>*>(value.GetRawPtr());
643 vec->~vector();
644 if (!dtorOnly)
645 free(vec);
646}
647
648
649//------------------------------------------------------------------------------
650
651
653 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField, std::size_t arrayLength)
654 : ROOT::Experimental::Detail::RFieldBase(
655 fieldName, "std::array<" + itemField->GetType() + "," + std::to_string(arrayLength) + ">",
656 ENTupleStructure::kLeaf, false /* isSimple */, arrayLength)
657 , fItemSize(itemField->GetValueSize()), fArrayLength(arrayLength)
658{
659 Attach(std::move(itemField));
660}
661
663{
664 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
665 return new RFieldArray(newName, std::unique_ptr<Detail::RFieldBase>(newItemField), fArrayLength);
666}
667
669 auto arrayPtr = value.Get<unsigned char>();
670 for (unsigned i = 0; i < fArrayLength; ++i) {
671 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
672 fSubFields[0]->Append(itemValue);
673 }
674}
675
677{
678 auto arrayPtr = value->Get<unsigned char>();
679 for (unsigned i = 0; i < fArrayLength; ++i) {
680 auto itemValue = fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
681 fSubFields[0]->Read(globalIndex * fArrayLength + i, &itemValue);
682 }
683}
684
686{
687 auto arrayPtr = value->Get<unsigned char>();
688 for (unsigned i = 0; i < fArrayLength; ++i) {
689 auto itemValue = fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
690 fSubFields[0]->Read(RClusterIndex(clusterIndex.GetClusterId(), clusterIndex.GetIndex() * fArrayLength + i),
691 &itemValue);
692 }
693}
694
696{
697}
698
700{
701 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
702 for (unsigned i = 0; i < fArrayLength; ++i) {
703 fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
704 }
705 return Detail::RFieldValue(true /* captureFlag */, this, where);
706}
707
709{
710 auto arrayPtr = value.Get<unsigned char>();
711 for (unsigned i = 0; i < fArrayLength; ++i) {
712 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
713 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
714 }
715 if (!dtorOnly)
716 free(arrayPtr);
717}
718
720{
721 return Detail::RFieldValue(true /* captureFlag */, this, where);
722}
723
724
725//------------------------------------------------------------------------------
726
727#if __cplusplus >= 201703L
728std::string ROOT::Experimental::RFieldVariant::GetTypeList(const std::vector<Detail::RFieldBase *> &itemFields)
729{
730 std::string result;
731 for (size_t i = 0; i < itemFields.size(); ++i) {
732 result += itemFields[i]->GetType() + ",";
733 }
734 R__ASSERT(!result.empty()); // there is always at least one variant
735 result.pop_back(); // remove trailing comma
736 return result;
737}
738
739ROOT::Experimental::RFieldVariant::RFieldVariant(
740 std::string_view fieldName, const std::vector<Detail::RFieldBase *> &itemFields)
741 : ROOT::Experimental::Detail::RFieldBase(fieldName,
742 "std::variant<" + GetTypeList(itemFields) + ">", ENTupleStructure::kVariant, false /* isSimple */)
743{
744 auto nFields = itemFields.size();
745 R__ASSERT(nFields > 0);
746 fNWritten.resize(nFields, 0);
747 for (unsigned int i = 0; i < nFields; ++i) {
748 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
749 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
750 Attach(std::unique_ptr<Detail::RFieldBase>(itemFields[i]));
751 }
752 fTagOffset = (fMaxItemSize < fMaxAlignment) ? fMaxAlignment : fMaxItemSize;
753}
754
755ROOT::Experimental::Detail::RFieldBase *ROOT::Experimental::RFieldVariant::Clone(std::string_view newName)
756{
757 auto nFields = fSubFields.size();
758 std::vector<Detail::RFieldBase *> itemFields;
759 for (unsigned i = 0; i < nFields; ++i) {
760 itemFields.emplace_back(fSubFields[i]->Clone(fSubFields[i]->GetName()));
761 }
762 return new RFieldVariant(newName, itemFields);
763}
764
765std::uint32_t ROOT::Experimental::RFieldVariant::GetTag(void *variantPtr) const
766{
767 auto index = *(reinterpret_cast<char *>(variantPtr) + fTagOffset);
768 return (index < 0) ? 0 : index + 1;
769}
770
771void ROOT::Experimental::RFieldVariant::SetTag(void *variantPtr, std::uint32_t tag) const
772{
773 auto index = reinterpret_cast<char *>(variantPtr) + fTagOffset;
774 *index = static_cast<char>(tag - 1);
775}
776
777void ROOT::Experimental::RFieldVariant::DoAppend(const Detail::RFieldValue& value)
778{
779 auto tag = GetTag(value.GetRawPtr());
780 auto index = 0;
781 if (tag > 0) {
782 auto itemValue = fSubFields[tag - 1]->CaptureValue(value.GetRawPtr());
783 fSubFields[tag - 1]->Append(itemValue);
784 index = fNWritten[tag - 1]++;
785 }
786 RColumnSwitch varSwitch(ClusterSize_t(index), tag);
787 Detail::RColumnElement<RColumnSwitch, EColumnType::kSwitch> elemSwitch(&varSwitch);
788 fColumns[0]->Append(elemSwitch);
789}
790
791void ROOT::Experimental::RFieldVariant::DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value)
792{
793 RClusterIndex variantIndex;
794 std::uint32_t tag;
795 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
796 R__ASSERT(tag > 0); // TODO(jblomer): deal with invalid variants
797
798 auto itemValue = fSubFields[tag - 1]->GenerateValue(value->GetRawPtr());
799 fSubFields[tag - 1]->Read(variantIndex, &itemValue);
800 SetTag(value->GetRawPtr(), tag);
801}
802
803void ROOT::Experimental::RFieldVariant::DoGenerateColumns()
804{
805 RColumnModel modelSwitch(EColumnType::kSwitch, false);
806 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
807 Detail::RColumn::Create<RColumnSwitch, EColumnType::kSwitch>(modelSwitch, 0)));
808 fPrincipalColumn = fColumns[0].get();
809}
810
811ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVariant::GenerateValue(void *where)
812{
813 memset(where, 0, GetValueSize());
814 fSubFields[0]->GenerateValue(where);
815 SetTag(where, 1);
816 return Detail::RFieldValue(this, reinterpret_cast<unsigned char *>(where));
817}
818
819void ROOT::Experimental::RFieldVariant::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
820{
821 auto variantPtr = value.GetRawPtr();
822 auto tag = GetTag(variantPtr);
823 if (tag > 0) {
824 auto itemValue = fSubFields[tag - 1]->CaptureValue(variantPtr);
825 fSubFields[tag - 1]->DestroyValue(itemValue, true /* dtorOnly */);
826 }
827 if (!dtorOnly)
828 free(variantPtr);
829}
830
831ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVariant::CaptureValue(void *where)
832{
833 return Detail::RFieldValue(true /* captureFlag */, this, where);
834}
835
836size_t ROOT::Experimental::RFieldVariant::GetValueSize() const
837{
838 return fMaxItemSize + fMaxAlignment; // TODO: fix for more than 255 items
839}
840
841void ROOT::Experimental::RFieldVariant::CommitCluster()
842{
843 std::fill(fNWritten.begin(), fNWritten.end(), 0);
844}
845#endif
846
847
848//------------------------------------------------------------------------------
849
850
853 std::shared_ptr<RCollectionNTuple> collectionNTuple,
854 std::unique_ptr<RNTupleModel> collectionModel)
855 : RFieldBase(name, ":Collection:", ENTupleStructure::kCollection, true /* isSimple */)
856 , fCollectionNTuple(collectionNTuple)
857{
858 for (unsigned i = 0; i < collectionModel->GetRootField()->fSubFields.size(); ++i) {
859 auto& subField = collectionModel->GetRootField()->fSubFields[i];
860 Attach(std::move(subField));
861 }
862}
863
864
866{
867 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
868 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
869 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
870 fPrincipalColumn = fColumns[0].get();
871}
872
873
875{
876 // TODO(jblomer)
877 return nullptr;
878 //auto result = new RFieldCollection(newName, fCollectionNTuple, RNTupleModel::Create());
879 //for (auto& f : fSubFields) {
880 // // switch the name prefix for the new parent name
881 // std::string cloneName = std::string(newName) + f->GetName().substr(GetName().length());
882 // auto clone = f->Clone(cloneName);
883 // result->Attach(std::unique_ptr<RFieldBase>(clone));
884 //}
885 //return result;
886}
887
889 *fCollectionNTuple->GetOffsetPtr() = 0;
890}
891
PyObject * fType
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
#define f(i)
Definition: RSha256.hxx:104
#define R__ASSERT(e)
Definition: TError.h:96
char name[80]
Definition: TGX11.cxx:109
int type
Definition: TGX11.cxx:120
#define free
Definition: civetweb.c:1539
#define malloc
Definition: civetweb.c:1536
static RColumn * Create(const RColumnModel &model, std::uint32_t index)
Definition: RColumn.hxx:71
Iterates over the sub fields in depth-first search order.
Definition: RField.hxx:153
void Advance()
Given that the iterator points to a valid field which is not the end iterator, go to the next field i...
Definition: RField.cxx:244
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Definition: RField.hxx:130
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:88
virtual void DoAppend(const RFieldValue &value)
Operations on values of complex types, e.g.
Definition: RField.cxx:175
virtual void DoGenerateColumns()=0
Creates the backing columns corresponsing to the field type and name.
virtual void DestroyValue(const RFieldValue &value, bool dtorOnly=false)
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:193
void Flush() const
Ensure that all received items are written from page buffers to the storage.
Definition: RField.cxx:207
virtual void AcceptVisitor(RNTupleVisitor &visitor, int level) const
Definition: RField.cxx:224
virtual void CommitCluster()
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.hxx:241
virtual void DoReadGlobal(NTupleSize_t globalIndex, RFieldValue *value)
Definition: RField.cxx:179
virtual void TraverseVisitor(RNTupleVisitor &visitor, int level=0) const
Used for the visitor design pattern, see for example RNTupleReader::Print()
Definition: RField.cxx:214
static RFieldBase * Create(const std::string &fieldName, const std::string &typeName)
Factory method to resurrect a field from the stored on-disk type information.
Definition: RField.cxx:100
std::vector< std::unique_ptr< RColumn > > fColumns
The columns are connected either to a sink or to a source (not to both); they are owned by the field.
Definition: RField.hxx:138
void Attach(std::unique_ptr< Detail::RFieldBase > child)
Definition: RField.cxx:199
RFieldValue GenerateValue()
Generates a tree value of the field type and allocates new initialized memory according to the type.
Definition: RField.cxx:186
static void Connect(DescriptorId_t fieldId, RPageStorage &pageStorage, RFieldBase &field)
Definition: RField.cxx:76
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitField(const Detail::RFieldBase &field, int level)=0
virtual void VisitRootField(const RFieldRoot &field, int level)=0
Common functionality of an ntuple storage for both reading and writing.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Definition: RNTupleUtil.hxx:83
DescriptorId_t GetClusterId() const
ClusterSize_t::ValueType GetIndex() const
Holds the static meta-data of a column in a tree.
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
Definition: REntry.hxx:42
The generic field for fixed size arrays, which do not need an offset column.
Definition: RField.hxx:361
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:719
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:708
RFieldArray(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField, std::size_t arrayLength)
Definition: RField.cxx:652
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:384
void DoAppend(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:668
void DoReadInCluster(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:685
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:695
void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:676
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:662
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:383
A field translates read and write calls from/to underlying columns to/from tree values.
Definition: RField.hxx:60
The field for a class with dictionary.
Definition: RField.hxx:307
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:481
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:497
void DoAppend(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:449
RFieldClass(std::string_view fieldName, std::string_view className)
Definition: RField.cxx:428
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition: RField.cxx:502
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:490
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:444
void DoReadInCluster(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:470
void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:459
RFieldCollection(std::string_view name, std::shared_ptr< RCollectionNTuple > collectionNTuple, std::unique_ptr< RNTupleModel > collectionModel)
Definition: RField.cxx:851
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:865
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.cxx:888
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:874
The container field for an ntuple model, which itself has no physical representation.
Definition: RField.hxx:290
RFieldBase * Clone(std::string_view newName)
Definition: RField.cxx:270
REntry * GenerateEntry()
Generates managed values for the top-level sub fields.
Definition: RField.cxx:281
void AcceptVisitor(Detail::RNTupleVisitor &visitor, int level) const final
Definition: RField.cxx:290
The generic field for a (nested) std::vector<Type> except for std::vector<bool>
Definition: RField.hxx:333
void DoAppend(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:526
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.cxx:586
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:554
void DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:539
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:520
RFieldVector(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition: RField.cxx:511
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:567
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:581
Template specializations for concrete C++ types.
Definition: RField.hxx:483
Classes with dictionaries that can be inspected by TClass.
Definition: RField.hxx:428
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3606
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:2906
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
basic_string_view< char > string_view
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:150
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Definition: RNTupleUtil.hxx:43
RClusterSize ClusterSize_t
Definition: RNTupleUtil.hxx:58
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
Definition: RNTupleUtil.hxx:33
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
Definition: RNTupleUtil.hxx:79
VSD Structures.
Definition: StringConv.hxx:21
TClass * GetClass(T *)
Definition: TClass.h:608
Type GetType(const std::string &Name)
Definition: Systematics.cxx:34
fill
Definition: fit1_py.py:6
Wrap the 32bit integer in a struct in order to avoid template specialization clash with std::uint32_t...
Definition: RNTupleUtil.hxx:46