Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-14 10:31:18

0001 /// \file ROOT/RNTupleProcessor.hxx
0002 /// \ingroup NTuple
0003 /// \author Florine de Geus <florine.de.geus@cern.ch>
0004 /// \date 2025-06-25
0005 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
0006 /// is welcome!
0007 
0008 /*************************************************************************
0009  * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers.               *
0010  * All rights reserved.                                                  *
0011  *                                                                       *
0012  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0013  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0014  *************************************************************************/
0015 
0016 #ifndef ROOT_RNTupleProcessorEntry
0017 #define ROOT_RNTupleProcessorEntry
0018 
0019 #include <ROOT/RNTupleModel.hxx>
0020 #include <ROOT/RFieldBase.hxx>
0021 
0022 #include <cassert>
0023 #include <string>
0024 #include <string_view>
0025 #include <unordered_map>
0026 #include <vector>
0027 
0028 namespace ROOT {
0029 namespace Experimental {
0030 namespace Internal {
0031 /**
0032 \class ROOT::Experimental::RNTupleProcessorProvenance
0033 \ingroup NTuple
0034 \brief Identifies how a processor is composed.
0035 
0036 The processor provenance is used in RNTupleProcessorEntry to identify how an (auxiliary) field in a composed processor
0037 can be accessed.
0038 */
0039 // clang-format on
0040 class RNTupleProcessorProvenance {
0041 private:
0042    std::string fProvenance{};
0043 
0044 public:
0045    RNTupleProcessorProvenance() = default;
0046    RNTupleProcessorProvenance(const std::string &provenance) : fProvenance(provenance) {}
0047 
0048    /////////////////////////////////////////////////////////////////////////////
0049    /// \brief Get the full processor provenance, in the form of "x.y.z".
0050    std::string Get() const { return fProvenance; }
0051 
0052    /////////////////////////////////////////////////////////////////////////////
0053    /// \brief Add a new processor to the provenance.
0054    ///
0055    /// \param[in] processorName Name of the processor to add.
0056    ///
0057    /// \return The updated provenance.
0058    RNTupleProcessorProvenance Evolve(const std::string &processorName) const
0059    {
0060       if (fProvenance.empty())
0061          return RNTupleProcessorProvenance(processorName);
0062 
0063       return RNTupleProcessorProvenance(fProvenance + "." + processorName);
0064    }
0065 
0066    /////////////////////////////////////////////////////////////////////////////
0067    /// \brief Check whether the provenance subsumes the provenance in `other`.
0068    ///
0069    /// \param[in] other The other provenance
0070    bool Contains(const RNTupleProcessorProvenance &other) const
0071    {
0072       return fProvenance.rfind(other.fProvenance) != std::string::npos;
0073    }
0074 
0075    /////////////////////////////////////////////////////////////////////////////
0076    /// \brief Check whether the provided field name contains this provenance.
0077    ///
0078    /// \param[in] fieldName Field name to check.
0079    bool IsPresentInFieldName(std::string_view fieldName) const
0080    {
0081       return !fProvenance.empty() && fieldName.find(fProvenance + ".") == 0;
0082    }
0083 };
0084 
0085 // clang-format off
0086 /**
0087 \class ROOT::Experimental::Internal::RNTupleProcessorEntry
0088 \ingroup NTuple
0089 \brief Collection of values in an RNTupleProcessor, analogous to REntry, with checks and support for missing values.
0090 */
0091 // clang-format on
0092 class RNTupleProcessorEntry {
0093 public:
0094    // We don't use RFieldTokens here, because it (semantically) does not make sense for the entry to be fixed to the
0095    // schema ID of a particular model.
0096    using FieldIndex_t = std::uint64_t;
0097 
0098 private:
0099    struct RProcessorValue {
0100       ROOT::RFieldBase::RValue fValue;
0101       bool fIsValid;
0102       RNTupleProcessorProvenance fProcessorProvenance;
0103 
0104       RProcessorValue(ROOT::RFieldBase::RValue &&value, bool isValid, RNTupleProcessorProvenance provenance)
0105          : fValue(std::move(value)), fIsValid(isValid), fProcessorProvenance(provenance)
0106       {
0107       }
0108    };
0109 
0110    std::vector<RProcessorValue> fProcessorValues;
0111    std::unordered_map<std::string, FieldIndex_t> fFieldName2Index;
0112 
0113 public:
0114    /////////////////////////////////////////////////////////////////////////////
0115    /// \brief Set the validity of a field, i.e. whether it is possible to read its value in the current entry.
0116    ///
0117    /// \param[in] fieldIdx The index of the field in the entry.
0118    /// \param[in] isValid The new validity of the field.
0119    void SetFieldValidity(FieldIndex_t fieldIdx, bool isValid)
0120    {
0121       assert(fieldIdx < fProcessorValues.size());
0122       fProcessorValues[fieldIdx].fIsValid = isValid;
0123    }
0124 
0125    /////////////////////////////////////////////////////////////////////////////
0126    /// \brief Check whether a field is valid for reading.
0127    ///
0128    /// \param[in] fieldIdx The index of the field in the entry.
0129    bool IsValidField(FieldIndex_t fieldIdx) const
0130    {
0131       assert(fieldIdx < fProcessorValues.size());
0132       return fProcessorValues[fieldIdx].fIsValid;
0133    }
0134 
0135    /////////////////////////////////////////////////////////////////////////////
0136    /// \brief Find the name of a field from its field index.
0137    ///
0138    /// \param[in] fieldIdx The index of the field in the entry.
0139    ///
0140    /// \warning This function has linear complexity, only use it for more helpful error messages!
0141    const std::string &FindFieldName(FieldIndex_t fieldIdx) const
0142    {
0143       assert(fieldIdx < fProcessorValues.size());
0144 
0145       for (const auto &[fieldName, index] : fFieldName2Index) {
0146          if (index == fieldIdx) {
0147             return fieldName;
0148          }
0149       }
0150       // Should never happen, but avoid compiler warning about "returning reference to local temporary object".
0151       R__ASSERT(false);
0152       static const std::string empty = "";
0153       return empty;
0154    }
0155 
0156    /////////////////////////////////////////////////////////////////////////////
0157    /// \brief Find the field index of the provided field in the entry.
0158    ///
0159    /// \param[in] fieldName The name of the field in the entry.
0160    ///
0161    /// \return A `std::optional` containing the field index if it was found.
0162    std::optional<FieldIndex_t> FindFieldIndex(std::string_view fieldName) const
0163    {
0164       auto it = fFieldName2Index.find(std::string(fieldName));
0165       if (it == fFieldName2Index.end()) {
0166          return std::nullopt;
0167       }
0168       return it->second;
0169    }
0170 
0171    /////////////////////////////////////////////////////////////////////////////
0172    /// \brief Add a new field to the entry.
0173    ///
0174    /// \param[in] fieldName Name of the field to add.
0175    /// \param[in] field Reference to the field to add, used to to create its corresponding RValue.
0176    /// \param[in] valuePtr Pointer to an object corresponding to the field's type to bind to its value. If this is a
0177    /// `nullptr`, a pointer will be created.
0178    /// \param[in] provenance Processor provenance of the field.
0179    ///
0180    /// \return The field index of the newly added field.
0181    FieldIndex_t AddField(std::string_view fieldName, ROOT::RFieldBase &field, void *valuePtr,
0182                          const RNTupleProcessorProvenance &provenance)
0183    {
0184       if (FindFieldIndex(fieldName))
0185          throw ROOT::RException(
0186             R__FAIL("field \"" + field.GetQualifiedFieldName() + "\" is already present in the entry"));
0187 
0188       auto value = field.CreateValue();
0189       if (valuePtr)
0190          value.BindRawPtr(valuePtr);
0191       auto fieldIdx = fProcessorValues.size();
0192       fFieldName2Index[std::string(fieldName)] = fieldIdx;
0193       fProcessorValues.emplace_back(RProcessorValue(std::move(value), true, provenance));
0194 
0195       return fieldIdx;
0196    }
0197 
0198    /////////////////////////////////////////////////////////////////////////////
0199    /// \brief Update a field in the entry, preserving the value pointer.
0200    ///
0201    /// \param[in] fieldIdx Index of the field to update.
0202    /// \param[in] field The new field to use in the entry.
0203    void UpdateField(FieldIndex_t fieldIdx, ROOT::RFieldBase &field)
0204    {
0205       assert(fieldIdx < fProcessorValues.size());
0206 
0207       auto currValuePtr = fProcessorValues[fieldIdx].fValue.GetPtr<void>();
0208       auto value = field.CreateValue();
0209       value.Bind(currValuePtr);
0210       fProcessorValues[fieldIdx].fValue = value;
0211    }
0212 
0213    /////////////////////////////////////////////////////////////////////////////
0214    /// \brief Bind a new value pointer to a field in the entry.
0215    ///
0216    /// \param[in] fieldIdx The index of the field in the entry.
0217    /// \param[in] valuePtr Pointer to the value to bind to the field.
0218    void BindRawPtr(FieldIndex_t fieldIdx, void *valuePtr)
0219    {
0220       assert(fieldIdx < fProcessorValues.size());
0221       fProcessorValues[fieldIdx].fValue.BindRawPtr(valuePtr);
0222    }
0223 
0224    /////////////////////////////////////////////////////////////////////////////
0225    /// \brief Read the field value corresponding to the given field index for the provided entry index.
0226    ///
0227    /// \param[in] fieldIdx The index of the field in the entry.
0228    /// \param[in] entryIdx The entry number to read.
0229    void ReadValue(FieldIndex_t fieldIdx, ROOT::NTupleSize_t entryIdx)
0230    {
0231       assert(fieldIdx < fProcessorValues.size());
0232 
0233       if (fProcessorValues[fieldIdx].fIsValid) {
0234          fProcessorValues[fieldIdx].fValue.Read(entryIdx);
0235       }
0236    }
0237 
0238    /////////////////////////////////////////////////////////////////////////////
0239    /// \brief Get a pointer to the value for the field represented by the provided field index.
0240    ///
0241    /// \tparam T The type of the pointer.
0242    ///
0243    /// \param[in] fieldIdx The index of the field in the entry.
0244    ///
0245    /// \return A shared pointer of type `T` with the field's value.
0246    template <typename T>
0247    std::shared_ptr<T> GetPtr(FieldIndex_t fieldIdx) const
0248    {
0249       assert(fieldIdx < fProcessorValues.size());
0250 
0251       if (fProcessorValues[fieldIdx].fIsValid)
0252          return fProcessorValues[fieldIdx].fValue.GetPtr<T>();
0253 
0254       return nullptr;
0255    }
0256 
0257    /////////////////////////////////////////////////////////////////////////////
0258    /// \brief Get a reference to a field in the entry.
0259    ///
0260    /// \param[in] fieldIdx The index of the field in the entry.
0261    const ROOT::RFieldBase &GetField(FieldIndex_t fieldIdx) const
0262    {
0263       assert(fieldIdx < fProcessorValues.size());
0264       return fProcessorValues[fieldIdx].fValue.GetField();
0265    }
0266 
0267    /////////////////////////////////////////////////////////////////////////////
0268    /// \brief Get the processor provenance of a field in the entry.
0269    ///
0270    /// \param[in] fieldIdx The index of the field in the entry.
0271    const RNTupleProcessorProvenance &GetFieldProvenance(FieldIndex_t fieldIdx) const
0272    {
0273       assert(fieldIdx < fProcessorValues.size());
0274       return fProcessorValues[fieldIdx].fProcessorProvenance;
0275    }
0276 
0277    /////////////////////////////////////////////////////////////////////////////
0278    /// \brief Get the name of a field in the entry, including processor name prefixes in the case of auxiliary fields.
0279    ///
0280    /// \param[in] fieldIdx The index of the field in the entry.
0281    std::string GetFieldName(FieldIndex_t fieldIdx) const
0282    {
0283       assert(fieldIdx < fProcessorValues.size());
0284       return fProcessorValues[fieldIdx].fProcessorProvenance.Get() + "." +
0285              fProcessorValues[fieldIdx].fValue.GetField().GetQualifiedFieldName();
0286    }
0287 
0288    /////////////////////////////////////////////////////////////////////////////
0289    /// \brief Get all field indices of this entry.
0290    std::unordered_set<FieldIndex_t> GetFieldIndices() const
0291    {
0292       // Field indices are sequentially assigned, and the entry (currently) offers no way to remove fields, so we can
0293       // just generate and return a set {0, ..., |fProcessorValues| - 1}.
0294       std::unordered_set<FieldIndex_t> fieldIdxs(fProcessorValues.size());
0295       std::generate_n(std::inserter(fieldIdxs, fieldIdxs.begin()), fProcessorValues.size(),
0296                       [i = 0]() mutable { return i++; });
0297       return fieldIdxs;
0298    }
0299 };
0300 } // namespace Internal
0301 } // namespace Experimental
0302 } // namespace ROOT
0303 
0304 #endif // ROOT_RNTupleProcessorEntry