Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-18 09:24:18

0001 /// \file ROOT/RNTupleView.hxx
0002 /// \ingroup NTuple
0003 /// \author Jakob Blomer <jblomer@cern.ch>
0004 /// \date 2018-10-05
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_RNTupleView
0015 #define ROOT_RNTupleView
0016 
0017 #include <ROOT/RError.hxx>
0018 #include <ROOT/RField.hxx>
0019 #include <ROOT/RNTupleRange.hxx>
0020 #include <ROOT/RNTupleUtil.hxx>
0021 #include <string_view>
0022 
0023 #include <iterator>
0024 #include <memory>
0025 #include <type_traits>
0026 #include <utility>
0027 #include <unordered_map>
0028 
0029 namespace ROOT {
0030 
0031 class RNTupleReader;
0032 
0033 namespace Internal {
0034 
0035 /// Helper to get the iteration space of the given field that needs to be connected to the given page source.
0036 /// The indexes are given by the number of elements of the principal column of the field or, if none exists,
0037 /// by the number of elements of the first principal column found in the subfields searched by BFS.
0038 /// If the field hierarchy is empty on columns, the returned field range is invalid (start and end set to
0039 /// kInvalidNTupleIndex). An attempt to use such a field range in RNTupleViewBase::GetFieldRange will throw.
0040 ROOT::RNTupleGlobalRange GetFieldRange(const ROOT::RFieldBase &field, const ROOT::Internal::RPageSource &pageSource);
0041 
0042 } // namespace Internal
0043 
0044 // clang-format off
0045 /**
0046 \class ROOT::RNTupleViewBase
0047 \ingroup NTuple
0048 \brief An RNTupleView provides read-only access to a single field of an RNTuple
0049 
0050 \tparam T The type of the object that will be read by the view; can be void if unknown at compile time.
0051 
0052 The view owns a field and its underlying columns in order to fill an RField::RValue object with data. Data can be
0053 accessed by index. For top-level fields, the index refers to the entry number. Fields that are part of
0054 nested collections have global index numbers that are derived from their parent indexes (\see GetFieldRange()).
0055 
0056 View can only be created by a reader or by a collection view.
0057 
0058 **Example: read an RNTuple's field with a view**
0059 ~~~ {.cpp}
0060 auto reader = RNTupleReader::Open("myNtuple", "myntuple.root");
0061 auto viewFoo = reader->GetView<float>("foo");
0062 for (auto idx : reader->GetEntryRange()) {
0063    float foo = viewFoo(idx); // read field "foo" of the `idx`-th entry
0064    std::cout << foo << "\n";
0065 }
0066 ~~~
0067 
0068 **Example: read an RNTuple's collection subfield with a view**
0069 ~~~ {.cpp}
0070 auto reader = RNTupleReader::Open("myNtuple", "myntuple.root");
0071 // Assuming "v" is a std::vector<int>:
0072 auto view = reader->GetView<int>("v._0");
0073 // Effectively flattens all fields "v" in all entries and reads their elements.
0074 for (auto idx : view.GetFieldRange()) {
0075    int x = view(idx);
0076    std::cout << x << "\n";
0077 }
0078 ~~~
0079 */
0080 // clang-format on
0081 template <typename T>
0082 class RNTupleViewBase {
0083 protected:
0084    std::unique_ptr<ROOT::RFieldBase> fField;
0085    ROOT::RNTupleGlobalRange fFieldRange;
0086    ROOT::RFieldBase::RValue fValue;
0087 
0088    static std::unique_ptr<ROOT::RFieldBase>
0089    CreateField(ROOT::DescriptorId_t fieldId, Internal::RPageSource &pageSource, std::string_view typeName = "")
0090    {
0091       std::unique_ptr<ROOT::RFieldBase> field;
0092       {
0093          const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
0094          const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
0095          if constexpr (std::is_void_v<T>) {
0096             if (typeName.empty())
0097                field = fieldDesc.CreateField(desc);
0098             else
0099                field = ROOT::RFieldBase::Create(fieldDesc.GetFieldName(), std::string(typeName)).Unwrap();
0100          } else {
0101             field = std::make_unique<ROOT::RField<T>>(fieldDesc.GetFieldName());
0102          }
0103       }
0104       field->SetOnDiskId(fieldId);
0105       ROOT::Internal::CallConnectPageSourceOnField(*field, pageSource);
0106       return field;
0107    }
0108 
0109    RNTupleViewBase(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range)
0110       : fField(std::move(field)), fFieldRange(range), fValue(fField->CreateValue())
0111    {
0112    }
0113 
0114    RNTupleViewBase(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
0115       : fField(std::move(field)), fFieldRange(range), fValue(fField->BindValue(objPtr))
0116    {
0117    }
0118 
0119    RNTupleViewBase(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, T *rawPtr)
0120       : fField(std::move(field)),
0121         fFieldRange(range),
0122         fValue(fField->BindValue(ROOT::Internal::MakeAliasedSharedPtr(rawPtr)))
0123    {
0124    }
0125 
0126 public:
0127    RNTupleViewBase(const RNTupleViewBase &other) = delete;
0128    RNTupleViewBase(RNTupleViewBase &&other) = default;
0129    RNTupleViewBase &operator=(const RNTupleViewBase &other) = delete;
0130    RNTupleViewBase &operator=(RNTupleViewBase &&other) = default;
0131    ~RNTupleViewBase() = default;
0132 
0133    const ROOT::RFieldBase &GetField() const { return *fField; }
0134    ROOT::RFieldBase::RBulkValues CreateBulk() { return fField->CreateBulk(); }
0135 
0136    const ROOT::RFieldBase::RValue &GetValue() const { return fValue; }
0137    /// Returns the global field range of this view.
0138    /// This may differ from the RNTuple's entry range in case of subfields and can be used to iterate
0139    /// over all the concatenated elements of the subfield without caring which entry they belong to.
0140    /// Throws an RException if the underlying field of this view is empty, i.e. if it's a class or
0141    /// record field with no associated columns.
0142    ROOT::RNTupleGlobalRange GetFieldRange() const
0143    {
0144       if (!fFieldRange.IsValid()) {
0145          throw RException(R__FAIL("field iteration over empty fields is unsupported: " + fField->GetFieldName()));
0146       }
0147       return fFieldRange;
0148    }
0149 
0150    void Bind(std::shared_ptr<T> objPtr) { fValue.Bind(objPtr); }
0151    void BindRawPtr(T *rawPtr) { fValue.BindRawPtr(rawPtr); }
0152    void EmplaceNew() { fValue.EmplaceNew(); }
0153 };
0154 
0155 // clang-format off
0156 /**
0157 \class ROOT::RNTupleView
0158 \ingroup NTuple
0159 \brief An RNTupleView for a known type. See RNTupleViewBase.
0160 */
0161 // clang-format on
0162 template <typename T>
0163 class RNTupleView : public RNTupleViewBase<T> {
0164    friend class ROOT::RNTupleReader;
0165    friend class RNTupleCollectionView;
0166 
0167 protected:
0168    RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range)
0169       : RNTupleViewBase<T>(std::move(field), range)
0170    {
0171    }
0172 
0173    RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, std::shared_ptr<T> objPtr)
0174       : RNTupleViewBase<T>(std::move(field), range, objPtr)
0175    {
0176    }
0177 
0178    RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, T *rawPtr)
0179       : RNTupleViewBase<T>(std::move(field), range, rawPtr)
0180    {
0181    }
0182 
0183 public:
0184    RNTupleView(const RNTupleView &other) = delete;
0185    RNTupleView(RNTupleView &&other) = default;
0186    RNTupleView &operator=(const RNTupleView &other) = delete;
0187    RNTupleView &operator=(RNTupleView &&other) = default;
0188    ~RNTupleView() = default;
0189 
0190    /// Reads the value of this view for the entry with the provided `globalIndex`.
0191    const T &operator()(ROOT::NTupleSize_t globalIndex)
0192    {
0193       RNTupleViewBase<T>::fValue.Read(globalIndex);
0194       return RNTupleViewBase<T>::fValue.template GetRef<T>();
0195    }
0196 
0197    /// Reads the value of this view for the entry with the provided `localIndex`.
0198    /// See RNTupleLocalIndex for more details.
0199    const T &operator()(RNTupleLocalIndex localIndex)
0200    {
0201       RNTupleViewBase<T>::fValue.Read(localIndex);
0202       return RNTupleViewBase<T>::fValue.template GetRef<T>();
0203    }
0204 };
0205 
0206 // clang-format off
0207 /**
0208 \class ROOT::RNTupleView
0209 \ingroup NTuple
0210 \brief An RNTupleView that can be used when the type is unknown at compile time. See RNTupleViewBase.
0211 */
0212 // clang-format on
0213 template <>
0214 class RNTupleView<void> final : public RNTupleViewBase<void> {
0215    friend class ROOT::RNTupleReader;
0216    friend class RNTupleCollectionView;
0217 
0218 protected:
0219    RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range)
0220       : RNTupleViewBase<void>(std::move(field), range)
0221    {
0222    }
0223 
0224    RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, std::shared_ptr<void> objPtr)
0225       : RNTupleViewBase<void>(std::move(field), range, objPtr)
0226    {
0227    }
0228 
0229    RNTupleView(std::unique_ptr<ROOT::RFieldBase> field, ROOT::RNTupleGlobalRange range, void *rawPtr)
0230       : RNTupleViewBase<void>(std::move(field), range, rawPtr)
0231    {
0232    }
0233 
0234 public:
0235    RNTupleView(const RNTupleView &other) = delete;
0236    RNTupleView(RNTupleView &&other) = default;
0237    RNTupleView &operator=(const RNTupleView &other) = delete;
0238    RNTupleView &operator=(RNTupleView &&other) = default;
0239    ~RNTupleView() = default;
0240 
0241    /// \see RNTupleView::operator()(ROOT::NTupleSize_t)
0242    void operator()(ROOT::NTupleSize_t globalIndex) { fValue.Read(globalIndex); }
0243    /// \see RNTupleView::operator()(RNTupleLocalIndex)
0244    void operator()(RNTupleLocalIndex localIndex) { fValue.Read(localIndex); }
0245 };
0246 
0247 // clang-format off
0248 /**
0249 \class ROOT::RNTupleDirectAccessView
0250 \ingroup NTuple
0251 \brief A view variant that provides direct access to the I/O buffers. Only works for mappable fields.
0252 */
0253 // clang-format on
0254 template <typename T>
0255 class RNTupleDirectAccessView {
0256    friend class ROOT::RNTupleReader;
0257    friend class RNTupleCollectionView;
0258 
0259 protected:
0260    ROOT::RField<T> fField;
0261    ROOT::RNTupleGlobalRange fFieldRange;
0262 
0263    static ROOT::RField<T> CreateField(ROOT::DescriptorId_t fieldId, ROOT::Internal::RPageSource &pageSource)
0264    {
0265       const auto &desc = pageSource.GetSharedDescriptorGuard().GetRef();
0266       const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
0267       if (fieldDesc.GetTypeName() != ROOT::RField<T>::TypeName()) {
0268          throw RException(R__FAIL("type mismatch for field " + fieldDesc.GetFieldName() + ": " +
0269                                   fieldDesc.GetTypeName() + " vs. " + ROOT::RField<T>::TypeName()));
0270       }
0271       ROOT::RField<T> field(fieldDesc.GetFieldName());
0272       field.SetOnDiskId(fieldId);
0273       ROOT::Internal::CallConnectPageSourceOnField(field, pageSource);
0274       return field;
0275    }
0276 
0277    RNTupleDirectAccessView(ROOT::RField<T> field, ROOT::RNTupleGlobalRange range)
0278       : fField(std::move(field)), fFieldRange(range)
0279    {
0280    }
0281 
0282 public:
0283    RNTupleDirectAccessView(const RNTupleDirectAccessView &other) = delete;
0284    RNTupleDirectAccessView(RNTupleDirectAccessView &&other) = default;
0285    RNTupleDirectAccessView &operator=(const RNTupleDirectAccessView &other) = delete;
0286    RNTupleDirectAccessView &operator=(RNTupleDirectAccessView &&other) = default;
0287    ~RNTupleDirectAccessView() = default;
0288 
0289    const ROOT::RFieldBase &GetField() const { return fField; }
0290    /// \see RNTupleView::GetFieldRange()
0291    ROOT::RNTupleGlobalRange GetFieldRange() const { return fFieldRange; }
0292 
0293    /// \see RNTupleView::operator()(ROOT::NTupleSize_t)
0294    const T &operator()(ROOT::NTupleSize_t globalIndex) { return *fField.Map(globalIndex); }
0295    /// \see RNTupleView::operator()(RNTupleLocalIndex)
0296    const T &operator()(RNTupleLocalIndex localIndex) { return *fField.Map(localIndex); }
0297 };
0298 
0299 // clang-format off
0300 /**
0301 \class ROOT::RNTupleCollectionView
0302 \ingroup NTuple
0303 \brief A view for a collection, that can itself generate new ntuple views for its nested fields.
0304 */
0305 // clang-format on
0306 class RNTupleCollectionView {
0307    friend class ROOT::RNTupleReader;
0308 
0309 private:
0310    ROOT::Internal::RPageSource *fSource;
0311    ROOT::RField<RNTupleCardinality<std::uint64_t>> fField;
0312    ROOT::RFieldBase::RValue fValue;
0313 
0314    RNTupleCollectionView(ROOT::DescriptorId_t fieldId, const std::string &fieldName,
0315                          ROOT::Internal::RPageSource *source)
0316       : fSource(source), fField(fieldName), fValue(fField.CreateValue())
0317    {
0318       fField.SetOnDiskId(fieldId);
0319       ROOT::Internal::CallConnectPageSourceOnField(fField, *source);
0320    }
0321 
0322    static RNTupleCollectionView Create(ROOT::DescriptorId_t fieldId, ROOT::Internal::RPageSource *source)
0323    {
0324       std::string fieldName;
0325       {
0326          const auto &desc = source->GetSharedDescriptorGuard().GetRef();
0327          const auto &fieldDesc = desc.GetFieldDescriptor(fieldId);
0328          if (fieldDesc.GetStructure() != ROOT::ENTupleStructure::kCollection) {
0329             throw RException(
0330                R__FAIL("invalid attemt to create collection view on non-collection field " + fieldDesc.GetFieldName()));
0331          }
0332          fieldName = fieldDesc.GetFieldName();
0333       }
0334       return RNTupleCollectionView(fieldId, fieldName, source);
0335    }
0336 
0337    ROOT::DescriptorId_t GetFieldId(std::string_view fieldName)
0338    {
0339       auto descGuard = fSource->GetSharedDescriptorGuard();
0340       auto fieldId = descGuard->FindFieldId(fieldName, fField.GetOnDiskId());
0341       if (fieldId == ROOT::kInvalidDescriptorId) {
0342          throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in collection '" +
0343                                   descGuard->GetQualifiedFieldName(fField.GetOnDiskId()) + "'"));
0344       }
0345       return fieldId;
0346    }
0347 
0348 public:
0349    RNTupleCollectionView(const RNTupleCollectionView &other) = delete;
0350    RNTupleCollectionView(RNTupleCollectionView &&other) = default;
0351    RNTupleCollectionView &operator=(const RNTupleCollectionView &other) = delete;
0352    RNTupleCollectionView &operator=(RNTupleCollectionView &&other) = default;
0353    ~RNTupleCollectionView() = default;
0354 
0355    ROOT::RNTupleLocalRange GetCollectionRange(ROOT::NTupleSize_t globalIndex)
0356    {
0357       ROOT::NTupleSize_t size;
0358       RNTupleLocalIndex collectionStart;
0359       fField.GetCollectionInfo(globalIndex, &collectionStart, &size);
0360       return ROOT::RNTupleLocalRange(collectionStart.GetClusterId(), collectionStart.GetIndexInCluster(),
0361                                      collectionStart.GetIndexInCluster() + size);
0362    }
0363 
0364    ROOT::RNTupleLocalRange GetCollectionRange(RNTupleLocalIndex localIndex)
0365    {
0366       ROOT::NTupleSize_t size;
0367       RNTupleLocalIndex collectionStart;
0368       fField.GetCollectionInfo(localIndex, &collectionStart, &size);
0369       return ROOT::RNTupleLocalRange(collectionStart.GetClusterId(), collectionStart.GetIndexInCluster(),
0370                                      collectionStart.GetIndexInCluster() + size);
0371    }
0372 
0373    /// Provides access to an individual (sub)field.
0374    ///
0375    /// Raises an exception if there is no field with the given name.
0376    ///
0377    /// \sa ROOT::RNTupleReader::GetView(std::string_view)
0378    template <typename T>
0379    RNTupleView<T> GetView(std::string_view fieldName)
0380    {
0381       auto field = RNTupleView<T>::CreateField(GetFieldId(fieldName), *fSource);
0382       auto range = Internal::GetFieldRange(*field, *fSource);
0383       return RNTupleView<T>(std::move(field), range);
0384    }
0385 
0386    /// Provides direct access to the I/O buffers of a **mappable** (sub)field.
0387    ///
0388    /// Raises an exception if there is no field with the given name.
0389    /// Attempting to access the values of a direct-access view for non-mappable fields will yield compilation errors.
0390    ///
0391    /// \sa ROOT::RNTupleReader::DirectAccessView(std::string_view)
0392    template <typename T>
0393    RNTupleDirectAccessView<T> GetDirectAccessView(std::string_view fieldName)
0394    {
0395       auto field = RNTupleDirectAccessView<T>::CreateField(GetFieldId(fieldName), *fSource);
0396       auto range = Internal::GetFieldRange(field, *fSource);
0397       return RNTupleDirectAccessView<T>(std::move(field), range);
0398    }
0399 
0400    /// Provides access to a collection field, that can itself generate new RNTupleViews for its nested fields.
0401    ///
0402    /// Raises an exception if:
0403    /// * there is no field with the given name or,
0404    /// * the field is not a collection
0405    ///
0406    /// \sa ROOT::RNTupleReader::GetCollectionView(std::string_view)
0407    RNTupleCollectionView GetCollectionView(std::string_view fieldName)
0408    {
0409       return RNTupleCollectionView::Create(GetFieldId(fieldName), fSource);
0410    }
0411 
0412    /// \see RNTupleView::operator()(ROOT::NTupleSize_t)
0413    std::uint64_t operator()(ROOT::NTupleSize_t globalIndex)
0414    {
0415       fValue.Read(globalIndex);
0416       return fValue.GetRef<std::uint64_t>();
0417    }
0418 
0419    /// \see RNTupleView::operator()(RNTupleLocalIndex)
0420    std::uint64_t operator()(RNTupleLocalIndex localIndex)
0421    {
0422       fValue.Read(localIndex);
0423       return fValue.GetRef<std::uint64_t>();
0424    }
0425 };
0426 
0427 } // namespace ROOT
0428 
0429 #endif