27std::uint64_t GetNewModelId()
29 static std::atomic<std::uint64_t> gLastModelId = 0;
30 return ++gLastModelId;
36 if (model.IsExpired()) {
39 return *model.fFieldZero;
44 if (model.IsExpired()) {
47 return *model.fProjectedFields;
61 auto source = fieldMap.at(target);
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 "
76 const bool hasCompatibleStructure = (source->GetStructure() == target->
GetStructure()) ||
79 if (!hasCompatibleStructure)
80 return R__FAIL(
"field mapping structural mismatch: " + source->GetFieldName() +
" --> " + target->
GetFieldName());
84 return R__FAIL(
"field mapping type mismatch: " + source->GetFieldName() +
" --> " + target->
GetFieldName());
88 auto parent =
f.GetParent();
90 if (parent->GetNRepetitions() > 0)
92 parent = parent->GetParent();
96 if (fnHasArrayParent(*source) || fnHasArrayParent(*target)) {
97 return R__FAIL(
"unsupported field mapping across fixed-size arrays");
105 auto parent =
f->GetParent();
111 parent = parent->GetParent();
118 auto *sourceBreakPoint = fnBreakPoint(source);
120 return R__FAIL(
"unsupported field mapping (source structure)");
121 auto *targetBreakPoint = fnBreakPoint(target);
123 return R__FAIL(
"unsupported field mapping (target structure)");
125 if (!sourceBreakPoint && !targetBreakPoint) {
129 if (sourceBreakPoint && targetBreakPoint) {
130 if (sourceBreakPoint == targetBreakPoint) {
134 if (
auto it = fieldMap.find(targetBreakPoint); it != fieldMap.end() && it->second == sourceBreakPoint) {
139 return R__FAIL(
"field mapping structure mismatch: " + source->GetFieldName() +
" --> " + target->
GetFieldName());
143 return R__FAIL(
"field mapping structure mismatch: " + source->GetFieldName() +
" --> " + target->
GetFieldName());
152 for (
const auto &
f : *field) {
158 fFieldMap.insert(fieldMap.begin(), fieldMap.end());
170std::unique_ptr<ROOT::Internal::RProjectedFields>
173 auto cloneFieldZero =
175 auto clone = std::unique_ptr<RProjectedFields>(
new RProjectedFields(std::move(cloneFieldZero)));
176 clone->fModel = &newModel;
180 for (
const auto &
f : clone->GetFieldZero()) {
181 if (
f.GetQualifiedFieldName() == k->GetQualifiedFieldName()) {
182 clone->fFieldMap[&
f] = &newModel.
GetConstField(
v->GetQualifiedFieldName());
226 if (parentName.empty())
230 throw RException(
R__FAIL(
"invalid attempt to late-model-extend an untyped record of a non-bare model"));
233 auto &parentField =
fModel.GetMutableField(parentName);
235 if (!parentRecord || !parentRecord->GetTypeName().empty()) {
237 R__FAIL(
"invalid attempt to extend a field that is not an untyped record: " + std::string(parentName)));
246 throw RException(
R__FAIL(
"invalid attempt to extend an untyped record that has a non-record parent: " +
247 std::string(parentName)));
250 itr = itr->GetParent();
257 std::string_view parentName)
259 auto fieldp = field.get();
263 fModel.AddField(std::move(field));
276 auto fieldp = field.get();
277 auto result =
fModel.AddProjectedField(std::move(field), mapping);
295 if (fieldName.empty()) {
298 auto fieldNameStr = std::string(fieldName);
300 throw RException(
R__FAIL(
"field name '" + fieldNameStr +
"' already exists in NTuple model"));
322 return CreateBare(std::make_unique<ROOT::RFieldZero>());
327 auto model = std::unique_ptr<RNTupleModel>(
new RNTupleModel(std::move(fieldZero)));
328 model->fProjectedFields = std::make_unique<Internal::RProjectedFields>(*model);
334 return Create(std::make_unique<ROOT::RFieldZero>());
339 auto model =
CreateBare(std::move(fieldZero));
340 model->fDefaultEntry = std::unique_ptr<ROOT::REntry>(
new ROOT::REntry(model->fModelId, model->fSchemaId));
346 auto cloneModel = std::unique_ptr<RNTupleModel>(
new RNTupleModel(
348 cloneModel->fModelId = GetNewModelId();
354 cloneModel->fSchemaId = cloneModel->fModelId;
362 cloneModel->fDefaultEntry =
363 std::unique_ptr<ROOT::REntry>(
new ROOT::REntry(cloneModel->fModelId, cloneModel->fSchemaId));
364 for (
const auto &
f : cloneModel->fFieldZero->GetMutableSubfields()) {
365 cloneModel->fDefaultEntry->AddValue(
f->CreateValue());
367 for (
const auto &
f : cloneModel->fRegisteredSubfields) {
368 cloneModel->AddSubfield(
f, *cloneModel->fDefaultEntry);
376 if (fieldName.empty())
380 for (
auto subfieldName :
ROOT::Split(fieldName,
".")) {
381 const auto subfields = field->GetMutableSubfields();
382 auto it = std::find_if(subfields.begin(), subfields.end(),
383 [&](
const auto *
f) { return f->GetFieldName() == subfieldName; });
384 if (it != subfields.end()) {
409 bool initializeValue)
const
411 auto field =
FindField(qualifiedFieldName);
413 entry.
AddValue(field->CreateValue());
415 entry.
AddValue(field->BindValue(
nullptr));
420 if (qualifiedFieldName.empty())
425 R__FAIL(
"cannot register top-level field \"" + std::string(qualifiedFieldName) +
"\" as a subfield"));
429 throw RException(
R__FAIL(
"subfield \"" + std::string(qualifiedFieldName) +
"\" already registered"));
433 auto *field =
FindField(qualifiedFieldName);
435 throw RException(
R__FAIL(
"could not find subfield \"" + std::string(qualifiedFieldName) +
"\" in model"));
438 auto parent = field->GetParent();
439 while (parent && !parent->GetFieldName().empty()) {
443 "registering a subfield as part of a collection, fixed-sized array or std::variant is not supported"));
445 parent = parent->GetParent();
459 auto fieldName = field->GetFieldName();
462 auto sourceField =
FindField(mapping(fieldName));
464 return R__FAIL(
"no such field: " + mapping(fieldName));
465 fieldMap[field.get()] = sourceField;
466 for (
const auto &subField : *field) {
467 sourceField =
FindField(mapping(subField.GetQualifiedFieldName()));
469 return R__FAIL(
"no such field: " + mapping(subField.GetQualifiedFieldName()));
470 fieldMap[&subField] = sourceField;
485 throw RException(
R__FAIL(
"invalid attempt to get mutable zero field of frozen model"));
492 throw RException(
R__FAIL(
"invalid attempt to get mutable field of frozen model"));
518 throw RException(
R__FAIL(
"invalid attempt to get default entry of unfrozen model"));
532 for (
const auto &
f :
fFieldZero->GetMutableSubfields()) {
533 entry->AddValue(
f->CreateValue());
550 for (
const auto &
f :
fFieldZero->GetMutableSubfields()) {
551 entry->AddValue(
f->BindValue(
nullptr));
568 for (
const auto &
f :
fFieldZero->GetMutableSubfields()) {
577 const auto &topLevelFields =
fFieldZero->GetConstSubfields();
578 auto it = std::find_if(topLevelFields.begin(), topLevelFields.end(),
579 [&fieldName](
const ROOT::RFieldBase *
f) { return f->GetFieldName() == fieldName; });
581 if (it == topLevelFields.end()) {
598 return f->CreateBulk();
647 std::size_t bytes = 0;
648 std::size_t minPageBufferSize = 0;
651 std::size_t nColumns = 0;
653 for (
const auto &
r : field.GetColumnRepresentatives()) {
654 nColumns +=
r.size();
663 bytes += minPageBufferSize;
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking).
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
#define R__LOG_WARNING(...)
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.
RProjectedFields(std::unique_ptr< ROOT::RFieldZero > fieldZero)
std::unique_ptr< RProjectedFields > Clone(const RNTupleModel &newModel) const
Clones this container and all the projected fields it owns.
FieldMap_t fFieldMap
Maps the source fields from fModel to the target projected fields attached to fFieldZero.
std::unique_ptr< ROOT::RFieldZero > fFieldZero
The projected fields are attached to this zero field.
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...
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
void AddValue(ROOT::RFieldBase::RValue &&value)
Base class for all ROOT issued exceptions.
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.
ROOT::ENTupleStructure GetStructure() const
const RFieldBase * GetParent() const
const std::string & GetFieldName() const
RColumnRepresentations::Selection_t GetColumnRepresentatives() const
Returns the fColumnRepresentative pointee or, if unset (always the case for artificial fields),...
const std::string & GetTypeName() const
A field token identifies a (sub)field in an entry.
The container field for an ntuple model, which itself has no physical representation.
ROOT::RNTupleWriter & fWriter
std::uint64_t fNewModelId
The model ID after committing.
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)
Internal::RNTupleModelChangeset fOpenChangeset
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::unordered_set< std::string > fRegisteredSubfields
Keeps track of which subfields have been registered to be included in entries belonging to this model...
std::size_t EstimateWriteMemoryUsage(const ROOT::RNTupleWriteOptions &options=ROOT::RNTupleWriteOptions()) const
Estimate the memory usage for this model during writing.
EState fModelState
Changed by Freeze() / Unfreeze() and by the RUpdater.
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()
std::string fDescription
Free text set by the user.
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...
std::unique_ptr< ROOT::REntry > fDefaultEntry
Contains field values corresponding to the created top-level fields, as well as registered subfields.
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...
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.
bool GetUseBufferedWrite() const
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.
The field for an untyped record.
void Throw()
Throws an RException with fError.
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
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)
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="")
std::vector< ROOT::RFieldBase * > fAddedProjectedFields
Points to the projected fields in fModel that were added as part of an updater transaction.
std::vector< ROOT::RFieldBase * > fAddedFields
Points to the fields in fModel that were added as part of an updater transaction.
ROOT::RResult< void > AddProjectedField(std::unique_ptr< ROOT::RFieldBase > field, RNTupleModel::FieldMappingFunc_t mapping)
ROOT::RRecordField * GetParentRecordField(std::string_view parentName) const