Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleModel.cxx
Go to the documentation of this file.
1/// \file RNTupleModel.cxx
2/// \ingroup NTuple
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-15
5
6/*************************************************************************
7 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#include <ROOT/RError.hxx>
15#include <ROOT/RField.hxx>
16#include <ROOT/RFieldToken.hxx>
17#include <ROOT/RNTupleModel.hxx>
18#include <ROOT/RNTupleUtils.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
36{
37 if (model.IsExpired()) {
38 throw RException(R__FAIL("invalid use of expired model"));
39 }
40 return *model.fFieldZero;
41}
42
44{
45 if (model.IsExpired()) {
46 throw RException(R__FAIL("invalid use of expired model"));
47 }
48 return *model.fProjectedFields;
49}
50
51//------------------------------------------------------------------------------
52
55{
56 auto source = fieldMap.at(target);
57
58 if (!target->GetColumnRepresentatives()[0].empty()) {
59 const auto representative = target->GetColumnRepresentatives()[0][0];
60 // If the user is trying to add a projected field upon which they called SetTruncated() or SetQuantized(),
61 // they probably have the wrong expectations about what should happen. Warn them about it.
64 << "calling SetQuantized() or SetTruncated() on a projected field has no effect, as the on-disk "
65 "representation of the value is decided by the projection source field. Reading back the field will "
66 "yield the correct values, but the value range and bits of precision you set on the projected field "
67 "will be ignored.";
68 }
69 }
70
71 const bool hasCompatibleStructure = (source->GetStructure() == target->GetStructure()) ||
72 ((source->GetStructure() == ROOT::ENTupleStructure::kCollection) &&
73 dynamic_cast<const ROOT::RCardinalityField *>(target));
75 return R__FAIL("field mapping structural mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
76 if ((source->GetStructure() == ROOT::ENTupleStructure::kPlain) ||
77 (source->GetStructure() == ROOT::ENTupleStructure::kStreamer)) {
78 if (target->GetTypeName() != source->GetTypeName())
79 return R__FAIL("field mapping type mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
80 }
81
82 auto fnHasArrayParent = [](const ROOT::RFieldBase &f) -> bool {
83 auto parent = f.GetParent();
84 while (parent) {
85 if (parent->GetNRepetitions() > 0)
86 return true;
87 parent = parent->GetParent();
88 }
89 return false;
90 };
92 return R__FAIL("unsupported field mapping across fixed-size arrays");
93 }
94
95 // We support projections only across records and collections. In the following, we check that the projected
96 // field is on the same path of collection fields in the field tree than the source field.
97
98 // Finds the first non-record parent field of the input field
99 auto fnBreakPoint = [](const ROOT::RFieldBase *f) -> const ROOT::RFieldBase * {
100 auto parent = f->GetParent();
101 while (parent) {
102 if ((parent->GetStructure() != ROOT::ENTupleStructure::kRecord) &&
103 (parent->GetStructure() != ROOT::ENTupleStructure::kPlain)) {
104 return parent;
105 }
106 parent = parent->GetParent();
107 }
108 // We reached the zero field
109 return nullptr;
110 };
111
112 // If source or target has a variant or reference as a parent, error out
115 return R__FAIL("unsupported field mapping (source structure)");
118 return R__FAIL("unsupported field mapping (target structure)");
119
121 // Source and target have no collections as parent
122 return RResult<void>::Success();
123 }
126 // Source and target are children of the same collection
127 return RResult<void>::Success();
128 }
129 if (auto it = fieldMap.find(targetBreakPoint); it != fieldMap.end() && it->second == sourceBreakPoint) {
130 // The parent collection of parent is mapped to the parent collection of the source
131 return RResult<void>::Success();
132 }
133 // Source and target are children of different collections
134 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
135 }
136
137 // Either source or target have no collection as a parent, but the other one has; that doesn't fit
138 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
139}
140
142ROOT::Internal::RProjectedFields::Add(std::unique_ptr<ROOT::RFieldBase> field, const FieldMap_t &fieldMap)
143{
144 auto result = EnsureValidMapping(field.get(), fieldMap);
145 if (!result)
146 return R__FORWARD_ERROR(result);
147 for (const auto &f : *field) {
148 result = EnsureValidMapping(&f, fieldMap);
149 if (!result)
150 return R__FORWARD_ERROR(result);
151 }
152
153 fFieldMap.insert(fieldMap.begin(), fieldMap.end());
154 fFieldZero->Attach(std::move(field));
155 return RResult<void>::Success();
156}
157
159{
160 if (auto it = fFieldMap.find(target); it != fFieldMap.end())
161 return it->second;
162 return nullptr;
163}
164
165std::unique_ptr<ROOT::Internal::RProjectedFields>
167{
168 auto cloneFieldZero =
169 std::unique_ptr<ROOT::RFieldZero>(static_cast<ROOT::RFieldZero *>(fFieldZero->Clone("").release()));
170 auto clone = std::unique_ptr<RProjectedFields>(new RProjectedFields(std::move(cloneFieldZero)));
171 clone->fModel = &newModel;
172 // TODO(jblomer): improve quadratic search to re-wire the field mappings given the new model and the cloned
173 // projected fields. Not too critical as we generally expect a limited number of projected fields
174 for (const auto &[k, v] : fFieldMap) {
175 for (const auto &f : clone->GetFieldZero()) {
176 if (f.GetQualifiedFieldName() == k->GetQualifiedFieldName()) {
177 clone->fFieldMap[&f] = &newModel.GetConstField(v->GetQualifiedFieldName());
178 break;
179 }
180 }
181 }
182 return clone;
183}
184
186 : fWriter(writer), fOpenChangeset(fWriter.GetUpdatableModel())
187{
188}
189
191{
192 fOpenChangeset.fModel.Unfreeze();
193 // We set the model ID to zero until CommitUpdate(). That prevents calls to RNTupleWriter::Fill() in the middle
194 // of updates
195 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
196}
197
199{
200 fOpenChangeset.fModel.Freeze();
201 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
202 if (fOpenChangeset.IsEmpty())
203 return;
204 Internal::RNTupleModelChangeset toCommit{fOpenChangeset.fModel};
205 std::swap(fOpenChangeset.fAddedFields, toCommit.fAddedFields);
206 std::swap(fOpenChangeset.fAddedProjectedFields, toCommit.fAddedProjectedFields);
207 fWriter.GetSink().UpdateSchema(toCommit, fWriter.GetNEntries());
208}
209
210void ROOT::Internal::RNTupleModelChangeset::AddField(std::unique_ptr<ROOT::RFieldBase> field)
211{
212 auto fieldp = field.get();
213 fModel.AddField(std::move(field));
214 fAddedFields.emplace_back(fieldp);
215}
216
217void ROOT::RNTupleModel::RUpdater::AddField(std::unique_ptr<ROOT::RFieldBase> field)
218{
219 fOpenChangeset.AddField(std::move(field));
220}
221
224{
225 auto fieldp = field.get();
226 auto result = fModel.AddProjectedField(std::move(field), mapping);
227 if (result)
228 fAddedProjectedFields.emplace_back(fieldp);
230}
231
234{
235 return R__FORWARD_RESULT(fOpenChangeset.AddProjectedField(std::move(field), std::move(mapping)));
236}
237
239{
241 if (!nameValid) {
242 nameValid.Throw();
243 }
244 if (fieldName.empty()) {
245 throw RException(R__FAIL("name cannot be empty string \"\""));
246 }
247 auto fieldNameStr = std::string(fieldName);
248 if (fFieldNames.count(fieldNameStr) > 0)
249 throw RException(R__FAIL("field name '" + fieldNameStr + "' already exists in NTuple model"));
250}
251
253{
254 if (IsFrozen())
255 throw RException(R__FAIL("invalid attempt to modify frozen model"));
256}
257
259{
260 if (IsBare())
261 throw RException(R__FAIL("invalid attempt to use default entry of bare model"));
262}
263
264ROOT::RNTupleModel::RNTupleModel(std::unique_ptr<ROOT::RFieldZero> fieldZero)
266{
267}
268
269std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::CreateBare()
270{
271 return CreateBare(std::make_unique<ROOT::RFieldZero>());
272}
273
274std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::CreateBare(std::unique_ptr<ROOT::RFieldZero> fieldZero)
275{
276 auto model = std::unique_ptr<RNTupleModel>(new RNTupleModel(std::move(fieldZero)));
277 model->fProjectedFields = std::make_unique<Internal::RProjectedFields>(*model);
278 return model;
279}
280
281std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Create()
282{
283 return Create(std::make_unique<ROOT::RFieldZero>());
284}
285
286std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Create(std::unique_ptr<ROOT::RFieldZero> fieldZero)
287{
288 auto model = CreateBare(std::move(fieldZero));
289 model->fDefaultEntry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(model->fModelId, model->fSchemaId));
290 return model;
291}
292
293std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Clone() const
294{
295 auto cloneModel = std::unique_ptr<RNTupleModel>(new RNTupleModel(
296 std::unique_ptr<ROOT::RFieldZero>(static_cast<ROOT::RFieldZero *>(fFieldZero->Clone("").release()))));
297 cloneModel->fModelId = GetNewModelId();
298 // For a frozen model, we can keep the schema id because adding new fields is forbidden. It is reset in Unfreeze()
299 // if called by the user.
300 if (IsFrozen()) {
301 cloneModel->fSchemaId = fSchemaId;
302 } else {
303 cloneModel->fSchemaId = cloneModel->fModelId;
304 }
305 cloneModel->fModelState = (fModelState == EState::kExpired) ? EState::kFrozen : fModelState;
306 cloneModel->fFieldNames = fFieldNames;
307 cloneModel->fDescription = fDescription;
308 cloneModel->fProjectedFields = fProjectedFields->Clone(*cloneModel);
309 cloneModel->fRegisteredSubfields = fRegisteredSubfields;
310 if (fDefaultEntry) {
311 cloneModel->fDefaultEntry =
312 std::unique_ptr<ROOT::REntry>(new ROOT::REntry(cloneModel->fModelId, cloneModel->fSchemaId));
313 for (const auto &f : cloneModel->fFieldZero->GetMutableSubfields()) {
314 cloneModel->fDefaultEntry->AddValue(f->CreateValue());
315 }
316 for (const auto &f : cloneModel->fRegisteredSubfields) {
317 cloneModel->AddSubfield(f, *cloneModel->fDefaultEntry);
318 }
319 }
320 return cloneModel;
321}
322
324{
325 if (fieldName.empty())
326 return nullptr;
327
328 auto *field = static_cast<ROOT::RFieldBase *>(fFieldZero.get());
329 for (auto subfieldName : ROOT::Split(fieldName, ".")) {
330 const auto subfields = field->GetMutableSubfields();
331 auto it = std::find_if(subfields.begin(), subfields.end(),
332 [&](const auto *f) { return f->GetFieldName() == subfieldName; });
333 if (it != subfields.end()) {
334 field = *it;
335 } else {
336 field = nullptr;
337 break;
338 }
339 }
340
341 return field;
342}
343
344void ROOT::RNTupleModel::AddField(std::unique_ptr<ROOT::RFieldBase> field)
345{
346 EnsureNotFrozen();
347 if (!field)
348 throw RException(R__FAIL("null field"));
349 EnsureValidFieldName(field->GetFieldName());
350
351 if (fDefaultEntry)
352 fDefaultEntry->AddValue(field->CreateValue());
353 fFieldNames.insert(field->GetFieldName());
354 fFieldZero->Attach(std::move(field));
355}
356
358 bool initializeValue) const
359{
360 auto field = FindField(qualifiedFieldName);
361 if (initializeValue)
362 entry.AddValue(field->CreateValue());
363 else
364 entry.AddValue(field->BindValue(nullptr));
365}
366
368{
369 if (qualifiedFieldName.empty())
370 throw RException(R__FAIL("no field name provided"));
371
372 if (fFieldNames.find(std::string(qualifiedFieldName)) != fFieldNames.end()) {
373 throw RException(
374 R__FAIL("cannot register top-level field \"" + std::string(qualifiedFieldName) + "\" as a subfield"));
375 }
376
377 if (fRegisteredSubfields.find(std::string(qualifiedFieldName)) != fRegisteredSubfields.end())
378 throw RException(R__FAIL("subfield \"" + std::string(qualifiedFieldName) + "\" already registered"));
379
380 EnsureNotFrozen();
381
382 auto *field = FindField(qualifiedFieldName);
383 if (!field) {
384 throw RException(R__FAIL("could not find subfield \"" + std::string(qualifiedFieldName) + "\" in model"));
385 }
386
387 auto parent = field->GetParent();
388 while (parent && !parent->GetFieldName().empty()) {
389 if (parent->GetStructure() == ROOT::ENTupleStructure::kCollection || parent->GetNRepetitions() > 0 ||
390 parent->GetStructure() == ROOT::ENTupleStructure::kVariant) {
391 throw RException(R__FAIL(
392 "registering a subfield as part of a collection, fixed-sized array or std::variant is not supported"));
393 }
394 parent = parent->GetParent();
395 }
396
397 if (fDefaultEntry)
398 AddSubfield(qualifiedFieldName, *fDefaultEntry);
399 fRegisteredSubfields.emplace(qualifiedFieldName);
400}
401
404{
405 EnsureNotFrozen();
406 if (!field)
407 return R__FAIL("null field");
408 auto fieldName = field->GetFieldName();
409
411 auto sourceField = FindField(mapping(fieldName));
412 if (!sourceField)
413 return R__FAIL("no such field: " + mapping(fieldName));
414 fieldMap[field.get()] = sourceField;
415 for (const auto &subField : *field) {
416 sourceField = FindField(mapping(subField.GetQualifiedFieldName()));
417 if (!sourceField)
418 return R__FAIL("no such field: " + mapping(subField.GetQualifiedFieldName()));
420 }
421
422 EnsureValidFieldName(fieldName);
423 auto result = fProjectedFields->Add(std::move(field), fieldMap);
424 if (!result) {
425 return R__FORWARD_ERROR(result);
426 }
427 fFieldNames.insert(fieldName);
428 return RResult<void>::Success();
429}
430
432{
433 if (IsFrozen())
434 throw RException(R__FAIL("invalid attempt to get mutable zero field of frozen model"));
435 return *fFieldZero;
436}
437
439{
440 if (IsFrozen())
441 throw RException(R__FAIL("invalid attempt to get mutable field of frozen model"));
442 auto f = FindField(fieldName);
443 if (!f)
444 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
445
446 return *f;
447}
448
450{
451 auto f = FindField(fieldName);
452 if (!f)
453 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
454
455 return *f;
456}
457
459{
460 EnsureNotBare();
461 return *fDefaultEntry;
462}
463
465{
466 if (!IsFrozen())
467 throw RException(R__FAIL("invalid attempt to get default entry of unfrozen model"));
468 EnsureNotBare();
469 return *fDefaultEntry;
470}
471
472std::unique_ptr<ROOT::REntry> ROOT::RNTupleModel::CreateEntry() const
473{
474 switch (fModelState) {
475 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
476 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
477 case EState::kFrozen: break;
478 }
479
480 auto entry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(fModelId, fSchemaId));
481 for (const auto &f : fFieldZero->GetMutableSubfields()) {
482 entry->AddValue(f->CreateValue());
483 }
484 for (const auto &f : fRegisteredSubfields) {
485 AddSubfield(f, *entry);
486 }
487 return entry;
488}
489
490std::unique_ptr<ROOT::REntry> ROOT::RNTupleModel::CreateBareEntry() const
491{
492 switch (fModelState) {
493 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
494 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
495 case EState::kFrozen: break;
496 }
497
498 auto entry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(fModelId, fSchemaId));
499 for (const auto &f : fFieldZero->GetMutableSubfields()) {
500 entry->AddValue(f->BindValue(nullptr));
501 }
502 for (const auto &f : fRegisteredSubfields) {
503 AddSubfield(f, *entry, false /* initializeValue */);
504 }
505 return entry;
506}
507
508std::unique_ptr<ROOT::Experimental::Detail::RRawPtrWriteEntry> ROOT::RNTupleModel::CreateRawPtrWriteEntry() const
509{
510 switch (fModelState) {
511 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
512 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
513 case EState::kFrozen: break;
514 }
515
516 auto entry = std::unique_ptr<Experimental::Detail::RRawPtrWriteEntry>(
517 new Experimental::Detail::RRawPtrWriteEntry(fModelId, fSchemaId));
518 for (const auto &f : fFieldZero->GetMutableSubfields()) {
519 entry->AddField(*f);
520 }
521 // fRegisteredSubfields are not relevant for writing
522 return entry;
523}
524
526{
527 const auto &topLevelFields = fFieldZero->GetConstSubfields();
528 auto it = std::find_if(topLevelFields.begin(), topLevelFields.end(),
529 [&fieldName](const ROOT::RFieldBase *f) { return f->GetFieldName() == fieldName; });
530
531 if (it == topLevelFields.end()) {
532 throw RException(R__FAIL("invalid field name: " + std::string(fieldName)));
533 }
534 return ROOT::RFieldToken(std::distance(topLevelFields.begin(), it), fSchemaId);
535}
536
538{
539 switch (fModelState) {
540 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create bulk of unfrozen model"));
541 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create bulk of expired model"));
542 case EState::kFrozen: break;
543 }
544
545 auto f = FindField(fieldName);
546 if (!f)
547 throw RException(R__FAIL("no such field: " + std::string(fieldName)));
548 return f->CreateBulk();
549}
550
552{
553 switch (fModelState) {
554 case EState::kExpired: return;
555 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to expire unfrozen model"));
556 case EState::kFrozen: break;
557 }
558
559 // Ensure that Fill() does not work anymore
560 fModelId = 0;
561 fModelState = EState::kExpired;
562}
563
565{
566 switch (fModelState) {
567 case EState::kBuilding: return;
568 case EState::kExpired: throw RException(R__FAIL("invalid attempt to unfreeze expired model"));
569 case EState::kFrozen: break;
570 }
571
572 fModelId = GetNewModelId();
573 fSchemaId = fModelId;
574 if (fDefaultEntry) {
575 fDefaultEntry->fModelId = fModelId;
576 fDefaultEntry->fSchemaId = fSchemaId;
577 }
578 fModelState = EState::kBuilding;
579}
580
582{
583 if (fModelState == EState::kExpired)
584 throw RException(R__FAIL("invalid attempt to freeze expired model"));
585
586 fModelState = EState::kFrozen;
587}
588
590{
591 EnsureNotFrozen();
592 fDescription = std::string(description);
593}
594
596{
597 std::size_t bytes = 0;
598 std::size_t minPageBufferSize = 0;
599
600 // Start with the size of the page buffers used to fill a persistent sink
601 std::size_t nColumns = 0;
602 for (auto &&field : *fFieldZero) {
603 for (const auto &r : field.GetColumnRepresentatives()) {
604 nColumns += r.size();
605 minPageBufferSize += r.size() * options.GetInitialUnzippedPageSize();
606 }
607 }
608 bytes = std::min(options.GetPageBufferBudget(), nColumns * options.GetMaxUnzippedPageSize());
609
610 // If using buffered writing with RPageSinkBuf, we create a clone of the model and keep at least
611 // the compressed pages in memory.
612 if (options.GetUseBufferedWrite()) {
614 // Use the target cluster size as an estimate for all compressed pages combined.
616 int compression = options.GetCompression();
618 // With IMT, compression happens asynchronously which means that the uncompressed pages also stay around. Use a
619 // compression factor of 2x as a very rough estimate.
620 bytes += 2 * options.GetApproxZippedClusterSize();
621 }
622 }
623
624 return bytes;
625}
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
Definition RError.hxx:304
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:302
#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:300
#define R__LOG_WARNING(...)
Definition RLogger.hxx:358
#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
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:314
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:79
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:54
void CommitUpdate()
Commit changes since the last call to BeginUpdate().
RResult< void > AddProjectedField(std::unique_ptr< ROOT::RFieldBase > field, FieldMappingFunc_t mapping)
RUpdater(ROOT::RNTupleWriter &writer)
void AddField(std::unique_ptr< ROOT::RFieldBase > field)
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()
bool IsFrozen() const
void SetDescription(std::string_view description)
std::unique_ptr< Experimental::Detail::RRawPtrWriteEntry > CreateRawPtrWriteEntry() const
std::unique_ptr< Internal::RProjectedFields > fProjectedFields
The set of projected top-level fields.
RResult< void > AddProjectedField(std::unique_ptr< ROOT::RFieldBase > field, FieldMappingFunc_t mapping)
Adds a top-level field based on existing fields.
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 class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:198
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.
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)
ROOT::RResult< void > AddProjectedField(std::unique_ptr< ROOT::RFieldBase > field, RNTupleModel::FieldMappingFunc_t mapping)