Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleModel.cxx
Go to the documentation of this file.
1/// \file RNTupleModel.cxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2018-10-15
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#include <ROOT/RError.hxx>
14#include <ROOT/RField.hxx>
15#include <ROOT/RFieldToken.hxx>
16#include <ROOT/RNTupleModel.hxx>
17#include <ROOT/RNTupleUtils.hxx>
19#include <ROOT/StringUtils.hxx>
20
21#include <atomic>
22#include <cstdlib>
23#include <memory>
24#include <utility>
25
26namespace {
27std::uint64_t GetNewModelId()
28{
29 static std::atomic<std::uint64_t> gLastModelId = 0;
30 return ++gLastModelId;
31}
32} // anonymous namespace
33
35{
36 if (model.IsExpired()) {
37 throw RException(R__FAIL("invalid use of expired model"));
38 }
39 return *model.fFieldZero;
40}
41
43{
44 if (model.IsExpired()) {
45 throw RException(R__FAIL("invalid use of expired model"));
46 }
47 return *model.fProjectedFields;
48}
49
55
56//------------------------------------------------------------------------------
57
60{
61 auto source = fieldMap.at(target);
62
63 if (!target->GetColumnRepresentatives()[0].empty()) {
64 const auto representative = target->GetColumnRepresentatives()[0][0];
65 // If the user is trying to add a projected field upon which they called SetTruncated() or SetQuantized(),
66 // they probably have the wrong expectations about what should happen. Warn them about it.
69 << "calling SetQuantized() or SetTruncated() on a projected field has no effect, as the on-disk "
70 "representation of the value is decided by the projection source field. Reading back the field will "
71 "yield the correct values, but the value range and bits of precision you set on the projected field "
72 "will be ignored.";
73 }
74 }
75
76 const bool hasCompatibleStructure = (source->GetStructure() == target->GetStructure()) ||
77 ((source->GetStructure() == ROOT::ENTupleStructure::kCollection) &&
78 dynamic_cast<const ROOT::RCardinalityField *>(target));
80 return R__FAIL("field mapping structural mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
81 if ((source->GetStructure() == ROOT::ENTupleStructure::kPlain) ||
82 (source->GetStructure() == ROOT::ENTupleStructure::kStreamer)) {
83 if (target->GetTypeName() != source->GetTypeName())
84 return R__FAIL("field mapping type mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
85 }
86
87 auto fnHasArrayParent = [](const ROOT::RFieldBase &f) -> bool {
88 auto parent = f.GetParent();
89 while (parent) {
90 if (parent->GetNRepetitions() > 0)
91 return true;
92 parent = parent->GetParent();
93 }
94 return false;
95 };
97 return R__FAIL("unsupported field mapping across fixed-size arrays");
98 }
99
100 // We support projections only across records and collections. In the following, we check that the projected
101 // field is on the same path of collection fields in the field tree than the source field.
102
103 // Finds the first non-record parent field of the input field
104 auto fnBreakPoint = [](const ROOT::RFieldBase *f) -> const ROOT::RFieldBase * {
105 auto parent = f->GetParent();
106 while (parent) {
107 if ((parent->GetStructure() != ROOT::ENTupleStructure::kRecord) &&
108 (parent->GetStructure() != ROOT::ENTupleStructure::kPlain)) {
109 return parent;
110 }
111 parent = parent->GetParent();
112 }
113 // We reached the zero field
114 return nullptr;
115 };
116
117 // If source or target has a variant or reference as a parent, error out
120 return R__FAIL("unsupported field mapping (source structure)");
123 return R__FAIL("unsupported field mapping (target structure)");
124
126 // Source and target have no collections as parent
127 return RResult<void>::Success();
128 }
131 // Source and target are children of the same collection
132 return RResult<void>::Success();
133 }
134 if (auto it = fieldMap.find(targetBreakPoint); it != fieldMap.end() && it->second == sourceBreakPoint) {
135 // The parent collection of parent is mapped to the parent collection of the source
136 return RResult<void>::Success();
137 }
138 // Source and target are children of different collections
139 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
140 }
141
142 // Either source or target have no collection as a parent, but the other one has; that doesn't fit
143 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
144}
145
147ROOT::Internal::RProjectedFields::Add(std::unique_ptr<ROOT::RFieldBase> field, const FieldMap_t &fieldMap)
148{
149 auto result = EnsureValidMapping(field.get(), fieldMap);
150 if (!result)
151 return R__FORWARD_ERROR(result);
152 for (const auto &f : *field) {
153 result = EnsureValidMapping(&f, fieldMap);
154 if (!result)
155 return R__FORWARD_ERROR(result);
156 }
157
158 fFieldMap.insert(fieldMap.begin(), fieldMap.end());
159 fFieldZero->Attach(std::move(field));
160 return RResult<void>::Success();
161}
162
164{
165 if (auto it = fFieldMap.find(target); it != fFieldMap.end())
166 return it->second;
167 return nullptr;
168}
169
170std::unique_ptr<ROOT::Internal::RProjectedFields>
172{
173 auto cloneFieldZero =
174 std::unique_ptr<ROOT::RFieldZero>(static_cast<ROOT::RFieldZero *>(fFieldZero->Clone("").release()));
175 auto clone = std::unique_ptr<RProjectedFields>(new RProjectedFields(std::move(cloneFieldZero)));
176 clone->fModel = &newModel;
177 // TODO(jblomer): improve quadratic search to re-wire the field mappings given the new model and the cloned
178 // projected fields. Not too critical as we generally expect a limited number of projected fields
179 for (const auto &[k, v] : fFieldMap) {
180 for (const auto &f : clone->GetFieldZero()) {
181 if (f.GetQualifiedFieldName() == k->GetQualifiedFieldName()) {
182 clone->fFieldMap[&f] = &newModel.GetConstField(v->GetQualifiedFieldName());
183 break;
184 }
185 }
186 }
187 return clone;
188}
189
191 : fWriter(writer), fOpenChangeset(fWriter.GetUpdatableModel())
192{
193}
194
196{
197 // If we made any changes, we should commit them because the model was already altered.
198 // Otherwise, we _do not_ commit -- it may be that the referenced model is already expired if the
199 // corresponding writer is already destructed.
200 if (fOpenChangeset.IsEmpty())
201 return;
202
203 try {
205 } catch (std::runtime_error &e) {
206 Fatal("RNTupleModel::RUpdater::~RUpdater", "cannot commit model changes during updater destructor: %s", e.what());
207 }
208}
209
211{
212 fOpenChangeset.fModel.Unfreeze();
213 // We set the model ID to zero until CommitUpdate(). That prevents calls to RNTupleWriter::Fill() in the middle
214 // of updates
215 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
216}
217
219{
220 fOpenChangeset.fModel.Freeze();
221 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
222 if (fOpenChangeset.IsEmpty())
223 return;
224 Internal::RNTupleModelChangeset toCommit{fOpenChangeset.fModel};
225 std::swap(fOpenChangeset.fAddedFields, toCommit.fAddedFields);
226 std::swap(fOpenChangeset.fAddedProjectedFields, toCommit.fAddedProjectedFields);
227 fWriter.GetSink().UpdateSchema(toCommit, fWriter.GetNEntries());
228}
229
231{
232 if (parentName.empty())
233 return nullptr;
234
235 if (!fModel.IsBare()) {
236 throw RException(R__FAIL("invalid attempt to late-model-extend an untyped record of a non-bare model"));
237 }
238
239 auto &parentField = fModel.GetMutableField(parentName);
240 auto parentRecord = dynamic_cast<ROOT::RRecordField *>(&parentField);
241 if (!parentRecord || !parentRecord->GetTypeName().empty()) {
242 throw RException(
243 R__FAIL("invalid attempt to extend a field that is not an untyped record: " + std::string(parentName)));
244 }
245
246 auto itr = parentRecord->GetParent();
247 while (itr) {
248 if (typeid(*itr) == typeid(RFieldZero))
249 break;
250
251 if (!dynamic_cast<const ROOT::RRecordField *>(itr)) {
252 throw RException(R__FAIL("invalid attempt to extend an untyped record that has a non-record parent: " +
253 std::string(parentName)));
254 }
255
256 itr = itr->GetParent();
257 }
258
259 return parentRecord;
260}
261
262void ROOT::Internal::RNTupleModelChangeset::AddField(std::unique_ptr<ROOT::RFieldBase> field,
263 std::string_view parentName)
264{
265 auto fieldp = field.get();
266 if (auto parent = GetParentRecordField(parentName)) {
267 Internal::AddItemToRecord(*parent, std::move(field));
268 } else {
269 fModel.AddField(std::move(field));
270 }
271 fAddedFields.emplace_back(fieldp);
272}
273
274void ROOT::RNTupleModel::RUpdater::AddField(std::unique_ptr<ROOT::RFieldBase> field, std::string_view parentName)
275{
276 fOpenChangeset.AddField(std::move(field), parentName);
277}
278
282{
283 auto fieldp = field.get();
284 auto result = fModel.AddProjectedField(std::move(field), mapping);
285 if (result)
286 fAddedProjectedFields.emplace_back(fieldp);
288}
289
292{
293 return R__FORWARD_RESULT(fOpenChangeset.AddProjectedField(std::move(field), mapping));
294}
295
297{
299 if (!nameValid) {
300 nameValid.Throw();
301 }
302 if (fieldName.empty()) {
303 throw RException(R__FAIL("name cannot be empty string \"\""));
304 }
305 auto fieldNameStr = std::string(fieldName);
306 if (fFieldNames.count(fieldNameStr) > 0)
307 throw RException(R__FAIL("field name '" + fieldNameStr + "' already exists in NTuple model"));
308}
309
311{
312 if (IsFrozen())
313 throw RException(R__FAIL("invalid attempt to modify frozen model"));
314}
315
317{
318 if (IsBare())
319 throw RException(R__FAIL("invalid attempt to use default entry of bare model"));
320}
321
322ROOT::RNTupleModel::RNTupleModel(std::unique_ptr<ROOT::RFieldZero> fieldZero)
324{
325}
326
327std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::CreateBare()
328{
329 return CreateBare(std::make_unique<ROOT::RFieldZero>());
330}
331
332std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::CreateBare(std::unique_ptr<ROOT::RFieldZero> fieldZero)
333{
334 auto model = std::unique_ptr<RNTupleModel>(new RNTupleModel(std::move(fieldZero)));
335 model->fProjectedFields = std::make_unique<Internal::RProjectedFields>(*model);
336 return model;
337}
338
339std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Create()
340{
341 return Create(std::make_unique<ROOT::RFieldZero>());
342}
343
344std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Create(std::unique_ptr<ROOT::RFieldZero> fieldZero)
345{
346 auto model = CreateBare(std::move(fieldZero));
347 model->fDefaultEntry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(model->fModelId, model->fSchemaId));
348 return model;
349}
350
351std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Clone() const
352{
353 auto cloneModel = std::unique_ptr<RNTupleModel>(new RNTupleModel(
354 std::unique_ptr<ROOT::RFieldZero>(static_cast<ROOT::RFieldZero *>(fFieldZero->Clone("").release()))));
355 cloneModel->fModelId = GetNewModelId();
356 // For a frozen model, we can keep the schema id because adding new fields is forbidden. It is reset in Unfreeze()
357 // if called by the user.
358 if (IsFrozen()) {
359 cloneModel->fSchemaId = fSchemaId;
360 } else {
361 cloneModel->fSchemaId = cloneModel->fModelId;
362 }
363 cloneModel->fModelState = (fModelState == EState::kExpired) ? EState::kFrozen : fModelState;
364 cloneModel->fFieldNames = fFieldNames;
365 cloneModel->fDescription = fDescription;
366 cloneModel->fProjectedFields = fProjectedFields->Clone(*cloneModel);
367 cloneModel->fRegisteredSubfields = fRegisteredSubfields;
368 if (fDefaultEntry) {
369 cloneModel->fDefaultEntry =
370 std::unique_ptr<ROOT::REntry>(new ROOT::REntry(cloneModel->fModelId, cloneModel->fSchemaId));
371 for (const auto &f : cloneModel->fFieldZero->GetMutableSubfields()) {
372 cloneModel->fDefaultEntry->AddValue(f->CreateValue());
373 }
374 for (const auto &f : cloneModel->fRegisteredSubfields) {
375 cloneModel->AddSubfield(f, *cloneModel->fDefaultEntry);
376 }
377 }
378 return cloneModel;
379}
380
382{
383 if (fieldName.empty())
384 return nullptr;
385
386 auto *field = static_cast<ROOT::RFieldBase *>(fFieldZero.get());
387 for (auto subfieldName : ROOT::Split(fieldName, ".")) {
388 const auto subfields = field->GetMutableSubfields();
389 auto it = std::find_if(subfields.begin(), subfields.end(),
390 [&](const auto *f) { return f->GetFieldName() == subfieldName; });
391 if (it != subfields.end()) {
392 field = *it;
393 } else {
394 field = nullptr;
395 break;
396 }
397 }
398
399 return field;
400}
401
402void ROOT::RNTupleModel::AddField(std::unique_ptr<ROOT::RFieldBase> field)
403{
404 EnsureNotFrozen();
405 if (!field)
406 throw RException(R__FAIL("null field"));
407 EnsureValidFieldName(field->GetFieldName());
408
409 if (fDefaultEntry)
410 fDefaultEntry->AddValue(field->CreateValue());
411 fFieldNames.insert(field->GetFieldName());
412 fFieldZero->Attach(std::move(field));
413}
414
416 bool initializeValue) const
417{
418 auto field = FindField(qualifiedFieldName);
419 if (initializeValue)
420 entry.AddValue(field->CreateValue());
421 else
422 entry.AddValue(field->BindValue(nullptr));
423}
424
426{
427 if (qualifiedFieldName.empty())
428 throw RException(R__FAIL("no field name provided"));
429
430 if (fFieldNames.find(std::string(qualifiedFieldName)) != fFieldNames.end()) {
431 throw RException(
432 R__FAIL("cannot register top-level field \"" + std::string(qualifiedFieldName) + "\" as a subfield"));
433 }
434
435 if (fRegisteredSubfields.find(std::string(qualifiedFieldName)) != fRegisteredSubfields.end())
436 throw RException(R__FAIL("subfield \"" + std::string(qualifiedFieldName) + "\" already registered"));
437
438 EnsureNotFrozen();
439
440 auto *field = FindField(qualifiedFieldName);
441 if (!field) {
442 throw RException(R__FAIL("could not find subfield \"" + std::string(qualifiedFieldName) + "\" in model"));
443 }
444
445 auto parent = field->GetParent();
446 while (parent && !parent->GetFieldName().empty()) {
447 if (parent->GetStructure() == ROOT::ENTupleStructure::kCollection || parent->GetNRepetitions() > 0 ||
448 parent->GetStructure() == ROOT::ENTupleStructure::kVariant) {
449 throw RException(R__FAIL(
450 "registering a subfield as part of a collection, fixed-sized array or std::variant is not supported"));
451 }
452 parent = parent->GetParent();
453 }
454
455 if (fDefaultEntry)
456 AddSubfield(qualifiedFieldName, *fDefaultEntry);
457 fRegisteredSubfields.emplace(qualifiedFieldName);
458}
459
462{
463 EnsureNotFrozen();
464 if (!field)
465 return R__FAIL("null field");
466 auto fieldName = field->GetFieldName();
467
469 auto sourceField = FindField(mapping(fieldName));
470 if (!sourceField)
471 return R__FAIL("no such field: " + mapping(fieldName));
472 fieldMap[field.get()] = sourceField;
473 for (const auto &subField : *field) {
474 sourceField = FindField(mapping(subField.GetQualifiedFieldName()));
475 if (!sourceField)
476 return R__FAIL("no such field: " + mapping(subField.GetQualifiedFieldName()));
478 }
479
480 EnsureValidFieldName(fieldName);
481 auto result = fProjectedFields->Add(std::move(field), fieldMap);
482 if (!result) {
483 return R__FORWARD_ERROR(result);
484 }
485 fFieldNames.insert(fieldName);
486 return RResult<void>::Success();
487}
488
490{
491 if (IsFrozen())
492 throw RException(R__FAIL("invalid attempt to get mutable zero field of frozen model"));
493 return *fFieldZero;
494}
495
497{
498 if (IsFrozen())
499 throw RException(R__FAIL("invalid attempt to get mutable field of frozen model"));
500 auto f = FindField(fieldName);
501 if (!f)
502 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
503
504 return *f;
505}
506
508{
509 auto f = FindField(fieldName);
510 if (!f)
511 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
512
513 return *f;
514}
515
517{
518 EnsureNotBare();
519 return *fDefaultEntry;
520}
521
523{
524 if (!IsFrozen())
525 throw RException(R__FAIL("invalid attempt to get default entry of unfrozen model"));
526 EnsureNotBare();
527 return *fDefaultEntry;
528}
529
530std::unique_ptr<ROOT::REntry> ROOT::RNTupleModel::CreateEntry() const
531{
532 switch (fModelState) {
533 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
534 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
535 case EState::kFrozen: break;
536 }
537
538 auto entry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(fModelId, fSchemaId));
539 for (const auto &f : fFieldZero->GetMutableSubfields()) {
540 entry->AddValue(f->CreateValue());
541 }
542 for (const auto &f : fRegisteredSubfields) {
543 AddSubfield(f, *entry);
544 }
545 return entry;
546}
547
548std::unique_ptr<ROOT::REntry> ROOT::RNTupleModel::CreateBareEntry() const
549{
550 switch (fModelState) {
551 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
552 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
553 case EState::kFrozen: break;
554 }
555
556 auto entry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(fModelId, fSchemaId));
557 for (const auto &f : fFieldZero->GetMutableSubfields()) {
558 entry->AddValue(f->BindValue(nullptr));
559 }
560 for (const auto &f : fRegisteredSubfields) {
561 AddSubfield(f, *entry, false /* initializeValue */);
562 }
563 return entry;
564}
565
566std::unique_ptr<ROOT::Detail::RRawPtrWriteEntry> ROOT::RNTupleModel::CreateRawPtrWriteEntry() const
567{
568 switch (fModelState) {
569 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
570 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
571 case EState::kFrozen: break;
572 }
573
574 auto entry = std::unique_ptr<Detail::RRawPtrWriteEntry>(new Detail::RRawPtrWriteEntry(fModelId, fSchemaId));
575 for (const auto &f : fFieldZero->GetMutableSubfields()) {
576 entry->AddField(*f);
577 }
578 // fRegisteredSubfields are not relevant for writing
579 return entry;
580}
581
583{
584 const auto &topLevelFields = fFieldZero->GetConstSubfields();
585 auto it = std::find_if(topLevelFields.begin(), topLevelFields.end(),
586 [&fieldName](const ROOT::RFieldBase *f) { return f->GetFieldName() == fieldName; });
587
588 if (it == topLevelFields.end()) {
589 throw RException(R__FAIL("invalid field name: " + std::string(fieldName)));
590 }
591 return ROOT::RFieldToken(std::distance(topLevelFields.begin(), it), fSchemaId);
592}
593
595{
596 switch (fModelState) {
597 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create bulk of unfrozen model"));
598 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create bulk of expired model"));
599 case EState::kFrozen: break;
600 }
601
602 auto f = FindField(fieldName);
603 if (!f)
604 throw RException(R__FAIL("no such field: " + std::string(fieldName)));
605 return f->CreateBulk();
606}
607
609{
610 switch (fModelState) {
611 case EState::kExpired: return;
612 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to expire unfrozen model"));
613 case EState::kFrozen: break;
614 }
615
616 // Ensure that Fill() does not work anymore
617 fModelId = 0;
618 fModelState = EState::kExpired;
619}
620
622{
623 switch (fModelState) {
624 case EState::kBuilding: return;
625 case EState::kExpired: throw RException(R__FAIL("invalid attempt to unfreeze expired model"));
626 case EState::kFrozen: break;
627 }
628
629 fModelId = GetNewModelId();
630 fSchemaId = fModelId;
631 if (fDefaultEntry) {
632 fDefaultEntry->fModelId = fModelId;
633 fDefaultEntry->fSchemaId = fSchemaId;
634 }
635 fModelState = EState::kBuilding;
636}
637
639{
640 if (fModelState == EState::kExpired)
641 throw RException(R__FAIL("invalid attempt to freeze expired model"));
642
643 fModelState = EState::kFrozen;
644}
645
647{
648 EnsureNotFrozen();
649 fDescription = std::string(description);
650}
651
653{
654 std::size_t bytes = 0;
655 std::size_t minPageBufferSize = 0;
656
657 // Start with the size of the page buffers used to fill a persistent sink
658 std::size_t nColumns = 0;
659 for (auto &&field : *fFieldZero) {
660 for (const auto &r : field.GetColumnRepresentatives()) {
661 nColumns += r.size();
662 minPageBufferSize += r.size() * options.GetInitialUnzippedPageSize();
663 }
664 }
665 bytes = std::min(options.GetPageBufferBudget(), nColumns * options.GetMaxUnzippedPageSize());
666
667 // If using buffered writing with RPageSinkBuf, we create a clone of the model and keep at least
668 // the compressed pages in memory.
669 if (options.GetUseBufferedWrite()) {
671 // Use the target cluster size as an estimate for all compressed pages combined.
673 int compression = options.GetCompression();
675 // With IMT, compression happens asynchronously which means that the uncompressed pages also stay around. Use a
676 // compression factor of 2x as a very rough estimate.
677 bytes += 2 * options.GetApproxZippedClusterSize();
678 }
679 }
680
681 return bytes;
682}
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
Definition RError.hxx:326
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:324
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:322
#define R__LOG_WARNING(...)
Definition RLogger.hxx:357
#define f(i)
Definition RSha256.hxx:104
#define e(i)
Definition RSha256.hxx:103
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
void Fatal(const char *location, const char *msgfmt,...)
Use this function in case of a fatal error. It will abort the program.
Definition TError.cxx:267
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t bytes
A container of const raw pointers, corresponding to a row in the data set.
Container for the projected fields of an RNTupleModel.
const ROOT::RFieldBase * GetSourceField(const ROOT::RFieldBase *target) const
std::unordered_map< const ROOT::RFieldBase *, const ROOT::RFieldBase * > FieldMap_t
The map keys are the projected target fields, the map values are the backing source fields Note that ...
RResult< void > Add(std::unique_ptr< ROOT::RFieldBase > field, const FieldMap_t &fieldMap)
Adds a new projected field.
std::unique_ptr< RProjectedFields > Clone(const RNTupleModel &newModel) const
Clones this container and all the projected fields it owns.
RResult< void > EnsureValidMapping(const ROOT::RFieldBase *target, const FieldMap_t &fieldMap)
Asserts that the passed field is a valid target of the source field provided in the field map.
An artificial field that transforms an RNTuple column that contains the offset of collections into co...
Definition RField.hxx:346
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:54
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Points to an array of objects with RNTuple I/O support, used for bulk reading.
A field translates read and write calls from/to underlying columns to/from tree values.
const RFieldBase * GetParent() const
A field token identifies a (sub)field in an entry.
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:58
void CommitUpdate()
Commit changes since the last call to BeginUpdate().
RUpdater(ROOT::RNTupleWriter &writer)
void AddField(std::unique_ptr< ROOT::RFieldBase > field, std::string_view parentName="")
RResult< void > AddProjectedField(std::unique_ptr< ROOT::RFieldBase > field, const FieldMappingFunc_t &mapping)
void BeginUpdate()
Begin a new set of alterations to the underlying model.
The RNTupleModel encapulates the schema of an RNTuple.
std::unique_ptr< REntry > CreateEntry() const
Creates a new entry with default values for each field.
RNTupleModel(std::unique_ptr< ROOT::RFieldZero > fieldZero)
void AddSubfield(std::string_view fieldName, ROOT::REntry &entry, bool initializeValue=true) const
Add a subfield to the provided entry.
std::unique_ptr< RNTupleModel > Clone() const
std::uint64_t fModelId
Every model has a unique ID to distinguish it from other models.
void EnsureValidFieldName(std::string_view fieldName)
Checks that user-provided field names are valid in the context of this RNTupleModel.
ROOT::RFieldZero & GetMutableFieldZero()
Retrieves the field zero of this model, i.e.
std::size_t EstimateWriteMemoryUsage(const ROOT::RNTupleWriteOptions &options=ROOT::RNTupleWriteOptions()) const
Estimate the memory usage for this model during writing.
void Unfreeze()
Transitions an RNTupleModel from the frozen state back to the building state, invalidating all previo...
REntry & GetDefaultEntry()
Retrieves the default entry of this model.
ROOT::RFieldBase::RBulkValues CreateBulk(std::string_view fieldName) const
Calls the given field's CreateBulk() method. Throws an RException if no field with the given name exi...
void EnsureNotFrozen() const
Throws an RException if fFrozen is true.
void AddField(std::unique_ptr< ROOT::RFieldBase > field)
Adds a field whose type is not known at compile time.
static std::unique_ptr< RNTupleModel > Create()
RResult< void > AddProjectedField(std::unique_ptr< ROOT::RFieldBase > field, const FieldMappingFunc_t &mapping)
Adds a top-level field based on existing fields.
bool IsFrozen() const
void SetDescription(std::string_view description)
std::unique_ptr< Internal::RProjectedFields > fProjectedFields
The set of projected top-level fields.
std::unique_ptr< Detail::RRawPtrWriteEntry > CreateRawPtrWriteEntry() const
ROOT::RFieldToken GetToken(std::string_view fieldName) const
Creates a token to be used in REntry methods to address a field present in the entry.
std::unordered_set< std::string > fFieldNames
Keeps track of which field names are taken, including projected field names.
std::unique_ptr< ROOT::RFieldZero > fFieldZero
Hierarchy of fields consisting of simple types and collections (sub trees)
void EnsureNotBare() const
Throws an RException if fDefaultEntry is nullptr.
void RegisterSubfield(std::string_view qualifiedFieldName)
Register a subfield so it can be accessed directly from entries belonging to the model.
ROOT::RFieldBase * FindField(std::string_view fieldName) const
The field name can be a top-level field or a nested field. Returns nullptr if the field is not in the...
void Freeze()
Transitions an RNTupleModel from the building state to the frozen state, disabling adding additional ...
ROOT::RFieldBase & GetMutableField(std::string_view fieldName)
Retrieves the field with fully-qualified name fieldName.
static std::unique_ptr< RNTupleModel > CreateBare()
Creates a "bare model", i.e. an RNTupleModel with no default entry.
std::function< std::string(const std::string &)> FieldMappingFunc_t
User-provided function that describes the mapping of existing source fields to projected fields in te...
void Expire()
Transitions an RNTupleModel from the frozen state to the expired state, invalidating all previously c...
bool IsExpired() const
std::uint64_t fSchemaId
Models have a separate schema ID to remember that the clone of a frozen model still has the same sche...
const ROOT::RFieldBase & GetConstField(std::string_view fieldName) const
std::unique_ptr< REntry > CreateBareEntry() const
Creates a "bare entry", i.e.
Common user-tunable settings for storing RNTuples.
std::size_t GetPageBufferBudget() const
std::size_t GetApproxZippedClusterSize() const
std::size_t GetMaxUnzippedPageSize() const
std::uint32_t GetCompression() const
EImplicitMT GetUseImplicitMT() const
std::size_t GetInitialUnzippedPageSize() const
An RNTuple that gets filled with entries (data) and writes them to storage.
const_iterator begin() const
const_iterator end() const
The field for an untyped record.
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:222
ROOT::RFieldZero & GetFieldZeroOfModel(RNTupleModel &model)
RResult< void > EnsureValidNameForRNTuple(std::string_view name, std::string_view where)
Check whether a given string is a valid name according to the RNTuple specification.
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
void AddItemToRecord(RRecordField &record, std::unique_ptr< RFieldBase > newItem)
Definition RField.cxx:641
RProjectedFields & GetProjectedFieldsOfModel(RNTupleModel &model)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
The incremental changes to a RNTupleModel
void AddField(std::unique_ptr< ROOT::RFieldBase > field, std::string_view parentName="")
ROOT::RResult< void > AddProjectedField(std::unique_ptr< ROOT::RFieldBase > field, const RNTupleModel::FieldMappingFunc_t &mapping)
ROOT::RRecordField * GetParentRecordField(std::string_view parentName) const