29std::uint64_t GetNewModelId()
31 static std::atomic<std::uint64_t> gLastModelId = 0;
32 return ++gLastModelId;
36std::unique_ptr<ROOT::Experimental::RNTupleModel>
38 std::string_view rightFieldPrefix)
43 auto newModel = left.
Clone();
46 if (!rightFieldPrefix.empty()) {
47 newModel->MakeCollection(std::string(rightFieldPrefix), right.
Clone());
50 newModel->AddField(
f->Clone(
f->GetFieldName()));
64 auto source = fieldMap.at(
target);
65 const bool hasCompatibleStructure =
66 (source->GetStructure() ==
target->GetStructure()) ||
68 if (!hasCompatibleStructure)
69 return R__FAIL(
"field mapping structural mismatch: " + source->GetFieldName() +
" --> " +
target->GetFieldName());
71 if (
target->GetTypeName() != source->GetTypeName())
72 return R__FAIL(
"field mapping type mismatch: " + source->GetFieldName() +
" --> " +
target->GetFieldName());
91 auto *sourceBreakPoint = fnBreakPoint(source);
93 return R__FAIL(
"unsupported field mapping (source structure)");
94 auto *targetBreakPoint = fnBreakPoint(
target);
96 return R__FAIL(
"unsupported field mapping (target structure)");
98 if (!sourceBreakPoint && !targetBreakPoint) {
102 if (sourceBreakPoint && targetBreakPoint) {
103 if (sourceBreakPoint == targetBreakPoint) {
107 if (
auto it = fieldMap.find(targetBreakPoint); it != fieldMap.end() && it->second == sourceBreakPoint) {
112 return R__FAIL(
"field mapping structure mismatch: " + source->GetFieldName() +
" --> " +
target->GetFieldName());
116 return R__FAIL(
"field mapping structure mismatch: " + source->GetFieldName() +
" --> " +
target->GetFieldName());
122 auto result = EnsureValidMapping(field.get(), fieldMap);
125 for (
const auto &
f : *field) {
126 result = EnsureValidMapping(&
f, fieldMap);
131 fFieldMap.insert(fieldMap.begin(), fieldMap.end());
139 if (
auto it = fFieldMap.find(
target); it != fFieldMap.end())
144std::unique_ptr<ROOT::Experimental::RNTupleModel::RProjectedFields>
147 auto cloneFieldZero = std::unique_ptr<RFieldZero>(
static_cast<RFieldZero *
>(
fFieldZero->Clone(
"").release()));
148 auto clone = std::unique_ptr<RProjectedFields>(
new RProjectedFields(std::move(cloneFieldZero)));
149 clone->fModel = newModel;
152 for (
const auto &[k,
v] : fFieldMap) {
153 for (
const auto &
f : *clone->GetFieldZero()) {
154 if (
f.GetQualifiedFieldName() == k->GetQualifiedFieldName()) {
155 clone->fFieldMap[&
f] = clone->fModel->
FindField(
v->GetQualifiedFieldName());
164 : fWriter(
writer), fOpenChangeset(fWriter.GetUpdatableModel())
170 fOpenChangeset.fModel.Unfreeze();
173 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
178 fOpenChangeset.fModel.Freeze();
179 std::swap(fOpenChangeset.fModel.fModelId, fNewModelId);
180 if (fOpenChangeset.IsEmpty())
183 std::swap(fOpenChangeset.fAddedFields, toCommit.fAddedFields);
184 std::swap(fOpenChangeset.fAddedProjectedFields, toCommit.fAddedProjectedFields);
185 fWriter.GetSink().UpdateSchema(toCommit, fWriter.GetNEntries());
190 auto fieldp = field.get();
191 fOpenChangeset.fModel.AddField(std::move(field));
192 fOpenChangeset.fAddedFields.emplace_back(fieldp);
199 auto fieldp = field.get();
200 auto result = fOpenChangeset.fModel.AddProjectedField(std::move(field), mapping);
202 fOpenChangeset.fAddedProjectedFields.emplace_back(fieldp);
212 auto fieldNameStr = std::string(fieldName);
214 throw RException(
R__FAIL(
"field name '" + fieldNameStr +
"' already exists in NTuple model"));
235 return CreateBare(std::make_unique<RFieldZero>());
238std::unique_ptr<ROOT::Experimental::RNTupleModel>
241 auto model = std::unique_ptr<RNTupleModel>(
new RNTupleModel(std::move(fieldZero)));
242 model->fProjectedFields = std::make_unique<RProjectedFields>(model.get());
248 return Create(std::make_unique<RFieldZero>());
251std::unique_ptr<ROOT::Experimental::RNTupleModel>
254 auto model = CreateBare(std::move(fieldZero));
255 model->fDefaultEntry = std::unique_ptr<REntry>(
new REntry(model->fModelId, model->fSchemaId));
261 auto cloneModel = std::unique_ptr<RNTupleModel>(
262 new RNTupleModel(std::unique_ptr<RFieldZero>(
static_cast<RFieldZero *
>(fFieldZero->Clone(
"").release()))));
263 cloneModel->fModelId = GetNewModelId();
267 cloneModel->fSchemaId = fSchemaId;
269 cloneModel->fSchemaId = cloneModel->fModelId;
271 cloneModel->fIsFrozen = fIsFrozen;
272 cloneModel->fFieldNames = fFieldNames;
273 cloneModel->fDescription = fDescription;
274 cloneModel->fProjectedFields = fProjectedFields->Clone(cloneModel.get());
276 cloneModel->fDefaultEntry = std::unique_ptr<REntry>(
new REntry(cloneModel->fModelId, cloneModel->fSchemaId));
277 for (
const auto &
f : cloneModel->fFieldZero->GetSubFields()) {
278 cloneModel->fDefaultEntry->AddValue(
f->CreateValue());
286 if (fieldName.empty())
290 for (
auto subfieldName :
ROOT::Split(fieldName,
".")) {
292 auto it = std::find_if(subfields.begin(), subfields.end(),
293 [&](
const auto *
f) { return f->GetFieldName() == subfieldName; });
294 if (it != subfields.end()) {
310 EnsureValidFieldName(field->GetFieldName());
313 fDefaultEntry->AddValue(field->CreateValue());
314 fFieldNames.insert(field->GetFieldName());
315 fFieldZero->Attach(std::move(field));
324 auto fieldName = field->GetFieldName();
327 auto sourceField = FindField(mapping(fieldName));
329 return R__FAIL(
"no such field: " + mapping(fieldName));
330 fieldMap[field.get()] = sourceField;
331 for (
const auto &subField : *field) {
332 sourceField = FindField(mapping(subField.GetQualifiedFieldName()));
334 return R__FAIL(
"no such field: " + mapping(fieldName));
335 fieldMap[&subField] = sourceField;
338 EnsureValidFieldName(fieldName);
339 auto result = fProjectedFields->Add(std::move(field), fieldMap);
343 fFieldNames.insert(fieldName);
347std::shared_ptr<ROOT::Experimental::RNTupleCollectionWriter>
349 std::unique_ptr<RNTupleModel> collectionModel)
352 EnsureValidFieldName(fieldName);
353 if (!collectionModel) {
357 auto collectionWriter = std::make_shared<RNTupleCollectionWriter>(std::move(collectionModel->fDefaultEntry));
359 auto field = std::make_unique<RCollectionField>(fieldName, collectionWriter, std::move(collectionModel->fFieldZero));
360 field->SetDescription(collectionModel->GetDescription());
363 fDefaultEntry->AddValue(field->BindValue(std::shared_ptr<void>(collectionWriter->GetOffsetPtr(), [](
void *) {})));
365 fFieldNames.insert(field->GetFieldName());
366 fFieldZero->Attach(std::move(field));
367 return collectionWriter;
373 throw RException(
R__FAIL(
"invalid attempt to get mutable zero field of unfrozen model"));
379 auto f = FindField(fieldName);
389 return *fDefaultEntry;
395 throw RException(
R__FAIL(
"invalid attempt to get default entry of unfrozen model"));
397 return *fDefaultEntry;
405 auto entry = std::unique_ptr<REntry>(
new REntry(fModelId, fSchemaId));
406 for (
const auto &
f : fFieldZero->GetSubFields()) {
407 entry->AddValue(
f->CreateValue());
417 auto entry = std::unique_ptr<REntry>(
new REntry(fModelId, fSchemaId));
418 for (
const auto &
f : fFieldZero->GetSubFields()) {
419 entry->AddValue(
f->BindValue(
nullptr));
426 const auto &topLevelFields = fFieldZero->GetSubFields();
427 auto it = std::find_if(topLevelFields.begin(), topLevelFields.end(),
428 [&fieldName](
const RFieldBase *
f) { return f->GetFieldName() == fieldName; });
430 if (it == topLevelFields.end()) {
441 auto f = FindField(fieldName);
444 return f->CreateBulk();
452 fModelId = GetNewModelId();
453 fSchemaId = fModelId;
455 fDefaultEntry->fModelId = fModelId;
456 fDefaultEntry->fSchemaId = fSchemaId;
469 fDescription = std::string(description);
474 std::size_t
bytes = 0;
475 std::size_t minPageBufferSize = 0;
478 std::size_t nColumns = 0;
479 for (
auto &&field : *fFieldZero) {
480 for (
const auto &
r : field.GetColumnRepresentatives()) {
481 nColumns +=
r.size();
482 for (
auto columnType :
r) {
493 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...
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
static std::unique_ptr< RColumnElementBase > Generate(EColumnType type)
If CppT == void, use the default C++ type for the given column type.
An artificial field that transforms an RNTuple column that contains the offset of collections into co...
The field token identifies a top-level field in this entry.
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
Base class for all ROOT issued exceptions.
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
std::vector< RFieldBase * > GetSubFields()
static RResult< void > EnsureValidFieldName(std::string_view fieldName)
Check whether a given string is a valid field name.
The container field for an ntuple model, which itself has no physical representation.
Projected fields are fields whose columns are reused from existing fields.
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::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 ...
const RFieldBase * GetSourceField(const RFieldBase *target) const
RResult< void > Add(std::unique_ptr< RFieldBase > field, const FieldMap_t &fieldMap)
Adds a new projected field.
std::unique_ptr< RProjectedFields > Clone(const RNTupleModel *newModel) const
The new model needs to be a clone of fModel.
RUpdater(RNTupleWriter &writer)
void CommitUpdate()
Commit changes since the last call to BeginUpdate().
void BeginUpdate()
Begin a new set of alterations to the underlying model.
RResult< void > AddProjectedField(std::unique_ptr< RFieldBase > field, FieldMappingFunc_t mapping)
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 NTuple 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::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 top-level field.
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.
REntry & GetDefaultEntry()
std::size_t EstimateWriteMemoryUsage(const RNTupleWriteOptions &options=RNTupleWriteOptions()) const
Estimate the memory usage for this model during writing.
std::shared_ptr< RNTupleCollectionWriter > MakeCollection(std::string_view fieldName, std::unique_ptr< RNTupleModel > collectionModel)
Ingests a model for a sub collection and attaches it to the current model.
const RFieldBase & GetField(std::string_view fieldName) const
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()
RResult< void > AddProjectedField(std::unique_ptr< RFieldBase > field, FieldMappingFunc_t mapping)
Adds a top-level field based on existing fields.
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...
RNTupleModel(std::unique_ptr< RFieldZero > fieldZero)
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.
RFieldZero & GetFieldZero()
Non-const access to the root field is used to commit clusters during writing, and to make adjustments...
std::unique_ptr< RFieldZero > fFieldZero
Hierarchy of fields consisting of simple types and collections (sub trees)
Common user-tunable settings for storing ntuples.
int GetCompression() const
std::size_t GetPageBufferBudget() const
std::size_t GetApproxZippedClusterSize() const
std::size_t GetInitialNElementsPerPage() const
bool GetUseBufferedWrite() const
std::size_t GetMaxUnzippedPageSize() const
EImplicitMT GetUseImplicitMT() const
An RNTuple that gets filled with entries (data) and writes them to storage.
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...
std::unique_ptr< RNTupleModel > MergeModels(const RNTupleModel &left, const RNTupleModel &right, std::string_view rightFieldPrefix="")
Merge two RNTuple models.
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