File indexing completed on 2026-09-20 09:25:58
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
0171
0172
0173 std::unique_ptr<unsigned char[]> fStagingArea;
0174
0175
0176
0177
0178 TClass *fStagingClass = nullptr;
0179 std::unordered_map<std::string, RStagingItem> fStagingItems;
0180
0181 private:
0182 RClassField(std::string_view fieldName, const RClassField &source);
0183 RClassField(std::string_view fieldName, TClass *classp);
0184 void Attach(std::unique_ptr<RFieldBase> child, RSubfieldInfo info);
0185
0186
0187
0188 ROOT::DescriptorId_t
0189 LookupMember(const ROOT::RNTupleDescriptor &desc, std::string_view memberName, ROOT::DescriptorId_t classFieldId);
0190
0191 void SetStagingClass(const std::string &className, unsigned int classVersion);
0192
0193
0194 void PrepareStagingArea(const std::vector<const TSchemaRule *> &rules, const ROOT::RNTupleDescriptor &desc,
0195 const ROOT::RFieldDescriptor &classFieldId);
0196
0197 void AddReadCallbacksFromIORule(const TSchemaRule *rule);
0198
0199
0200
0201
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
0229
0230 const std::type_info *GetPolymorphicTypeInfo() const;
0231
0232 const TClass *GetClass() const { return fClass; }
0233 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0234 };
0235
0236
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;
0250 ROOT::Internal::RColumnIndex fIndex;
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
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
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
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
0345
0346
0347
0348
0349 class RCardinalityField : public RFieldBase {
0350 friend class ROOT::RNTupleCollectionView;
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 )
0365 {
0366 }
0367
0368 const RColumnRepresentations &GetColumnRepresentations() const final;
0369
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 )
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
0436
0437
0438 }
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
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
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
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);
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
0554
0555 namespace Internal {
0556
0557
0558
0559
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 }
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
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 }
0591
0592 #endif