Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-03 10:40:30

0001 /// \file ROOT/REntry.hxx
0002 /// \ingroup NTuple
0003 /// \author Jakob Blomer <jblomer@cern.ch>
0004 /// \date 2018-07-19
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_REntry
0015 #define ROOT_REntry
0016 
0017 #include <ROOT/RError.hxx>
0018 #include <ROOT/RField.hxx>
0019 #include <ROOT/RFieldToken.hxx>
0020 #include <string_view>
0021 
0022 #include <TError.h>
0023 
0024 #include <algorithm>
0025 #include <iterator>
0026 #include <memory>
0027 #include <type_traits>
0028 #include <utility>
0029 #include <vector>
0030 #include <unordered_map>
0031 
0032 namespace ROOT {
0033 
0034 class RNTupleFillContext;
0035 class RNTupleReader;
0036 
0037 namespace Experimental {
0038 class RNTupleAttrSetReader;
0039 
0040 namespace Internal {
0041 struct RNTupleAttrEntry;
0042 }
0043 } // namespace Experimental
0044 
0045 // clang-format off
0046 /**
0047 \class ROOT::REntry
0048 \ingroup NTuple
0049 \brief The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
0050 
0051 The entry provides a memory-managed binder for a set of values read from fields in an RNTuple. The memory locations that are associated
0052 with values are managed through shared pointers.
0053 */
0054 // clang-format on
0055 class REntry {
0056    friend class RNTupleFillContext;
0057    friend class RNTupleModel;
0058    friend class RNTupleReader;
0059    friend class Experimental::RNTupleAttrSetReader;
0060    friend struct Experimental::Internal::RNTupleAttrEntry;
0061 
0062 private:
0063    /// The entry must be linked to a specific model, identified by a model ID
0064    std::uint64_t fModelId = 0;
0065    /// The entry and its tokens are also linked to a specific schema, identified by a schema ID
0066    std::uint64_t fSchemaId = 0;
0067    /// Corresponds to the fields of the linked model
0068    std::vector<ROOT::RFieldBase::RValue> fValues;
0069    /// For fast lookup of token IDs given a (sub)field name present in the entry
0070    std::unordered_map<std::string, std::size_t> fFieldName2Token;
0071    /// To ensure that the entry is standalone, a copy of all field types
0072    std::vector<std::string> fFieldTypes;
0073 
0074    /// Creation of entries can be done by the RNTupleModel, the RNTupleReader, or the RNTupleWriter.
0075    REntry() = default;
0076    explicit REntry(std::uint64_t modelId, std::uint64_t schemaId) : fModelId(modelId), fSchemaId(schemaId) {}
0077 
0078    void AddValue(ROOT::RFieldBase::RValue &&value)
0079    {
0080       fFieldName2Token[value.GetField().GetQualifiedFieldName()] = fValues.size();
0081       fFieldTypes.push_back(value.GetField().GetTypeName());
0082       fValues.emplace_back(std::move(value));
0083    }
0084 
0085    /// While building the entry, adds a new value for the field and returns the value's shared pointer
0086    template <typename T>
0087    std::shared_ptr<T> AddValue(ROOT::RField<T> &field)
0088    {
0089       fFieldName2Token[field.GetQualifiedFieldName()] = fValues.size();
0090       fFieldTypes.push_back(field.GetTypeName());
0091       auto value = field.CreateValue();
0092       fValues.emplace_back(value);
0093       // We know that the created RValue has the right type, skip the unnecessary check.
0094       return std::static_pointer_cast<T>(value.template GetPtr<void>());
0095    }
0096 
0097    void Read(ROOT::NTupleSize_t index)
0098    {
0099       for (auto &v : fValues) {
0100          v.Read(index);
0101       }
0102    }
0103 
0104    std::size_t Append()
0105    {
0106       std::size_t bytesWritten = 0;
0107       for (auto &v : fValues) {
0108          bytesWritten += v.Append();
0109       }
0110       return bytesWritten;
0111    }
0112 
0113    void EnsureMatchingModel(ROOT::RFieldToken token) const
0114    {
0115       if (fSchemaId != token.fSchemaId) {
0116          throw RException(R__FAIL("invalid token for this entry, "
0117                                   "make sure to use a token from a model with the same schema as this entry."));
0118       }
0119    }
0120 
0121    /// This function has linear complexity, only use it for more helpful error messages!
0122    const std::string &FindFieldName(ROOT::RFieldToken token) const
0123    {
0124       for (const auto &[fieldName, index] : fFieldName2Token) {
0125          if (index == token.fIndex) {
0126             return fieldName;
0127          }
0128       }
0129       // Should never happen, but avoid compiler warning about "returning reference to local temporary object".
0130       static const std::string empty = "";
0131       return empty;
0132    }
0133 
0134    template <typename T>
0135    void EnsureMatchingType(ROOT::RFieldToken token [[maybe_unused]]) const
0136    {
0137       if constexpr (!std::is_void_v<T>) {
0138          if (!Internal::IsMatchingFieldType<T>(fFieldTypes[token.fIndex])) {
0139             throw RException(R__FAIL("type mismatch for field " + FindFieldName(token) + ": " +
0140                                      fFieldTypes[token.fIndex] + " vs. " + ROOT::RField<T>::TypeName()));
0141          }
0142       }
0143    }
0144 
0145 public:
0146    using ConstIterator_t = decltype(fValues)::const_iterator;
0147 
0148    REntry(const REntry &other) = delete;
0149    REntry &operator=(const REntry &other) = delete;
0150    REntry(REntry &&other) = default;
0151    REntry &operator=(REntry &&other) = default;
0152    ~REntry() = default;
0153 
0154    /// The ordinal of the (sub)field fieldName; can be used in other methods to address the corresponding value
0155    ROOT::RFieldToken GetToken(std::string_view fieldName) const
0156    {
0157       auto it = fFieldName2Token.find(std::string(fieldName));
0158       if (it == fFieldName2Token.end()) {
0159          throw RException(R__FAIL("invalid field name: " + std::string(fieldName)));
0160       }
0161       return ROOT::RFieldToken(it->second, fSchemaId);
0162    }
0163 
0164    /// Create a new value for the field referenced by `token`.
0165    void EmplaceNewValue(ROOT::RFieldToken token)
0166    {
0167       EnsureMatchingModel(token);
0168       fValues[token.fIndex].EmplaceNew();
0169    }
0170 
0171    /// Create a new value for the field referenced by its name.
0172    void EmplaceNewValue(std::string_view fieldName) { EmplaceNewValue(GetToken(fieldName)); }
0173 
0174    /// Bind the value for the field, referenced by `token`, to `objPtr`.
0175    ///
0176    /// \sa BindValue(std::string_view, std::shared_ptr<T>)
0177    template <typename T>
0178    void BindValue(ROOT::RFieldToken token, std::shared_ptr<T> objPtr)
0179    {
0180       EnsureMatchingModel(token);
0181       EnsureMatchingType<T>(token);
0182       fValues[token.fIndex].Bind(objPtr);
0183    }
0184 
0185    /// Bind the value for the field, referenced by its name, to `objPtr`.
0186    ///
0187    /// Ownership is shared with the caller and the object will be kept alive until it is replaced (by a call to
0188    /// EmplaceNewValue, BindValue, or BindRawPtr) or the entry is destructed.
0189    ///
0190    /// **Note**: if `T = void`, type checks are disabled. It is the caller's responsibility to match the field and
0191    /// object types.
0192    template <typename T>
0193    void BindValue(std::string_view fieldName, std::shared_ptr<T> objPtr)
0194    {
0195       BindValue<T>(GetToken(fieldName), objPtr);
0196    }
0197 
0198    /// Bind the value for the field, referenced by `token`, to `rawPtr`.
0199    ///
0200    /// \sa BindRawPtr(std::string_view, T *)
0201    template <typename T>
0202    void BindRawPtr(ROOT::RFieldToken token, T *rawPtr)
0203    {
0204       EnsureMatchingModel(token);
0205       EnsureMatchingType<T>(token);
0206       fValues[token.fIndex].BindRawPtr(rawPtr);
0207    }
0208 
0209    /// Bind the value for the field, referenced by its name, to `rawPtr`.
0210    ///
0211    /// The caller retains ownership of the object and must ensure it is kept alive when reading or writing using the
0212    /// entry.
0213    ///
0214    /// **Note**: if `T = void`, type checks are disabled. It is the caller's responsibility to match the field and
0215    /// object types.
0216    template <typename T>
0217    void BindRawPtr(std::string_view fieldName, T *rawPtr)
0218    {
0219       BindRawPtr<T>(GetToken(fieldName), rawPtr);
0220    }
0221 
0222    /// Get the (typed) pointer to the value for the field referenced by `token`.
0223    ///
0224    /// \sa GetPtr(std::string_view)
0225    template <typename T>
0226    std::shared_ptr<T> GetPtr(ROOT::RFieldToken token) const
0227    {
0228       EnsureMatchingModel(token);
0229       EnsureMatchingType<T>(token);
0230       return std::static_pointer_cast<T>(fValues[token.fIndex].GetPtr<void>());
0231    }
0232 
0233    /// Get the (typed) pointer to the value for the field referenced by `token`.
0234    ///
0235    /// Ownership is shared and the caller can continue to use the object after the entry is destructed.
0236    ///
0237    /// **Note**: if `T = void`, type checks are disabled. It is the caller's responsibility to use the returned pointer
0238    /// according to the field type.
0239    template <typename T>
0240    std::shared_ptr<T> GetPtr(std::string_view fieldName) const
0241    {
0242       return GetPtr<T>(GetToken(fieldName));
0243    }
0244 
0245    const std::string &GetTypeName(ROOT::RFieldToken token) const
0246    {
0247       EnsureMatchingModel(token);
0248       return fFieldTypes[token.fIndex];
0249    }
0250 
0251    const std::string &GetTypeName(std::string_view fieldName) const { return GetTypeName(GetToken(fieldName)); }
0252 
0253    bool HasField(std::string_view fieldName) const { return fFieldName2Token.count(std::string(fieldName)) > 0; }
0254 
0255    std::uint64_t GetModelId() const { return fModelId; }
0256    std::uint64_t GetSchemaId() const { return fSchemaId; }
0257 
0258    ConstIterator_t begin() const { return fValues.cbegin(); }
0259    ConstIterator_t end() const { return fValues.cend(); }
0260 };
0261 
0262 } // namespace ROOT
0263 
0264 #endif