Skip to content

Commit b774cde

Browse files
committed
[ntuple] Make RValue::fTypeInfo cache atomic
This allows concurrent calls to const methods that modifify this mutable member. Unfortunately, std::atomic is neither copyable nor movable and requires custom copy/move constructors and operators for RValue.
1 parent dbdca9e commit b774cde

File tree

1 file changed

+23
-7
lines changed

1 file changed

+23
-7
lines changed

tree/ntuple/inc/ROOT/RFieldBase.hxx

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <ROOT/RNTupleRange.hxx>
2222
#include <ROOT/RNTupleTypes.hxx>
2323

24+
#include <atomic>
2425
#include <cstddef>
2526
#include <functional>
2627
#include <iterator>
@@ -710,15 +711,29 @@ private:
710711
RFieldBase *fField = nullptr; ///< The field that created the RValue
711712
/// Set by Bind() or by RFieldBase::CreateValue(), RFieldBase::SplitValue() or RFieldBase::BindValue()
712713
std::shared_ptr<void> fObjPtr;
713-
mutable const std::type_info *fTypeInfo = nullptr;
714+
mutable std::atomic<const std::type_info *> fTypeInfo = nullptr;
714715

715716
RValue(RFieldBase *field, std::shared_ptr<void> objPtr) : fField(field), fObjPtr(objPtr) {}
716717

717718
public:
718-
RValue(const RValue &) = default;
719-
RValue &operator=(const RValue &) = default;
720-
RValue(RValue &&other) = default;
721-
RValue &operator=(RValue &&other) = default;
719+
RValue(const RValue &other) : fField(other.fField), fObjPtr(other.fObjPtr) {}
720+
RValue &operator=(const RValue &other)
721+
{
722+
fField = other.fField;
723+
fObjPtr = other.fObjPtr;
724+
// We could copy over the cached type info, or just start with a fresh state...
725+
fTypeInfo = nullptr;
726+
return *this;
727+
}
728+
RValue(RValue &&other) : fField(other.fField), fObjPtr(other.fObjPtr) {}
729+
RValue &operator=(RValue &&other)
730+
{
731+
fField = other.fField;
732+
fObjPtr = other.fObjPtr;
733+
// We could copy over the cached type info, or just start with a fresh state...
734+
fTypeInfo = nullptr;
735+
return *this;
736+
}
722737
~RValue() = default;
723738

724739
private:
@@ -729,12 +744,13 @@ private:
729744
const std::type_info &ti = typeid(T);
730745
// Fast path: if we had a matching type before, try comparing the type_info's. This may still fail in case the
731746
// type has a suppressed template argument that may change the typeid.
732-
if (fTypeInfo != nullptr && *fTypeInfo == ti) {
747+
auto *cachedTypeInfo = fTypeInfo.load();
748+
if (cachedTypeInfo != nullptr && *cachedTypeInfo == ti) {
733749
return;
734750
}
735751
std::string renormalizedTypeName = Internal::GetRenormalizedTypeName(ti);
736752
if (Internal::IsMatchingFieldType(fField->GetTypeName(), renormalizedTypeName, ti)) {
737-
fTypeInfo = &ti;
753+
fTypeInfo.store(&ti);
738754
return;
739755
}
740756
throw RException(R__FAIL("type mismatch for field \"" + fField->GetFieldName() + "\": expected " +

0 commit comments

Comments
 (0)