Back to home page

EIC code displayed by LXR

 
 

    


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

0001 /// \file ROOT/RField/STLMisc.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_STLMisc
0015 #define ROOT_RField_STLMisc
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 <atomic>
0025 #include <bitset>
0026 #include <cstddef>
0027 #include <memory>
0028 #include <optional>
0029 #include <string>
0030 #include <string_view>
0031 #include <typeinfo>
0032 #include <variant>
0033 
0034 namespace ROOT {
0035 namespace Experimental {
0036 
0037 namespace Detail {
0038 class RFieldVisitor;
0039 } // namespace Detail
0040 
0041 } // namespace Experimental
0042 
0043 ////////////////////////////////////////////////////////////////////////////////
0044 /// Template specializations for C++ std::atomic
0045 ////////////////////////////////////////////////////////////////////////////////
0046 
0047 class RAtomicField : public RFieldBase {
0048 protected:
0049    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0050 
0051    void ConstructValue(void *where) const final { CallConstructValueOn(*fSubfields[0], where); }
0052    std::unique_ptr<RDeleter> GetDeleter() const final { return GetDeleterOf(*fSubfields[0]); }
0053 
0054    std::size_t AppendImpl(const void *from) final { return CallAppendOn(*fSubfields[0], from); }
0055    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final { CallReadOn(*fSubfields[0], globalIndex, to); }
0056    void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final { CallReadOn(*fSubfields[0], localIndex, to); }
0057 
0058    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0059 
0060 public:
0061    RAtomicField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField);
0062    RAtomicField(RAtomicField &&other) = default;
0063    RAtomicField &operator=(RAtomicField &&other) = default;
0064    ~RAtomicField() override = default;
0065 
0066    std::vector<RValue> SplitValue(const RValue &value) const final;
0067 
0068    size_t GetValueSize() const final { return fSubfields[0]->GetValueSize(); }
0069    size_t GetAlignment() const final { return fSubfields[0]->GetAlignment(); }
0070 
0071    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0072 };
0073 
0074 template <typename ItemT>
0075 class RField<std::atomic<ItemT>> final : public RAtomicField {
0076 public:
0077    static std::string TypeName() { return "std::atomic<" + RField<ItemT>::TypeName() + ">"; }
0078    explicit RField(std::string_view name) : RAtomicField(name, std::make_unique<RField<ItemT>>("_0")) {}
0079    RField(RField &&other) = default;
0080    RField &operator=(RField &&other) = default;
0081    ~RField() final = default;
0082 };
0083 
0084 ////////////////////////////////////////////////////////////////////////////////
0085 /// Template specializations for C++ std::bitset
0086 ////////////////////////////////////////////////////////////////////////////////
0087 
0088 /// The generic field for a `std::bitset<N>`.
0089 /// GCC and Clang store the bits in an array of unsigned long, whereas MSVC uses either a single uint32_t for `N <= 32`
0090 /// or an array of uint64_t for `N > 32` (reference: https://github.com/microsoft/STL/blob/main/stl/inc/bitset).
0091 /// TODO(jblomer): reading and writing efficiency should be improved; currently it is one bit at a time
0092 /// with an array of bools on the page level.
0093 class RBitsetField : public RFieldBase {
0094 protected:
0095    std::size_t fN;
0096 
0097 protected:
0098    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0099    {
0100       return std::make_unique<RBitsetField>(newName, fN);
0101    }
0102    const RColumnRepresentations &GetColumnRepresentations() const final;
0103    void GenerateColumns() final;
0104    void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final;
0105    void ConstructValue(void *where) const final { memset(where, 0, GetValueSize()); }
0106    std::size_t AppendImpl(const void *from) final;
0107    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0108    void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final;
0109 
0110    size_t WordSize() const
0111    {
0112 #if defined(_MSC_VER)
0113       const size_t wordSize = (fN <= sizeof(unsigned long) * 8) ? sizeof(unsigned long) : sizeof(unsigned long long);
0114 #else
0115       const size_t wordSize = sizeof(unsigned long);
0116 #endif
0117       return wordSize;
0118    }
0119 
0120    template <typename FUlong, typename FUlonglong, typename... Args>
0121    void SelectWordSize(FUlong &&fUlong, FUlonglong &&fUlonglong, Args &&...args);
0122 
0123 public:
0124    RBitsetField(std::string_view fieldName, std::size_t N);
0125    RBitsetField(RBitsetField &&other) = default;
0126    RBitsetField &operator=(RBitsetField &&other) = default;
0127    ~RBitsetField() override = default;
0128 
0129    size_t GetValueSize() const final
0130    {
0131       const size_t bitsPerWord = WordSize() * 8;
0132       return WordSize() * ((fN + bitsPerWord - 1) / bitsPerWord);
0133    }
0134 
0135    size_t GetAlignment() const final
0136    {
0137 #if defined(_MSC_VER)
0138       return WordSize() == sizeof(unsigned long) ? alignof(unsigned long) : alignof(unsigned long long);
0139 #else
0140       return alignof(unsigned long);
0141 #endif
0142    }
0143 
0144    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0145 
0146    /// Get the number of bits in the bitset, i.e. the `N` in `std::bitset<N>`
0147    std::size_t GetN() const { return fN; }
0148 };
0149 
0150 template <std::size_t N>
0151 class RField<std::bitset<N>> final : public RBitsetField {
0152 public:
0153    static std::string TypeName() { return "std::bitset<" + std::to_string(N) + ">"; }
0154    explicit RField(std::string_view name) : RBitsetField(name, N) {}
0155    RField(RField &&other) = default;
0156    RField &operator=(RField &&other) = default;
0157    ~RField() final = default;
0158 };
0159 
0160 ////////////////////////////////////////////////////////////////////////////////
0161 /// Template specializations for C++ std::byte
0162 ////////////////////////////////////////////////////////////////////////////////
0163 
0164 extern template class RSimpleField<std::byte>;
0165 
0166 template <>
0167 class RField<std::byte> final : public RSimpleField<std::byte> {
0168 protected:
0169    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0170    {
0171       return std::make_unique<RField>(newName);
0172    }
0173 
0174    const RColumnRepresentations &GetColumnRepresentations() const final;
0175 
0176 public:
0177    static std::string TypeName() { return "std::byte"; }
0178    explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
0179    RField(RField &&other) = default;
0180    RField &operator=(RField &&other) = default;
0181    ~RField() final = default;
0182 
0183    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0184 };
0185 
0186 ////////////////////////////////////////////////////////////////////////////////
0187 /// Template specializations for C++ std::optional and std::unique_ptr
0188 ////////////////////////////////////////////////////////////////////////////////
0189 
0190 /// The field for values that may or may not be present in an entry. Parent class for unique pointer field and
0191 /// optional field. A nullable field cannot be instantiated itself but only its descendants.
0192 /// The RNullableField takes care of the on-disk representation. Child classes are responsible for the in-memory
0193 /// representation.  Nullable fields use a `(Split)Index[64|32]` column to point to the available items.
0194 class RNullableField : public RFieldBase {
0195    /// The number of written non-null items in this cluster
0196    ROOT::Internal::RColumnIndex fNWritten{0};
0197 
0198 protected:
0199    // For reading, indicates that we read type T as a nullable field of type T, i.e. the value is always present
0200    bool fIsEvolvedFromInnerType = false;
0201 
0202    const RFieldBase::RColumnRepresentations &GetColumnRepresentations() const final;
0203    void GenerateColumns() final;
0204    void GenerateColumns(const ROOT::RNTupleDescriptor &) final;
0205 
0206    std::size_t AppendNull();
0207    std::size_t AppendValue(const void *from);
0208    void CommitClusterImpl() final { fNWritten = 0; }
0209 
0210    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0211 
0212    /// Given the global index of the nullable field, returns the corresponding cluster-local index of the subfield or,
0213    /// if it is null, returns a default constructed RNTupleLocalIndex
0214    RNTupleLocalIndex GetItemIndex(NTupleSize_t globalIndex);
0215    /// Given the cluster-local index of the nullable field, returns the corresponding cluster-local index of
0216    /// the subfield or, if it is null, returns a default constructed RNTupleLocalIndex
0217    RNTupleLocalIndex GetItemIndex(RNTupleLocalIndex localIndex);
0218 
0219    RNullableField(std::string_view fieldName, const std::string &typePrefix, std::unique_ptr<RFieldBase> itemField);
0220 
0221 public:
0222    RNullableField(RNullableField &&other) = default;
0223    RNullableField &operator=(RNullableField &&other) = default;
0224    ~RNullableField() override = default;
0225 
0226    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0227 };
0228 
0229 class ROptionalField : public RNullableField {
0230    class ROptionalDeleter : public RDeleter {
0231    private:
0232       std::unique_ptr<RDeleter> fItemDeleter; // nullptr for trivially destructible items
0233       std::size_t fEngagementPtrOffset = 0;
0234 
0235    public:
0236       ROptionalDeleter(std::unique_ptr<RDeleter> itemDeleter, std::size_t engagementPtrOffset)
0237          : fItemDeleter(std::move(itemDeleter)), fEngagementPtrOffset(engagementPtrOffset) {}
0238       void operator()(void *objPtr, bool dtorOnly) final;
0239    };
0240 
0241    std::unique_ptr<RDeleter> fItemDeleter;
0242 
0243    /// Given a pointer to an `std::optional<T>` in `optionalPtr`, extract a pointer to the engagement boolean.
0244    /// Assumes that an `std::optional<T>` is stored as `struct { T t; bool engagement; };`
0245    const bool *GetEngagementPtr(const void *optionalPtr) const;
0246    bool *GetEngagementPtr(void *optionalPtr) const;
0247    std::size_t GetEngagementPtrOffset() const;
0248    void PrepareRead(void *to, bool hasOnDiskValue);
0249 
0250 protected:
0251    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0252 
0253    void ConstructValue(void *where) const final;
0254    std::unique_ptr<RDeleter> GetDeleter() const final;
0255 
0256    std::size_t AppendImpl(const void *from) final;
0257    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0258    void ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to) final;
0259 
0260 public:
0261    ROptionalField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField);
0262    ROptionalField(ROptionalField &&other) = default;
0263    ROptionalField &operator=(ROptionalField &&other) = default;
0264    ~ROptionalField() override = default;
0265 
0266    std::vector<RValue> SplitValue(const RValue &value) const final;
0267    size_t GetValueSize() const final;
0268    size_t GetAlignment() const final;
0269 };
0270 
0271 template <typename ItemT>
0272 class RField<std::optional<ItemT>> final : public ROptionalField {
0273 public:
0274    static std::string TypeName() { return "std::optional<" + RField<ItemT>::TypeName() + ">"; }
0275    explicit RField(std::string_view name) : ROptionalField(name, std::make_unique<RField<ItemT>>("_0")) {}
0276    RField(RField &&other) = default;
0277    RField &operator=(RField &&other) = default;
0278    ~RField() final = default;
0279 };
0280 
0281 class RUniquePtrField : public RNullableField {
0282    class RUniquePtrDeleter : public RDeleter {
0283    private:
0284       std::unique_ptr<RDeleter> fItemDeleter;
0285 
0286    public:
0287       explicit RUniquePtrDeleter(std::unique_ptr<RDeleter> itemDeleter) : fItemDeleter(std::move(itemDeleter)) {}
0288       void operator()(void *objPtr, bool dtorOnly) final;
0289    };
0290 
0291    std::unique_ptr<RDeleter> fItemDeleter;
0292    /// If the item type is a polymorphic class (that declares or inherits at least one virtual method), points to the
0293    /// expected dynamic type of any user object; otherwise nullptr.
0294    const std::type_info *fPolymorphicTypeInfo = nullptr;
0295 
0296    // Returns the value pointer, i.e. where to read the subfield into
0297    void *PrepareRead(void *to, bool hasOnDiskValue);
0298 
0299 protected:
0300    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0301 
0302    void ConstructValue(void *where) const final { new (where) std::unique_ptr<char>(); }
0303    std::unique_ptr<RDeleter> GetDeleter() const final;
0304 
0305    std::size_t AppendImpl(const void *from) final;
0306    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0307    void ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to) final;
0308 
0309 public:
0310    RUniquePtrField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField);
0311    RUniquePtrField(RUniquePtrField &&other) = default;
0312    RUniquePtrField &operator=(RUniquePtrField &&other) = default;
0313    ~RUniquePtrField() override = default;
0314 
0315    std::vector<RValue> SplitValue(const RValue &value) const final;
0316    size_t GetValueSize() const final { return sizeof(std::unique_ptr<char>); }
0317    size_t GetAlignment() const final { return alignof(std::unique_ptr<char>); }
0318 };
0319 
0320 template <typename ItemT>
0321 class RField<std::unique_ptr<ItemT>> final : public RUniquePtrField {
0322 public:
0323    static std::string TypeName() { return "std::unique_ptr<" + RField<ItemT>::TypeName() + ">"; }
0324    explicit RField(std::string_view name) : RUniquePtrField(name, std::make_unique<RField<ItemT>>("_0")) {}
0325    RField(RField &&other) = default;
0326    RField &operator=(RField &&other) = default;
0327    ~RField() final = default;
0328 };
0329 
0330 ////////////////////////////////////////////////////////////////////////////////
0331 /// Template specializations for C++ std::string
0332 ////////////////////////////////////////////////////////////////////////////////
0333 
0334 template <>
0335 class RField<std::string> final : public RFieldBase {
0336 private:
0337    ROOT::Internal::RColumnIndex fIndex;
0338 
0339    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
0340    {
0341       return std::make_unique<RField>(newName);
0342    }
0343 
0344    const RColumnRepresentations &GetColumnRepresentations() const final;
0345    void GenerateColumns() final;
0346    void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final;
0347 
0348    void ConstructValue(void *where) const final { new (where) std::string(); }
0349    std::unique_ptr<RDeleter> GetDeleter() const final { return std::make_unique<RTypedDeleter<std::string>>(); }
0350 
0351    std::size_t AppendImpl(const void *from) final;
0352    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0353 
0354    void CommitClusterImpl() final { fIndex = 0; }
0355 
0356 public:
0357    static std::string TypeName() { return "std::string"; }
0358    explicit RField(std::string_view name)
0359       : RFieldBase(name, TypeName(), ROOT::ENTupleStructure::kPlain, false /* isSimple */), fIndex(0)
0360    {
0361    }
0362    RField(RField &&other) = default;
0363    RField &operator=(RField &&other) = default;
0364    ~RField() final = default;
0365 
0366    size_t GetValueSize() const final { return sizeof(std::string); }
0367    size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
0368    void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
0369 };
0370 
0371 ////////////////////////////////////////////////////////////////////////////////
0372 /// Template specializations for C++ std::variant
0373 ////////////////////////////////////////////////////////////////////////////////
0374 
0375 /// The generic field for std::variant types
0376 class RVariantField : public RFieldBase {
0377 private:
0378    // Most compilers support at least 255 variants (256 - 1 value for the empty variant).
0379    // Some compilers switch to a two-byte tag field already with 254 variants.
0380    // MSVC only supports 163 variants in older versions, 250 in newer ones. It switches to a 2 byte
0381    // tag as of 128 variants (at least in debug mode), so for simplicity we set the limit to 125 variants.
0382    static constexpr std::size_t kMaxVariants = 125;
0383 
0384    class RVariantDeleter : public RDeleter {
0385    private:
0386       std::size_t fTagOffset;
0387       std::size_t fVariantOffset;
0388       std::vector<std::unique_ptr<RDeleter>> fItemDeleters;
0389 
0390    public:
0391       RVariantDeleter(std::size_t tagOffset, std::size_t variantOffset,
0392                       std::vector<std::unique_ptr<RDeleter>> itemDeleters)
0393          : fTagOffset(tagOffset), fVariantOffset(variantOffset), fItemDeleters(std::move(itemDeleters))
0394       {
0395       }
0396       void operator()(void *objPtr, bool dtorOnly) final;
0397    };
0398 
0399    size_t fMaxItemSize = 0;
0400    size_t fMaxAlignment = 1;
0401    /// In the `std::variant` memory layout, at which byte number is the index stored
0402    size_t fTagOffset = 0;
0403    /// In the `std::variant` memory layout, the actual union of types may start at an offset > 0
0404    size_t fVariantOffset = 0;
0405    std::vector<ROOT::Internal::RColumnIndex::ValueType> fNWritten;
0406 
0407    static std::string GetTypeList(const std::vector<std::unique_ptr<RFieldBase>> &itemFields);
0408    /// Extracts the index from an `std::variant` and transforms it into the 1-based index used for the switch column
0409    /// The implementation supports two memory layouts that are in use: a trailing unsigned byte, zero-indexed,
0410    /// having the exception caused empty state encoded by the max tag value,
0411    /// or a trailing unsigned int instead of a char.
0412    static std::uint8_t GetTag(const void *variantPtr, std::size_t tagOffset);
0413    static void SetTag(void *variantPtr, std::size_t tagOffset, std::uint8_t tag);
0414 
0415    RVariantField(std::string_view name, const RVariantField &source); // Used by CloneImpl()
0416 
0417 protected:
0418    std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final;
0419 
0420    const RColumnRepresentations &GetColumnRepresentations() const final;
0421    void GenerateColumns() final;
0422    void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final;
0423 
0424    void ConstructValue(void *where) const final;
0425    std::unique_ptr<RDeleter> GetDeleter() const final;
0426 
0427    std::size_t AppendImpl(const void *from) final;
0428    void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final;
0429 
0430    void CommitClusterImpl() final;
0431 
0432    void ReconcileOnDiskField(const RNTupleDescriptor &desc) final;
0433 
0434 public:
0435    RVariantField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields);
0436    RVariantField(RVariantField &&other) = default;
0437    RVariantField &operator=(RVariantField &&other) = default;
0438    ~RVariantField() override = default;
0439 
0440    size_t GetValueSize() const final;
0441    size_t GetAlignment() const final;
0442 };
0443 
0444 template <typename... ItemTs>
0445 class RField<std::variant<ItemTs...>> final : public RVariantField {
0446 private:
0447    template <typename HeadT, typename... TailTs>
0448    static std::string BuildItemTypes()
0449    {
0450       std::string result = RField<HeadT>::TypeName();
0451       if constexpr (sizeof...(TailTs) > 0)
0452          result += "," + BuildItemTypes<TailTs...>();
0453       return result;
0454    }
0455 
0456    template <typename HeadT, typename... TailTs>
0457    static void _BuildItemFields(std::vector<std::unique_ptr<RFieldBase>> &itemFields, unsigned int index = 0)
0458    {
0459       itemFields.emplace_back(new RField<HeadT>("_" + std::to_string(index)));
0460       if constexpr (sizeof...(TailTs) > 0)
0461          _BuildItemFields<TailTs...>(itemFields, index + 1);
0462    }
0463    static std::vector<std::unique_ptr<RFieldBase>> BuildItemFields()
0464    {
0465       std::vector<std::unique_ptr<RFieldBase>> result;
0466       _BuildItemFields<ItemTs...>(result);
0467       return result;
0468    }
0469 
0470 public:
0471    static std::string TypeName() { return "std::variant<" + BuildItemTypes<ItemTs...>() + ">"; }
0472    explicit RField(std::string_view name) : RVariantField(name, BuildItemFields()) {}
0473    RField(RField &&other) = default;
0474    RField &operator=(RField &&other) = default;
0475    ~RField() final = default;
0476 };
0477 
0478 } // namespace ROOT
0479 
0480 #endif