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
56
57//------------------------------------------------------------------------------
58
61{
62 auto source = fieldMap.at(target);
63
64 if (!target->GetColumnRepresentatives()[0].empty()) {
65 const auto representative = target->GetColumnRepresentatives()[0][0];
66 // If the user is trying to add a projected field upon which they called SetTruncated() or SetQuantized(),
67 // they probably have the wrong expectations about what should happen. Warn them about it.
70 << "calling SetQuantized() or SetTruncated() on a projected field has no effect, as the on-disk "
71 "representation of the value is decided by the projection source field. Reading back the field will "
72 "yield the correct values, but the value range and bits of precision you set on the projected field "
73 "will be ignored.";
74 }
75 }
76
77 const bool hasCompatibleStructure = (source->GetStructure() == target->GetStructure()) ||
78 ((source->GetStructure() == ROOT::ENTupleStructure::kCollection) &&
79 dynamic_cast<const ROOT::RCardinalityField *>(target));
81 return R__FAIL("field mapping structural mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
82 if ((source->GetStructure() == ROOT::ENTupleStructure::kPlain) ||
83 (source->GetStructure() == ROOT::ENTupleStructure::kStreamer)) {
84 if (target->GetTypeName() != source->GetTypeName())
85 return R__FAIL("field mapping type mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
86 }
87
88 auto fnHasArrayParent = [](const ROOT::RFieldBase &f) -> bool {
89 auto parent = f.GetParent();
90 while (parent) {
91 if (parent->GetNRepetitions() > 0)
92 return true;
93 parent = parent->GetParent();
94 }
95 return false;
96 };
98 return R__FAIL("unsupported field mapping across fixed-size arrays");
99 }
100
101 // We support projections only across records and collections. In the following, we check that the projected
102 // field is on the same path of collection fields in the field tree than the source field.
103
104 // Finds the first non-record parent field of the input field
105 auto fnBreakPoint = [](const ROOT::RFieldBase *f) -> const ROOT::RFieldBase * {
106 auto parent = f->GetParent();
107 while (parent) {
108 if ((parent->GetStructure() != ROOT::ENTupleStructure::kRecord) &&
109 (parent->GetStructure() != ROOT::ENTupleStructure::kPlain)) {
110 return parent;
111 }
112 parent = parent->GetParent();
113 }
114 // We reached the zero field
115 return nullptr;
116 };
117
118 // If source or target has a variant or reference as a parent, error out
121 return R__FAIL("unsupported field mapping (source structure)");
124 return R__FAIL("unsupported field mapping (target structure)");
125
127 // Source and target have no collections as parent
128 return RResult<void>::Success();
129 }
132 // Source and target are children of the same collection
133 return RResult<void>::Success();
134 }
135 if (auto it = fieldMap.find(targetBreakPoint); it != fieldMap.end() && it->second == sourceBreakPoint) {
136 // The parent collection of parent is mapped to the parent collection of the source
137 return RResult<void>::Success();
138 }
139 // Source and target are children of different collections
140 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
141 }
142
143 // Either source or target have no collection as a parent, but the other one has; that doesn't fit
144 return R__FAIL("field mapping structure mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
145}
146
148ROOT::Internal::RProjectedFields::Add(std::unique_ptr<ROOT::RFieldBase> field, const FieldMap_t &fieldMap)
149{
150 auto result = EnsureValidMapping(field.get(), fieldMap);
151 if (!result)
152 return R__FORWARD_ERROR(result);
153 for (const auto &f : *field) {
154 result = EnsureValidMapping(&f, fieldMap);
155 if (!result)
156 return R__FORWARD_ERROR(result);
157 }
158
159 fFieldMap.insert(fieldMap.begin(), fieldMap.end());
160 fFieldZero->Attach(std::move(field));
161 return RResult<void>::Success();
162}
163
165{
166 if (auto it = fFieldMap.find(target); it != fFieldMap.end())
167 return it->second;
168 return nullptr;
169}
170
171std::unique_ptr<ROOT::Internal::RProjectedFields>
173{
174 auto cloneFieldZero =
175 std::unique_ptr<ROOT::RFieldZero>(static_cast<ROOT::RFieldZero *>(fFieldZero->Clone("").release()));
176 auto clone = std::unique_ptr<RProjectedFields>(new RProjectedFields(std::move(cloneFieldZero)));
177 clone->fModel = &newModel;
178 // TODO(jblomer): improve quadratic search to re-wire the field mappings given the new model and the cloned
179 // projected fields. Not too critical as we generally expect a limited number of projected fields
180 for (const auto &[k, v] : fFieldMap) {
181 for (const auto &f : clone->GetFieldZero()) {
182 if (f.GetQualifiedFieldName() == k->GetQualifiedFieldName()) {
183 clone->fFieldMap[&f] = &newModel.GetConstField(v->GetQualifiedFieldName());
184 break;
185 }
186 }
187 }
188 return clone;
189}
190
192 : fWriter(writer), fOpenChangeset(fWriter.GetUpdatableModel())
193{
194}
195
197{
198 // If we made any changes, we should commit them because the model was already altered.
199 // Otherwise, we _do not_ commit -- it may be that the referenced model is already expired if the
200 // corresponding writer is already destructed.
201 if (!fOpenChangeset.IsEmpty())
203}
204
206{
207 fOpenChangeset.fModel.Unfreeze();
208 // We set the model ID to zero until CommitUpdate(). That prevents calls to RNTupleWriter::Fill() in the middle
209 // of updates
210 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
211}
212
214{
215 fOpenChangeset.fModel.Freeze();
216 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
217 if (fOpenChangeset.IsEmpty())
218 return;
219 Internal::RNTupleModelChangeset toCommit{fOpenChangeset.fModel};
220 std::swap(fOpenChangeset.fAddedFields, toCommit.fAddedFields);
221 std::swap(fOpenChangeset.fAddedProjectedFields, toCommit.fAddedProjectedFields);
222 fWriter.GetSink().UpdateSchema(toCommit, fWriter.GetNEntries());
223}
224
226{
227 if (parentName.empty())
228 return nullptr;
229
230 if (!fModel.IsBare()) {
231 throw RException(R__FAIL("invalid attempt to late-model-extend an untyped record of a non-bare model"));
232 }
233
234 auto &parentField = fModel.GetMutableField(parentName);
235 auto parentRecord = dynamic_cast<ROOT::RRecordField *>(&parentField);
236 if (!parentRecord || !parentRecord->GetTypeName().empty()) {
237 throw RException(
238 R__FAIL("invalid attempt to extend a field that is not an untyped record: " + std::string(parentName)));
239 }
240
241 auto itr = parentRecord->GetParent();
242 while (itr) {
243 if (typeid(*itr) == typeid(RFieldZero))
244 break;
245
246 if (!dynamic_cast<const ROOT::RRecordField *>(itr)) {
247 throw RException(R__FAIL("invalid attempt to extend an untyped record that has a non-record parent: " +
248 std::string(parentName)));
249 }
250
251 itr = itr->GetParent();
252 }
253
254 return parentRecord;
255}
256
257void ROOT::Internal::RNTupleModelChangeset::AddField(std::unique_ptr<ROOT::RFieldBase> field,
258 std::string_view parentName)
259{
260 auto fieldp = field.get();
261 if (auto parent = GetParentRecordField(parentName)) {
262 Internal::AddItemToRecord(*parent, std::move(field));
263 } else {
264 fModel.AddField(std::move(field));
265 }
266 fAddedFields.emplace_back(fieldp);
267}
268
269void ROOT::RNTupleModel::RUpdater::AddField(std::unique_ptr<ROOT::RFieldBase> field, std::string_view parentName)
270{
271 fOpenChangeset.AddField(std::move(field), parentName);
272}
273
276{
277 auto fieldp = field.get();
278 auto result = fModel.AddProjectedField(std::move(field), mapping);
279 if (result)
280 fAddedProjectedFields.emplace_back(fieldp);
282}
283
286{
287 return R__FORWARD_RESULT(fOpenChangeset.AddProjectedField(std::move(field), std::move(mapping)));
288}
289
291{
293 if (!nameValid) {
294 nameValid.Throw();
295 }
296 if (fieldName.empty()) {
297 throw RException(R__FAIL("name cannot be empty string \"\""));
298 }
299 auto fieldNameStr = std::string(fieldName);
300 if (fFieldNames.count(fieldNameStr) > 0)
301 throw RException(R__FAIL("field name '" + fieldNameStr + "' already exists in NTuple model"));
302}
303
305{
306 if (IsFrozen())
307 throw RException(R__FAIL("invalid attempt to modify frozen model"));
308}
309
311{
312 if (IsBare())
313 throw RException(R__FAIL("invalid attempt to use default entry of bare model"));
314}
315
316ROOT::RNTupleModel::RNTupleModel(std::unique_ptr<ROOT::RFieldZero> fieldZero)
318{
319}
320
321std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::CreateBare()
322{
323 return CreateBare(std::make_unique<ROOT::RFieldZero>());
324}
325
326std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::CreateBare(std::unique_ptr<ROOT::RFieldZero> fieldZero)
327{
328 auto model = std::unique_ptr<RNTupleModel>(new RNTupleModel(std::move(fieldZero)));
329 model->fProjectedFields = std::make_unique<Internal::RProjectedFields>(*model);
330 return model;
331}
332
333std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Create()
334{
335 return Create(std::make_unique<ROOT::RFieldZero>());
336}
337
338std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Create(std::unique_ptr<ROOT::RFieldZero> fieldZero)
339{
340 auto model = CreateBare(std::move(fieldZero));
341 model->fDefaultEntry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(model->fModelId, model->fSchemaId));
342 return model;
343}
344
345std::unique_ptr<ROOT::RNTupleModel> ROOT::RNTupleModel::Clone() const
346{
347 auto cloneModel = std::unique_ptr<RNTupleModel>(new RNTupleModel(
348 std::unique_ptr<ROOT::RFieldZero>(static_cast<ROOT::RFieldZero *>(fFieldZero->Clone("").release()))));
349 cloneModel->fModelId = GetNewModelId();
350 // For a frozen model, we can keep the schema id because adding new fields is forbidden. It is reset in Unfreeze()
351 // if called by the user.
352 if (IsFrozen()) {
353 cloneModel->fSchemaId = fSchemaId;
354 } else {
355 cloneModel->fSchemaId = cloneModel->fModelId;
356 }
357 cloneModel->fModelState = (fModelState == EState::kExpired) ? EState::kFrozen : fModelState;
358 cloneModel->fFieldNames = fFieldNames;
359 cloneModel->fDescription = fDescription;
360 cloneModel->fProjectedFields = fProjectedFields->Clone(*cloneModel);
361 cloneModel->fRegisteredSubfields = fRegisteredSubfields;
362 if (fDefaultEntry) {
363 cloneModel->fDefaultEntry =
364 std::unique_ptr<ROOT::REntry>(new ROOT::REntry(cloneModel->fModelId, cloneModel->fSchemaId));
365 for (const auto &f : cloneModel->fFieldZero->GetMutableSubfields()) {
366 cloneModel->fDefaultEntry->AddValue(f->CreateValue());
367 }
368 for (const auto &f : cloneModel->fRegisteredSubfields) {
369 cloneModel->AddSubfield(f, *cloneModel->fDefaultEntry);
370 }
371 }
372 return cloneModel;
373}
374
376{
377 if (fieldName.empty())
378 return nullptr;
379
380 auto *field = static_cast<ROOT::RFieldBase *>(fFieldZero.get());
381 for (auto subfieldName : ROOT::Split(fieldName, ".")) {
382 const auto subfields = field->GetMutableSubfields();
383 auto it = std::find_if(subfields.begin(), subfields.end(),
384 [&](const auto *f) { return f->GetFieldName() == subfieldName; });
385 if (it != subfields.end()) {
386 field = *it;
387 } else {
388 field = nullptr;
389 break;
390 }
391 }
392
393 return field;
394}
395
396void ROOT::RNTupleModel::AddField(std::unique_ptr<ROOT::RFieldBase> field)
397{
398 EnsureNotFrozen();
399 if (!field)
400 throw RException(R__FAIL("null field"));
401 EnsureValidFieldName(field->GetFieldName());
402
403 if (fDefaultEntry)
404 fDefaultEntry->AddValue(field->CreateValue());
405 fFieldNames.insert(field->GetFieldName());
406 fFieldZero->Attach(std::move(field));
407}
408
410 bool initializeValue) const
411{
412 auto field = FindField(qualifiedFieldName);
413 if (initializeValue)
414 entry.AddValue(field->CreateValue());
415 else
416 entry.AddValue(field->BindValue(nullptr));
417}
418
420{
421 if (qualifiedFieldName.empty())
422 throw RException(R__FAIL("no field name provided"));
423
424 if (fFieldNames.find(std::string(qualifiedFieldName)) != fFieldNames.end()) {
425 throw RException(
426 R__FAIL("cannot register top-level field \"" + std::string(qualifiedFieldName) + "\" as a subfield"));
427 }
428
429 if (fRegisteredSubfields.find(std::string(qualifiedFieldName)) != fRegisteredSubfields.end())
430 throw RException(R__FAIL("subfield \"" + std::string(qualifiedFieldName) + "\" already registered"));
431
432 EnsureNotFrozen();
433
434 auto *field = FindField(qualifiedFieldName);
435 if (!field) {
436 throw RException(R__FAIL("could not find subfield \"" + std::string(qualifiedFieldName) + "\" in model"));
437 }
438
439 auto parent = field->GetParent();
440 while (parent && !parent->GetFieldName().empty()) {
441 if (parent->GetStructure() == ROOT::ENTupleStructure::kCollection || parent->GetNRepetitions() > 0 ||
442 parent->GetStructure() == ROOT::ENTupleStructure::kVariant) {
443 throw RException(R__FAIL(
444 "registering a subfield as part of a collection, fixed-sized array or std::variant is not supported"));
445 }
446 parent = parent->GetParent();
447 }
448
449 if (fDefaultEntry)
450 AddSubfield(qualifiedFieldName, *fDefaultEntry);
451 fRegisteredSubfields.emplace(qualifiedFieldName);
452}
453
456{
457 EnsureNotFrozen();
458 if (!field)
459 return R__FAIL("null field");
460 auto fieldName = field->GetFieldName();
461
463 auto sourceField = FindField(mapping(fieldName));
464 if (!sourceField)
465 return R__FAIL("no such field: " + mapping(fieldName));
466 fieldMap[field.get()] = sourceField;
467 for (const auto &subField : *field) {
468 sourceField = FindField(mapping(subField.GetQualifiedFieldName()));
469 if (!sourceField)
470 return R__FAIL("no such field: " + mapping(subField.GetQualifiedFieldName()));
472 }
473
474 EnsureValidFieldName(fieldName);
475 auto result = fProjectedFields->Add(std::move(field), fieldMap);
476 if (!result) {
477 return R__FORWARD_ERROR(result);
478 }
479 fFieldNames.insert(fieldName);
480 return RResult<void>::Success();
481}
482
484{
485 if (IsFrozen())
486 throw RException(R__FAIL("invalid attempt to get mutable zero field of frozen model"));
487 return *fFieldZero;
488}
489
491{
492 if (IsFrozen())
493 throw RException(R__FAIL("invalid attempt to get mutable field of frozen model"));
494 auto f = FindField(fieldName);
495 if (!f)
496 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
497
498 return *f;
499}
500
502{
503 auto f = FindField(fieldName);
504 if (!f)
505 throw RException(R__FAIL("invalid field: " + std::string(fieldName)));
506
507 return *f;
508}
509
511{
512 EnsureNotBare();
513 return *fDefaultEntry;
514}
515
517{
518 if (!IsFrozen())
519 throw RException(R__FAIL("invalid attempt to get default entry of unfrozen model"));
520 EnsureNotBare();
521 return *fDefaultEntry;
522}
523
524std::unique_ptr<ROOT::REntry> ROOT::RNTupleModel::CreateEntry() const
525{
526 switch (fModelState) {
527 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
528 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
529 case EState::kFrozen: break;
530 }
531
532 auto entry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(fModelId, fSchemaId));
533 for (const auto &f : fFieldZero->GetMutableSubfields()) {
534 entry->AddValue(f->CreateValue());
535 }
536 for (const auto &f : fRegisteredSubfields) {
537 AddSubfield(f, *entry);
538 }
539 return entry;
540}
541
542std::unique_ptr<ROOT::REntry> ROOT::RNTupleModel::CreateBareEntry() const
543{
544 switch (fModelState) {
545 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
546 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
547 case EState::kFrozen: break;
548 }
549
550 auto entry = std::unique_ptr<ROOT::REntry>(new ROOT::REntry(fModelId, fSchemaId));
551 for (const auto &f : fFieldZero->GetMutableSubfields()) {
552 entry->AddValue(f->BindValue(nullptr));
553 }
554 for (const auto &f : fRegisteredSubfields) {
555 AddSubfield(f, *entry, false /* initializeValue */);
556 }
557 return entry;
558}
559
560std::unique_ptr<ROOT::Detail::RRawPtrWriteEntry> ROOT::RNTupleModel::CreateRawPtrWriteEntry() const
561{
562 switch (fModelState) {
563 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create entry of unfrozen model"));
564 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create entry of expired model"));
565 case EState::kFrozen: break;
566 }
567
568 auto entry = std::unique_ptr<Detail::RRawPtrWriteEntry>(new Detail::RRawPtrWriteEntry(fModelId, fSchemaId));
569 for (const auto &f : fFieldZero->GetMutableSubfields()) {
570 entry->AddField(*f);
571 }
572 // fRegisteredSubfields are not relevant for writing
573 return entry;
574}
575
577{
578 const auto &topLevelFields = fFieldZero->GetConstSubfields();
579 auto it = std::find_if(topLevelFields.begin(), topLevelFields.end(),
580 [&fieldName](const ROOT::RFieldBase *f) { return f->GetFieldName() == fieldName; });
581
582 if (it == topLevelFields.end()) {
583 throw RException(R__FAIL("invalid field name: " + std::string(fieldName)));
584 }
585 return ROOT::RFieldToken(std::distance(topLevelFields.begin(), it), fSchemaId);
586}
587
589{
590 switch (fModelState) {
591 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to create bulk of unfrozen model"));
592 case EState::kExpired: throw RException(R__FAIL("invalid attempt to create bulk of expired model"));
593 case EState::kFrozen: break;
594 }
595
596 auto f = FindField(fieldName);
597 if (!f)
598 throw RException(R__FAIL("no such field: " + std::string(fieldName)));
599 return f->CreateBulk();
600}
601
603{
604 switch (fModelState) {
605 case EState::kExpired: return;
606 case EState::kBuilding: throw RException(R__FAIL("invalid attempt to expire unfrozen model"));
607 case EState::kFrozen: break;
608 }
609
610 // Ensure that Fill() does not work anymore
611 fModelId = 0;
612 fModelState = EState::kExpired;
613}
614
616{
617 switch (fModelState) {
618 case EState::kBuilding: return;
619 case EState::kExpired: throw RException(R__FAIL("invalid attempt to unfreeze expired model"));
620 case EState::kFrozen: break;
621 }
622
623 fModelId = GetNewModelId();
624 fSchemaId = fModelId;
625 if (fDefaultEntry) {
626 fDefaultEntry->fModelId = fModelId;
627 fDefaultEntry->fSchemaId = fSchemaId;
628 }
629 fModelState = EState::kBuilding;
630}
631
633{
634 if (fModelState == EState::kExpired)
635 throw RException(R__FAIL("invalid attempt to freeze expired model"));
636
637 fModelState = EState::kFrozen;
638}
639
641{
642 EnsureNotFrozen();
643 fDescription = std::string(description);
644}
645
647{
648 std::size_t bytes = 0;
649 std::size_t minPageBufferSize = 0;
650
651 // Start with the size of the page buffers used to fill a persistent sink
652 std::size_t nColumns = 0;
653 for (auto &&field : *fFieldZero) {
654 for (const auto &r : field.GetColumnRepresentatives()) {
655 nColumns += r.size();
656 minPageBufferSize += r.size() * options.GetInitialUnzippedPageSize();
657 }
658 }
659 bytes = std::min(options.GetPageBufferBudget(), nColumns * options.GetMaxUnzippedPageSize());
660
661 // If using buffered writing with RPageSinkBuf, we create a clone of the model and keep at least
662 // the compressed pages in memory.
663 if (options.GetUseBufferedWrite()) {
665 // Use the target cluster size as an estimate for all compressed pages combined.
667 int compression = options.GetCompression();
669 // With IMT, compression happens asynchronously which means that the uncompressed pages also stay around. Use a
670 // compression factor of 2x as a very rough estimate.
671 bytes += 2 * options.GetApproxZippedClusterSize();
672 }
673 }
674
675 return bytes;
676}
#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:350
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:47
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:59
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, std::string_view parentName="")
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< Internal::RProjectedFields > fProjectedFields
The set of projected top-level fields.
std::unique_ptr< Detail::RRawPtrWriteEntry > CreateRawPtrWriteEntry() const
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 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: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.
void AddItemToRecord(RRecordField &record, std::unique_ptr< RFieldBase > newItem)
Definition RField.cxx:637
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, RNTupleModel::FieldMappingFunc_t mapping)
ROOT::RRecordField * GetParentRecordField(std::string_view parentName) const