Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
RNTupleModel.cxx
Go to the documentation of this file.
1/// \file RNTupleModel.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/RError.hxx>
17#include <ROOT/RField.hxx>
18#include <ROOT/RNTupleModel.hxx>
20#include <ROOT/StringUtils.hxx>
21
22#include <atomic>
23#include <cstdlib>
24#include <memory>
25#include <utility>
26
27namespace {
28std::uint64_t GetNewModelId()
29{
30 static std::atomic<std::uint64_t> gLastModelId = 0;
31 return ++gLastModelId;
32}
33} // anonymous namespace
34
37{
38 if (model.IsExpired()) {
39 throw RException(R__FAIL("invalid use of expired model"));
40 }
41 return *model.fFieldZero;
42}
43
46{
47 if (model.IsExpired()) {
48 throw RException(R__FAIL("invalid use of expired model"));
49 }
50 return *model.fProjectedFields;
51}
52
53//------------------------------------------------------------------------------
54
57{
58 auto source = fieldMap.at(target);
59 const bool hasCompatibleStructure = (source->GetStructure() == target->GetStructure()) ||
60 ((source->GetStructure() == ROOT::ENTupleStructure::kCollection) &&
61 dynamic_cast<const RCardinalityField *>(target));
63 return R__FAIL("field mapping structural mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
64 if ((source->GetStructure() == ROOT::ENTupleStructure::kLeaf) ||
65 (source->GetStructure() == ROOT::ENTupleStructure::kStreamer)) {
66 if (target->GetTypeName() != source->GetTypeName())
67 return R__FAIL("field mapping type mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
68 }
69
70 auto fnHasArrayParent = [](const RFieldBase &f) -> bool {
71 auto parent = f.GetParent();
72 while (parent) {
73 if (parent->GetNRepetitions() > 0)
74 return true;
75 parent = parent->GetParent();
76 }
77 return false;
78 };
80 return R__FAIL("unsupported field mapping across fixed-size arrays");
81 }
82
83 // We support projections only across records and collections. In the following, we check that the projected
84 // field is on the same path of collection fields in the field tree than the source field.
85
86 // Finds the first non-record parent field of the input field
87 auto fnBreakPoint = [](const RFieldBase *f) -> const RFieldBase * {
88 auto parent = f->GetParent();
89 while (parent) {
90 if ((parent->GetStructure() != ROOT::ENTupleStructure::kRecord) &&
91 (parent->GetStructure() != ROOT::ENTupleStructure::kLeaf)) {
92 return parent;
93 }
94 parent = parent->GetParent();
95 }
96 // We reached the zero field
97 return nullptr;
98 };
99
100 // If source or target has a variant or reference as a parent, error out
103 return R__FAIL("unsupported field mapping (source structure)");
106 return R__FAIL("unsupported field mapping (target structure)");
107
109 // Source and target have no collections as parent
110 return RResult<void>::Success();
111 }
114 // Source and target are children of the same collection
115 return RResult<void>::Success();
116 }
117 if (auto it = fieldMap.find(targetBreakPoint); it != fieldMap.end() && it->second == sourceBreakPoint) {
118 // The parent collection of parent is mapped to the parent collection of the source
119 return RResult<void>::Success();
120 }
121 // Source and target are children of different collections
122 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
123 }
124
125 // Either source or target have no collection as a parent, but the other one has; that doesn't fit
126 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
127}
128
131{
132 auto result = EnsureValidMapping(field.get(), fieldMap);
133 if (!result)
134 return R__FORWARD_ERROR(result);
135 for (const auto &f : *field) {
136 result = EnsureValidMapping(&f, fieldMap);
137 if (!result)
138 return R__FORWARD_ERROR(result);
139 }
140
141 fFieldMap.insert(fieldMap.begin(), fieldMap.end());
142 fFieldZero->Attach(std::move(field));
143 return RResult<void>::Success();
144}
145
148{
149 if (auto it = fFieldMap.find(target); it != fFieldMap.end())
150 return it->second;
151 return nullptr;
152}
153
154std::unique_ptr<ROOT::Experimental::Internal::RProjectedFields>
156{
157 auto cloneFieldZero = std::unique_ptr<RFieldZero>(static_cast<RFieldZero *>(fFieldZero->Clone("").release()));
158 auto clone = std::unique_ptr<RProjectedFields>(new RProjectedFields(std::move(cloneFieldZero)));
159 clone->fModel = &newModel;
160 // TODO(jblomer): improve quadratic search to re-wire the field mappings given the new model and the cloned
161 // projected fields. Not too critical as we generally expect a limited number of projected fields
162 for (const auto &[k, v] : fFieldMap) {
163 for (const auto &f : clone->GetFieldZero()) {
164 if (f.GetQualifiedFieldName() == k->GetQualifiedFieldName()) {
165 clone->fFieldMap[&f] = &newModel.GetConstField(v->GetQualifiedFieldName());
166 break;
167 }
168 }
169 }
170 return clone;
171}
172
174 : fWriter(writer), fOpenChangeset(fWriter.GetUpdatableModel())
175{
176}
177
179{
180 fOpenChangeset.fModel.Unfreeze();
181 // We set the model ID to zero until CommitUpdate(). That prevents calls to RNTupleWriter::Fill() in the middle
182 // of updates
183 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
184}
185
187{
188 fOpenChangeset.fModel.Freeze();
189 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
190 if (fOpenChangeset.IsEmpty())
191 return;
192 Internal::RNTupleModelChangeset toCommit{fOpenChangeset.fModel};
193 std::swap(fOpenChangeset.fAddedFields, toCommit.fAddedFields);
194 std::swap(fOpenChangeset.fAddedProjectedFields, toCommit.fAddedProjectedFields);
195 fWriter.GetSink().UpdateSchema(toCommit, fWriter.GetNEntries());
196}
197
199{
200 auto fieldp = field.get();
201 fModel.AddField(std::move(field));
202 fAddedFields.emplace_back(fieldp);
203}
204
206{
207 fOpenChangeset.AddField(std::move(field));
208}
209
213{
214 auto fieldp = field.get();
215 auto result = fModel.AddProjectedField(std::move(field), mapping);
216 if (result)
217 fAddedProjectedFields.emplace_back(fieldp);
219}
220
223{
224 return R__FORWARD_RESULT(fOpenChangeset.AddProjectedField(std::move(field), std::move(mapping)));
225}
226
228{
230 if (!nameValid) {
231 nameValid.Throw();
232 }
233 if (fieldName.empty()) {
234 throw RException(R__FAIL("name cannot be empty string \"\""));
235 }
236 auto fieldNameStr = std::string(fieldName);
237 if (fFieldNames.count(fieldNameStr) > 0)
238 throw RException(R__FAIL("field name '" + fieldNameStr + "' already exists in NTuple model"));
239}
240
242{
243 if (IsFrozen())
244 throw RException(R__FAIL("invalid attempt to modify frozen model"));
245}
246
248{
249 if (IsBare())
250 throw RException(R__FAIL("invalid attempt to use default entry of bare model"));
251}
252
257
258std::unique_ptr<ROOT::Experimental::RNTupleModel> ROOT::Experimental::RNTupleModel::CreateBare()
259{
260 return CreateBare(std::make_unique<RFieldZero>());
261}
262
263std::unique_ptr<ROOT::Experimental::RNTupleModel>
265{
266 auto model = std::unique_ptr<RNTupleModel>(new RNTupleModel(std::move(fieldZero)));
267 model->fProjectedFields = std::make_unique<Internal::RProjectedFields>(*model);
268 return model;
269}
270
271std::unique_ptr<ROOT::Experimental::RNTupleModel> ROOT::Experimental::RNTupleModel::Create()
272{
273 return Create(std::make_unique<RFieldZero>());
274}
275
276std::unique_ptr<ROOT::Experimental::RNTupleModel>
278{
279 auto model = CreateBare(std::move(fieldZero));
280 model->fDefaultEntry = std::unique_ptr<REntry>(new REntry(model->fModelId, model->fSchemaId));
281 return model;
282}
283
284std::unique_ptr<ROOT::Experimental::RNTupleModel> ROOT::Experimental::RNTupleModel::Clone() const
285{
286 auto cloneModel = std::unique_ptr<RNTupleModel>(
287 new RNTupleModel(std::unique_ptr<RFieldZero>(static_cast<RFieldZero *>(fFieldZero->Clone("").release()))));
288 cloneModel->fModelId = GetNewModelId();
289 // For a frozen model, we can keep the schema id because adding new fields is forbidden. It is reset in Unfreeze()
290 // if called by the user.
291 if (IsFrozen()) {
292 cloneModel->fSchemaId = fSchemaId;
293 } else {
294 cloneModel->fSchemaId = cloneModel->fModelId;
295 }
296 cloneModel->fModelState = (fModelState == EState::kExpired) ? EState::kFrozen : fModelState;
297 cloneModel->fFieldNames = fFieldNames;
298 cloneModel->fDescription = fDescription;
299 cloneModel->fProjectedFields = fProjectedFields->Clone(*cloneModel);
300 cloneModel->fRegisteredSubfields = fRegisteredSubfields;
301 if (fDefaultEntry) {
302 cloneModel->fDefaultEntry = std::unique_ptr<REntry>(new REntry(cloneModel->fModelId, cloneModel->fSchemaId));
303 for (const auto &f : cloneModel->fFieldZero->GetSubFields()) {
304 cloneModel->fDefaultEntry->AddValue(f->CreateValue());
305 }
306 for (const auto &f : cloneModel->fRegisteredSubfields) {
307 cloneModel->AddSubfield(f, *cloneModel->fDefaultEntry);
308 }
309 }
310 return cloneModel;
311}
312
314{
315 if (fieldName.empty())
316 return nullptr;
317
318 auto *field = static_cast<ROOT::Experimental::RFieldBase *>(fFieldZero.get());
319 for (auto subfieldName : ROOT::Split(fieldName, ".")) {
320 const auto subfields = field->GetSubFields();
321 auto it = std::find_if(subfields.begin(), subfields.end(),
322 [&](const auto *f) { return f->GetFieldName() == subfieldName; });
323 if (it != subfields.end()) {
324 field = *it;
325 } else {
326 field = nullptr;
327 break;
328 }
329 }
330
331 return field;
332}
333
334void ROOT::Experimental::RNTupleModel::AddField(std::unique_ptr<RFieldBase> field)
335{
336 EnsureNotFrozen();
337 if (!field)
338 throw RException(R__FAIL("null field"));
339 EnsureValidFieldName(field->GetFieldName());
340
341 if (fDefaultEntry)
342 fDefaultEntry->AddValue(field->CreateValue());
343 fFieldNames.insert(field->GetFieldName());
344 fFieldZero->Attach(std::move(field));
345}
346
348 bool initializeValue) const
349{
350 auto field = FindField(qualifiedFieldName);
351 if (initializeValue)
352 entry.AddValue(field->CreateValue());
353 else
354 entry.AddValue(field->BindValue(nullptr));
355}
356
358{
359 if (qualifiedFieldName.empty())
360 throw RException(R__FAIL("no field name provided"));
361
362 if (fFieldNames.find(std::string(qualifiedFieldName)) != fFieldNames.end()) {
363 throw RException(
364 R__FAIL("cannot register top-level field \"" + std::string(qualifiedFieldName) + "\" as a subfield"));
365 }
366
367 if (fRegisteredSubfields.find(std::string(qualifiedFieldName)) != fRegisteredSubfields.end())
368 throw RException(R__FAIL("subfield \"" + std::string(qualifiedFieldName) + "\" already registered"));
369
370 EnsureNotFrozen();
371
372 auto *field = FindField(qualifiedFieldName);
373 if (!field) {
374 throw RException(R__FAIL("could not find subfield \"" + std::string(qualifiedFieldName) + "\" in model"));
375 }
376
377 auto parent = field->GetParent();
378 while (parent && !parent->GetFieldName().empty()) {
379 if (parent->GetStructure() == ROOT::ENTupleStructure::kCollection || parent->GetNRepetitions() > 0 ||
380 parent->GetStructure() == ROOT::ENTupleStructure::kVariant) {
381 throw RException(R__FAIL(
382 "registering a subfield as part of a collection, fixed-sized array or std::variant is not supported"));
383 }
384 parent = parent->GetParent();
385 }
386
387 if (fDefaultEntry)
388 AddSubfield(qualifiedFieldName, *fDefaultEntry);
389 fRegisteredSubfields.emplace(qualifiedFieldName);
390}
391
394{
395 EnsureNotFrozen();
396 if (!field)
397 return R__FAIL("null field");
398 auto fieldName = field->GetFieldName();
399
401 auto sourceField = FindField(mapping(fieldName));
402 if (!sourceField)
403 return R__FAIL("no such field: " + mapping(fieldName));
404 fieldMap[field.get()] = sourceField;
405 for (const auto &subField : *field) {
406 sourceField = FindField(mapping(subField.GetQualifiedFieldName()));
407 if (!sourceField)
408 return R__FAIL("no such field: " + mapping(subField.GetQualifiedFieldName()));
410 }
411
412 EnsureValidFieldName(fieldName);
413 auto result = fProjectedFields->Add(std::move(field), fieldMap);
414 if (!result) {
415 return R__FORWARD_ERROR(result);
416 }
417 fFieldNames.insert(fieldName);
418 return RResult<void>::Success();
419}
420
422{
423 if (IsFrozen())
424 throw RException(R__FAIL("invalid attempt to get mutable zero field of frozen model"));
425 return *fFieldZero;
426}
427
429{
430 if (IsFrozen())
431 throw RException(R__FAIL("invalid attempt to get mutable field of frozen model"));
432 auto f = FindField(fieldName);
433 if (!f)
434 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
435
436 return *f;
437}
438
440{
441 auto f = FindField(fieldName);
442 if (!f)
443 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
444
445 return *f;
446}
447
449{
450 EnsureNotBare();
451 return *fDefaultEntry;
452}
453
455{
456 if (!IsFrozen())
457 throw RException(R__FAIL("invalid attempt to get default entry of unfrozen model"));
458 EnsureNotBare();
459 return *fDefaultEntry;
460}
461
462std::unique_ptr<ROOT::Experimental::REntry> ROOT::Experimental::RNTupleModel::CreateEntry() const
463{
464 switch (fModelState) {
465 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
466 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
467 case EState::kFrozen: break;
468 }
469
470 auto entry = std::unique_ptr<REntry>(new REntry(fModelId, fSchemaId));
471 for (const auto &f : fFieldZero->GetSubFields()) {
472 entry->AddValue(f->CreateValue());
473 }
474 for (const auto &f : fRegisteredSubfields) {
475 AddSubfield(f, *entry);
476 }
477 return entry;
478}
479
480std::unique_ptr<ROOT::Experimental::REntry> ROOT::Experimental::RNTupleModel::CreateBareEntry() const
481{
482 switch (fModelState) {
483 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
484 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
485 case EState::kFrozen: break;
486 }
487
488 auto entry = std::unique_ptr<REntry>(new REntry(fModelId, fSchemaId));
489 for (const auto &f : fFieldZero->GetSubFields()) {
490 entry->AddValue(f->BindValue(nullptr));
491 }
492 for (const auto &f : fRegisteredSubfields) {
493 AddSubfield(f, *entry, false /* initializeValue */);
494 }
495 return entry;
496}
497
499{
500 const auto &topLevelFields = fFieldZero->GetSubFields();
501 auto it = std::find_if(topLevelFields.begin(), topLevelFields.end(),
502 [&fieldName](const RFieldBase *f) { return f->GetFieldName() == fieldName; });
503
504 if (it == topLevelFields.end()) {
505 throw RException(R__FAIL("invalid field name: " + std::string(fieldName)));
506 }
507 return REntry::RFieldToken(std::distance(topLevelFields.begin(), it), fSchemaId);
508}
509
511{
512 switch (fModelState) {
513 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create bulk of unfrozen model"));
514 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create bulk of expired model"));
515 case EState::kFrozen: break;
516 }
517
518 auto f = FindField(fieldName);
519 if (!f)
520 throw RException(R__FAIL("no such field: " + std::string(fieldName)));
521 return f->CreateBulk();
522}
523
525{
526 switch (fModelState) {
527 case EState::kExpired: return;
528 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to expire unfrozen model"));
529 case EState::kFrozen: break;
530 }
531
532 // Ensure that Fill() does not work anymore
533 fModelId = 0;
534 fModelState = EState::kExpired;
535}
536
538{
539 switch (fModelState) {
540 case EState::kBuilding: return;
541 case EState::kExpired: throw RException(R__FAIL("invalid attempt to unfreeze expired model"));
542 case EState::kFrozen: break;
543 }
544
545 fModelId = GetNewModelId();
546 fSchemaId = fModelId;
547 if (fDefaultEntry) {
548 fDefaultEntry->fModelId = fModelId;
549 fDefaultEntry->fSchemaId = fSchemaId;
550 }
551 fModelState = EState::kBuilding;
552}
553
555{
556 if (fModelState == EState::kExpired)
557 throw RException(R__FAIL("invalid attempt to freeze expired model"));
558
559 fModelState = EState::kFrozen;
560}
561
563{
564 EnsureNotFrozen();
565 fDescription = std::string(description);
566}
567
569{
570 std::size_t bytes = 0;
571 std::size_t minPageBufferSize = 0;
572
573 // Start with the size of the page buffers used to fill a persistent sink
574 std::size_t nColumns = 0;
575 for (auto &&field : *fFieldZero) {
576 for (const auto &r : field.GetColumnRepresentatives()) {
577 nColumns += r.size();
578 minPageBufferSize += r.size() * options.GetInitialUnzippedPageSize();
579 }
580 }
581 bytes = std::min(options.GetPageBufferBudget(), nColumns * options.GetMaxUnzippedPageSize());
582
583 // If using buffered writing with RPageSinkBuf, we create a clone of the model and keep at least
584 // the compressed pages in memory.
585 if (options.GetUseBufferedWrite()) {
587 // Use the target cluster size as an estimate for all compressed pages combined.
589 int compression = options.GetCompression();
591 // With IMT, compression happens asynchronously which means that the uncompressed pages also stay around. Use a
592 // compression factor of 2x as a very rough estimate.
593 bytes += 2 * options.GetApproxZippedClusterSize();
594 }
595 }
596
597 return bytes;
598}
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
Definition RError.hxx:303
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:301
#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:299
#define f(i)
Definition RSha256.hxx:104
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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
The projected fields of a RNTupleModel
RResult< void > EnsureValidMapping(const RFieldBase *target, const FieldMap_t &fieldMap)
Asserts that the passed field is a valid target of the source field provided in the field map.
std::unique_ptr< RProjectedFields > Clone(const RNTupleModel &newModel) const
The new model needs to be a clone of fModel.
std::unordered_map< const RFieldBase *, const 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< RFieldBase > field, const FieldMap_t &fieldMap)
Adds a new projected field.
const RFieldBase * GetSourceField(const RFieldBase *target) const
An artificial field that transforms an RNTuple column that contains the offset of collections into co...
Definition RField.hxx:314
The field token identifies a (sub)field in this entry.
Definition REntry.hxx:63
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
Definition REntry.hxx:51
Similar to RValue but manages an array of consecutive values.
A field translates read and write calls from/to underlying columns to/from tree values.
const RFieldBase * GetParent() const
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:58
RResult< void > AddProjectedField(std::unique_ptr< RFieldBase > field, FieldMappingFunc_t mapping)
void CommitUpdate()
Commit changes since the last call to BeginUpdate().
void BeginUpdate()
Begin a new set of alterations to the underlying model.
void AddField(std::unique_ptr< RFieldBase > field)
The RNTupleModel encapulates the schema of an ntuple.
std::unordered_set< std::string > fFieldNames
Keeps track of which field names are taken, including projected field names.
void EnsureValidFieldName(std::string_view fieldName)
Checks that user-provided field names are valid in the context of this RNTuple model.
std::uint64_t fModelId
Every model has a unique ID to distinguish it from other models.
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...
std::unique_ptr< Internal::RProjectedFields > fProjectedFields
The set of projected top-level fields.
const RFieldBase & GetConstField(std::string_view fieldName) 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...
REntry::RFieldToken GetToken(std::string_view fieldName) const
Creates a token to be used in REntry methods to address a field present in the entry.
void EnsureNotBare() const
Throws an RException if fDefaultEntry is nullptr.
std::unique_ptr< RNTupleModel > Clone() const
void EnsureNotFrozen() const
Throws an RException if fFrozen is true.
RFieldZero & GetMutableFieldZero()
Mutable access to the root field is used to make adjustments to the fields.
std::size_t EstimateWriteMemoryUsage(const ROOT::RNTupleWriteOptions &options=ROOT::RNTupleWriteOptions()) const
Estimate the memory usage for this model during writing.
std::unique_ptr< REntry > CreateBareEntry() const
In a bare entry, all values point to nullptr.
std::unique_ptr< REntry > CreateEntry() const
RFieldBase::RBulk CreateBulk(std::string_view fieldName) const
Calls the given field's CreateBulk() method. Throws an exception if no field with the given name exis...
static std::unique_ptr< RNTupleModel > Create()
void AddSubfield(std::string_view fieldName, REntry &entry, bool initializeValue=true) const
Add a subfield to the provided entry.
void SetDescription(std::string_view description)
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...
RResult< void > AddProjectedField(std::unique_ptr< RFieldBase > field, FieldMappingFunc_t mapping)
Adds a top-level field based on existing fields.
RNTupleModel(std::unique_ptr< RFieldZero > fieldZero)
RFieldBase & GetMutableField(std::string_view fieldName)
static std::unique_ptr< RNTupleModel > CreateBare()
A bare model has no default entry.
void AddField(std::unique_ptr< RFieldBase > field)
Adds a field whose type is not known at compile time.
void RegisterSubfield(std::string_view qualifiedFieldName)
Register a subfield so it can be accessed directly from entries belonging to the model.
std::unique_ptr< RFieldZero > fFieldZero
Hierarchy of fields consisting of simple types and collections (sub trees)
An RNTuple that gets filled with entries (data) and writes them to storage.
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
Common user-tunable settings for storing ntuples.
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
const_iterator begin() const
const_iterator end() const
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:197
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.
RProjectedFields & GetProjectedFieldsOfModel(RNTupleModel &model)
RFieldZero & GetFieldZeroOfModel(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< RFieldBase > field)
ROOT::RResult< void > AddProjectedField(std::unique_ptr< RFieldBase > field, RNTupleModel::FieldMappingFunc_t mapping)