Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 09:08:28

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