File indexing completed on 2026-08-21 09:23:46
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
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 }
0051
0052 class RFieldZero;
0053 namespace Internal {
0054 void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val);
0055 }
0056
0057
0058
0059 class RFieldZero final : public RFieldBase {
0060 friend void ROOT::Internal::SetAllowFieldSubstitutions(RFieldZero &, bool);
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 bool fAllowFieldSubstitutions = false;
0071
0072 std::unordered_set<std::string> fSubfieldNames;
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
0082
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
0091 std::vector<std::unique_ptr<RFieldBase>> ReleaseSubfields();
0092 };
0093
0094
0095
0096
0097 class RInvalidField final : public RFieldBase {
0098 public:
0099 enum class ECategory {
0100
0101 kGeneric,
0102
0103 kTypeError,
0104
0105 kUnknownType,
0106
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 ), 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 };
0136
0137
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
0149 struct RStagingItem {
0150
0151
0152 std::unique_ptr<RFieldBase> fField;
0153 std::size_t fOffset;
0154 };
0155
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
0169 std::vector<RSubfieldInfo> fSubfieldsInfo;
0170 std::size_t fMaxAlignment = 1;
0171
0172
0173
0174 std::unique_ptr<unsigned char[]> fStagingArea;
0175
0176
0177
0178
0179 TClass *fStagingClass = nullptr;
0180 std::unordered_map<std::string, RStagingItem> fStagingItems;
0181
0182 private:
0183 RClassField(std::string_view fieldName, const RClassField &source);
0184 RClassField(std::string_view fieldName, TClass *classp);
0185 void Attach(std::unique_ptr<RFieldBase> child, RSubfieldInfo info);
0186
0187
0188
0189 ROOT::DescriptorId_t
0190 LookupMember(const ROOT::RNTupleDescriptor &desc, std::string_view memberName, ROOT::DescriptorId_t classFieldId);
0191
0192 void SetStagingClass(const std::string &className, unsigned int classVersion);
0193
0194
0195 void PrepareStagingArea(const std::vector<const TSchemaRule *> &rules, const ROOT::RNTupleDescriptor &desc,
0196 const ROOT::RFieldDescriptor &classFieldId);
0197
0198 void AddReadCallbacksFromIORule(const TSchemaRule *rule);
0199
0200
0201
0202
0203 std::vector<const TSchemaRule *> FindRules(const ROOT::RFieldDescriptor *fieldDesc);
0204
0205 protected:
0206 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0207
0208 void ConstructValue(void *where) const final;
0209 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RClassDeleter>(fClass); }
0210
0211 std::size_t AppendImpl(const void *from) final;
0212 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0213 void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
0214
0215 std::unique_ptr<RFieldBase> BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final;
0216 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0217
0218 public:
0219 RClassField(std::string_view fieldName, std::string_view className);
0220 RClassField(RClassField &&other) = default;
0221 RClassField &operator=(RClassField &&other) = default;
0222 ~RClassField() override;
0223
0224 std::vector<RValue> SplitValue(const RValue &value) const final;
0225 size_t GetValueSize() const final;
0226 size_t GetAlignment() const final { return fMaxAlignment; }
0227 std::uint32_t GetTypeVersion() const final;
0228 std::uint32_t GetTypeChecksum() const final;
0229
0230
0231 const std::type_info *GetPolymorphicTypeInfo() const;
0232
0233 const TClass *GetClass() const { return fClass; }
0234 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0235 };
0236
0237
0238 class RStreamerField final : public RFieldBase {
0239 private:
0240 class RStreamerFieldDeleter : public RDeleter {
0241 private:
0242 TClass *fClass;
0243
0244 public:
0245 explicit RStreamerFieldDeleter(TClass *cl) : fClass(cl) {}
0246 void operator()(void *objPtr, bool dtorOnly) final;
0247 };
0248
0249 TClass *fClass = nullptr;
0250 ROOT::Internal::RNTupleSerializer::StreamerInfoMap_t fStreamerInfos;
0251 ROOT::Internal::RColumnIndex fIndex;
0252
0253 private:
0254 RStreamerField(std::string_view fieldName, TClass *classp);
0255
0256 protected:
0257 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0258
0259 const RColumnRepresentations &GetColumnRepresentations() const final;
0260 void GenerateColumns() final;
0261 void GenerateColumns(const ROOT::RNTupleDescriptor &) final;
0262
0263 void ConstructValue(void *where) const final;
0264 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RStreamerFieldDeleter>(fClass); }
0265
0266 std::size_t AppendImpl(const void *from) final;
0267 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0268
0269 void CommitClusterImpl() final { fIndex = 0; }
0270
0271 bool HasExtraTypeInfo() const final { return true; }
0272
0273 ROOT::RExtraTypeInfoDescriptor GetExtraTypeInfo() const final;
0274
0275 std::unique_ptr<RFieldBase> BeforeConnectPageSource(ROOT::Internal::RPageSource &source) final;
0276 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0277
0278 public:
0279 RStreamerField(std::string_view fieldName, std::string_view className);
0280 RStreamerField(RStreamerField &&other) = default;
0281 RStreamerField &operator=(RStreamerField &&other) = default;
0282 ~RStreamerField() final = default;
0283
0284 size_t GetValueSize() const final;
0285 size_t GetAlignment() const final;
0286 std::uint32_t GetTypeVersion() const final;
0287 std::uint32_t GetTypeChecksum() const final;
0288 TClass *GetClass() const { return fClass; }
0289 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0290 };
0291
0292
0293 class REnumField : public RFieldBase {
0294 private:
0295 REnumField(std::string_view fieldName, TEnum *enump);
0296 REnumField(std::string_view fieldName, std::string_view enumName, std::unique_ptr<RFieldBase> intField);
0297
0298 protected:
0299 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0300
0301 void ConstructValue(void *where) const final { CallConstructValueOn(*fSubfields[0], where); }
0302
0303 std::size_t AppendImpl(const void *from) final { return CallAppendOn(*fSubfields[0], from); }
0304 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final { CallReadOn(*fSubfields[0], globalIndex, to); }
0305 void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final { CallReadOn(*fSubfields[0], localIndex, to); }
0306
0307 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0308
0309 public:
0310 REnumField(std::string_view fieldName, std::string_view enumName);
0311 REnumField(REnumField &&other) = default;
0312 REnumField &operator=(REnumField &&other) = default;
0313 ~REnumField() override = default;
0314
0315 std::vector<RValue> SplitValue(const RValue &value) const final;
0316 size_t GetValueSize() const final { return fSubfields[0]->GetValueSize(); }
0317 size_t GetAlignment() const final { return fSubfields[0]->GetAlignment(); }
0318 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0319 };
0320
0321
0322 template <typename T, typename = void>
0323 class RField final : public RClassField {
0324 public:
0325 static std::string TypeName() { return ROOT::Internal::GetRenormalizedTypeName(typeid(T)); }
0326 RField(std::string_view name) : RClassField(name, Internal::GetDemangledTypeName(typeid(T)))
0327 {
0328 static_assert(std::is_class_v<T>, "no I/O support for this basic C++ type");
0329 }
0330 RField(RField &&other) = default;
0331 RField &operator=(RField &&other) = default;
0332 ~RField() final = default;
0333 };
0334
0335 template <typename T>
0336 class RField<T, typename std::enable_if<std::is_enum_v<T>>::type> final : public REnumField {
0337 public:
0338 static std::string TypeName() { return ROOT::Internal::GetRenormalizedTypeName(typeid(T)); }
0339 RField(std::string_view name) : REnumField(name, TypeName()) {}
0340 RField(RField &&other) = default;
0341 RField &operator=(RField &&other) = default;
0342 ~RField() final = default;
0343 };
0344
0345
0346
0347
0348
0349
0350 class RCardinalityField : public RFieldBase {
0351 friend class ROOT::RNTupleCollectionView;
0352
0353 private:
0354 void GetCollectionInfo(ROOT::NTupleSize_t globalIndex, RNTupleLocalIndex *collectionStart, ROOT::NTupleSize_t *size)
0355 {
0356 fPrincipalColumn->GetCollectionInfo(globalIndex, collectionStart, size);
0357 }
0358 void GetCollectionInfo(RNTupleLocalIndex localIndex, RNTupleLocalIndex *collectionStart, ROOT::NTupleSize_t *size)
0359 {
0360 fPrincipalColumn->GetCollectionInfo(localIndex, collectionStart, size);
0361 }
0362
0363 protected:
0364 RCardinalityField(std::string_view fieldName, std::string_view typeName)
0365 : RFieldBase(fieldName, typeName, ROOT::ENTupleStructure::kPlain, false )
0366 {
0367 }
0368
0369 const RColumnRepresentations &GetColumnRepresentations() const final;
0370
0371 void GenerateColumns() final { throw RException(R__FAIL("Cardinality fields must only be used for reading")); }
0372 void GenerateColumns(const ROOT::RNTupleDescriptor &) final;
0373
0374 void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0375
0376 public:
0377 RCardinalityField(RCardinalityField &&other) = default;
0378 RCardinalityField &operator=(RCardinalityField &&other) = default;
0379 ~RCardinalityField() override = default;
0380
0381 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0382
0383 const RField<RNTupleCardinality<std::uint32_t>> *As32Bit() const;
0384 const RField<RNTupleCardinality<std::uint64_t>> *As64Bit() const;
0385 };
0386
0387 template <typename T>
0388 class RSimpleField : public RFieldBase {
0389 void ReconcileIntegralField(const RNTupleDescriptor &desc);
0390 void ReconcileFloatingPointField(const RNTupleDescriptor &desc);
0391
0392 protected:
0393 void GenerateColumns() override { GenerateColumnsImpl<T>(); }
0394 void GenerateColumns(const ROOT::RNTupleDescriptor &desc) override { GenerateColumnsImpl<T>(desc); }
0395
0396 void ConstructValue(void *where) const final { new (where) T{0}; }
0397
0398 void ReconcileOnDiskField(const RNTupleDescriptor &desc) override
0399 {
0400 if constexpr (std::is_integral_v<T>) {
0401 ReconcileIntegralField(desc);
0402 } else if constexpr (std::is_floating_point_v<T>) {
0403 ReconcileFloatingPointField(desc);
0404 } else {
0405 RFieldBase::ReconcileOnDiskField(desc);
0406 }
0407 }
0408
0409 RSimpleField(std::string_view name, std::string_view type)
0410 : RFieldBase(name, type, ROOT::ENTupleStructure::kPlain, true )
0411 {
0412 fTraits |= kTraitTrivialType;
0413 }
0414
0415 public:
0416 RSimpleField(RSimpleField &&other) = default;
0417 RSimpleField &operator=(RSimpleField &&other) = default;
0418 ~RSimpleField() override = default;
0419
0420 T *Map(ROOT::NTupleSize_t globalIndex) { return fPrincipalColumn->Map<T>(globalIndex); }
0421 T *Map(RNTupleLocalIndex localIndex) { return fPrincipalColumn->Map<T>(localIndex); }
0422 T *MapV(ROOT::NTupleSize_t globalIndex, ROOT::NTupleSize_t &nItems)
0423 {
0424 return fPrincipalColumn->MapV<T>(globalIndex, nItems);
0425 }
0426 T *MapV(RNTupleLocalIndex localIndex, ROOT::NTupleSize_t &nItems)
0427 {
0428 return fPrincipalColumn->MapV<T>(localIndex, nItems);
0429 }
0430
0431 size_t GetValueSize() const final { return sizeof(T); }
0432 size_t GetAlignment() const final { return alignof(T); }
0433 };
0434
0435
0436
0437
0438
0439 }
0440
0441 #include "RField/RFieldFundamental.hxx"
0442 #include "RField/RFieldProxiedCollection.hxx"
0443 #include "RField/RFieldRecord.hxx"
0444 #include "RField/RFieldSequenceContainer.hxx"
0445 #include "RField/RFieldSoA.hxx"
0446 #include "RField/RFieldSTLMisc.hxx"
0447
0448 namespace ROOT {
0449
0450 template <typename SizeT>
0451 class RField<RNTupleCardinality<SizeT>> final : public RCardinalityField {
0452 using CardinalityType = RNTupleCardinality<SizeT>;
0453
0454 protected:
0455 std::unique_ptr<ROOT::RFieldBase> CloneImpl(std::string_view newName) const final
0456 {
0457 return std::make_unique<RField>(newName);
0458 }
0459 void ConstructValue(void *where) const final { new (where) CardinalityType(0); }
0460
0461
0462 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
0463 {
0464 RNTupleLocalIndex collectionStart;
0465 ROOT::NTupleSize_t size;
0466 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &size);
0467 *static_cast<CardinalityType *>(to) = size;
0468 }
0469
0470
0471 void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
0472 {
0473 RNTupleLocalIndex collectionStart;
0474 ROOT::NTupleSize_t size;
0475 fPrincipalColumn->GetCollectionInfo(localIndex, &collectionStart, &size);
0476 *static_cast<CardinalityType *>(to) = size;
0477 }
0478
0479 std::size_t ReadBulkImpl(const RBulkSpec &bulkSpec) final
0480 {
0481 RNTupleLocalIndex collectionStart;
0482 ROOT::NTupleSize_t collectionSize;
0483 fPrincipalColumn->GetCollectionInfo(bulkSpec.fFirstIndex, &collectionStart, &collectionSize);
0484
0485 auto typedValues = static_cast<CardinalityType *>(bulkSpec.fValues);
0486 typedValues[0] = collectionSize;
0487
0488 auto lastOffset = collectionStart.GetIndexInCluster() + collectionSize;
0489 ROOT::NTupleSize_t nRemainingEntries = bulkSpec.fCount - 1;
0490 std::size_t nEntries = 1;
0491 while (nRemainingEntries > 0) {
0492 ROOT::NTupleSize_t nItemsUntilPageEnd;
0493 auto offsets =
0494 fPrincipalColumn->MapV<ROOT::Internal::RColumnIndex>(bulkSpec.fFirstIndex + nEntries, nItemsUntilPageEnd);
0495 std::size_t nBatch = std::min(nRemainingEntries, nItemsUntilPageEnd);
0496 for (std::size_t i = 0; i < nBatch; ++i) {
0497 typedValues[nEntries + i] = offsets[i] - lastOffset;
0498 lastOffset = offsets[i];
0499 }
0500 nRemainingEntries -= nBatch;
0501 nEntries += nBatch;
0502 }
0503 return RBulkSpec::kAllSet;
0504 }
0505
0506 public:
0507 static std::string TypeName() { return "ROOT::RNTupleCardinality<" + RField<SizeT>::TypeName() + ">"; }
0508 explicit RField(std::string_view name) : RCardinalityField(name, TypeName()) {}
0509 RField(RField &&other) = default;
0510 RField &operator=(RField &&other) = default;
0511 ~RField() final = default;
0512
0513 size_t GetValueSize() const final { return sizeof(CardinalityType); }
0514 size_t GetAlignment() const final { return alignof(CardinalityType); }
0515 };
0516
0517
0518 template <>
0519 class RField<TObject> final : public RFieldBase {
0520 static std::size_t GetOffsetOfMember(const char *name);
0521 static std::size_t GetOffsetUniqueID() { return GetOffsetOfMember("fUniqueID"); }
0522 static std::size_t GetOffsetBits() { return GetOffsetOfMember("fBits"); }
0523
0524 private:
0525 RField(std::string_view fieldName, const RField<TObject> &source);
0526
0527 protected:
0528 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0529
0530 void ConstructValue(void *where) const final;
0531 std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<TObject>>(); }
0532
0533 std::size_t AppendImpl(const void *from) final;
0534 void ReadTObject(void *to, UInt_t uniqueID, UInt_t bits);
0535 void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0536 void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
0537
0538 public:
0539 static std::string TypeName() { return "TObject"; }
0540
0541 RField(std::string_view fieldName);
0542 RField(RField &&other) = default;
0543 RField &operator=(RField &&other) = default;
0544 ~RField() final = default;
0545
0546 std::vector<RValue> SplitValue(const RValue &value) const final;
0547 size_t GetValueSize() const final;
0548 size_t GetAlignment() const final;
0549 std::uint32_t GetTypeVersion() const final;
0550 std::uint32_t GetTypeChecksum() const final;
0551 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0552 };
0553
0554
0555
0556 namespace Internal {
0557
0558
0559
0560
0561 template <class T>
0562 bool IsMatchingFieldType(const std::string &actualTypeName)
0563 {
0564 return IsMatchingFieldType(actualTypeName, ROOT::RField<T>::TypeName(), typeid(T));
0565 }
0566
0567 }
0568
0569 template <typename T>
0570 std::unique_ptr<T, typename RFieldBase::RCreateObjectDeleter<T>::deleter> RFieldBase::CreateObject() const
0571 {
0572 if (!Internal::IsMatchingFieldType<T>(GetTypeName())) {
0573 throw RException(
0574 R__FAIL("type mismatch for field " + GetFieldName() + ": " + GetTypeName() + " vs. " + RField<T>::TypeName()));
0575 }
0576 return std::unique_ptr<T>(static_cast<T *>(CreateObjectRawPtr()));
0577 }
0578
0579
0580
0581 template <>
0582 struct RFieldBase::RCreateObjectDeleter<void> {
0583 using deleter = RCreateObjectDeleter<void>;
0584 void operator()(void *);
0585 };
0586
0587 template <>
0588 std::unique_ptr<void, typename RFieldBase::RCreateObjectDeleter<void>::deleter>
0589 ROOT::RFieldBase::CreateObject<void>() const;
0590
0591 }
0592
0593 #endif