Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:10:46

0001 /// \file ROOT/RNTupleView.hxx
0002 /// \ingroup NTuple ROOT7
0003 /// \author Jakob Blomer <jblomer@cern.ch>
0004 /// \date 2018-10-05
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-2019, 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 ROOT7_RNTupleView
0017 #define ROOT7_RNTupleView
0018 
0019 #include <ROOT/RField.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 namespace Experimental {
0031 
0032 
0033 // clang-format off
0034 /**
0035 \class ROOT::Experimental::RNTupleGlobalRange
0036 \ingroup NTuple
0037 \brief Used to loop over indexes (entries or collections) between start and end
0038 */
0039 // clang-format on
0040 class RNTupleGlobalRange {
0041 private:
0042    const NTupleSize_t fStart;
0043    const NTupleSize_t fEnd;
0044 public:
0045    class RIterator {
0046    private:
0047       NTupleSize_t fIndex = kInvalidNTupleIndex;
0048    public:
0049       using iterator = RIterator;
0050       using iterator_category = std::forward_iterator_tag;
0051       using value_type = NTupleSize_t;
0052       using difference_type = NTupleSize_t;
0053       using pointer = NTupleSize_t*;
0054       using reference = NTupleSize_t&;
0055 
0056       RIterator() = default;
0057       explicit RIterator(NTupleSize_t index) : fIndex(index) {}
0058       ~RIterator() = default;
0059 
0060       iterator  operator++(int) /* postfix */        { auto r = *this; fIndex++; return r; }
0061       iterator& operator++()    /* prefix */         { ++fIndex; return *this; }
0062       reference operator* ()                         { return fIndex; }
0063       pointer   operator->()                         { return &fIndex; }
0064       bool      operator==(const iterator& rh) const { return fIndex == rh.fIndex; }
0065       bool      operator!=(const iterator& rh) const { return fIndex != rh.fIndex; }
0066    };
0067 
0068    RNTupleGlobalRange(NTupleSize_t start, NTupleSize_t end) : fStart(start), fEnd(end) {}
0069    RIterator begin() { return RIterator(fStart); }
0070    RIterator end() { return RIterator(fEnd); }
0071 };
0072 
0073 
0074 // clang-format off
0075 /**
0076 \class ROOT::Experimental::RNTupleClusterRange
0077 \ingroup NTuple
0078 \brief Used to loop over entries of collections in a single cluster
0079 */
0080 // clang-format on
0081 class RNTupleClusterRange {
0082 private:
0083    const DescriptorId_t fClusterId;
0084    const ClusterSize_t::ValueType fStart;
0085    const ClusterSize_t::ValueType fEnd;
0086 public:
0087    class RIterator {
0088    private:
0089       RClusterIndex fIndex;
0090    public:
0091       using iterator = RIterator;
0092       using iterator_category = std::forward_iterator_tag;
0093       using value_type = RClusterIndex;
0094       using difference_type = RClusterIndex;
0095       using pointer = RClusterIndex*;
0096       using reference = RClusterIndex&;
0097 
0098       RIterator() = default;
0099       explicit RIterator(RClusterIndex index) : fIndex(index) {}
0100       ~RIterator() = default;
0101 
0102       iterator  operator++(int) /* postfix */        { auto r = *this; fIndex++; return r; }
0103       iterator& operator++()    /* prefix */         { fIndex++; return *this; }
0104       reference operator* ()                         { return fIndex; }
0105       pointer   operator->()                         { return &fIndex; }
0106       bool      operator==(const iterator& rh) const { return fIndex == rh.fIndex; }
0107       bool      operator!=(const iterator& rh) const { return fIndex != rh.fIndex; }
0108    };
0109 
0110    RNTupleClusterRange(DescriptorId_t clusterId, ClusterSize_t::ValueType start, ClusterSize_t::ValueType end)
0111       : fClusterId(clusterId), fStart(start), fEnd(end) {}
0112    RIterator begin() { return RIterator(RClusterIndex(fClusterId, fStart)); }
0113    RIterator end() { return RIterator(RClusterIndex(fClusterId, fEnd)); }
0114 };
0115 
0116 
0117 namespace Internal {
0118 // TODO(bgruber): convert this trait into a requires clause in C++20
0119 template <typename FieldT, typename SFINAE = void>
0120 inline constexpr bool isMappable = false;
0121 
0122 template <typename FieldT>
0123 inline constexpr bool isMappable<FieldT, std::void_t<decltype(std::declval<FieldT>().Map(NTupleSize_t{}))>> = true;
0124 } // namespace Internal
0125 
0126 
0127 // clang-format off
0128 /**
0129 \class ROOT::Experimental::RNTupleView
0130 \ingroup NTuple
0131 \brief An RNTupleView provides read-only access to a single field of the ntuple
0132 
0133 \tparam T The type of the object that will be read by the view
0134 \tparam UserProvidedAddress Whether the user provided an external memory location to read data into
0135 
0136 The view owns a field and its underlying columns in order to fill an ntuple value object with data. Data can be
0137 accessed by index. For top-level fields, the index refers to the entry number. Fields that are part of
0138 nested collections have global index numbers that are derived from their parent indexes.
0139 
0140 Fields of simple types with a Map() method will use that and thus expose zero-copy access.
0141 */
0142 // clang-format on
0143 template <typename T, bool UserProvidedAddress>
0144 class RNTupleView {
0145    friend class RNTupleReader;
0146    friend class RNTupleCollectionView;
0147 
0148    using FieldT = RField<T>;
0149 
0150 private:
0151    /// fFieldId has fParent always set to null; views access nested fields without looking at the parent
0152    FieldT fField;
0153    /// Used as a Read() destination for fields that are not mappable
0154    RFieldBase::RValue fValue;
0155 
0156    void SetupField(DescriptorId_t fieldId, Internal::RPageSource *pageSource)
0157    {
0158       fField.SetOnDiskId(fieldId);
0159       Internal::CallConnectPageSourceOnField(fField, *pageSource);
0160       if constexpr (!UserProvidedAddress) {
0161          if ((fField.GetTraits() & RFieldBase::kTraitMappable) && fField.HasReadCallbacks())
0162             throw RException(R__FAIL("view disallowed on field with mappable type and read callback"));
0163       }
0164    }
0165 
0166    RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource)
0167       : fField(pageSource->GetSharedDescriptorGuard()->GetFieldDescriptor(fieldId).GetFieldName()),
0168         fValue(fField.CreateValue())
0169    {
0170       SetupField(fieldId, pageSource);
0171    }
0172 
0173    RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource, std::shared_ptr<T> objPtr)
0174       : fField(pageSource->GetSharedDescriptorGuard()->GetFieldDescriptor(fieldId).GetFieldName()),
0175         fValue(fField.BindValue(objPtr))
0176    {
0177       SetupField(fieldId, pageSource);
0178    }
0179 
0180    RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource, T *rawPtr)
0181       : fField(pageSource->GetSharedDescriptorGuard()->GetFieldDescriptor(fieldId).GetFieldName()),
0182         fValue(fField.BindValue(Internal::MakeAliasedSharedPtr(rawPtr)))
0183    {
0184       SetupField(fieldId, pageSource);
0185    }
0186 
0187 public:
0188    RNTupleView(const RNTupleView& other) = delete;
0189    RNTupleView(RNTupleView&& other) = default;
0190    RNTupleView& operator=(const RNTupleView& other) = delete;
0191    RNTupleView& operator=(RNTupleView&& other) = default;
0192    ~RNTupleView() = default;
0193 
0194    const FieldT &GetField() const { return fField; }
0195    RNTupleGlobalRange GetFieldRange() const { return RNTupleGlobalRange(0, fField.GetNElements()); }
0196 
0197    const T &operator()(NTupleSize_t globalIndex)
0198    {
0199       if constexpr (Internal::isMappable<FieldT> && !UserProvidedAddress) {
0200          return *fField.Map(globalIndex);
0201       } else {
0202          fValue.Read(globalIndex);
0203          return fValue.GetRef<T>();
0204       }
0205    }
0206 
0207    const T &operator()(RClusterIndex clusterIndex)
0208    {
0209       if constexpr (Internal::isMappable<FieldT> && !UserProvidedAddress) {
0210          return *fField.Map(clusterIndex);
0211       } else {
0212          fValue.Read(clusterIndex);
0213          return fValue.GetRef<T>();
0214       }
0215    }
0216 
0217    // TODO(bgruber): turn enable_if into requires clause with C++20
0218    template <typename C = T, std::enable_if_t<Internal::isMappable<FieldT>, C*> = nullptr>
0219    const C *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
0220    {
0221       return fField.MapV(globalIndex, nItems);
0222    }
0223 
0224    // TODO(bgruber): turn enable_if into requires clause with C++20
0225    template <typename C = T, std::enable_if_t<Internal::isMappable<FieldT>, C *> = nullptr>
0226    const C *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
0227    {
0228       return fField.MapV(clusterIndex, nItems);
0229    }
0230 
0231    void Bind(std::shared_ptr<T> objPtr)
0232    {
0233       static_assert(
0234          UserProvidedAddress,
0235          "Only views which were created with an external memory location at construction time can be bound to a "
0236          "different memory location afterwards. Call the RNTupleReader::GetView overload with a shared_ptr.");
0237       fValue.Bind(objPtr);
0238    }
0239 
0240    void BindRawPtr(T *rawPtr)
0241    {
0242       static_assert(
0243          UserProvidedAddress,
0244          "Only views which were created with an external memory location at construction time can be bound to a "
0245          "different memory location afterwards. Call the RNTupleReader::GetView overload with a shared_ptr.");
0246       fValue.BindRawPtr(rawPtr);
0247    }
0248 
0249    void EmplaceNew()
0250    {
0251       // Let the user know they are misusing this function in case the field is
0252       // mappable and they are providing an external address after construction.
0253       // This would mean creating a new RValue member but not using it since
0254       // reading would be done by RField::Map directly.
0255       static_assert(!(Internal::isMappable<FieldT> && !UserProvidedAddress),
0256                     "Cannot emplace a new value into a view of a mappable type, unless an external memory location is "
0257                     "provided at construction time.");
0258       fValue.EmplaceNew();
0259    }
0260 };
0261 
0262 // clang-format off
0263 /**
0264 \class ROOT::Experimental::RNTupleView<void>
0265 \ingroup NTuple
0266 \brief An RNTupleView where the type is not known at compile time.
0267 
0268 Can be used to read individual fields whose type is unknown. The void view gives access to the RValue
0269 in addition to the field, so that the read object can be retrieved.
0270 */
0271 // clang-format on
0272 template <bool UserProvidedAddress>
0273 class RNTupleView<void, UserProvidedAddress> {
0274    friend class RNTupleReader;
0275    friend class RNTupleCollectionView;
0276 
0277 private:
0278    std::unique_ptr<RFieldBase> fField;
0279    RFieldBase::RValue fValue;
0280 
0281    static std::unique_ptr<RFieldBase> CreateField(DescriptorId_t fieldId, const RNTupleDescriptor &desc)
0282    {
0283       return desc.GetFieldDescriptor(fieldId).CreateField(desc);
0284    }
0285 
0286    void SetupField(DescriptorId_t fieldId, Internal::RPageSource *pageSource)
0287    {
0288       fField->SetOnDiskId(fieldId);
0289       Internal::CallConnectPageSourceOnField(*fField, *pageSource);
0290    }
0291 
0292    RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource)
0293       : fField(CreateField(fieldId, pageSource->GetSharedDescriptorGuard().GetRef())), fValue(fField->CreateValue())
0294    {
0295       SetupField(fieldId, pageSource);
0296    }
0297 
0298    RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource, std::shared_ptr<void> objPtr)
0299       : fField(CreateField(fieldId, pageSource->GetSharedDescriptorGuard().GetRef())), fValue(fField->BindValue(objPtr))
0300    {
0301       SetupField(fieldId, pageSource);
0302    }
0303 
0304    RNTupleView(DescriptorId_t fieldId, Internal::RPageSource *pageSource, void *rawPtr)
0305       : fField(CreateField(fieldId, pageSource->GetSharedDescriptorGuard().GetRef())),
0306         fValue(fField->BindValue(Internal::MakeAliasedSharedPtr(rawPtr)))
0307    {
0308       SetupField(fieldId, pageSource);
0309    }
0310 
0311 public:
0312    RNTupleView(const RNTupleView &other) = delete;
0313    RNTupleView(RNTupleView &&other) = default;
0314    RNTupleView &operator=(const RNTupleView &other) = delete;
0315    RNTupleView &operator=(RNTupleView &&other) = default;
0316    ~RNTupleView() = default;
0317 
0318    const RFieldBase &GetField() const { return *fField; }
0319    const RFieldBase::RValue &GetValue() const { return fValue; }
0320    RNTupleGlobalRange GetFieldRange() const { return RNTupleGlobalRange(0, fField->GetNElements()); }
0321 
0322    void operator()(NTupleSize_t globalIndex) { fValue.Read(globalIndex); }
0323    void operator()(RClusterIndex clusterIndex) { fValue.Read(clusterIndex); }
0324 
0325    void Bind(std::shared_ptr<void> objPtr)
0326    {
0327       static_assert(
0328          UserProvidedAddress,
0329          "Only views which were created with an external memory location at construction time can be bound to a "
0330          "different memory location afterwards. Call the RNTupleReader::GetView overload with a shared_ptr.");
0331       fValue.Bind(objPtr);
0332    }
0333 
0334    void BindRawPtr(void *rawPtr)
0335    {
0336       static_assert(
0337          UserProvidedAddress,
0338          "Only views which were created with an external memory location at construction time can be bound to a "
0339          "different memory location afterwards. Call the RNTupleReader::GetView overload with a shared_ptr.");
0340       fValue.BindRawPtr(rawPtr);
0341    }
0342 
0343    void EmplaceNew() { fValue.EmplaceNew(); }
0344 };
0345 
0346 // clang-format off
0347 /**
0348 \class ROOT::Experimental::RNTupleCollectionView
0349 \ingroup NTuple
0350 \brief A view for a collection, that can itself generate new ntuple views for its nested fields.
0351 */
0352 // clang-format on
0353 class RNTupleCollectionView : public RNTupleView<ClusterSize_t, false> {
0354    friend class RNTupleReader;
0355 
0356 private:
0357    Internal::RPageSource *fSource;
0358    DescriptorId_t fCollectionFieldId;
0359 
0360    RNTupleCollectionView(DescriptorId_t fieldId, Internal::RPageSource *source)
0361       : RNTupleView<ClusterSize_t, false>(fieldId, source), fSource(source), fCollectionFieldId(fieldId)
0362    {}
0363 
0364 public:
0365    RNTupleCollectionView(const RNTupleCollectionView &other) = delete;
0366    RNTupleCollectionView(RNTupleCollectionView &&other) = default;
0367    RNTupleCollectionView &operator=(const RNTupleCollectionView &other) = delete;
0368    RNTupleCollectionView &operator=(RNTupleCollectionView &&other) = default;
0369    ~RNTupleCollectionView() = default;
0370 
0371    RNTupleClusterRange GetCollectionRange(NTupleSize_t globalIndex) {
0372       ClusterSize_t size;
0373       RClusterIndex collectionStart;
0374       fField.GetCollectionInfo(globalIndex, &collectionStart, &size);
0375       return RNTupleClusterRange(collectionStart.GetClusterId(), collectionStart.GetIndex(),
0376                                  collectionStart.GetIndex() + size);
0377    }
0378    RNTupleClusterRange GetCollectionRange(RClusterIndex clusterIndex)
0379    {
0380       ClusterSize_t size;
0381       RClusterIndex collectionStart;
0382       fField.GetCollectionInfo(clusterIndex, &collectionStart, &size);
0383       return RNTupleClusterRange(collectionStart.GetClusterId(), collectionStart.GetIndex(),
0384                                  collectionStart.GetIndex() + size);
0385    }
0386 
0387    /// Raises an exception if there is no field with the given name.
0388    template <typename T>
0389    RNTupleView<T, false> GetView(std::string_view fieldName)
0390    {
0391       auto fieldId = fSource->GetSharedDescriptorGuard()->FindFieldId(fieldName, fCollectionFieldId);
0392       if (fieldId == kInvalidDescriptorId) {
0393          throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in RNTuple '" +
0394                                   fSource->GetSharedDescriptorGuard()->GetName() + "'"));
0395       }
0396       return RNTupleView<T, false>(fieldId, fSource);
0397    }
0398    /// Raises an exception if there is no field with the given name.
0399    RNTupleCollectionView GetCollectionView(std::string_view fieldName)
0400    {
0401       auto fieldId = fSource->GetSharedDescriptorGuard()->FindFieldId(fieldName, fCollectionFieldId);
0402       if (fieldId == kInvalidDescriptorId) {
0403          throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in RNTuple '" +
0404                                   fSource->GetSharedDescriptorGuard()->GetName() + "'"));
0405       }
0406       return RNTupleCollectionView(fieldId, fSource);
0407    }
0408 
0409    ClusterSize_t operator()(NTupleSize_t globalIndex) {
0410       ClusterSize_t size;
0411       RClusterIndex collectionStart;
0412       fField.GetCollectionInfo(globalIndex, &collectionStart, &size);
0413       return size;
0414    }
0415    ClusterSize_t operator()(RClusterIndex clusterIndex)
0416    {
0417       ClusterSize_t size;
0418       RClusterIndex collectionStart;
0419       fField.GetCollectionInfo(clusterIndex, &collectionStart, &size);
0420       return size;
0421    }
0422 };
0423 
0424 } // namespace Experimental
0425 } // namespace ROOT
0426 
0427 #endif