Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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 
76 void ROOT::Experimental::Detail::RFieldFuse::Connect(DescriptorId_t fieldId, RPageStorage &pageStorage, RFieldBase &field)
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 
88 ROOT::Experimental::Detail::RFieldBase::RFieldBase(
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 
95 ROOT::Experimental::Detail::RFieldBase::~RFieldBase()
96 {
97 }
98 
99 ROOT::Experimental::Detail::RFieldBase*
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 
175 void ROOT::Experimental::Detail::RFieldBase::DoAppend(const ROOT::Experimental::Detail::RFieldValue& /*value*/) {
176  R__ASSERT(false);
177 }
178 
179 void ROOT::Experimental::Detail::RFieldBase::DoReadGlobal(
180  ROOT::Experimental::NTupleSize_t /*index*/,
181  RFieldValue* /*value*/)
182 {
183  R__ASSERT(false);
184 }
185 
186 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::Detail::RFieldBase::GenerateValue()
187 {
188  void *where = malloc(GetValueSize());
189  R__ASSERT(where != nullptr);
190  return GenerateValue(where);
191 }
192 
193 void ROOT::Experimental::Detail::RFieldBase::DestroyValue(const RFieldValue &value, bool dtorOnly)
194 {
195  if (!dtorOnly)
196  free(value.GetRawPtr());
197 }
198 
199 void ROOT::Experimental::Detail::RFieldBase::Attach(
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 
207 void ROOT::Experimental::Detail::RFieldBase::Flush() const
208 {
209  for (auto& column : fColumns) {
210  column->Flush();
211  }
212 }
213 
214 void ROOT::Experimental::Detail::RFieldBase::TraverseVisitor(RNTupleVisitor &visitor, int level) const
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 
224 void ROOT::Experimental::Detail::RFieldBase::AcceptVisitor(Detail::RNTupleVisitor &visitor, int level) const
225 {
226  visitor.VisitField(*this, level);
227 }
228 
229 ROOT::Experimental::Detail::RFieldBase::RIterator ROOT::Experimental::Detail::RFieldBase::begin()
230 {
231  if (fSubFields.empty()) return RIterator(this, -1);
232  return RIterator(this->fSubFields[0].get(), 0);
233 }
234 
235 ROOT::Experimental::Detail::RFieldBase::RIterator ROOT::Experimental::Detail::RFieldBase::end()
236 {
237  return RIterator(this, -1);
238 }
239 
240 
241 //-----------------------------------------------------------------------------
242 
243 
244 void ROOT::Experimental::Detail::RFieldBase::RIterator::Advance()
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 
270 ROOT::Experimental::Detail::RFieldBase *ROOT::Experimental::RFieldRoot::Clone(std::string_view /*newName*/)
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 
281 ROOT::Experimental::REntry* ROOT::Experimental::RFieldRoot::GenerateEntry()
282 {
283  auto entry = new REntry();
284  for (auto& f : fSubFields) {
285  entry->AddValue(f->GenerateValue());
286  }
287  return entry;
288 }
289 
290 void ROOT::Experimental::RFieldRoot::AcceptVisitor(Detail::RNTupleVisitor &visitor, int level) const
291 {
292  visitor.VisitRootField(*this, level);
293 }
294 
295 
296 //------------------------------------------------------------------------------
297 
298 
299 void ROOT::Experimental::RField<ROOT::Experimental::ClusterSize_t>::DoGenerateColumns()
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 
309 void ROOT::Experimental::RField<std::uint8_t>::DoGenerateColumns()
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 
321 void ROOT::Experimental::RField<bool>::DoGenerateColumns()
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 
333 void ROOT::Experimental::RField<float>::DoGenerateColumns()
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 
343 void ROOT::Experimental::RField<double>::DoGenerateColumns()
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 
354 void ROOT::Experimental::RField<std::int32_t>::DoGenerateColumns()
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 
364 void ROOT::Experimental::RField<std::uint32_t>::DoGenerateColumns()
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 
374 void ROOT::Experimental::RField<std::uint64_t>::DoGenerateColumns()
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 
385 void ROOT::Experimental::RField<std::string>::DoGenerateColumns()
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 
397 void ROOT::Experimental::RField<std::string>::DoAppend(const ROOT::Experimental::Detail::RFieldValue& value)
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 
407 void ROOT::Experimental::RField<std::string>::DoReadGlobal(
408  ROOT::Experimental::NTupleSize_t globalIndex, ROOT::Experimental::Detail::RFieldValue *value)
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 
419 void ROOT::Experimental::RField<std::string>::CommitCluster()
420 {
421  fIndex = 0;
422 }
423 
424 
425 //------------------------------------------------------------------------------
426 
427 
428 ROOT::Experimental::RFieldClass::RFieldClass(std::string_view fieldName, std::string_view className)
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  }
435  TIter next(fClass->GetListOfDataMembers());
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 
444 ROOT::Experimental::Detail::RFieldBase* ROOT::Experimental::RFieldClass::Clone(std::string_view newName)
445 {
446  return new RFieldClass(newName, GetType());
447 }
448 
449 void ROOT::Experimental::RFieldClass::DoAppend(const Detail::RFieldValue& value) {
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 
459 void ROOT::Experimental::RFieldClass::DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value)
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 
470 void ROOT::Experimental::RFieldClass::DoReadInCluster(const RClusterIndex &clusterIndex, Detail::RFieldValue *value)
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 
481 void ROOT::Experimental::RFieldClass::DoGenerateColumns()
482 {
483 }
484 
485 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldClass::GenerateValue(void* where)
486 {
487  return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
488 }
489 
490 void ROOT::Experimental::RFieldClass::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
491 {
492  fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
493  if (!dtorOnly)
494  free(value.GetRawPtr());
495 }
496 
497 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldClass::CaptureValue(void* where)
498 {
499  return Detail::RFieldValue(true /* captureFlat */, this, where);
500 }
501 
502 size_t ROOT::Experimental::RFieldClass::GetValueSize() const
503 {
504  return fClass->GetClassSize();
505 }
506 
507 
508 //------------------------------------------------------------------------------
509 
510 
511 ROOT::Experimental::RFieldVector::RFieldVector(
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 
520 ROOT::Experimental::Detail::RFieldBase* ROOT::Experimental::RFieldVector::Clone(std::string_view newName)
521 {
522  auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
523  return new RFieldVector(newName, std::unique_ptr<Detail::RFieldBase>(newItemField));
524 }
525 
526 void ROOT::Experimental::RFieldVector::DoAppend(const Detail::RFieldValue& value) {
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  }
534  Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> elemIndex(&fNWritten);
535  fNWritten += count;
536  fColumns[0]->Append(elemIndex);
537 }
538 
539 void ROOT::Experimental::RFieldVector::DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value)
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 
554 void ROOT::Experimental::RFieldVector::DoGenerateColumns()
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 
562 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVector::GenerateValue(void* where)
563 {
564  return Detail::RFieldValue(this, reinterpret_cast<std::vector<char>*>(where));
565 }
566 
567 void ROOT::Experimental::RFieldVector::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
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 
581 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVector::CaptureValue(void* where)
582 {
583  return Detail::RFieldValue(true /* captureFlag */, this, where);
584 }
585 
586 void ROOT::Experimental::RFieldVector::CommitCluster()
587 {
588  fNWritten = 0;
589 }
590 
591 
592 //------------------------------------------------------------------------------
593 
594 
595 ROOT::Experimental::RField<std::vector<bool>>::RField(std::string_view name)
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 
602 void 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 
615 void 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 
632 void 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 
640 void 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 
652 ROOT::Experimental::RFieldArray::RFieldArray(
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 
662 ROOT::Experimental::Detail::RFieldBase *ROOT::Experimental::RFieldArray::Clone(std::string_view newName)
663 {
664  auto newItemField = fSubFields[0]->Clone(fSubFields[0]->GetName());
665  return new RFieldArray(newName, std::unique_ptr<Detail::RFieldBase>(newItemField), fArrayLength);
666 }
667 
668 void ROOT::Experimental::RFieldArray::DoAppend(const Detail::RFieldValue& value) {
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 
676 void ROOT::Experimental::RFieldArray::DoReadGlobal(NTupleSize_t globalIndex, Detail::RFieldValue *value)
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 
685 void ROOT::Experimental::RFieldArray::DoReadInCluster(const RClusterIndex &clusterIndex, Detail::RFieldValue *value)
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 
695 void ROOT::Experimental::RFieldArray::DoGenerateColumns()
696 {
697 }
698 
699 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldArray::GenerateValue(void *where)
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 
708 void ROOT::Experimental::RFieldArray::DestroyValue(const Detail::RFieldValue& value, bool dtorOnly)
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 
719 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldArray::CaptureValue(void *where)
720 {
721  return Detail::RFieldValue(true /* captureFlag */, this, where);
722 }
723 
724 
725 //------------------------------------------------------------------------------
726 
727 #if __cplusplus >= 201703L
728 std::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 
739 ROOT::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 
755 ROOT::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 
765 std::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 
771 void 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 
777 void 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 
791 void 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 
803 void 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 
811 ROOT::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 
819 void 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 
831 ROOT::Experimental::Detail::RFieldValue ROOT::Experimental::RFieldVariant::CaptureValue(void *where)
832 {
833  return Detail::RFieldValue(true /* captureFlag */, this, where);
834 }
835 
836 size_t ROOT::Experimental::RFieldVariant::GetValueSize() const
837 {
838  return fMaxItemSize + fMaxAlignment; // TODO: fix for more than 255 items
839 }
840 
841 void ROOT::Experimental::RFieldVariant::CommitCluster()
842 {
843  std::fill(fNWritten.begin(), fNWritten.end(), 0);
844 }
845 #endif
846 
847 
848 //------------------------------------------------------------------------------
849 
850 
851 ROOT::Experimental::RFieldCollection::RFieldCollection(
852  std::string_view name,
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 
865 void ROOT::Experimental::RFieldCollection::DoGenerateColumns()
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 
874 ROOT::Experimental::Detail::RFieldBase* ROOT::Experimental::RFieldCollection::Clone(std::string_view /*newName*/)
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 
888 void ROOT::Experimental::RFieldCollection::CommitCluster() {
889  *fCollectionNTuple->GetOffsetPtr() = 0;
890 }
891