Skip to content

[ntuple] rename 'leaf' structural role to 'static' #19502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions tree/dataframe/src/RNTupleDS.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ class RRDFCardinalityField final : public ROOT::RFieldBase {
void ConstructValue(void *where) const final { *static_cast<std::size_t *>(where) = 0; }

public:
RRDFCardinalityField() : ROOT::RFieldBase("", "std::size_t", ROOT::ENTupleStructure::kLeaf, false /* isSimple */) {}
RRDFCardinalityField() : ROOT::RFieldBase("", "std::size_t", ROOT::ENTupleStructure::kStatic, false /* isSimple */)
{
}
RRDFCardinalityField(RRDFCardinalityField &&other) = default;
RRDFCardinalityField &operator=(RRDFCardinalityField &&other) = default;
~RRDFCardinalityField() override = default;
Expand Down Expand Up @@ -135,7 +137,7 @@ class RArraySizeField final : public ROOT::RFieldBase {

public:
RArraySizeField(std::size_t arrayLength)
: ROOT::RFieldBase("", "std::size_t", ROOT::ENTupleStructure::kLeaf, false /* isSimple */),
: ROOT::RFieldBase("", "std::size_t", ROOT::ENTupleStructure::kStatic, false /* isSimple */),
fArrayLength(arrayLength)
{
}
Expand Down
15 changes: 9 additions & 6 deletions tree/ntuple/doc/BinaryFormatSpecification.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,12 +376,15 @@ The structural role of the field can have one of the following values:

| Value | Structural role |
|----------|--------------------------------------------------------------------------|
| 0x00 | Leaf field in the schema tree |
| 0x00 | Static field in the schema tree (see below) |
| 0x01 | The field is the parent of a collection (e.g., a vector) |
| 0x02 | The field is the parent of a record (e.g., a struct) |
| 0x03 | The field is the parent of a variant |
| 0x04 | The field stores objects serialized with the ROOT streamer |

A static field is either a leaf or an inner field with exactly one subfield of same cardinality
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence sounds a bit obscure to me; maybe add an example?

(modulo field repetition).

The "flags" field can have any of the following bits set:

| Bit | Meaning |
Expand All @@ -403,7 +406,7 @@ these columns are alias columns to physical columns attached to the source field
The following restrictions apply on field projections:
- The source field and the target field must have the same structural role,
except for an `RNTupleCardinality` field, which must have a collection field as a source.
- For streamer fields and leaf fields, the type name of the source field and the projected field must be identical.
- For streamer fields and static fields, the type name of the source field and the projected field must be identical.
- Projections involving variants or fixed-size arrays are unsupported.
- Projected fields must be on the same schema path of collection fields as the source field.
For instance, one can project a vector of structs with floats to individual vectors of floats but cannot
Expand Down Expand Up @@ -830,7 +833,7 @@ For example, the type name `const pair<size_t, array<class ::Event, 2>>` will be

### Fundamental Types

The following fundamental types are stored as `leaf` fields with a single column each.
The following fundamental types are stored as `static` fields with a single column each.
Fundamental C++ types can potentially be stored in multiple possible column types.
The possible combinations are marked as `W` in the following table.
Additionally, some types allow for reading from certain column types but not to write into them.
Expand Down Expand Up @@ -923,7 +926,7 @@ The child fields are named `_0`, `_1`, ...

#### std::bitset\<N\>

A bitset is stored as a repetitive leaf field with an attached `Bit` column.
A bitset is stored as a repetitive static field with an attached `Bit` column.
The bitset size `N` is stored as repetition parameter in the field metadata.
Within the repetition blocks, bits are stored in little-endian order, i.e. the least significant bits come first.

Expand Down Expand Up @@ -952,13 +955,13 @@ whose principal column is of type `(Split)Index[64|32]` and a child field of typ

### std::atomic\<T\>

Atomic types are stored as a leaf field with a single subfield named `_0`.
Atomic types are stored as a static field with a single subfield named `_0`.
The parent field has no attached columns.
The subfield corresponds to the inner type `T`.

### User-defined enums

User-defined enums are stored as a leaf field with a single subfield named `_0`.
User-defined enums are stored as a static field with a single subfield named `_0`.
The parent field has no attached columns.
The subfield corresponds to the integer type the underlies the enum.
Unscoped and scoped enums are supported as long as the enum has a dictionary.
Expand Down
8 changes: 5 additions & 3 deletions tree/ntuple/inc/ROOT/RField.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ protected:

public:
RInvalidField(std::string_view name, std::string_view type, std::string_view error, RCategory category)
: RFieldBase(name, type, ROOT::ENTupleStructure::kLeaf, false /* isSimple */), fError(error), fCategory(category)
: RFieldBase(name, type, ROOT::ENTupleStructure::kStatic, false /* isSimple */),
fError(error),
fCategory(category)
{
fTraits |= kTraitInvalidField;
}
Expand Down Expand Up @@ -324,7 +326,7 @@ private:

protected:
RCardinalityField(std::string_view fieldName, std::string_view typeName)
: RFieldBase(fieldName, typeName, ROOT::ENTupleStructure::kLeaf, false /* isSimple */)
: RFieldBase(fieldName, typeName, ROOT::ENTupleStructure::kStatic, false /* isSimple */)
{
}

Expand Down Expand Up @@ -354,7 +356,7 @@ protected:

public:
RSimpleField(std::string_view name, std::string_view type)
: RFieldBase(name, type, ROOT::ENTupleStructure::kLeaf, true /* isSimple */)
: RFieldBase(name, type, ROOT::ENTupleStructure::kStatic, true /* isSimple */)
{
fTraits |= kTraitTrivialType;
}
Expand Down
2 changes: 1 addition & 1 deletion tree/ntuple/inc/ROOT/RField/RFieldSTLMisc.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ private:
public:
static std::string TypeName() { return "std::string"; }
explicit RField(std::string_view name)
: RFieldBase(name, TypeName(), ROOT::ENTupleStructure::kLeaf, false /* isSimple */), fIndex(0)
: RFieldBase(name, TypeName(), ROOT::ENTupleStructure::kStatic, false /* isSimple */), fIndex(0)
{
}
RField(RField &&other) = default;
Expand Down
17 changes: 11 additions & 6 deletions tree/ntuple/inc/ROOT/RNTupleTypes.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,28 @@ enum class ENTupleColumnType {
kMax,
};

/// The fields in the ntuple model tree can carry different structural information about the type system.
/// Leaf fields contain just data, collection fields resolve to offset columns, record fields have no
/// materialization on the primitive column layer.
/// The fields in the RNTuple data model tree can carry different structural information about the type system.
/// Collection fields have an offset column and subfields with arbitrary cardinality, record fields have no
/// materialization on the primitive column layer and an arbitrary number of subfields. Static fields are either
/// leafs (e.g., `float`) or fields with exactly one child that has the same cardinality as the parent
/// (modulo field repetitions, e.g. std::atomic<T>).
Comment on lines +102 to +106
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't 'grasp' the static semantic in this context. To me static field evoke the idea describe here https://en.cppreference.com/w/cpp/language/static.html.
Is the intent to refer to the fact that the cardinality of the element is fixed within the context of its parent/container? eg. Fixed size arrays or single value? Or is it something else.

Leaf was evoking something that could be not further decomposed, for example numerical types and array thereof ... but also technically 'streamer field'.

Can you expand more on the rational of the choice of spelling for kStatic?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the proper semantic association would be with "static array" (as opposed to dynamic array): something with a size known a-priori

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If/since this is the case I think we do need to extend the name to include this notion of size.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure how, in this context, the meaning of the C++ static keyword comes to mind.

But I'm not clinging to that name. The currently used leaf is certainly wrong. We also discussed fixed and other.

Concretely, fields of this structural role are either leafs in the schema tree (e.g., float, bool, std::string) or it is an enum field or it is a std::atomic<T> field. For both, enums and atomics, their corresponding field is a wrapper field for the actual data field(s) underneath. My reasoning was that none of leaf fields, enums, and atomics add structural information to the schema tree. I.e., those fields are either leafs or they could be merged with their subfield.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure how, in this context, the meaning of the C++ static keyword comes to mind.

Because a field is akin (and often equal) to a data member and thus it can be easily read as 'static data member' ...

// IMPORTANT: if you add members, remember to change the related `operator<<` below.
enum class ENTupleStructure : std::uint16_t {
kInvalid,
kLeaf,
kStatic,
kCollection,
kRecord,
kVariant,
kStreamer,
kUnknown
kUnknown,

// for backwards compatibility
kLeaf R__DEPRECATED(6, 40, "use instead ROOT::ENTupleStructure::kStatic") = kStatic
};

inline std::ostream &operator<<(std::ostream &os, ENTupleStructure structure)
{
static const char *const names[] = {"Invalid", "Leaf", "Collection", "Record", "Variant", "Streamer", "Unknown"};
static const char *const names[] = {"Invalid", "Static", "Collection", "Record", "Variant", "Streamer", "Unknown"};
static_assert((std::size_t)ENTupleStructure::kUnknown + 1 == std::size(names));

if (R__likely(static_cast<std::size_t>(structure) <= std::size(names)))
Expand Down
4 changes: 2 additions & 2 deletions tree/ntuple/src/RField.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ void ROOT::RRecordField::AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) con
//------------------------------------------------------------------------------

ROOT::RBitsetField::RBitsetField(std::string_view fieldName, std::size_t N)
: ROOT::RFieldBase(fieldName, "std::bitset<" + std::to_string(N) + ">", ROOT::ENTupleStructure::kLeaf,
: ROOT::RFieldBase(fieldName, "std::bitset<" + std::to_string(N) + ">", ROOT::ENTupleStructure::kStatic,
false /* isSimple */, N),
fN(N)
{
Expand Down Expand Up @@ -981,7 +981,7 @@ size_t ROOT::ROptionalField::GetAlignment() const

ROOT::RAtomicField::RAtomicField(std::string_view fieldName, std::string_view typeName,
std::unique_ptr<RFieldBase> itemField)
: RFieldBase(fieldName, typeName, ROOT::ENTupleStructure::kLeaf, false /* isSimple */)
: RFieldBase(fieldName, typeName, ROOT::ENTupleStructure::kStatic, false /* isSimple */)
{
if (itemField->GetTraits() & kTraitTriviallyConstructible)
fTraits |= kTraitTriviallyConstructible;
Expand Down
4 changes: 2 additions & 2 deletions tree/ntuple/src/RFieldMeta.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ ROOT::REnumField::REnumField(std::string_view fieldName, std::string_view enumNa
}

ROOT::REnumField::REnumField(std::string_view fieldName, TEnum *enump)
: ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(enump->GetQualifiedName()), ROOT::ENTupleStructure::kLeaf,
: ROOT::RFieldBase(fieldName, GetRenormalizedTypeName(enump->GetQualifiedName()), ROOT::ENTupleStructure::kStatic,
false /* isSimple */)
{
// Avoid accidentally supporting std types through TEnum.
Expand All @@ -545,7 +545,7 @@ ROOT::REnumField::REnumField(std::string_view fieldName, TEnum *enump)

ROOT::REnumField::REnumField(std::string_view fieldName, std::string_view enumName,
std::unique_ptr<RFieldBase> intField)
: ROOT::RFieldBase(fieldName, enumName, ROOT::ENTupleStructure::kLeaf, false /* isSimple */)
: ROOT::RFieldBase(fieldName, enumName, ROOT::ENTupleStructure::kStatic, false /* isSimple */)
{
Attach(std::move(intField));
fTraits |= kTraitTriviallyConstructible | kTraitTriviallyDestructible;
Expand Down
2 changes: 1 addition & 1 deletion tree/ntuple/src/RFieldSequenceContainer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ ROOT::RArrayField::RArrayField(std::string_view fieldName, std::unique_ptr<RFiel
: ROOT::RFieldBase(fieldName,
"std::array<" + itemField->GetTypeName() + "," +
Internal::GetNormalizedInteger(static_cast<unsigned long long>(arrayLength)) + ">",
ROOT::ENTupleStructure::kLeaf, false /* isSimple */, arrayLength),
ROOT::ENTupleStructure::kStatic, false /* isSimple */, arrayLength),
fItemSize(itemField->GetValueSize()),
fArrayLength(arrayLength)
{
Expand Down
2 changes: 1 addition & 1 deletion tree/ntuple/src/RNTupleMerger.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ static void GenerateZeroPagesForColumns(size_t nEntriesToGenerate, std::span<con

// NOTE: we cannot have a Record here because it has no associated columns.
R__ASSERT(structure == ROOT::ENTupleStructure::kCollection || structure == ROOT::ENTupleStructure::kVariant ||
structure == ROOT::ENTupleStructure::kLeaf);
structure == ROOT::ENTupleStructure::kStatic);

const auto &columnDesc = dstDescriptor.GetColumnDescriptor(column.fOutputId);
const auto colElement = RColumnElementBase::Generate(columnDesc.GetType());
Expand Down
4 changes: 2 additions & 2 deletions tree/ntuple/src/RNTupleModel.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ ROOT::Internal::RProjectedFields::EnsureValidMapping(const ROOT::RFieldBase *tar
dynamic_cast<const ROOT::RCardinalityField *>(target));
if (!hasCompatibleStructure)
return R__FAIL("field mapping structural mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
if ((source->GetStructure() == ROOT::ENTupleStructure::kLeaf) ||
if ((source->GetStructure() == ROOT::ENTupleStructure::kStatic) ||
(source->GetStructure() == ROOT::ENTupleStructure::kStreamer)) {
if (target->GetTypeName() != source->GetTypeName())
return R__FAIL("field mapping type mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName());
Expand All @@ -100,7 +100,7 @@ ROOT::Internal::RProjectedFields::EnsureValidMapping(const ROOT::RFieldBase *tar
auto parent = f->GetParent();
while (parent) {
if ((parent->GetStructure() != ROOT::ENTupleStructure::kRecord) &&
(parent->GetStructure() != ROOT::ENTupleStructure::kLeaf)) {
(parent->GetStructure() != ROOT::ENTupleStructure::kStatic)) {
return parent;
}
parent = parent->GetParent();
Expand Down
6 changes: 3 additions & 3 deletions tree/ntuple/src/RNTupleSerialize.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ DeserializeField(const void *buffer, std::uint64_t bufSize, ROOT::Internal::RFie
std::uint32_t typeVersion;
std::uint32_t parentId;
// initialize properly for call to SerializeFieldStructure()
ENTupleStructure structure{ENTupleStructure::kLeaf};
ENTupleStructure structure{ENTupleStructure::kStatic};
std::uint16_t flags;
std::uint32_t result;
if (auto res = RNTupleSerializer::SerializeFieldStructure(structure, nullptr)) {
Expand Down Expand Up @@ -811,7 +811,7 @@ ROOT::Internal::RNTupleSerializer::SerializeFieldStructure(ROOT::ENTupleStructur
{
using ENTupleStructure = ROOT::ENTupleStructure;
switch (structure) {
case ENTupleStructure::kLeaf: return SerializeUInt16(0x00, buffer);
case ENTupleStructure::kStatic: return SerializeUInt16(0x00, buffer);
case ENTupleStructure::kCollection: return SerializeUInt16(0x01, buffer);
case ENTupleStructure::kRecord: return SerializeUInt16(0x02, buffer);
case ENTupleStructure::kVariant: return SerializeUInt16(0x03, buffer);
Expand All @@ -830,7 +830,7 @@ ROOT::Internal::RNTupleSerializer::DeserializeFieldStructure(const void *buffer,
std::uint16_t onDiskValue;
auto result = DeserializeUInt16(buffer, onDiskValue);
switch (onDiskValue) {
case 0x00: structure = ENTupleStructure::kLeaf; break;
case 0x00: structure = ENTupleStructure::kStatic; break;
case 0x01: structure = ENTupleStructure::kCollection; break;
case 0x02: structure = ENTupleStructure::kRecord; break;
case 0x03: structure = ENTupleStructure::kVariant; break;
Expand Down
20 changes: 10 additions & 10 deletions tree/ntuple/test/ntuple_descriptor.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ TEST(RNTupleDescriptorBuilder, CatchBadLinks)
.FieldId(1)
.FieldName("field")
.TypeName("int32_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
try {
Expand Down Expand Up @@ -70,21 +70,21 @@ TEST(RNTupleDescriptorBuilder, CatchBadProjections)
.FieldId(1)
.FieldName("field")
.TypeName("int32_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
descBuilder.AddField(RFieldDescriptorBuilder()
.FieldId(2)
.FieldName("projField")
.TypeName("int32_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
descBuilder.AddField(RFieldDescriptorBuilder()
.FieldId(3)
.FieldName("projField")
.TypeName("int32_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());

Expand Down Expand Up @@ -131,14 +131,14 @@ TEST(RNTupleDescriptorBuilder, CatchBadColumnDescriptors)
.FieldId(1)
.FieldName("field")
.TypeName("int32_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
descBuilder.AddField(RFieldDescriptorBuilder()
.FieldId(2)
.FieldName("fieldAlias")
.TypeName("int32_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
descBuilder.AddFieldLink(0, 1);
Expand Down Expand Up @@ -211,7 +211,7 @@ TEST(RFieldDescriptorBuilder, HeaderExtension)
.FieldId(1)
.FieldName("i32")
.TypeName("int32_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
descBuilder.AddColumn(RColumnDescriptorBuilder()
Expand Down Expand Up @@ -239,7 +239,7 @@ TEST(RFieldDescriptorBuilder, HeaderExtension)
.FieldId(3)
.FieldName("i64")
.TypeName("int64_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
descBuilder.AddColumn(RColumnDescriptorBuilder()
Expand All @@ -258,7 +258,7 @@ TEST(RFieldDescriptorBuilder, HeaderExtension)
.FieldId(4)
.FieldName("topLevel2")
.TypeName("bool")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
descBuilder.AddColumn(RColumnDescriptorBuilder()
Expand All @@ -276,7 +276,7 @@ TEST(RFieldDescriptorBuilder, HeaderExtension)
.FieldId(5)
.FieldName("projected")
.TypeName("int64_t")
.Structure(ROOT::ENTupleStructure::kLeaf)
.Structure(ROOT::ENTupleStructure::kStatic)
.MakeDescriptor()
.Unwrap());
descBuilder.AddColumn(RColumnDescriptorBuilder()
Expand Down
2 changes: 1 addition & 1 deletion tree/ntuple/test/ntuple_emulated.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ TEST(RNTupleEmulated, EmulatedFields_VecsTemplatedWrapper)
const auto *innerField = wrapperField->GetConstSubfields()[0];
ASSERT_EQ(innerField->GetTypeName(), "float");
ASSERT_EQ(innerField->GetFieldName(), "fValue");
ASSERT_EQ(innerField->GetStructure(), ROOT::ENTupleStructure::kLeaf);
ASSERT_EQ(innerField->GetStructure(), ROOT::ENTupleStructure::kStatic);
}

// Now test loading entries with a reader
Expand Down
Loading
Loading