Logo ROOT   master
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>
21 #include <ROOT/RFieldVisitor.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 
40 namespace {
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>"
44 std::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.GenerateColumnsImpl();
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 
100 ROOT::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 
199 std::vector<ROOT::Experimental::Detail::RFieldValue>
201 {
202  return std::vector<RFieldValue>();
203 }
204 
206  std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> child)
207 {
208  child->fParent = this;
209  fSubFields.emplace_back(std::move(child));
210 }
211 
212 
213 std::vector<const ROOT::Experimental::Detail::RFieldBase *>
215 {
216  std::vector<const RFieldBase *> result;
217  for (const auto &f : fSubFields) {
218  result.emplace_back(f.get());
219  }
220  return result;
221 }
222 
223 
225 {
226  for (auto& column : fColumns) {
227  column->Flush();
228  }
229 }
230 
231 
233 {
234  visitor.VisitField(*this);
235 }
236 
237 
239 {
240  if (fSubFields.empty()) return RSchemaIterator(this, -1);
241  return RSchemaIterator(this->fSubFields[0].get(), 0);
242 }
243 
244 
246 {
247  return RSchemaIterator(this, -1);
248 }
249 
250 
251 //-----------------------------------------------------------------------------
252 
253 
255 {
256  auto itr = fStack.rbegin();
257  if (!itr->fFieldPtr->fSubFields.empty()) {
258  fStack.emplace_back(Position(itr->fFieldPtr->fSubFields[0].get(), 0));
259  return;
260  }
261 
262  unsigned int nextIdxInParent = ++(itr->fIdxInParent);
263  while (nextIdxInParent >= itr->fFieldPtr->fParent->fSubFields.size()) {
264  if (fStack.size() == 1) {
265  itr->fFieldPtr = itr->fFieldPtr->fParent;
266  itr->fIdxInParent = -1;
267  return;
268  }
269  fStack.pop_back();
270  itr = fStack.rbegin();
271  nextIdxInParent = ++(itr->fIdxInParent);
272  }
273  itr->fFieldPtr = itr->fFieldPtr->fParent->fSubFields[nextIdxInParent].get();
274 }
275 
276 
277 //------------------------------------------------------------------------------
278 
279 
281 {
282  Detail::RFieldBase* result = new RFieldRoot();
283  for (auto &f : fSubFields) {
284  auto clone = f->Clone(f->GetName());
285  result->Attach(std::unique_ptr<RFieldBase>(clone));
286  }
287  return result;
288 }
289 
290 
292 {
293  auto entry = new REntry();
294  for (auto& f : fSubFields) {
295  entry->AddValue(f->GenerateValue());
296  }
297  return entry;
298 }
299 
301 {
302  visitor.VisitRootField(*this);
303 }
304 
305 
306 //------------------------------------------------------------------------------
307 
308 
310 {
311  RColumnModel model(EColumnType::kIndex, true /* isSorted*/);
312  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
313  Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(model, 0)));
314  fPrincipalColumn = fColumns[0].get();
315 }
316 
318 {
319  visitor.VisitClusterSizeField(*this);
320 }
321 
322 //------------------------------------------------------------------------------
323 
325 {
326  RColumnModel model(EColumnType::kByte, false /* isSorted*/);
327  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
328  std::uint8_t, EColumnType::kByte>(model, 0)));
329  fPrincipalColumn = fColumns[0].get();
330 }
331 
332 void ROOT::Experimental::RField<std::uint8_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
333 {
334  visitor.VisitUInt8Field(*this);
335 }
336 
337 //------------------------------------------------------------------------------
338 
339 
341 {
342  RColumnModel model(EColumnType::kBit, false /* isSorted*/);
343  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
344  Detail::RColumn::Create<bool, EColumnType::kBit>(model, 0)));
345  fPrincipalColumn = fColumns[0].get();
346 }
347 
349 {
350  visitor.VisitBoolField(*this);
351 }
352 
353 //------------------------------------------------------------------------------
354 
355 
357 {
358  RColumnModel model(EColumnType::kReal32, false /* isSorted*/);
359  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
360  Detail::RColumn::Create<float, EColumnType::kReal32>(model, 0)));
361  fPrincipalColumn = fColumns[0].get();
362 }
363 
365 {
366  visitor.VisitFloatField(*this);
367 }
368 
369 
370 //------------------------------------------------------------------------------
371 
373 {
374  RColumnModel model(EColumnType::kReal64, false /* isSorted*/);
375  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
376  Detail::RColumn::Create<double, EColumnType::kReal64>(model, 0)));
377  fPrincipalColumn = fColumns[0].get();
378 }
379 
381 {
382  visitor.VisitDoubleField(*this);
383 }
384 
385 //------------------------------------------------------------------------------
386 
388 {
389  RColumnModel model(EColumnType::kInt32, false /* isSorted*/);
390  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(Detail::RColumn::Create<
391  std::int32_t, EColumnType::kInt32>(model, 0)));
392  fPrincipalColumn = fColumns[0].get();
393 }
394 
395 void ROOT::Experimental::RField<std::int32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
396 {
397  visitor.VisitIntField(*this);
398 }
399 
400 //------------------------------------------------------------------------------
401 
403 {
404  RColumnModel model(EColumnType::kInt32, false /* isSorted*/);
405  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
406  Detail::RColumn::Create<std::uint32_t, EColumnType::kInt32>(model, 0)));
407  fPrincipalColumn = fColumns[0].get();
408 }
409 
410 void ROOT::Experimental::RField<std::uint32_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
411 {
412  visitor.VisitUInt32Field(*this);
413 }
414 
415 //------------------------------------------------------------------------------
416 
418 {
419  RColumnModel model(EColumnType::kInt64, false /* isSorted*/);
420  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
421  Detail::RColumn::Create<std::uint64_t, EColumnType::kInt64>(model, 0)));
422  fPrincipalColumn = fColumns[0].get();
423 }
424 
425 void ROOT::Experimental::RField<std::uint64_t>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
426 {
427  visitor.VisitUInt64Field(*this);
428 }
429 
430 //------------------------------------------------------------------------------
431 
432 
434 {
435  RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
436  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
437  Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
438 
439  RColumnModel modelChars(EColumnType::kByte, false /* isSorted*/);
440  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
441  Detail::RColumn::Create<char, EColumnType::kByte>(modelChars, 1)));
442  fPrincipalColumn = fColumns[0].get();
443 }
444 
446 {
447  auto typedValue = value.Get<std::string>();
448  auto length = typedValue->length();
449  Detail::RColumnElement<char, EColumnType::kByte> elemChars(const_cast<char*>(typedValue->data()));
450  fColumns[1]->AppendV(elemChars, length);
451  fIndex += length;
452  fColumns[0]->Append(fElemIndex);
453 }
454 
457 {
458  auto typedValue = value->Get<std::string>();
459  RClusterIndex collectionStart;
460  ClusterSize_t nChars;
461  fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nChars);
462  if (nChars == 0) {
463  typedValue->clear();
464  } else {
465  typedValue->resize(nChars);
466  Detail::RColumnElement<char, EColumnType::kByte> elemChars(const_cast<char*>(typedValue->data()));
467  fColumns[1]->ReadV(collectionStart, nChars, &elemChars);
468  }
469 }
470 
472 {
473  fIndex = 0;
474 }
475 
476 void ROOT::Experimental::RField<std::string>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
477 {
478  visitor.VisitStringField(*this);
479 }
480 
481 //------------------------------------------------------------------------------
482 
483 
484 ROOT::Experimental::RFieldClass::RFieldClass(std::string_view fieldName, std::string_view className)
485  : ROOT::Experimental::Detail::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */)
486  , fClass(TClass::GetClass(std::string(className).c_str()))
487 {
488  if (fClass == nullptr) {
489  throw std::runtime_error("RField: no I/O support for type " + std::string(className));
490  }
492  while (auto dataMember = static_cast<TDataMember *>(next())) {
493  //printf("Now looking at %s %s\n", dataMember->GetName(), dataMember->GetFullTypeName());
494  auto subField = Detail::RFieldBase::Create(dataMember->GetName(), dataMember->GetFullTypeName());
495  fMaxAlignment = std::max(fMaxAlignment, subField->GetAlignment());
496  Attach(std::unique_ptr<Detail::RFieldBase>(subField));
497  }
498 }
499 
501 {
502  return new RFieldClass(newName, GetType());
503 }
504 
506  TIter next(fClass->GetListOfDataMembers());
507  unsigned i = 0;
508  while (auto dataMember = static_cast<TDataMember *>(next())) {
509  auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + dataMember->GetOffset());
510  fSubFields[i]->Append(memberValue);
511  i++;
512  }
513 }
514 
516 {
517  TIter next(fClass->GetListOfDataMembers());
518  unsigned i = 0;
519  while (auto dataMember = static_cast<TDataMember *>(next())) {
520  auto memberValue = fSubFields[i]->GenerateValue(value->Get<unsigned char>() + dataMember->GetOffset());
521  fSubFields[i]->Read(globalIndex, &memberValue);
522  i++;
523  }
524 }
525 
527 {
528  TIter next(fClass->GetListOfDataMembers());
529  unsigned i = 0;
530  while (auto dataMember = static_cast<TDataMember *>(next())) {
531  auto memberValue = fSubFields[i]->GenerateValue(value->Get<unsigned char>() + dataMember->GetOffset());
532  fSubFields[i]->Read(clusterIndex, &memberValue);
533  i++;
534  }
535 }
536 
538 {
539 }
540 
542 {
543  return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
544 }
545 
547 {
548  fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
549  if (!dtorOnly)
550  free(value.GetRawPtr());
551 }
552 
554 {
555  return Detail::RFieldValue(true /* captureFlat */, this, where);
556 }
557 
558 
559 std::vector<ROOT::Experimental::Detail::RFieldValue>
561 {
562  TIter next(fClass->GetListOfDataMembers());
563  unsigned i = 0;
564  std::vector<Detail::RFieldValue> result;
565  while (auto dataMember = static_cast<TDataMember *>(next())) {
566  auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + dataMember->GetOffset());
567  result.emplace_back(memberValue);
568  i++;
569  }
570  return result;
571 }
572 
573 
575 {
576  return fClass->GetClassSize();
577 }
578 
580 {
581  visitor.VisitClassField(*this);
582 }
583 
584 //------------------------------------------------------------------------------
585 
586 
588  std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
589  : ROOT::Experimental::Detail::RFieldBase(
590  fieldName, "std::vector<" + itemField->GetType() + ">", ENTupleStructure::kCollection, false /* isSimple */)
591  , fItemSize(itemField->GetValueSize()), fNWritten(0)
592 {
593  Attach(std::move(itemField));
594 }
595 
597 {
598  auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
599  return new RFieldVector(newName, std::unique_ptr<Detail::RFieldBase>(newItemField));
600 }
601 
603  auto typedValue = value.Get<std::vector<char>>();
604  R__ASSERT((typedValue->size() % fItemSize) == 0);
605  auto count = typedValue->size() / fItemSize;
606  for (unsigned i = 0; i < count; ++i) {
607  auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
608  fSubFields[0]->Append(itemValue);
609  }
611  fNWritten += count;
612  fColumns[0]->Append(elemIndex);
613 }
614 
616 {
617  auto typedValue = value->Get<std::vector<char>>();
618 
619  ClusterSize_t nItems;
620  RClusterIndex collectionStart;
621  fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
622 
623  typedValue->resize(nItems * fItemSize);
624  for (unsigned i = 0; i < nItems; ++i) {
625  auto itemValue = fSubFields[0]->GenerateValue(typedValue->data() + (i * fItemSize));
626  fSubFields[0]->Read(collectionStart + i, &itemValue);
627  }
628 }
629 
631 {
632  RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
633  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
634  Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
635  fPrincipalColumn = fColumns[0].get();
636 }
637 
639 {
640  return Detail::RFieldValue(this, reinterpret_cast<std::vector<char>*>(where));
641 }
642 
644 {
645  auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
646  R__ASSERT((vec->size() % fItemSize) == 0);
647  auto nItems = vec->size() / fItemSize;
648  for (unsigned i = 0; i < nItems; ++i) {
649  auto itemValue = fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize));
650  fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
651  }
652  vec->~vector();
653  if (!dtorOnly)
654  free(vec);
655 }
656 
658 {
659  return Detail::RFieldValue(true /* captureFlag */, this, where);
660 }
661 
662 std::vector<ROOT::Experimental::Detail::RFieldValue>
664 {
665  auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
666  R__ASSERT((vec->size() % fItemSize) == 0);
667  auto nItems = vec->size() / fItemSize;
668  std::vector<Detail::RFieldValue> result;
669  for (unsigned i = 0; i < nItems; ++i) {
670  result.emplace_back(fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize)));
671  }
672  return result;
673 }
674 
676 {
677  fNWritten = 0;
678 }
679 
681 {
682  visitor.VisitVectorField(*this);
683 }
684 
685 
686 //------------------------------------------------------------------------------
687 
688 
690  : ROOT::Experimental::Detail::RFieldBase(name, "std::vector<bool>", ENTupleStructure::kCollection,
691  false /* isSimple */)
692 {
693  Attach(std::make_unique<RField<bool>>("bool"));
694 }
695 
696 void ROOT::Experimental::RField<std::vector<bool>>::AppendImpl(const Detail::RFieldValue& value) {
697  auto typedValue = value.Get<std::vector<bool>>();
698  auto count = typedValue->size();
699  for (unsigned i = 0; i < count; ++i) {
700  bool bval = (*typedValue)[i];
701  auto itemValue = fSubFields[0]->CaptureValue(&bval);
702  fSubFields[0]->Append(itemValue);
703  }
704  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> elemIndex(&fNWritten);
705  fNWritten += count;
706  fColumns[0]->Append(elemIndex);
707 }
708 
709 void ROOT::Experimental::RField<std::vector<bool>>::ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue* value)
710 {
711  auto typedValue = value->Get<std::vector<bool>>();
712 
713  ClusterSize_t nItems;
714  RClusterIndex collectionStart;
715  fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nItems);
716 
717  typedValue->resize(nItems);
718  for (unsigned i = 0; i < nItems; ++i) {
719  bool bval;
720  auto itemValue = fSubFields[0]->GenerateValue(&bval);
721  fSubFields[0]->Read(collectionStart + i, &itemValue);
722  (*typedValue)[i] = bval;
723  }
724 }
725 
726 void ROOT::Experimental::RField<std::vector<bool>>::GenerateColumnsImpl()
727 {
728  RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
729  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
730  Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
731  fPrincipalColumn = fColumns[0].get();
732 }
733 
734 std::vector<ROOT::Experimental::Detail::RFieldValue>
735 ROOT::Experimental::RField<std::vector<bool>>::SplitValue(const Detail::RFieldValue& value) const
736 {
737  const static bool trueValue = true;
738  const static bool falseValue = false;
739 
740  auto typedValue = value.Get<std::vector<bool>>();
741  auto count = typedValue->size();
742  std::vector<Detail::RFieldValue> result;
743  for (unsigned i = 0; i < count; ++i) {
744  if ((*typedValue)[i])
745  result.emplace_back(fSubFields[0]->CaptureValue(const_cast<bool *>(&trueValue)));
746  else
747  result.emplace_back(fSubFields[0]->CaptureValue(const_cast<bool *>(&falseValue)));
748  }
749  return result;
750 }
751 
752 
753 void ROOT::Experimental::RField<std::vector<bool>>::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
754 {
755  auto vec = static_cast<std::vector<bool>*>(value.GetRawPtr());
756  vec->~vector();
757  if (!dtorOnly)
758  free(vec);
759 }
760 
761 void ROOT::Experimental::RField<std::vector<bool>>::AcceptVisitor(Detail::RFieldVisitor &visitor) const
762 {
763  visitor.VisitVectorBoolField(*this);
764 }
765 
766 
767 //------------------------------------------------------------------------------
768 
769 
771  std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField, std::size_t arrayLength)
772  : ROOT::Experimental::Detail::RFieldBase(
773  fieldName, "std::array<" + itemField->GetType() + "," + std::to_string(arrayLength) + ">",
774  ENTupleStructure::kLeaf, false /* isSimple */, arrayLength)
775  , fItemSize(itemField->GetValueSize()), fArrayLength(arrayLength)
776 {
777  Attach(std::move(itemField));
778 }
779 
781 {
782  auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
783  return new RFieldArray(newName, std::unique_ptr<Detail::RFieldBase>(newItemField), fArrayLength);
784 }
785 
787  auto arrayPtr = value.Get<unsigned char>();
788  for (unsigned i = 0; i < fArrayLength; ++i) {
789  auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
790  fSubFields[0]->Append(itemValue);
791  }
792 }
793 
795 {
796  auto arrayPtr = value->Get<unsigned char>();
797  for (unsigned i = 0; i < fArrayLength; ++i) {
798  auto itemValue = fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
799  fSubFields[0]->Read(globalIndex * fArrayLength + i, &itemValue);
800  }
801 }
802 
804 {
805  auto arrayPtr = value->Get<unsigned char>();
806  for (unsigned i = 0; i < fArrayLength; ++i) {
807  auto itemValue = fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
808  fSubFields[0]->Read(RClusterIndex(clusterIndex.GetClusterId(), clusterIndex.GetIndex() * fArrayLength + i),
809  &itemValue);
810  }
811 }
812 
814 {
815 }
816 
818 {
819  auto arrayPtr = reinterpret_cast<unsigned char *>(where);
820  for (unsigned i = 0; i < fArrayLength; ++i) {
821  fSubFields[0]->GenerateValue(arrayPtr + (i * fItemSize));
822  }
823  return Detail::RFieldValue(true /* captureFlag */, this, where);
824 }
825 
827 {
828  auto arrayPtr = value.Get<unsigned char>();
829  for (unsigned i = 0; i < fArrayLength; ++i) {
830  auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
831  fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
832  }
833  if (!dtorOnly)
834  free(arrayPtr);
835 }
836 
838 {
839  return Detail::RFieldValue(true /* captureFlag */, this, where);
840 }
841 
842 std::vector<ROOT::Experimental::Detail::RFieldValue>
844 {
845  auto arrayPtr = value.Get<unsigned char>();
846  std::vector<Detail::RFieldValue> result;
847  for (unsigned i = 0; i < fArrayLength; ++i) {
848  auto itemValue = fSubFields[0]->CaptureValue(arrayPtr + (i * fItemSize));
849  result.emplace_back(itemValue);
850  }
851  return result;
852 }
853 
855 {
856  visitor.VisitArrayField(*this);
857 }
858 
859 //------------------------------------------------------------------------------
860 
861 #if __cplusplus >= 201703L
862 std::string ROOT::Experimental::RFieldVariant::GetTypeList(const std::vector<Detail::RFieldBase *> &itemFields)
863 {
864  std::string result;
865  for (size_t i = 0; i < itemFields.size(); ++i) {
866  result += itemFields[i]->GetType() + ",";
867  }
868  R__ASSERT(!result.empty()); // there is always at least one variant
869  result.pop_back(); // remove trailing comma
870  return result;
871 }
872 
873 ROOT::Experimental::RFieldVariant::RFieldVariant(
874  std::string_view fieldName, const std::vector<Detail::RFieldBase *> &itemFields)
875  : ROOT::Experimental::Detail::RFieldBase(fieldName,
876  "std::variant<" + GetTypeList(itemFields) + ">", ENTupleStructure::kVariant, false /* isSimple */)
877 {
878  auto nFields = itemFields.size();
879  R__ASSERT(nFields > 0);
880  fNWritten.resize(nFields, 0);
881  for (unsigned int i = 0; i < nFields; ++i) {
882  fMaxItemSize = std::max(fMaxItemSize, itemFields[i]->GetValueSize());
883  fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
884  Attach(std::unique_ptr<Detail::RFieldBase>(itemFields[i]));
885  }
886  fTagOffset = (fMaxItemSize < fMaxAlignment) ? fMaxAlignment : fMaxItemSize;
887 }
888 
889 ROOT::Experimental::Detail::RFieldBase *ROOT::Experimental::RFieldVariant::Clone(std::string_view newName)
890 {
891  auto nFields = fSubFields.size();
892  std::vector<Detail::RFieldBase *> itemFields;
893  for (unsigned i = 0; i < nFields; ++i) {
894  itemFields.emplace_back(fSubFields[i]->Clone(fSubFields[i]->GetName()));
895  }
896  return new RFieldVariant(newName, itemFields);
897 }
898 
899 std::uint32_t ROOT::Experimental::RFieldVariant::GetTag(void *variantPtr) const
900 {
901  auto index = *(reinterpret_cast<char *>(variantPtr) + fTagOffset);
902  return (index < 0) ? 0 : index + 1;
903 }
904 
905 void ROOT::Experimental::RFieldVariant::SetTag(void *variantPtr, std::uint32_t tag) const
906 {
907  auto index = reinterpret_cast<char *>(variantPtr) + fTagOffset;
908  *index = static_cast<char>(tag - 1);
909 }
910 
911 void ROOT::Experimental::RFieldVariant::AppendImpl(const Detail::RFieldValue& value)
912 {
913  auto tag = GetTag(value.GetRawPtr());
914  auto index = 0;
915  if (tag > 0) {
916  auto itemValue = fSubFields[tag - 1]->CaptureValue(value.GetRawPtr());
917  fSubFields[tag - 1]->Append(itemValue);
918  index = fNWritten[tag - 1]++;
919  }
920  RColumnSwitch varSwitch(ClusterSize_t(index), tag);
921  Detail::RColumnElement<RColumnSwitch, EColumnType::kSwitch> elemSwitch(&varSwitch);
922  fColumns[0]->Append(elemSwitch);
923 }
924 
925 void ROOT::Experimental::RFieldVariant::ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value)
926 {
927  RClusterIndex variantIndex;
928  std::uint32_t tag;
929  fPrincipalColumn->GetSwitchInfo(globalIndex, &variantIndex, &tag);
930  R__ASSERT(tag > 0); // TODO(jblomer): deal with invalid variants
931 
932  auto itemValue = fSubFields[tag - 1]->GenerateValue(value->GetRawPtr());
933  fSubFields[tag - 1]->Read(variantIndex, &itemValue);
934  SetTag(value->GetRawPtr(), tag);
935 }
936 
937 void ROOT::Experimental::RFieldVariant::GenerateColumnsImpl()
938 {
939  RColumnModel modelSwitch(EColumnType::kSwitch, false);
940  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
941  Detail::RColumn::Create<RColumnSwitch, EColumnType::kSwitch>(modelSwitch, 0)));
942  fPrincipalColumn = fColumns[0].get();
943 }
944 
945 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVariant::GenerateValue(void *where)
946 {
947  memset(where, 0, GetValueSize());
948  fSubFields[0]->GenerateValue(where);
949  SetTag(where, 1);
950  return Detail::RFieldValue(this, reinterpret_cast<unsigned char *>(where));
951 }
952 
953 void ROOT::Experimental::RFieldVariant::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
954 {
955  auto variantPtr = value.GetRawPtr();
956  auto tag = GetTag(variantPtr);
957  if (tag > 0) {
958  auto itemValue = fSubFields[tag - 1]->CaptureValue(variantPtr);
959  fSubFields[tag - 1]->DestroyValue(itemValue, true /* dtorOnly */);
960  }
961  if (!dtorOnly)
962  free(variantPtr);
963 }
964 
965 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVariant::CaptureValue(void *where)
966 {
967  return Detail::RFieldValue(true /* captureFlag */, this, where);
968 }
969 
970 size_t ROOT::Experimental::RFieldVariant::GetValueSize() const
971 {
972  return fMaxItemSize + fMaxAlignment; // TODO: fix for more than 255 items
973 }
974 
975 void ROOT::Experimental::RFieldVariant::CommitCluster()
976 {
977  std::fill(fNWritten.begin(), fNWritten.end(), 0);
978 }
979 #endif
980 
981 
982 //------------------------------------------------------------------------------
983 
984 
986  std::string_view name,
987  std::shared_ptr<RCollectionNTuple> collectionNTuple,
988  std::unique_ptr<RNTupleModel> collectionModel)
989  : RFieldBase(name, ":Collection:", ENTupleStructure::kCollection, true /* isSimple */)
990  , fCollectionNTuple(collectionNTuple)
991 {
992  for (unsigned i = 0; i < collectionModel->GetRootField()->fSubFields.size(); ++i) {
993  auto& subField = collectionModel->GetRootField()->fSubFields[i];
994  Attach(std::move(subField));
995  }
996 }
997 
998 
1000 {
1001  RColumnModel modelIndex(EColumnType::kIndex, true /* isSorted*/);
1002  fColumns.emplace_back(std::unique_ptr<Detail::RColumn>(
1003  Detail::RColumn::Create<ClusterSize_t, EColumnType::kIndex>(modelIndex, 0)));
1004  fPrincipalColumn = fColumns[0].get();
1005 }
1006 
1007 
1009 {
1010  // TODO(jblomer)
1011  return nullptr;
1012  //auto result = new RFieldCollection(newName, fCollectionNTuple, RNTupleModel::Create());
1013  //for (auto& f : fSubFields) {
1014  // // switch the name prefix for the new parent name
1015  // std::string cloneName = std::string(newName) + f->GetName().substr(GetName().length());
1016  // auto clone = f->Clone(cloneName);
1017  // result->Attach(std::unique_ptr<RFieldBase>(clone));
1018  //}
1019  //return result;
1020 }
1021 
1023  *fCollectionNTuple->GetOffsetPtr() = 0;
1024 }
1025 
The container field for an ntuple model, which itself has no physical representation.
Definition: RField.hxx:251
virtual void VisitClassField(const RFieldClass &field)
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:150
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set ...
Definition: REntry.hxx:42
Holds the static meta-data of a column in a tree
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:1008
virtual void VisitVectorField(const RFieldVector &field)
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 CommitCluster()
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.hxx:206
Returns the available number of logical cores.
Definition: StringConv.hxx:21
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition: RField.cxx:854
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:780
virtual void VisitArrayField(const RFieldArray &field)
virtual void VisitFloatField(const RField< float > &field)
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:999
A field translates read and write calls from/to underlying columns to/from tree values ...
Definition: RField.hxx:60
fill
Definition: fit1_py.py:6
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system...
Definition: RNTupleUtil.hxx:32
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:843
#define R__ASSERT(e)
Definition: TError.h:96
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
Definition: RNTupleUtil.hxx:78
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3646
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Definition: RNTupleUtil.hxx:42
#define f(i)
Definition: RSha256.hxx:104
The generic field for fixed size arrays, which do not need an offset column.
Definition: RField.hxx:333
Type GetType(const std::string &Name)
Definition: Systematics.cxx:34
STL namespace.
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.cxx:1022
#define malloc
Definition: civetweb.c:1536
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:500
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:515
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:615
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:560
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:803
The field for a class with dictionary.
Definition: RField.hxx:268
TClass * GetClass(T *)
Definition: TClass.h:603
Wrap the 32bit integer in a struct in order to avoid template specialization clash with std::uint32_t...
Definition: RNTupleUtil.hxx:45
virtual void VisitField(const Detail::RFieldBase &field)=0
virtual void VisitDoubleField(const RField< double > &field)
void ReadInClusterImpl(const RClusterIndex &clusterIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:526
RFieldArray(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField, std::size_t arrayLength)
Definition: RField.cxx:770
REntry * GenerateEntry()
Generates managed values for the top-level sub fields.
Definition: RField.cxx:291
void ReadGlobalImpl(NTupleSize_t globalIndex, Detail::RFieldValue *value) final
Definition: RField.cxx:794
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:254
static RColumn * Create(const RColumnModel &model, std::uint32_t index)
Definition: RColumn.hxx:70
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:813
Classes with dictionaries that can be inspected by TClass.
Definition: RField.hxx:403
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:643
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
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:200
Common functionality of an ntuple storage for both reading and writing
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:630
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
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition: RField.hxx:357
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:663
virtual void AcceptVisitor(RFieldVisitor &visitor) const
Definition: RField.cxx:232
void Flush() const
Ensure that all received items are written from page buffers to the storage.
Definition: RField.cxx:224
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
RFieldClass(std::string_view fieldName, std::string_view className)
Definition: RField.cxx:484
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition: RField.cxx:574
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:553
RFieldValue GenerateValue()
Generates a tree value of the field type and allocates new initialized memory according to the type...
Definition: RField.cxx:186
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition: RField.cxx:300
The generic field for a (nested) std::vector<Type> except for std::vector<bool>
Definition: RField.hxx:297
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
virtual void ReadGlobalImpl(NTupleSize_t globalIndex, RFieldValue *value)
Definition: RField.cxx:179
Iterates over the sub tree of fields in depth-first search order.
Definition: RField.hxx:115
void GenerateColumnsImpl() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:537
PyObject * fType
size_t GetAlignment() const final
For many types, the alignment requirement is equal to the size; otherwise override.
Definition: RField.hxx:358
Template specializations for concrete C++ types.
Definition: RField.hxx:458
void AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:786
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.cxx:675
void AcceptVisitor(Detail::RFieldVisitor &visitor) const override
Definition: RField.cxx:579
int type
Definition: TGX11.cxx:120
#define free
Definition: civetweb.c:1539
virtual void AppendImpl(const RFieldValue &value)
Operations on values of complex types, e.g.
Definition: RField.cxx:175
virtual void VisitRootField(const RFieldRoot &field)
std::vector< const RFieldBase * > GetSubFields() const
Definition: RField.cxx:214
virtual void VisitBoolField(const RField< bool > &field)
RClusterSize ClusterSize_t
Definition: RNTupleUtil.hxx:57
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
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:657
void AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:602
void Attach(std::unique_ptr< Detail::RFieldBase > child)
Add a new subfield to the list of nested fields.
Definition: RField.cxx:205
RFieldBase * Clone(std::string_view newName)
Definition: RField.cxx:280
DescriptorId_t GetClusterId() const
void AcceptVisitor(Detail::RFieldVisitor &visitor) const final
Definition: RField.cxx:680
RFieldVector(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition: RField.cxx:587
void AppendImpl(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:505
Abstract base class for classes implementing the visitor design pattern.
ClusterSize_t::ValueType GetIndex() const
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:837
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Definition: RNTupleUtil.hxx:82
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:596
char name[80]
Definition: TGX11.cxx:109
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:546
RFieldCollection(std::string_view name, std::shared_ptr< RCollectionNTuple > collectionNTuple, std::unique_ptr< RNTupleModel > collectionModel)
Definition: RField.cxx:985
virtual void GenerateColumnsImpl()=0
Creates the backing columns corresponsing to the field type and name.
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:826
static void Connect(DescriptorId_t fieldId, RPageStorage &pageStorage, RFieldBase &field)
Definition: RField.cxx:76