Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-20 09:25:58

0001 /// \file ROOT/RField.hxx
0002 /// \ingroup NTuple
0003 /// \author Jakob Blomer <jblomer@cern.ch>
0004 /// \date 2018-10-09
0005 
0006 /*************************************************************************
0007  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
0008  * All rights reserved.                                                  *
0009  *                                                                       *
0010  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0011  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0012  *************************************************************************/
0013 
0014 #ifndef ROOT_RField
0015 #define ROOT_RField
0016 
0017 #include <ROOT/RError.hxx>
0018 #include <ROOT/RFieldBase.hxx>
0019 #include <ROOT/RFieldUtils.hxx>
0020 #include <ROOT/RNTupleSerialize.hxx>
0021 #include <ROOT/RNTupleTypes.hxx>
0022 #include <ROOT/RSpan.hxx>
0023 #include <string_view>
0024 #include <ROOT/TypeTraits.hxx>
0025 
0026 #include <TGenericClassInfo.h>
0027 
0028 #include <algorithm>
0029 #include <array>
0030 #include <cstddef>
0031 #include <iostream>
0032 #include <memory>
0033 #include <string>
0034 #include <type_traits>
0035 #include <typeinfo>
0036 #include <vector>
0037 
0038 class TClass;
0039 class TEnum;
0040 class TObject;
0041 class TVirtualStreamerInfo;
0042 
0043 namespace ROOT {
0044 
0045 class TSchemaRule;
0046 class RNTupleCollectionView;
0047 
0048 namespace Detail {
0049 class RFieldVisitor;
0050 } // namespace Detail
0051 
0052 class RFieldZero;
0053 namespace Internal {
0054 void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val);
0055 }
0056 
0057 /// The container field for an ntuple model, which itself has no physical representation.
0058 /// Therefore, the zero field must not be connected to a page source or sink.
0059 class RFieldZero final : public RFieldBase {
0060    friend void ROOT::Internal::SetAllowFieldSubstitutions(RFieldZero &, bool);
0061 
0062    /// If field substitutions are allowed, upon connecting to a page source the field hierarchy will replace created
0063    /// fields by fields that match the on-disk schema. This happens for
0064    ///     - Vector fields (RVectorField, RRVecField) that connect to an on-disk fixed-size array
0065    ///     - Streamer fields that connect to an on-disk class field
0066    /// Field substitutions must not be enabled when the field hierarchy already handed out RValue objects because
0067    /// they would leave dangling field pointers to the replaced fields. This is used in cases when the field/model
0068    /// is created by RNTuple (not imposed), before it is made available to the user.
0069    /// This flag is reset on Clone().
0070    bool fAllowFieldSubstitutions = false;
0071 
0072    std::unordered_set<std::string> fSubfieldNames; ///< Efficient detection of duplicate field names
0073 
0074 protected:
0075    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0076    void ConstructValue(void *) const final {}
0077 
0078 public:
0079    RFieldZero();
0080 
0081    /// A public version of the Attach method that allows piece-wise construction of the zero field.
0082    /// Will throw on duplicate subfield names.
0083    void Attach(std::unique_ptr<RFieldBase> child);
0084    size_t GetValueSize() const final { return 0; }
0085    size_t GetAlignment() const final { return 0; }
0086 
0087    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0088 
0089    bool GetAllowFieldSubstitutions() const { return fAllowFieldSubstitutions; }
0090    /// Moves all subfields into the returned vector.
0091    std::vector<std::unique_ptr<RFieldBase>> ReleaseSubfields();
0092 };
0093 
0094 /// Used in RFieldBase::Check() to record field creation failures.
0095 /// Also used when deserializing a field that contains unknown values that may come from
0096 /// future RNTuple versions (e.g. an unknown Structure)
0097 class RInvalidField final : public RFieldBase {
0098 public:
0099    enum class ECategory {
0100       /// Generic unrecoverable error
0101       kGeneric,
0102       /// The type given to RFieldBase::Create was invalid
0103       kTypeError,
0104       /// The type given to RFieldBase::Create was unknown
0105       kUnknownType,
0106       /// The field could not be created because its descriptor had an unknown structural role
0107       kUnknownStructure,
0108    };
0109 
0110    using RCategory R__DEPRECATED(6, 42, "enum renamed to ECategory") = ECategory;
0111 
0112 private:
0113    std::string fError;
0114    ECategory fCategory;
0115 
0116 protected:
0117    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0118    {
0119       return std::make_unique<RInvalidField>(newName, GetTypeName(), fError, fCategory);
0120    }
0121    void ConstructValue(void *) const final {}
0122 
0123 public:
0124    RInvalidField(std::string_view name, std::string_view type, std::string_view error, ECategory category)
0125       : RFieldBase(name, type, ROOT::ENTupleStructure::kPlain, false /* isSimple */), fError(error), fCategory(category)
0126    {
0127       fTraits |= kTraitInvalidField;
0128    }
0129 
0130    const std::string &GetError() const { return fError; }
0131    ECategory GetCategory() const { return fCategory; }
0132 
0133    size_t GetValueSize() const final { return 0; }
0134    size_t GetAlignment() const final { return 0; }
0135 }; // RInvalidField
0136 
0137 /// The field for a class with dictionary
0138 class RClassField : public RFieldBase {
0139 private:
0140    enum ESubfieldRole {
0141       kBaseClass,
0142       kDataMember,
0143    };
0144    struct RSubfieldInfo {
0145       ESubfieldRole fRole;
0146       std::size_t fOffset;
0147    };
0148    // Information to read into the staging area a field that is used as an input to an I/O customization rule
0149    struct RStagingItem {
0150       /// The field used to read the on-disk data. The fields type may be different from the on-disk type as long
0151       /// as the on-disk type can be converted to the fields type (through type cast / schema evolution).
0152       std::unique_ptr<RFieldBase> fField;
0153       std::size_t fOffset; ///< offset in fStagingArea
0154    };
0155    /// Prefix used in the subfield names generated for base classes
0156    static constexpr const char *kPrefixInherited{":"};
0157 
0158    class RClassDeleter : public RDeleter {
0159    private:
0160       TClass *fClass;
0161 
0162    public:
0163       explicit RClassDeleter(TClass *cl) : fClass(cl) {}
0164       void operator()(void *objPtr, bool dtorOnly) final;
0165    };
0166 
0167    TClass *fClass;
0168    /// Additional information kept for each entry in `fSubfields`
0169    std::vector<RSubfieldInfo> fSubfieldsInfo;
0170 
0171    /// The staging area stores inputs to I/O rules according to the offsets given by the streamer info of
0172    /// "TypeName@@Version". The area is allocated depending on I/O rules resp. the source members of the I/O rules.
0173    std::unique_ptr<unsigned char[]> fStagingArea;
0174    /// The TClass instance that corresponds to the staging area.
0175    /// The staging class exists as <class name>@@<on-disk version> if the on-disk version is different from the
0176    /// current in-memory version, or it can be accessed by the first @@alloc streamer element of the current streamer
0177    /// info.
0178    TClass *fStagingClass = nullptr;
0179    std::unordered_map<std::string, RStagingItem> fStagingItems; ///< Lookup staging items by member name
0180 
0181 private:
0182    RClassField(std::string_view fieldName, const RClassField &source); ///< Used by CloneImpl
0183    RClassField(std::string_view fieldName, TClass *classp);
0184    void Attach(std::unique_ptr<RFieldBase> child, RSubfieldInfo info);
0185 
0186    /// Returns the id of member 'name' in the class field given by 'fieldId', or kInvalidDescriptorId if no such
0187    /// member exist. Looks recursively in base classes.
0188    ROOT::DescriptorId_t
0189    LookupMember(const ROOT::RNTupleDescriptor &desc, std::string_view memberName, ROOT::DescriptorId_t classFieldId);
0190    /// Sets fStagingClass according to the given name and version
0191    void SetStagingClass(const std::string &className, unsigned int classVersion);
0192    /// If there are rules with inputs (source members), create the staging area according to the TClass instance
0193    /// that corresponds to the on-disk field.
0194    void PrepareStagingArea(const std::vector<const TSchemaRule *> &rules, const ROOT::RNTupleDescriptor &desc,
0195                            const ROOT::RFieldDescriptor &classFieldId);
0196    /// Register post-read callback corresponding to a ROOT I/O customization rules.
0197    void AddReadCallbacksFromIORule(const TSchemaRule *rule);
0198    /// Given the on-disk information from the page source, find all the I/O customization rules that apply
0199    /// to the class field at hand, to which the fieldDesc descriptor, if provided, must correspond.
0200    /// Fields may not have an on-disk representation (e.g., when inserted by schema evolution), in which case the passed
0201    /// field descriptor is nullptr.
0202    std::vector<const TSchemaRule *> FindRules(const ROOT::RFieldDescriptor *fieldDesc);
0203 
0204 protected:
0205    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0206 
0207    void ConstructValue(void *where) const final;
0208    std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RClassDeleter>(fClass); }
0209 
0210    std::size_t AppendImpl(const void *from) final;
0211    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0212    void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
0213 
0214    std::unique_ptr<RFieldBase> BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final;
0215    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0216 
0217 public:
0218    RClassField(std::string_view fieldName, std::string_view className);
0219    RClassField(RClassField &&other) = default;
0220    RClassField &operator=(RClassField &&other) = default;
0221    ~RClassField() override;
0222 
0223    std::vector<RValue> SplitValue(const RValue &value) const final;
0224    std::size_t GetValueSize() const final;
0225    std::size_t GetAlignment() const final;
0226    std::uint32_t GetTypeVersion() const final;
0227    std::uint32_t GetTypeChecksum() const final;
0228    /// For polymorphic classes (that declare or inherit at least one virtual method), return the expected dynamic type
0229    /// of any user object. If the class is not polymorphic, return nullptr.
0230    const std::type_info *GetPolymorphicTypeInfo() const;
0231    /// Return the TClass instance backing this field.
0232    const TClass *GetClass() const { return fClass; }
0233    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0234 };
0235 
0236 /// The field for a class using ROOT standard streaming
0237 class RStreamerField final : public RFieldBase {
0238 private:
0239    class RStreamerFieldDeleter : public RDeleter {
0240    private:
0241       TClass *fClass;
0242 
0243    public:
0244       explicit RStreamerFieldDeleter(TClass *cl) : fClass(cl) {}
0245       void operator()(void *objPtr, bool dtorOnly) final;
0246    };
0247 
0248    TClass *fClass = nullptr;
0249    ROOT::Internal::RNTupleSerializer::StreamerInfoMap_t fStreamerInfos; ///< streamer info records seen during writing
0250    ROOT::Internal::RColumnIndex fIndex; ///< number of bytes written in the current cluster
0251 
0252 private:
0253    RStreamerField(std::string_view fieldName, TClass *classp);
0254 
0255 protected:
0256    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0257 
0258    const RColumnRepresentations &GetColumnRepresentations() const final;
0259    void GenerateColumns() final;
0260    void GenerateColumns(const ROOT::RNTupleDescriptor &) final;
0261 
0262    void ConstructValue(void *where) const final;
0263    std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RStreamerFieldDeleter>(fClass); }
0264 
0265    std::size_t AppendImpl(const void *from) final;
0266    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0267 
0268    void CommitClusterImpl() final { fIndex = 0; }
0269 
0270    bool HasExtraTypeInfo() const final { return true; }
0271    // Returns the list of seen streamer infos
0272    ROOT::RExtraTypeInfoDescriptor GetExtraTypeInfo() const final;
0273 
0274    std::unique_ptr<RFieldBase> BeforeConnectPageSource(ROOT::Internal::RPageSource &source) final;
0275    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0276 
0277 public:
0278    RStreamerField(std::string_view fieldName, std::string_view className);
0279    RStreamerField(RStreamerField &&other) = default;
0280    RStreamerField &operator=(RStreamerField &&other) = default;
0281    ~RStreamerField() final = default;
0282 
0283    size_t GetValueSize() const final;
0284    size_t GetAlignment() const final;
0285    std::uint32_t GetTypeVersion() const final;
0286    std::uint32_t GetTypeChecksum() const final;
0287    TClass *GetClass() const { return fClass; }
0288    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0289 };
0290 
0291 /// The field for an unscoped or scoped enum with dictionary
0292 class REnumField : public RFieldBase {
0293 private:
0294    REnumField(std::string_view fieldName, TEnum *enump);
0295    REnumField(std::string_view fieldName, std::string_view enumName, std::unique_ptr<RFieldBase> intField);
0296 
0297 protected:
0298    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0299 
0300    void ConstructValue(void *where) const final { CallConstructValueOn(*fSubfields[0], where); }
0301 
0302    std::size_t AppendImpl(const void *from) final { return CallAppendOn(*fSubfields[0], from); }
0303    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final { CallReadOn(*fSubfields[0], globalIndex, to); }
0304    void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final { CallReadOn(*fSubfields[0], localIndex, to); }
0305 
0306    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0307 
0308 public:
0309    REnumField(std::string_view fieldName, std::string_view enumName);
0310    REnumField(REnumField &&other) = default;
0311    REnumField &operator=(REnumField &&other) = default;
0312    ~REnumField() override = default;
0313 
0314    std::vector<RValue> SplitValue(const RValue &value) const final;
0315    size_t GetValueSize() const final { return fSubfields[0]->GetValueSize(); }
0316    size_t GetAlignment() const final { return fSubfields[0]->GetAlignment(); }
0317    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0318 };
0319 
0320 /// Classes with dictionaries that can be inspected by TClass
0321 template <typename T, typename = void>
0322 class RField final : public RClassField {
0323 public:
0324    static std::string TypeName() { return ROOT::Internal::GetRenormalizedTypeName(typeid(T)); }
0325    RField(std::string_view name) : RClassField(name, Internal::GetDemangledTypeName(typeid(T)))
0326    {
0327       static_assert(std::is_class_v<T>, "no I/O support for this basic C++ type");
0328    }
0329    RField(RField &&other) = default;
0330    RField &operator=(RField &&other) = default;
0331    ~RField() final = default;
0332 };
0333 
0334 template <typename T>
0335 class RField<T, typename std::enable_if<std::is_enum_v<T>>::type> final : public REnumField {
0336 public:
0337    static std::string TypeName() { return ROOT::Internal::GetRenormalizedTypeName(typeid(T)); }
0338    RField(std::string_view name) : REnumField(name, TypeName()) {}
0339    RField(RField &&other) = default;
0340    RField &operator=(RField &&other) = default;
0341    ~RField() final = default;
0342 };
0343 
0344 /// An artificial field that transforms an RNTuple column that contains the offset of collections into
0345 /// collection sizes. It is only used for reading, e.g. as projected field or as an artificial field that provides the
0346 /// "number of" RDF columns for collections (e.g. `R_rdf_sizeof_jets` for a collection named `jets`).
0347 /// It is used in the templated RField<RNTupleCardinality<SizeT>> form, which represents the collection sizes either
0348 /// as 32bit unsigned int (std::uint32_t) or as 64bit unsigned int (std::uint64_t).
0349 class RCardinalityField : public RFieldBase {
0350    friend class ROOT::RNTupleCollectionView; // to access GetCollectionInfo()
0351 
0352 private:
0353    void GetCollectionInfo(ROOT::NTupleSize_t globalIndex, RNTupleLocalIndex *collectionStart, ROOT::NTupleSize_t *size)
0354    {
0355       fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
0356    }
0357    void GetCollectionInfo(RNTupleLocalIndex localIndex, RNTupleLocalIndex *collectionStart, ROOT::NTupleSize_t *size)
0358    {
0359       fPrincipalColumn->GetCollectionInfo(localIndex, collectionStart, size);
0360    }
0361 
0362 protected:
0363    RCardinalityField(std::string_view fieldName, std::string_view typeName)
0364       : RFieldBase(fieldName, typeName, ROOT::ENTupleStructure::kPlain, false /* isSimple */)
0365    {
0366    }
0367 
0368    const RColumnRepresentations &GetColumnRepresentations() const final;
0369    // Field is only used for reading
0370    void GenerateColumns() final { throw RException(R__FAIL("Cardinality fields must only be used for reading")); }
0371    void GenerateColumns(const ROOT::RNTupleDescriptor &) final;
0372 
0373    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0374 
0375 public:
0376    RCardinalityField(RCardinalityField &&other) = default;
0377    RCardinalityField &operator=(RCardinalityField &&other) = default;
0378    ~RCardinalityField() override = default;
0379 
0380    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0381 
0382    const RField<RNTupleCardinality<std::uint32_t>> *As32Bit() const;
0383    const RField<RNTupleCardinality<std::uint64_t>> *As64Bit() const;
0384 };
0385 
0386 template <typename T>
0387 class RSimpleField : public RFieldBase {
0388    void ReconcileIntegralField(const RNTupleDescriptor &desc);
0389    void ReconcileFloatingPointField(const RNTupleDescriptor &desc);
0390 
0391 protected:
0392    void GenerateColumns() override { GenerateColumnsImpl<T>(); }
0393    void GenerateColumns(const ROOT::RNTupleDescriptor &desc) override { GenerateColumnsImpl<T>(desc); }
0394 
0395    void ConstructValue(void *where) const final { new (where) T{0}; }
0396 
0397    void ReconcileOnDiskField(const RNTupleDescriptor &desc) override
0398    {
0399       if constexpr (std::is_integral_v<T>) {
0400          ReconcileIntegralField(desc);
0401       } else if constexpr (std::is_floating_point_v<T>) {
0402          ReconcileFloatingPointField(desc);
0403       } else {
0404          RFieldBase::ReconcileOnDiskField(desc);
0405       }
0406    }
0407 
0408    RSimpleField(std::string_view name, std::string_view type)
0409       : RFieldBase(name, type, ROOT::ENTupleStructure::kPlain, true /* isSimple */)
0410    {
0411       fTraits |= kTraitTrivialType;
0412    }
0413 
0414 public:
0415    RSimpleField(RSimpleField &&other) = default;
0416    RSimpleField &operator=(RSimpleField &&other) = default;
0417    ~RSimpleField() override = default;
0418 
0419    T *Map(ROOT::NTupleSize_t globalIndex) { return fPrincipalColumn->Map<T>(globalIndex); }
0420    T *Map(RNTupleLocalIndex localIndex) { return fPrincipalColumn->Map<T>(localIndex); }
0421    T *MapV(ROOT::NTupleSize_t globalIndex, ROOT::NTupleSize_t &nItems)
0422    {
0423       return fPrincipalColumn->MapV<T>(globalIndex, nItems);
0424    }
0425    T *MapV(RNTupleLocalIndex localIndex, ROOT::NTupleSize_t &nItems)
0426    {
0427       return fPrincipalColumn->MapV<T>(localIndex, nItems);
0428    }
0429 
0430    size_t GetValueSize() const final { return sizeof(T); }
0431    size_t GetAlignment() const final { return alignof(T); }
0432 };
0433 
0434 ////////////////////////////////////////////////////////////////////////////////
0435 /// Template specializations for concrete C++ types
0436 ////////////////////////////////////////////////////////////////////////////////
0437 
0438 } // namespace ROOT
0439 
0440 #include "RField/RFieldFundamental.hxx"
0441 #include "RField/RFieldProxiedCollection.hxx"
0442 #include "RField/RFieldRecord.hxx"
0443 #include "RField/RFieldSequenceContainer.hxx"
0444 #include "RField/RFieldSoA.hxx"
0445 #include "RField/RFieldSTLMisc.hxx"
0446 
0447 namespace ROOT {
0448 
0449 template <typename SizeT>
0450 class RField<RNTupleCardinality<SizeT>> final : public RCardinalityField {
0451    using CardinalityType = RNTupleCardinality<SizeT>;
0452 
0453 protected:
0454    std::unique_ptr<ROOT::RFieldBase> CloneImpl(std::string_view newName) const final
0455    {
0456       return std::make_unique<RField>(newName);
0457    }
0458    void ConstructValue(void *where) const final { new (where) CardinalityType(0); }
0459 
0460    /// Get the number of elements of the collection identified by globalIndex
0461    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
0462    {
0463       RNTupleLocalIndex collectionStart;
0464       ROOT::NTupleSize_t size;
0465       fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &size);
0466       *static_cast<CardinalityType *>(to) = size;
0467    }
0468 
0469    /// Get the number of elements of the collection identified by clusterIndex
0470    void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
0471    {
0472       RNTupleLocalIndex collectionStart;
0473       ROOT::NTupleSize_t size;
0474       fPrincipalColumn->GetCollectionInfo(localIndex, &collectionStart, &size);
0475       *static_cast<CardinalityType *>(to) = size;
0476    }
0477 
0478    std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec) final
0479    {
0480       RNTupleLocalIndex collectionStart;
0481       ROOT::NTupleSize_t collectionSize;
0482       fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &collectionStart, &collectionSize);
0483 
0484       auto typedValues = static_cast<CardinalityType *>(bulkSpec.fValues);
0485       typedValues[0] = collectionSize;
0486 
0487       auto lastOffset = collectionStart.GetIndexInCluster() + collectionSize;
0488       ROOT::NTupleSize_t nRemainingEntries = bulkSpec.fCount - 1;
0489       std::size_t nEntries = 1;
0490       while (nRemainingEntries > 0) {
0491          ROOT::NTupleSize_t nItemsUntilPageEnd;
0492          auto offsets =
0493             fPrincipalColumn->MapV<ROOT::Internal::RColumnIndex>(bulkSpec.fFirstIndex + nEntries, nItemsUntilPageEnd);
0494          std::size_t nBatch = std::min(nRemainingEntries, nItemsUntilPageEnd);
0495          for (std::size_t i = 0; i < nBatch; ++i) {
0496             typedValues[nEntries + i] = offsets[i] - lastOffset;
0497             lastOffset = offsets[i];
0498          }
0499          nRemainingEntries -= nBatch;
0500          nEntries += nBatch;
0501       }
0502       return RBulkSpec::kAllSet;
0503    }
0504 
0505 public:
0506    static std::string TypeName() { return "ROOT::RNTupleCardinality<" + RField<SizeT>::TypeName() + ">"; }
0507    explicit RField(std::string_view name) : RCardinalityField(name, TypeName()) {}
0508    RField(RField &&other) = default;
0509    RField &operator=(RField &&other) = default;
0510    ~RField() final = default;
0511 
0512    size_t GetValueSize() const final { return sizeof(CardinalityType); }
0513    size_t GetAlignment() const final { return alignof(CardinalityType); }
0514 };
0515 
0516 /// TObject requires special handling of the fBits and fUniqueID members
0517 template <>
0518 class RField<TObject> final : public RFieldBase {
0519    static std::size_t GetOffsetOfMember(const char *name);
0520    static std::size_t GetOffsetUniqueID() { return GetOffsetOfMember("fUniqueID"); }
0521    static std::size_t GetOffsetBits() { return GetOffsetOfMember("fBits"); }
0522 
0523 private:
0524    RField(std::string_view fieldName, const RField<TObject> &source); ///< Used by CloneImpl()
0525 
0526 protected:
0527    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0528 
0529    void ConstructValue(void *where) const final;
0530    std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<TObject>>(); }
0531 
0532    std::size_t AppendImpl(const void *from) final;
0533    void ReadTObject(void *to, UInt_t uniqueID, UInt_t bits);
0534    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0535    void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
0536 
0537 public:
0538    static std::string TypeName() { return "TObject"; }
0539 
0540    RField(std::string_view fieldName);
0541    RField(RField &&other) = default;
0542    RField &operator=(RField &&other) = default;
0543    ~RField() final = default;
0544 
0545    std::vector<RValue> SplitValue(const RValue &value) const final;
0546    size_t GetValueSize() const final;
0547    size_t GetAlignment() const final;
0548    std::uint32_t GetTypeVersion() const final;
0549    std::uint32_t GetTypeChecksum() const final;
0550    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0551 };
0552 
0553 // Have to be implemented after the definition of all RField<T> types
0554 
0555 namespace Internal {
0556 
0557 /// Helper to check if a given type name is the one expected of Field<T>. Usually, this check can be done by
0558 /// type renormalization of the demangled type name T. The failure case, however, needs to additionally check for
0559 /// ROOT-specific special cases.
0560 template <class T>
0561 bool IsMatchingFieldType(const std::string &actualTypeName)
0562 {
0563    return IsMatchingFieldType(actualTypeName, ROOT::RField<T>::TypeName(), typeid(T));
0564 }
0565 
0566 } // namespace Internal
0567 
0568 template <typename T>
0569 std::unique_ptr<T, typename RFieldBase::RCreateObjectDeleter<T>::deleter> RFieldBase::CreateObject() const
0570 {
0571    if (!Internal::IsMatchingFieldType<T>(GetTypeName())) {
0572       throw RException(
0573          R__FAIL("type mismatch for field " + GetFieldName() + ": " + GetTypeName() + " vs. " + RField<T>::TypeName()));
0574    }
0575    return std::unique_ptr<T>(static_cast<T *>(CreateObjectRawPtr()));
0576 }
0577 
0578 // The void type is specialized in RField.cxx
0579 
0580 template <>
0581 struct RFieldBase::RCreateObjectDeleter<void> {
0582    using deleter = RCreateObjectDeleter<void>;
0583    void operator()(void *);
0584 };
0585 
0586 template <>
0587 std::unique_ptr<void, typename RFieldBase::RCreateObjectDeleter<void>::deleter>
0588 ROOT::RFieldBase::CreateObject<void>() const;
0589 
0590 } // namespace ROOT
0591 
0592 #endif