Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 46 additions & 32 deletions tree/ntuple/inc/ROOT/RField.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,9 @@ public:
size_t GetAlignment() const final { return 0; }
}; // RInvalidField

/// The field for a class with dictionary
class RClassField : public RFieldBase {
private:
enum ESubfieldRole {
kBaseClass,
kDataMember,
};
struct RSubfieldInfo {
ESubfieldRole fRole;
std::size_t fOffset;
};
/// Base class for fields that are subject to I/O customization rules. Use by the class field and the SoA field.
class RRuleField : public RFieldBase {
protected:
// Information to read into the staging area a field that is used as an input to an I/O customization rule
struct RStagingItem {
/// The field used to read the on-disk data. The fields type may be different from the on-disk type as long
Expand All @@ -152,19 +144,6 @@ private:
/// Prefix used in the subfield names generated for base classes
static constexpr const char *kPrefixInherited{":"};

class RClassDeleter : public RDeleter {
private:
TClass *fClass;

public:
explicit RClassDeleter(TClass *cl);
void operator()(void *objPtr, bool dtorOnly) final;
};

TClass *fClass;
/// Additional information kept for each entry in `fSubfields`
std::vector<RSubfieldInfo> fSubfieldsInfo;

/// The staging area stores inputs to I/O rules according to the offsets given by the streamer info of
/// "TypeName@@Version". The area is allocated depending on I/O rules resp. the source members of the I/O rules.
std::unique_ptr<unsigned char[]> fStagingArea;
Expand All @@ -175,28 +154,61 @@ private:
TClass *fStagingClass = nullptr;
std::unordered_map<std::string, RStagingItem> fStagingItems; ///< Lookup staging items by member name

private:
RClassField(std::string_view fieldName, const RClassField &source); ///< Used by CloneImpl
RClassField(std::string_view fieldName, TClass *classp);
void Attach(std::unique_ptr<RFieldBase> child, RSubfieldInfo info);
RRuleField(std::string_view name, std::string_view type, ROOT::ENTupleStructure structure);

/// Derived classes should return the TClass instance representing the current in-memory layout.
virtual TClass *GetInMemoryClass() const = 0;

/// Returns the id of member 'name' in the class field given by 'fieldId', or kInvalidDescriptorId if no such
/// member exist. Looks recursively in base classes.
ROOT::DescriptorId_t
LookupMember(const ROOT::RNTupleDescriptor &desc, std::string_view memberName, ROOT::DescriptorId_t classFieldId);
ROOT::DescriptorId_t LookupMember(const ROOT::RNTupleDescriptor &desc, std::string_view memberName,
ROOT::DescriptorId_t classFieldId) const;
/// Sets fStagingClass according to the given name and version
void SetStagingClass(const std::string &className, unsigned int classVersion);
/// If there are rules with inputs (source members), create the staging area according to the TClass instance
/// that corresponds to the on-disk field.
void PrepareStagingArea(const std::vector<const TSchemaRule *> &rules, const ROOT::RNTupleDescriptor &desc,
const ROOT::RFieldDescriptor &classFieldId);
/// Register post-read callback corresponding to a ROOT I/O customization rules.
void AddReadCallbacksFromIORule(const TSchemaRule *rule);
/// The sub object offset allows to apply the rule to a nested object within the passed target.
/// This is used to execute rules on base classes and nested classes in a SoA field.
void AddReadCallbacksFromIORule(const TSchemaRule *rule, std::size_t subObjectOffset = 0);
/// Given the on-disk information from the page source, find all the I/O customization rules that apply
/// to the class field at hand, to which the fieldDesc descriptor, if provided, must correspond.
/// Fields may not have an on-disk representation (e.g., when inserted by schema evolution), in which case the passed
/// field descriptor is nullptr.
std::vector<const TSchemaRule *> FindRules(const ROOT::RFieldDescriptor *fieldDesc);
std::vector<const TSchemaRule *> FindRules(const ROOT::RFieldDescriptor *fieldDesc) const;
};

/// The field for a class with dictionary
class RClassField : public RRuleField {
private:
enum ESubfieldRole {
kBaseClass,
kDataMember,
};
struct RSubfieldInfo {
ESubfieldRole fRole;
std::size_t fOffset;
};

class RClassDeleter : public RDeleter {
private:
TClass *fClass;

public:
explicit RClassDeleter(TClass *cl);
void operator()(void *objPtr, bool dtorOnly) final;
};

TClass *fClass;
/// Additional information kept for each entry in `fSubfields`
std::vector<RSubfieldInfo> fSubfieldsInfo;

private:
RClassField(std::string_view fieldName, const RClassField &source); ///< Used by CloneImpl
RClassField(std::string_view fieldName, TClass *classp);
void Attach(std::unique_ptr<RFieldBase> child, RSubfieldInfo info);

protected:
std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
Expand All @@ -211,6 +223,8 @@ protected:
std::unique_ptr<RFieldBase> BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final;
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;

TClass *GetInMemoryClass() const final { return fClass; }

public:
RClassField(std::string_view fieldName, std::string_view className);
RClassField(RClassField &&other) = default;
Expand Down
17 changes: 15 additions & 2 deletions tree/ntuple/inc/ROOT/RField/RFieldSoA.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ namespace Experimental {
///
/// Since the on-disk representation is a collection of record type, the class version and checksum of the SoA type
/// itself is ignored.
class RSoAField : public RFieldBase {
class RSoAField : public RRuleField {
class RSoADeleter : public RDeleter {
private:
TClass *fSoAClass;
Expand All @@ -63,6 +63,13 @@ class RSoAField : public RFieldBase {
void operator()(void *objPtr, bool dtorOnly) final;
};

// A rule of the SoA type itself or one of its nested SoA types or base classes, togther with the offset
// of the nested object in the SoA type.
struct RRule {
const TSchemaRule *fRule = nullptr;
std::size_t fOffset = 0;
};

TClass *fSoAClass = nullptr;
/// Direct access to the member fields of the underlying record. In case of a nested SoA type, this vector
/// contains the contents of the inner fRecordMemberFields, too. Effectively, this record will contain all the
Expand All @@ -75,6 +82,9 @@ class RSoAField : public RFieldBase {
std::vector<std::unique_ptr<RDeleter>> fRecordMemberDeleters;
ROOT::Internal::RColumnIndex fNWritten;

/// Contains the I/O customization rules for fSoAClass and all nested SoA classes and base classes.
std::vector<RRule> fRules;

/// For reading and writing, the RVecs of the SoA class do not have a dedicated field. The in-memory RVecs of the
/// SoA object are used directly with the subfields of the underlying record type. For splitting a SoA class object
/// (SplitValue()), however, we need actual RRVecFields so that we can recursively split the in-memory SoA value.
Expand All @@ -90,7 +100,7 @@ class RSoAField : public RFieldBase {
RSoAField(std::string_view fieldName, TClass *clSoA);

/// Called during construction, picks up the (nested) member fields of the underlying record type(s) and its
/// base classes.
/// base classes. Also fills fRules.
void CollectRecordMemberFields();
/// For a nested SoA struct (either as a member of as a base class), use their fRecordMemberFields in this class,
/// i.e. "unroll" the vectors in the nested SoA struct into the SoA base class.
Expand All @@ -114,8 +124,11 @@ protected:

void CommitClusterImpl() final { fNWritten = 0; }

std::unique_ptr<RFieldBase> BeforeConnectPageSource(ROOT::Internal::RPageSource &pageSource) final;
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;

TClass *GetInMemoryClass() const final { return fSoAClass; }

public:
RSoAField(std::string_view fieldName, std::string_view className);
RSoAField(RSoAField &&other) = default;
Expand Down
Loading
Loading