Skip to content

Conversation

@jblomer
Copy link
Contributor

@jblomer jblomer commented Dec 3, 2025

The following two fixes to the treatment of subfield names:

  • Ensure that subfields of compound types with numbered fields actually carry the field number as a name
  • Prevent duplicate field names in RFieldZero and RRecordField

For fields that are constructed using existing item subfields, ensure
that the subfields are called _0, _1, ... in the final type.

This issue has been addressed for untyped collections only in commit
bdce4b5

The issue is, however, present in many other field constructors, too.
In RFieldZero and RRecordField, check that the passed subfields have
pairwise distinct names.
@jblomer jblomer self-assigned this Dec 3, 2025
@jblomer jblomer requested a review from bellenot as a code owner December 3, 2025 14:06
@github-actions
Copy link

github-actions bot commented Dec 4, 2025

Test Results

    22 files      22 suites   4d 5h 50m 55s ⏱️
 3 786 tests  3 786 ✅ 0 💤 0 ❌
81 274 runs  81 274 ✅ 0 💤 0 ❌

Results for commit e8d96e7.

std::string expected{std::string("") +
"$ Field 1 : arrayasrvecfield (ROOT::VecOps::RVec<float>) $\n" +
"$ Field 1.1 : myfloat (float) $\n"};
"$ Field 1.1 : _0 (float) $\n"};
Copy link
Member

Choose a reason for hiding this comment

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

This seems to be a degradation. The user used on line 121 the name myfloat which is now no longer represented in the schema ... is that the intent?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, because the binary format specification says that the item field has name _0

Copy link
Member

@pcanal pcanal Dec 18, 2025

Choose a reason for hiding this comment

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

Humm .... when reading back how will the user properly retrieve myfloat vs myotherfloat if they are both turned into _0 and the name are completely forgotten?
i.e. Is the name really gone (likely a blocker of sort) or is it just an artefact of the printing?

std::string expected{std::string("") +
"$ Field 1 : arrayasrvecfield (ROOT::VecOps::RVec<float>) $\n" +
"$ Field 1.1 : myfloat (float) $\n"};
"$ Field 1.1 : _0 (float) $\n"};
Copy link
Member

Choose a reason for hiding this comment

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

Yes, because the binary format specification says that the item field has name _0

Comment on lines +81 to +83
/// A public version of the Attach method that allows piece-wise construction of the zero field.
/// Will throw on duplicate subfield names.
void Attach(std::unique_ptr<RFieldBase> child);
Copy link
Member

Choose a reason for hiding this comment

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

Hm, RFieldBase::Attach is non-virtual so "overriding" it in the base class only works if we statically know the type of the RFieldZero - is that the case?


void ROOT::RFieldZero::Attach(std::unique_ptr<RFieldBase> child)
{
const std::string childName = child->GetFieldName();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const std::string childName = child->GetFieldName();
const std::string &childName = child->GetFieldName();

to avoid the copy?

Comment on lines +44 to +47
if (fSubFieldNames.count(childName) > 0)
throw RException(R__FAIL("duplicate field name: " + childName));
RFieldBase::Attach(std::move(child), "");
fSubFieldNames.insert(childName);
Copy link
Member

Choose a reason for hiding this comment

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

Can do this in one go:

Suggested change
if (fSubFieldNames.count(childName) > 0)
throw RException(R__FAIL("duplicate field name: " + childName));
RFieldBase::Attach(std::move(child), "");
fSubFieldNames.insert(childName);
if (!fSubFieldNames.insert(childName).second)
throw RException(R__FAIL("duplicate field name: " + childName));
RFieldBase::Attach(std::move(child), "");

{
fTraits |= kTraitTrivialType;
fOffsets.reserve(itemFields.size());
std::unordered_set<std::string> fieldNames;
Copy link
Member

Choose a reason for hiding this comment

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

For the local std::unordered_set, we probably only need std::string_view as the item type and avoid the string copies

fOffsets.reserve(itemFields.size());
std::unordered_set<std::string> fieldNames;
for (auto &item : itemFields) {
const auto itemName = item->GetFieldName();
Copy link
Member

Choose a reason for hiding this comment

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

This will copy the field name

Comment on lines +620 to +622
if (fieldNames.count(itemName) > 0) {
throw RException(R__FAIL("duplicate field name: " + itemName));
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (fieldNames.count(itemName) > 0) {
throw RException(R__FAIL("duplicate field name: " + itemName));
}
if (!fieldNames.insert(itemName).second) {
throw RException(R__FAIL("duplicate field name: " + itemName));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants