Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 10:28:35

0001 /// \file ROOT/RField/Fundamental.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_Record
0015 #define ROOT_RField_Record
0016 
0017 #ifndef ROOT_RField
0018 #error "Please include RField.hxx!"
0019 #endif
0020 
0021 #include <ROOT/RFieldBase.hxx>
0022 #include <ROOT/RNTupleTypes.hxx>
0023 
0024 #include <string>
0025 #include <string_view>
0026 #include <tuple>
0027 #include <utility>
0028 #include <vector>
0029 
0030 namespace ROOT {
0031 
0032 namespace Detail {
0033 class RFieldVisitor;
0034 } // namespace Detail
0035 
0036 namespace Internal {
0037 std::unique_ptr<RFieldBase> CreateEmulatedRecordField(std::string_view fieldName,
0038                                                       std::vector<std::unique_ptr<RFieldBase>> itemFields,
0039                                                       std::string_view emulatedFromType);
0040 } // namespace Internal
0041 
0042 /// The field for an untyped record. The subfields are stored consecutively in a memory block, i.e.
0043 /// the memory layout is identical to one that a C++ struct would have
0044 class RRecordField : public RFieldBase {
0045    friend std::unique_ptr<RFieldBase>
0046    Internal::CreateEmulatedRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
0047                                        std::string_view emulatedFromType);
0048 
0049    class RRecordDeleter : public RDeleter {
0050    private:
0051       std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
0052       std::vector<std::size_t> fOffsets;
0053 
0054    public:
0055       RRecordDeleter(std::vector<std::unique_ptr<RDeleter>> itemDeleters, const std::vector<std::size_t> &offsets)
0056          : fItemDeleters(std::move(itemDeleters)), fOffsets(offsets)
0057       {
0058       }
0059       void operator()(void *objPtr, bool dtorOnly) final;
0060    };
0061 
0062    RRecordField(std::string_view name, const RRecordField &source); // Used by CloneImpl()
0063 
0064    /// If `emulatedFromType` is non-empty, this field was created as a replacement for a ClassField that we lack a
0065    /// dictionary for and reconstructed from the on-disk information.
0066    /// Used by the public constructor and by Internal::CreateEmulatedRecordField().
0067    RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
0068                 std::string_view emulatedFromType);
0069 
0070 protected:
0071    std::size_t fMaxAlignment = 1;
0072    std::size_t fSize = 0;
0073    std::vector<std::size_t> fOffsets;
0074 
0075    std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const;
0076 
0077    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const override;
0078 
0079    void ConstructValue(void *where) const final;
0080    std::unique_ptr<RDeleter> GetDeleter() const final;
0081 
0082    std::size_t AppendImpl(const void *from) final;
0083    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0084    void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
0085 
0086    /// Used by RPairField and RTupleField descendants. These descendants have their own logic to attach the subfields
0087    /// that ensure that the resulting memory layout matches std::pair or std::tuple, resp.
0088    RRecordField(std::string_view fieldName, std::string_view typeName);
0089 
0090    void AttachItemFields(std::vector<std::unique_ptr<RFieldBase>> itemFields);
0091 
0092    template <std::size_t N>
0093    void AttachItemFields(std::array<std::unique_ptr<RFieldBase>, N> itemFields)
0094    {
0095       fTraits |= kTraitTrivialType;
0096       for (unsigned i = 0; i < N; ++i) {
0097          fMaxAlignment = std::max(fMaxAlignment, itemFields[i]->GetAlignment());
0098          fSize += GetItemPadding(fSize, itemFields[i]->GetAlignment()) + itemFields[i]->GetValueSize();
0099          fTraits &= itemFields[i]->GetTraits();
0100          Attach(std::move(itemFields[i]));
0101       }
0102       // Trailing padding: although this is implementation-dependent, most add enough padding to comply with the
0103       // requirements of the type with strictest alignment
0104       fSize += GetItemPadding(fSize, fMaxAlignment);
0105    }
0106 
0107    void ReconcileOnDiskField(const RNTupleDescriptor &desc) override;
0108 
0109 public:
0110    /// Construct a RRecordField based on a vector of child fields. The ownership of the child fields is transferred
0111    /// to the RRecordField instance.
0112    /// The resulting field uses a memory layout for its values as if there was a struct consisting of the passed
0113    /// item fields.
0114    RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
0115    RRecordField(RRecordField &&other) = default;
0116    RRecordField &operator=(RRecordField &&other) = default;
0117    ~RRecordField() override = default;
0118 
0119    std::vector<RValue> SplitValue(const RValue &value) const final;
0120    size_t GetValueSize() const final
0121    {
0122       // The minimum size is 1 to support having vectors of empty records
0123       return std::max<size_t>(1ul, fSize);
0124    }
0125    size_t GetAlignment() const final { return fMaxAlignment; }
0126    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0127 
0128    const std::vector<std::size_t> &GetOffsets() const { return fOffsets; }
0129 };
0130 
0131 ////////////////////////////////////////////////////////////////////////////////
0132 /// Template specializations for C++ std::pair
0133 ////////////////////////////////////////////////////////////////////////////////
0134 
0135 /// The generic field for `std::pair<T1, T2>` types
0136 class RPairField : public RRecordField {
0137 private:
0138    static std::string GetTypeList(const std::array<std::unique_ptr<RFieldBase>, 2> &itemFields);
0139 
0140 protected:
0141    RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields,
0142               const std::array<std::size_t, 2> &offsets);
0143 
0144    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0145 
0146    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0147 
0148 public:
0149    RPairField(std::string_view fieldName, std::array<std::unique_ptr<RFieldBase>, 2> itemFields);
0150    RPairField(RPairField &&other) = default;
0151    RPairField &operator=(RPairField &&other) = default;
0152    ~RPairField() override = default;
0153 };
0154 
0155 template <typename T1, typename T2>
0156 class RField<std::pair<T1, T2>> final : public RPairField {
0157    using ContainerT = typename std::pair<T1, T2>;
0158 
0159 private:
0160    static std::array<std::unique_ptr<RFieldBase>, 2> BuildItemFields()
0161    {
0162       return {std::make_unique<RField<T1>>("_0"), std::make_unique<RField<T2>>("_1")};
0163    }
0164 
0165    static std::array<std::size_t, 2> BuildItemOffsets()
0166    {
0167       auto pair = ContainerT();
0168       auto offsetFirst = reinterpret_cast<std::uintptr_t>(&(pair.first)) - reinterpret_cast<std::uintptr_t>(&pair);
0169       auto offsetSecond = reinterpret_cast<std::uintptr_t>(&(pair.second)) - reinterpret_cast<std::uintptr_t>(&pair);
0170       return {offsetFirst, offsetSecond};
0171    }
0172 
0173 public:
0174    static std::string TypeName() { return "std::pair<" + RField<T1>::TypeName() + "," + RField<T2>::TypeName() + ">"; }
0175    explicit RField(std::string_view name) : RPairField(name, BuildItemFields(), BuildItemOffsets())
0176    {
0177       R__ASSERT(fMaxAlignment >= std::max(alignof(T1), alignof(T2)));
0178       R__ASSERT(fSize >= sizeof(ContainerT));
0179    }
0180    RField(RField &&other) = default;
0181    RField &operator=(RField &&other) = default;
0182    ~RField() final = default;
0183 };
0184 
0185 ////////////////////////////////////////////////////////////////////////////////
0186 /// Template specializations for C++ std::tuple
0187 ////////////////////////////////////////////////////////////////////////////////
0188 
0189 /// The generic field for `std::tuple<Ts...>` types
0190 class RTupleField : public RRecordField {
0191 private:
0192    static std::string GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields);
0193 
0194 protected:
0195    RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
0196                const std::vector<std::size_t> &offsets);
0197 
0198    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0199 
0200    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0201 
0202 public:
0203    RTupleField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
0204    RTupleField(RTupleField &&other) = default;
0205    RTupleField &operator=(RTupleField &&other) = default;
0206    ~RTupleField() override = default;
0207 };
0208 
0209 template <typename... ItemTs>
0210 class RField<std::tuple<ItemTs...>> final : public RTupleField {
0211    using ContainerT = typename std::tuple<ItemTs...>;
0212 
0213 private:
0214    template <typename HeadT, typename... TailTs>
0215    static std::string BuildItemTypes()
0216    {
0217       std::string result = RField<HeadT>::TypeName();
0218       if constexpr (sizeof...(TailTs) > 0)
0219          result += "," + BuildItemTypes<TailTs...>();
0220       return result;
0221    }
0222 
0223    template <typename HeadT, typename... TailTs>
0224    static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
0225    {
0226       itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
0227       if constexpr (sizeof...(TailTs) > 0)
0228          _BuildItemFields<TailTs...>(itemFields, index + 1);
0229    }
0230    static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
0231    {
0232       std::vector<std::unique_ptr<RFieldBase>> result;
0233       _BuildItemFields<ItemTs...>(result);
0234       return result;
0235    }
0236 
0237    template <unsigned Index, typename HeadT, typename... TailTs>
0238    static void _BuildItemOffsets(std::vector<std::size_t> &offsets, const ContainerT &tuple)
0239    {
0240       auto offset =
0241          reinterpret_cast<std::uintptr_t>(&std::get<Index>(tuple)) - reinterpret_cast<std::uintptr_t>(&tuple);
0242       offsets.emplace_back(offset);
0243       if constexpr (sizeof...(TailTs) > 0)
0244          _BuildItemOffsets<Index + 1, TailTs...>(offsets, tuple);
0245    }
0246    static std::vector<std::size_t> BuildItemOffsets()
0247    {
0248       std::vector<std::size_t> result;
0249       _BuildItemOffsets<0, ItemTs...>(result, ContainerT());
0250       return result;
0251    }
0252 
0253 public:
0254    static std::string TypeName() { return "std::tuple<" + BuildItemTypes<ItemTs...>() + ">"; }
0255    explicit RField(std::string_view name) : RTupleField(name, BuildItemFields(), BuildItemOffsets())
0256    {
0257       R__ASSERT(fMaxAlignment >= std::max({alignof(ItemTs)...}));
0258       R__ASSERT(fSize >= sizeof(ContainerT));
0259    }
0260    RField(RField &&other) = default;
0261    RField &operator=(RField &&other) = default;
0262    ~RField() final = default;
0263 };
0264 
0265 } // namespace ROOT
0266 
0267 #endif