Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 09:14:21

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