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/// Remove leading and trailing white spaces
75std::string Trim(const std::string &raw) {
76 if (raw.empty()) return "";
77
78 unsigned start_pos = 0;
79 for (; (start_pos < raw.length()) && (raw[start_pos] == ' ' || raw[start_pos] == '\t'); ++start_pos) { }
80
81 unsigned end_pos = raw.length() - 1; // at least one character in raw
82 for (; (end_pos >= start_pos) && (raw[end_pos] == ' ' || raw[end_pos] == '\t'); --end_pos) { }
83
84 return raw.substr(start_pos, end_pos - start_pos + 1);
85}
86
87std::string GetNormalizedType(const std::string &typeName) {
88 std::string normalizedType(Trim(typeName));
89 // TODO(jblomer): use a type translation map
90 if (normalizedType == "Bool_t") normalizedType = "bool";
91 if (normalizedType == "Float_t") normalizedType = "float";
92 if (normalizedType == "Double_t") normalizedType = "double";
93 if (normalizedType == "UChar_t") normalizedType = "std::uint8_t";
94 if (normalizedType == "unsigned char") normalizedType = "std::uint8_t";
95 if (normalizedType == "uint8_t") normalizedType = "std::uint8_t";
96 if (normalizedType == "Int_t") normalizedType = "std::int32_t";
97 if (normalizedType == "int") normalizedType = "std::int32_t";
98 if (normalizedType == "int32_t") normalizedType = "std::int32_t";
99 if (normalizedType == "unsigned") normalizedType = "std::uint32_t";
100 if (normalizedType == "unsigned int") normalizedType = "std::uint32_t";
101 if (normalizedType == "UInt_t") normalizedType = "std::uint32_t";
102 if (normalizedType == "uint32_t") normalizedType = "std::uint32_t";
103 if (normalizedType == "ULong64_t") normalizedType = "std::uint64_t";
104 if (normalizedType == "uint64_t") normalizedType = "std::uint64_t";
105 if (normalizedType == "string") normalizedType = "std::string";
106 if (normalizedType.substr(0, 7) == "vector<") normalizedType = "std::" + normalizedType;
107 if (normalizedType.substr(0, 6) == "array<") normalizedType = "std::" + normalizedType;
108 if (normalizedType.substr(0, 8) == "variant<") normalizedType = "std::" + normalizedType;
109
110 return normalizedType;
111}
112
113} // anonymous namespace
114
116{
117 if (field.fColumns.empty())
118 field.GenerateColumnsImpl();
119 for (auto& column : field.fColumns)
120 column->Connect(fieldId, &pageStorage);
121}
122
123
124//------------------------------------------------------------------------------
125
126
128 std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple, std::size_t nRepetitions)
129 : fName(name), fType(type), fStructure(structure), fNRepetitions(nRepetitions), fIsSimple(isSimple),
130 fParent(nullptr), fPrincipalColumn(nullptr)
131{
132}
133
135{
136}
137
139ROOT::Experimental::Detail::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
140{
141 std::string normalizedType(GetNormalizedType(typeName));
142
143 if (normalizedType == "ROOT::Experimental::ClusterSize_t") return new RField<ClusterSize_t>(fieldName);
144 if (normalizedType == "bool") return new RField<bool>(fieldName);
145 if (normalizedType == "std::uint8_t") return new RField<std::uint8_t>(fieldName);
146 if (normalizedType == "std::int32_t") return new RField<std::int32_t>(fieldName);
147 if (normalizedType == "std::uint32_t") return new RField<std::uint32_t>(fieldName);
148 if (normalizedType == "std::uint64_t") return new RField<std::uint64_t>(fieldName);
149 if (normalizedType == "float") return new RField<float>(fieldName);
150 if (normalizedType == "double") return new RField<double>(fieldName);
151 if (normalizedType == "std::string") return new RField<std::string>(fieldName);
152 if (normalizedType == "std::vector<bool>") return new RField<std::vector<bool>>(fieldName);
153 if (normalizedType.substr(0, 12) == "std::vector<") {
154 std::string itemTypeName = normalizedType.substr(12, normalizedType.length() - 13);
155 auto itemField = Create(GetNormalizedType(itemTypeName), itemTypeName);
156 return new RFieldVector(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField));
157 }
158 // For the time being, we silently read RVec fields as std::vector
159 if (normalizedType == "ROOT::VecOps::RVec<bool>") return new RField<ROOT::VecOps::RVec<bool>>(fieldName);
160 if (normalizedType.substr(0, 19) == "ROOT::VecOps::RVec<") {
161 std::string itemTypeName = normalizedType.substr(19, normalizedType.length() - 20);
162 auto itemField = Create(GetNormalizedType(itemTypeName), itemTypeName);
163 return new RFieldVector(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField));
164 }
165 if (normalizedType.substr(0, 11) == "std::array<") {
166 auto arrayDef = TokenizeTypeList(normalizedType.substr(11, normalizedType.length() - 12));
167 R__ASSERT(arrayDef.size() == 2);
168 auto arrayLength = std::stoi(arrayDef[1]);
169 auto itemField = Create(GetNormalizedType(arrayDef[0]), arrayDef[0]);
170 return new RFieldArray(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField), arrayLength);
171 }
172#if __cplusplus >= 201703L
173 if (normalizedType.substr(0, 13) == "std::variant<") {
174 auto innerTypes = TokenizeTypeList(normalizedType.substr(13, normalizedType.length() - 14));
175 std::vector<RFieldBase *> items;
176 for (unsigned int i = 0; i < innerTypes.size(); ++i) {
177 items.emplace_back(Create("variant" + std::to_string(i), innerTypes[i]));
178 }
179 return new RFieldVariant(fieldName, items);
180 }
181#endif
182 // TODO: create an RFieldCollection?
183 if (normalizedType == ":Collection:") return new RField<ClusterSize_t>(fieldName);
184 auto cl = TClass::GetClass(normalizedType.c_str());
185 if (cl != nullptr) {
186 return new RFieldClass(fieldName, normalizedType);
187 }
188 R__ERROR_HERE("NTuple") << "Field " << fieldName << " has unknown type " << normalizedType;
189 R__ASSERT(false);
190 return nullptr;
191}
192
194 R__ASSERT(false);
195}
196
199 RFieldValue* /*value*/)
200{
201 R__ASSERT(false);
202}
203
205{
206 void *where = malloc(GetValueSize());
207 R__ASSERT(where != nullptr);
208 return GenerateValue(where);
209}
210
212{
213 if (!dtorOnly)
214 free(value.GetRawPtr());
215}
216
217std::vector<ROOT::Experimental::Detail::RFieldValue>
219{
220 return std::vector<RFieldValue>();
221}
222
224 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> child)
225{
226 child->fParent = this;
227 fSubFields.emplace_back(std::move(child));
228}
229
230
231std::vector<const ROOT::Experimental::Detail::RFieldBase *>
233{
234 std::vector<const RFieldBase *> result;
235 for (const auto &f : fSubFields) {
236 result.emplace_back(f.get());
237 }
238 return result;
239}
240
241
243{
244 for (auto& column : fColumns) {
245 column->Flush();
246 }
247}
248
249
251{
252 visitor.VisitField(*this);
253}
254
255
257{
258 if (fSubFields.empty()) return RSchemaIterator(this, -1);
259 return RSchemaIterator(this->fSubFields[0].get(), 0);
260}
261
262
264{
265 return RSchemaIterator(this, -1);
266}
267
268
269//-----------------------------------------------------------------------------
270
271
273{
274 auto itr = fStack.rbegin();
275 if (!itr->fFieldPtr->fSubFields.empty()) {
276 fStack.emplace_back(Position(itr->fFieldPtr->fSubFields[0].get(), 0));
277 return;
278 }
279
280 unsigned int nextIdxInParent = ++(itr->fIdxInParent);
281 while (nextIdxInParent >= itr->fFieldPtr->fParent->fSubFields.size()) {
282 if (fStack.size() == 1) {
283 itr->fFieldPtr = itr->fFieldPtr->fParent;
284 itr->fIdxInParent = -1;
285 return;
286 }
287 fStack.pop_back();
288 itr = fStack.rbegin();
289 nextIdxInParent = ++(itr->fIdxInParent);
290 }
291 itr->fFieldPtr = itr->fFieldPtr->fParent->fSubFields[nextIdxInParent].get();
292}
293
294
295//------------------------------------------------------------------------------
296
297
299{
300 Detail::RFieldBase* result = new RFieldRoot();
301 for (auto &f : fSubFields) {
302 auto clone = f->Clone(f->GetName());
303 result->Attach(std::unique_ptr<RFieldBase>(clone));
304 }
305 return result;
306}
307
308
310{
311 auto entry = new REntry();
312 for (auto& f : fSubFields) {
313 entry->AddValue(f->GenerateValue());
314 }
315 return entry;
316}
317
319{
320 visitor.VisitRootField(*this);
321}
322
323
324//------------------------------------------------------------------------------
325
326
328{
329 RColumnModel model(EColumnType::kIndex, true /* isSorted*/);
330 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
331 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(model, 0)));
332 fPrincipalColumn = fColumns[0].get();
333}
334
336{
337 visitor.VisitClusterSizeField(*this);
338}
339
340//------------------------------------------------------------------------------
341
343{
344 RColumnModel model(EColumnType::kByte, false /* isSorted*/);
345 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
346 std::uint8_t, EColumnType::kByte>(model, 0)));
347 fPrincipalColumn = fColumns[0].get();
348}
349
350void ROOT::Experimental::RField<std::uint8_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
351{
352 visitor.VisitUInt8Field(*this);
353}
354
355//------------------------------------------------------------------------------
356
357
359{
360 RColumnModel model(EColumnType::kBit, false /* isSorted*/);
361 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
362 Detail::RColumn::Create<bool, EColumnType::kBit>(model, 0)));
363 fPrincipalColumn = fColumns[0].get();
364}
365
367{
368 visitor.VisitBoolField(*this);
369}
370
371//------------------------------------------------------------------------------
372
373
375{
376 RColumnModel model(EColumnType::kReal32, false /* isSorted*/);
377 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
378 Detail::RColumn::Create<float, EColumnType::kReal32>(model, 0)));
379 fPrincipalColumn = fColumns[0].get();
380}
381
383{
384 visitor.VisitFloatField(*this);
385}
386
387
388//------------------------------------------------------------------------------
389
391{
392 RColumnModel model(EColumnType::kReal64, false /* isSorted*/);
393 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
394 Detail::RColumn::Create<double, EColumnType::kReal64>(model, 0)));
395 fPrincipalColumn = fColumns[0].get();
396}
397
399{
400 visitor.VisitDoubleField(*this);
401}
402
403//------------------------------------------------------------------------------
404
406{
407 RColumnModel model(EColumnType::kInt32, false /* isSorted*/);
408 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
409 std::int32_t, EColumnType::kInt32>(model, 0)));
410 fPrincipalColumn = fColumns[0].get();
411}
412
413void ROOT::Experimental::RField<std::int32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
414{
415 visitor.VisitIntField(*this);
416}
417
418//------------------------------------------------------------------------------
419
421{
422 RColumnModel model(EColumnType::kInt32, false /* isSorted*/);
423 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
424 Detail::RColumn::Create<std::uint32_t, EColumnType::kInt32>(model, 0)));
425 fPrincipalColumn = fColumns[0].get();
426}
427
428void ROOT::Experimental::RField<std::uint32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
429{
430 visitor.VisitUInt32Field(*this);
431}
432
433//------------------------------------------------------------------------------
434
436{
437 RColumnModel model(EColumnType::kInt64, false /* isSorted*/);
438 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
439 Detail::RColumn::Create<std::uint64_t, EColumnType::kInt64>(model, 0)));
440 fPrincipalColumn = fColumns[0].get();
441}
442
443void ROOT::Experimental::RField<std::uint64_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
444{
445 visitor.VisitUInt64Field(*this);
446}
447
448//------------------------------------------------------------------------------
449
450
452{
453 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
454 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
455 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
456
457 RColumnModel modelChars(EColumnType::kByte, false /* isSorted*/);
458 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
459 Detail::RColumn::Create<char, EColumnType::kByte>(modelChars, 1)));
460 fPrincipalColumn = fColumns[0].get();
461}
462
464{
465 auto typedValue = value.Get<std::string>();
466 auto length = typedValue->length();
467 Detail::RColumnElement<char, EColumnType::kByte> elemChars(const_cast<char*>(typedValue->data()));
468 fColumns[1]->AppendV(elemChars, length);
469 fIndex += length;
470 fColumns[0]->Append(fElemIndex);
471}
472
475{
476 auto typedValue = value->Get<std::string>();
477 RClusterIndex collectionStart;
478 ClusterSize_t nChars;
479 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nChars);
480 if (nChars == 0) {
481 typedValue->clear();
482 } else {
483 typedValue->resize(nChars);
484 Detail::RColumnElement<char, EColumnType::kByte> elemChars(const_cast<char*>(typedValue->data()));
485 fColumns[1]->ReadV(collectionStart, nChars, &elemChars);
486 }
487}
488
490{
491 fIndex = 0;
492}
493
494void ROOT::Experimental::RField<std::string>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
495{
496 visitor.VisitStringField(*this);
497}
498
499//------------------------------------------------------------------------------
500
501
503 : ROOT::Experimental::Detail::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */)
504 , fClass(TClass::GetClass(std::string(className).c_str()))
505{
506 if (fClass == nullptr) {
507 throw std::runtime_error("RField: no I/O support for type " + std::string(className));
508 }
510 while (auto dataMember = static_cast<TDataMember *>(next())) {
511 //printf("Now looking at %s %s\n", dataMember->GetName(), dataMember->GetFullTypeName());
512 auto subField = Detail::RFieldBase::Create(dataMember->GetName(), dataMember->GetFullTypeName());
513 fMaxAlignment = std::max(fMaxAlignment, subField->GetAlignment());
514 Attach(std::unique_ptr<Detail::RFieldBase>(subField));
515 }
516}
517
519{
520 return new RFieldClass(newName, GetType());
521}
522
524 TIter next(fClass->GetListOfDataMembers());
525 unsigned i = 0;
526 while (auto dataMember = static_cast<TDataMember *>(next())) {
527 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + dataMember->GetOffset());
528 fSubFields[i]->Append(memberValue);
529 i++;
530 }
531}
532
534{
535 TIter next(fClass->GetListOfDataMembers());
536 unsigned i = 0;
537 while (auto dataMember = static_cast<TDataMember *>(next())) {
538 auto memberValue = fSubFields[i]->GenerateValue(value->Get<unsigned char>() + dataMember->GetOffset());
539 fSubFields[i]->Read(globalIndex, &memberValue);
540 i++;
541 }
542}
543
545{
546 TIter next(fClass->GetListOfDataMembers());
547 unsigned i = 0;
548 while (auto dataMember = static_cast<TDataMember *>(next())) {
549 auto memberValue = fSubFields[i]->GenerateValue(value->Get<unsigned char>() + dataMember->GetOffset());
550 fSubFields[i]->Read(clusterIndex, &memberValue);
551 i++;
552 }
553}
554
556{
557}
558
560{
561 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
562}
563
565{
566 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
567 if (!dtorOnly)
568 free(value.GetRawPtr());
569}
570
572{
573 return Detail::RFieldValue(true /* captureFlat */, this, where);
574}
575
576
577std::vector<ROOT::Experimental::Detail::RFieldValue>
579{
580 TIter next(fClass->GetListOfDataMembers());
581 unsigned i = 0;
582 std::vector<Detail::RFieldValue> result;
583 while (auto dataMember = static_cast<TDataMember *>(next())) {
584 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + dataMember->GetOffset());
585 result.emplace_back(memberValue);
586 i++;
587 }
588 return result;
589}
590
591
593{
594 return fClass->GetClassSize();
595}
596
598{
599 visitor.VisitClassField(*this);
600}
601
602//------------------------------------------------------------------------------
603
604
606 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
607 : ROOT::Experimental::Detail::RFieldBase(
608 fieldName, "std::vector<" + itemField->GetType() + ">", ENTupleStructure::kCollection, false /* isSimple */)
609 , fItemSize(itemField->GetValueSize()), fNWritten(0)
610{
611 Attach(std::move(itemField));
612}
613
615{
616 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
617 return new RFieldVector(newName, std::unique_ptr<Detail::RFieldBase>(newItemField));
618}
619
621 auto typedValue = value.Get<std::vector<char>>();
622 R__ASSERT((typedValue->size() % fItemSize) == 0);
623 auto count = typedValue->size() / fItemSize;
624 for (unsigned i = 0; i < count; ++i) {
625 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
626 fSubFields[0]->Append(itemValue);
627 }
629 fNWritten += count;
630 fColumns[0]->Append(elemIndex);
631}
632
634{
635 auto typedValue = value->Get<std::vector<char>>();
636
637 ClusterSize_t nItems;
638 RClusterIndex collectionStart;
639 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
640
641 typedValue->resize(nItems * fItemSize);
642 for (unsigned i = 0; i < nItems; ++i) {
643 auto itemValue = fSubFields[0]->GenerateValue(typedValue->data() + (i * fItemSize));
644 fSubFields[0]->Read(collectionStart + i, &itemValue);
645 }
646}
647
649{
650 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
651 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
652 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
653 fPrincipalColumn = fColumns[0].get();
654}
655
657{
658 return Detail::RFieldValue(this, reinterpret_cast<std::vector<char>*>(where));
659}
660
662{
663 auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
664 R__ASSERT((vec->size() % fItemSize) == 0);
665 auto nItems = vec->size() / fItemSize;
666 for (unsigned i = 0; i < nItems; ++i) {
667 auto itemValue = fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize));
668 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
669 }
670 vec->~vector();
671 if (!dtorOnly)
672 free(vec);
673}
674
676{
677 return Detail::RFieldValue(true /* captureFlag */, this, where);
678}
679
680std::vector<ROOT::Experimental::Detail::RFieldValue>
682{
683 auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
684 R__ASSERT((vec->size() % fItemSize) == 0);
685 auto nItems = vec->size() / fItemSize;
686 std::vector<Detail::RFieldValue> result;
687 for (unsigned i = 0; i < nItems; ++i) {
688 result.emplace_back(fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize)));
689 }
690 return result;
691}
692
694{
695 fNWritten = 0;
696}
697
699{
700 visitor.VisitVectorField(*this);
701}
702
703
704//------------------------------------------------------------------------------
705
706
708 : ROOT::Experimental::Detail::RFieldBase(name, "std::vector<bool>", ENTupleStructure::kCollection,
709 false /* isSimple */)
710{
711 Attach(std::make_unique<RField<bool>>("bool"));
712}
713
714void ROOT::Experimental::RField<std::vector<bool>>::AppendImpl(const Detail::RFieldValue& value) {
715 auto typedValue = value.Get<std::vector<bool>>();
716 auto count = typedValue->size();
717 for (unsigned i = 0; i < count; ++i) {
718 bool bval = (*typedValue)[i];
719 auto itemValue = fSubFields[0]->CaptureValue(&bval);
720 fSubFields[0]->Append(itemValue);
721 }
722 Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> elemIndex(&fNWritten);
723 fNWritten += count;
724 fColumns[0]->Append(elemIndex);
725}
726
727void ROOT::Experimental::RField<std::vector<bool>>::ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue* value)
728{
729 auto typedValue = value->Get<std::vector<bool>>();
730
731 ClusterSize_t nItems;
732 RClusterIndex collectionStart;
733 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
734
735 typedValue->resize(nItems);
736 for (unsigned i = 0; i < nItems; ++i) {
737 bool bval;
738 auto itemValue = fSubFields[0]->GenerateValue(&bval);
739 fSubFields[0]->Read(collectionStart + i, &itemValue);
740 (*typedValue)[i] = bval;
741 }
742}
743
744void ROOT::Experimental::RField<std::vector<bool>>::GenerateColumnsImpl()
745{
746 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
747 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
748 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
749 fPrincipalColumn = fColumns[0].get();
750}
751
752std::vector<ROOT::Experimental::Detail::RFieldValue>
753ROOT::Experimental::RField<std::vector<bool>>::SplitValue(const Detail::RFieldValue& value) const
754{
755 const static bool trueValue = true;
756 const static bool falseValue = false;
757
758 auto typedValue = value.Get<std::vector<bool>>();
759 auto count = typedValue->size();
760 std::vector<Detail::RFieldValue> result;
761 for (unsigned i = 0; i < count; ++i) {
762 if ((*typedValue)[i])
763 result.emplace_back(fSubFields[0]->CaptureValue(const_cast<bool *>(&trueValue)));
764 else
765 result.emplace_back(fSubFields[0]->CaptureValue(const_cast<bool *>(&falseValue)));
766 }
767 return result;
768}
769
770
771void ROOT::Experimental::RField<std::vector<bool>>::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
772{
773 auto vec = static_cast<std::vector<bool>*>(value.GetRawPtr());
774 vec->~vector();
775 if (!dtorOnly)
776 free(vec);
777}
778
779void ROOT::Experimental::RField<std::vector<bool>>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
780{
781 visitor.VisitVectorBoolField(*this);
782}
783
784
785//------------------------------------------------------------------------------
786
787
789 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField, std::size_t arrayLength)
790 : ROOT::Experimental::Detail::RFieldBase(
791 fieldName, "std::array<" + itemField->GetType() + "," + std::to_string(arrayLength) + ">",
792 ENTupleStructure::kLeaf, false /* isSimple */, arrayLength)
793 , fItemSize(itemField->GetValueSize()), fArrayLength(arrayLength)
794{
795 Attach(std::move(itemField));
796}
797
799{
800 auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
801 return new RFieldArray(newName, std::unique_ptr<Detail::RFieldBase>(newItemField), fArrayLength);
802}
803
805 auto arrayPtr = value.Get<unsigned char>();
806 for (unsigned i = 0; i < fArrayLength; ++i) {
807 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
808 fSubFields[0]->Append(itemValue);
809 }
810}
811
813{
814 auto arrayPtr = value->Get<unsigned char>();
815 for (unsigned i = 0; i < fArrayLength; ++i) {
816 auto itemValue = fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
817 fSubFields[0]->Read(globalIndex * fArrayLength + i, &itemValue);
818 }
819}
820
822{
823 auto arrayPtr = value->Get<unsigned char>();
824 for (unsigned i = 0; i < fArrayLength; ++i) {
825 auto itemValue = fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
826 fSubFields[0]->Read(RClusterIndex(clusterIndex.GetClusterId(), clusterIndex.GetIndex() * fArrayLength + i),
827 &itemValue);
828 }
829}
830
832{
833}
834
836{
837 auto arrayPtr = reinterpret_cast<unsigned char *>(where);
838 for (unsigned i = 0; i < fArrayLength; ++i) {
839 fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
840 }
841 return Detail::RFieldValue(true /* captureFlag */, this, where);
842}
843
845{
846 auto arrayPtr = value.Get<unsigned char>();
847 for (unsigned i = 0; i < fArrayLength; ++i) {
848 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
849 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
850 }
851 if (!dtorOnly)
852 free(arrayPtr);
853}
854
856{
857 return Detail::RFieldValue(true /* captureFlag */, this, where);
858}
859
860std::vector<ROOT::Experimental::Detail::RFieldValue>
862{
863 auto arrayPtr = value.Get<unsigned char>();
864 std::vector<Detail::RFieldValue> result;
865 for (unsigned i = 0; i < fArrayLength; ++i) {
866 auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
867 result.emplace_back(itemValue);
868 }
869 return result;
870}
871
873{
874 visitor.VisitArrayField(*this);
875}
876
877//------------------------------------------------------------------------------
878
879#if __cplusplus >= 201703L
880std::string ROOT::Experimental::RFieldVariant::GetTypeList(const std::vector<Detail::RFieldBase *> &itemFields)
881{
882 std::string result;
883 for (size_t i = 0; i < itemFields.size(); ++i) {
884 result += itemFields[i]->GetType() + ",";
885 }
886 R__ASSERT(!result.empty()); // there is always at least one variant
887 result.pop_back(); // remove trailing comma
888 return result;
889}
890
891ROOT::Experimental::RFieldVariant::RFieldVariant(
892 std::string_view fieldName, const std::vector<Detail::RFieldBase *> &itemFields)
893 : ROOT::Experimental::Detail::RFieldBase(fieldName,
894 "std::variant<" + GetTypeList(itemFields) + ">", ENTupleStructure::kVariant, false /* isSimple */)
895{
896 auto nFields = itemFields.size();
897 R__ASSERT(nFields > 0);
898 fNWritten.resize(nFields, 0);
899 for (unsigned int i = 0; i < nFields; ++i) {
900 fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
901 fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
902 Attach(std::unique_ptr<Detail::RFieldBase>(itemFields[i]));
903 }
904 fTagOffset = (fMaxItemSize < fMaxAlignment) ? fMaxAlignment : fMaxItemSize;
905}
906
907ROOT::Experimental::Detail::RFieldBase *ROOT::Experimental::RFieldVariant::Clone(std::string_view newName)
908{
909 auto nFields = fSubFields.size();
910 std::vector<Detail::RFieldBase *> itemFields;
911 for (unsigned i = 0; i < nFields; ++i) {
912 itemFields.emplace_back(fSubFields[i]->Clone(fSubFields[i]->GetName()));
913 }
914 return new RFieldVariant(newName, itemFields);
915}
916
917std::uint32_t ROOT::Experimental::RFieldVariant::GetTag(void *variantPtr) const
918{
919 auto index = *(reinterpret_cast<char *>(variantPtr) + fTagOffset);
920 return (index < 0) ? 0 : index + 1;
921}
922
923void ROOT::Experimental::RFieldVariant::SetTag(void *variantPtr, std::uint32_t tag) const
924{
925 auto index = reinterpret_cast<char *>(variantPtr) + fTagOffset;
926 *index = static_cast<char>(tag - 1);
927}
928
929void ROOT::Experimental::RFieldVariant::AppendImpl(const Detail::RFieldValue& value)
930{
931 auto tag = GetTag(value.GetRawPtr());
932 auto index = 0;
933 if (tag > 0) {
934 auto itemValue = fSubFields[tag - 1]->CaptureValue(value.GetRawPtr());
935 fSubFields[tag - 1]->Append(itemValue);
936 index = fNWritten[tag - 1]++;
937 }
938 RColumnSwitch varSwitch(ClusterSize_t(index), tag);
939 Detail::RColumnElement<RColumnSwitch, EColumnType::kSwitch> elemSwitch(&varSwitch);
940 fColumns[0]->Append(elemSwitch);
941}
942
943void ROOT::Experimental::RFieldVariant::ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value)
944{
945 RClusterIndex variantIndex;
946 std::uint32_t tag;
947 fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
948 R__ASSERT(tag > 0); // TODO(jblomer): deal with invalid variants
949
950 auto itemValue = fSubFields[tag - 1]->GenerateValue(value->GetRawPtr());
951 fSubFields[tag - 1]->Read(variantIndex, &itemValue);
952 SetTag(value->GetRawPtr(), tag);
953}
954
955void ROOT::Experimental::RFieldVariant::GenerateColumnsImpl()
956{
957 RColumnModel modelSwitch(EColumnType::kSwitch, false);
958 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
959 Detail::RColumn::Create<RColumnSwitch, EColumnType::kSwitch>(modelSwitch, 0)));
960 fPrincipalColumn = fColumns[0].get();
961}
962
963ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVariant::GenerateValue(void *where)
964{
965 memset(where, 0, GetValueSize());
966 fSubFields[0]->GenerateValue(where);
967 SetTag(where, 1);
968 return Detail::RFieldValue(this, reinterpret_cast<unsigned char *>(where));
969}
970
971void ROOT::Experimental::RFieldVariant::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
972{
973 auto variantPtr = value.GetRawPtr();
974 auto tag = GetTag(variantPtr);
975 if (tag > 0) {
976 auto itemValue = fSubFields[tag - 1]->CaptureValue(variantPtr);
977 fSubFields[tag - 1]->DestroyValue(itemValue, true /* dtorOnly */);
978 }
979 if (!dtorOnly)
980 free(variantPtr);
981}
982
983ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVariant::CaptureValue(void *where)
984{
985 return Detail::RFieldValue(true /* captureFlag */, this, where);
986}
987
988size_t ROOT::Experimental::RFieldVariant::GetValueSize() const
989{
990 return fMaxItemSize + fMaxAlignment; // TODO: fix for more than 255 items
991}
992
993void ROOT::Experimental::RFieldVariant::CommitCluster()
994{
995 std::fill(fNWritten.begin(), fNWritten.end(), 0);
996}
997#endif
998
999
1000//------------------------------------------------------------------------------
1001
1002
1005 std::shared_ptr<RCollectionNTuple> collectionNTuple,
1006 std::unique_ptr<RNTupleModel> collectionModel)
1007 : RFieldBase(name, ":Collection:", ENTupleStructure::kCollection, true /* isSimple */)
1008 , fCollectionNTuple(collectionNTuple)
1009{
1010 for (unsigned i = 0; i < collectionModel->GetRootField()->fSubFields.size(); ++i) {
1011 auto& subField = collectionModel->GetRootField()->fSubFields[i];
1012 Attach(std::move(subField));
1013 }
1014}
1015
1016
1018{
1019 RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
1020 fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
1021 Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
1022 fPrincipalColumn = fColumns[0].get();
1023}
1024
1025
1027{
1028 // TODO(jblomer)
1029 return nullptr;
1030 //auto result = new RFieldCollection(newName, fCollectionNTuple, RNTupleModel::Create());
1031 //for (auto& f : fSubFields) {
1032 // // switch the name prefix for the new parent name
1033 // std::string cloneName = std::string(newName) + f->GetName().substr(GetName().length());
1034 // auto clone = f->Clone(cloneName);
1035 // result->Attach(std::unique_ptr<RFieldBase>(clone));
1036 //}
1037 //return result;
1038}
1039
1041 *fCollectionNTuple->GetOffsetPtr() = 0;
1042}
1043
uint8_t
Definition: Converters.cxx:858
Cppyy::TCppType_t fClass
#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:70
Iterates over the sub tree of fields in depth-first search order.
Definition: RField.hxx:115
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:272
virtual void GenerateColumnsImpl()=0
Creates the backing columns corresponsing to the field type and name.
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Definition: RField.hxx:92
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:127
virtual void DestroyValue(const RFieldValue &value, bool dtorOnly=false)
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:211
void Flush() const
Ensure that all received items are written from page buffers to the storage.
Definition: RField.cxx:242
virtual void CommitCluster()
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.hxx:206
virtual std::vector< RFieldValue > SplitValue(const RFieldValue &value) const
Creates the list of direct child values given a value for this field.
Definition: RField.cxx:218
virtual void AppendImpl(const RFieldValue &value)
Operations on values of complex types, e.g.
Definition: RField.cxx:193
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:139
virtual void AcceptVisitor(RFieldVisitor &visitor) const
Definition: RField.cxx:250
std::vector< const RFieldBase * > GetSubFields() const
Definition: RField.cxx:232
virtual void ReadGlobalImpl(NTupleSize_t globalIndex, RFieldValue *value)
Definition: RField.cxx:197
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:100
void Attach(std::unique_ptr< Detail::RFieldBase > child)
Add a new subfield to the list of nested fields.
Definition: RField.cxx:223
RFieldValue GenerateValue()
Generates an object of the field type and allocates new initialized memory according to the type.
Definition: RField.cxx:204
static void Connect(DescriptorId_t fieldId, RPageStorage &pageStorage, RFieldBase &field)
Definition: RField.cxx:115
Abstract base class for classes implementing the visitor design pattern.
virtual void VisitBoolField(const RField< bool > &field)
virtual void VisitArrayField(const RFieldArray &field)
virtual void VisitField(const Detail::RFieldBase &field)=0
virtual void VisitClassField(const RFieldClass &field)
virtual void VisitDoubleField(const RField< double > &field)
virtual void VisitRootField(const RFieldRoot &field)
virtual void VisitVectorField(const RFieldVector &field)
virtual void VisitFloatField(const RField< float > &field)
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:82
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:333
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:831
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition: RField.cxx:872
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:855
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:844
RFieldArray(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField, std::size_t arrayLength)
Definition: RField.cxx:788
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:812
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:358
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition: RField.cxx:861
void AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:804
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:821
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:798
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:357
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:268
void AcceptVisitor(Detail::RFieldVisitor &visitor) const override
Definition: RField.cxx:597
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:571
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:544
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition: RField.cxx:578
RFieldClass(std::string_view fieldName, std::string_view className)
Definition: RField.cxx:502
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition: RField.cxx:592
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:564
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:533
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:518
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:555
void AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:523
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:1017
RFieldCollection(std::string_view name, std::shared_ptr< RCollectionNTuple > collectionNTuple, std::unique_ptr< RNTupleModel > collectionModel)
Definition: RField.cxx:1003
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.cxx:1040
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:1026
The container field for an ntuple model, which itself has no physical representation.
Definition: RField.hxx:251
RFieldBase * Clone(std::string_view newName)
Definition: RField.cxx:298
REntry * GenerateEntry()
Generates managed values for the top-level sub fields.
Definition: RField.cxx:309
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition: RField.cxx:318
The generic field for a (nested) std::vector<Type> except for std::vector<bool>
Definition: RField.hxx:297
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:633
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:648
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition: RField.cxx:698
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.cxx:693
std::vector< Detail::RFieldValue > SplitValue(const Detail::RFieldValue &value) const final
Creates the list of direct child values given a value for this field.
Definition: RField.cxx:681
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:614
RFieldVector(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition: RField.cxx:605
void AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:620
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:661
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:675
Template specializations for concrete C++ types.
Definition: RField.hxx:458
Classes with dictionaries that can be inspected by TClass.
Definition: RField.hxx:403
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3738
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:2948
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
basic_string_view< char > string_view
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Definition: RNTupleUtil.hxx:42
RClusterSize ClusterSize_t
Definition: RNTupleUtil.hxx:57
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
Definition: RNTupleUtil.hxx:32
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
Definition: RNTupleUtil.hxx:78
clang::QualType GetNormalizedType(const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
Return the type normalized for ROOT, keeping only the ROOT opaque typedef (Double32_t,...
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
TClass * GetClass(T *)
Definition: TClass.h:658
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:45