Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-16 09:21:19

0001 /// \file ROOT/RNTupleAttrWriting.hxx
0002 /// \ingroup NTuple ROOT7
0003 /// \author Giacomo Parolini <giacomo.parolini@cern.ch>
0004 /// \date 2026-01-27
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 #ifndef ROOT7_RNTuple_Attr_Writing
0009 #define ROOT7_RNTuple_Attr_Writing
0010 
0011 #include <memory>
0012 #include <string_view>
0013 
0014 #include <ROOT/REntry.hxx>
0015 #include <ROOT/RNTupleFillContext.hxx>
0016 #include <ROOT/RNTupleUtils.hxx>
0017 
0018 namespace ROOT {
0019 
0020 class RNTupleModel;
0021 class RNTuple;
0022 class RNTupleWriter;
0023 
0024 namespace Experimental {
0025 
0026 class RNTupleAttrSetWriter;
0027 
0028 namespace Internal {
0029 
0030 // clang-format off
0031 /**
0032 \class ROOT::Experimental::Internal::RNTupleAttrEntry
0033 \ingroup NTuple
0034 \brief A pair of scoped + meta entry used by the RNTupleAttrSetWriter.
0035 
0036 The meta entry is used to write the "meta fields" that are always present in an Attribute Set (start/len); the scoped
0037 entry is used to write the user-provided fields.
0038 */
0039 // clang-format on
0040 struct RNTupleAttrEntry {
0041    REntry &fMetaEntry;
0042    REntry &fScopedEntry;
0043    ROOT::RNTupleModel &fMetaModel;
0044 
0045    std::size_t Append();
0046    ROOT::DescriptorId_t GetModelId() const { return fMetaEntry.GetModelId(); }
0047 };
0048 
0049 } // namespace Internal
0050 
0051 // clang-format off
0052 /**
0053 \class ROOT::Experimental::RNTupleAttrPendingRange
0054 \ingroup NTuple
0055 \brief A not-yet-finalized Attribute Range used for writing
0056 
0057 A range used for writing. It has a well-defined start but not a length/end yet.
0058 It is artificially made non-copyable in order to clarify the semantics of Begin/CommitRange.
0059 For the same reason, it can only be created by the AttrSetWriter.
0060 */
0061 // clang-format on
0062 class RNTupleAttrPendingRange final {
0063    friend class ROOT::Experimental::RNTupleAttrSetWriter;
0064 
0065    ROOT::NTupleSize_t fStart = 0;
0066    std::uint64_t fModelId = 0;
0067    bool fWasCommitted = false;
0068 
0069    explicit RNTupleAttrPendingRange(ROOT::NTupleSize_t start, ROOT::DescriptorId_t modelId)
0070       : fStart(start), fModelId(modelId)
0071    {
0072    }
0073 
0074 public:
0075    RNTupleAttrPendingRange() = default;
0076    RNTupleAttrPendingRange(const RNTupleAttrPendingRange &) = delete;
0077    RNTupleAttrPendingRange &operator=(const RNTupleAttrPendingRange &) = delete;
0078 
0079    RNTupleAttrPendingRange(RNTupleAttrPendingRange &&other) { *this = std::move(other); }
0080 
0081    // NOTE: explicitly implemented to make sure that 'other' gets invalidated upon move.
0082    RNTupleAttrPendingRange &operator=(RNTupleAttrPendingRange &&other)
0083    {
0084       if (&other != this) {
0085          std::swap(fStart, other.fStart);
0086          std::swap(fModelId, other.fModelId);
0087          other.fWasCommitted = true;
0088          fWasCommitted = false;
0089       }
0090       return *this;
0091    }
0092 
0093    ~RNTupleAttrPendingRange()
0094    {
0095       if (R__unlikely(!fWasCommitted))
0096          R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "A pending attribute range was not committed! If CommitRange() "
0097                                                         "is not explicitly called before closing the main "
0098                                                         "Writer, the attributes will not be saved to storage!";
0099    }
0100 
0101    ROOT::NTupleSize_t GetStart() const
0102    {
0103       if (!IsValid())
0104          throw ROOT::RException(R__FAIL("Tried to get the start of an invalid AttrPendingRange."));
0105       return fStart;
0106    }
0107 
0108    ROOT::DescriptorId_t GetModelId() const { return fModelId; }
0109 
0110    /// Returns true if this PendingRange is valid
0111    operator bool() const { return IsValid(); }
0112    bool IsValid() const { return fModelId != 0; }
0113 };
0114 
0115 // clang-format off
0116 /**
0117 \class ROOT::Experimental::RNTupleAttrSetWriter
0118 \ingroup NTuple
0119 \brief Class used to write an RNTupleAttrSet in the context of an RNTupleWriter.
0120 
0121 An Attribute Set is written as a separate RNTuple linked to the "main" RNTuple that created it.
0122 A RNTupleAttrSetWriter only lives as long as the RNTupleWriter that created it (or until CloseAttributeSet() is called).
0123 Users should not use this class directly but rather via RNTupleAttrSetWriterHandle, which is the type returned by
0124 RNTupleWriter::CreateAttributeSet().
0125 
0126 ~~~ {.cpp}
0127 // Writing attributes via RNTupleAttrSetWriter
0128 // -------------------------------------------
0129 
0130 // First define the schema of your Attribute Set:
0131 auto attrModel = ROOT::RNTupleModel::Create();
0132 auto pMyAttr = attrModel->MakeField<std::string>("myAttr");
0133 
0134 // Then, assuming `writer` is an RNTupleWriter, create it:
0135 auto attrSet = writer->CreateAttributeSet(std::move(attrModel), "MyAttrSet");
0136 
0137 // Attributes are assigned to entry ranges. A range is started via BeginRange():
0138 auto range = attrSet->BeginRange();
0139 
0140 // To assign actual attributes, you use the same interface as the main RNTuple:
0141 *pMyAttr = "This is my attribute for this range";
0142 
0143 // ... here you can fill your main RNTuple with data ...
0144 
0145 // Once you're done, close the range. This will commit the attribute data and bind it to all data written
0146 // between BeginRange() and CommitRange().
0147 attrSet->CommitRange(std::move(range));
0148 
0149 // You don't need to explicitly close the AttributeSet, but if you want to do so, use:
0150 // writer->CloseAttributeSet(std::move(attrSet));
0151 ~~~
0152 */
0153 // clang-format on
0154 class RNTupleAttrSetWriter final {
0155    friend class ROOT::RNTupleWriter;
0156 
0157    /// Our own fill context.
0158    RNTupleFillContext fFillContext;
0159    /// Fill context of the main RNTuple being written (i.e. the RNTuple whose attributes we are).
0160    const RNTupleFillContext *fMainFillContext = nullptr;
0161    /// The model that the user provided on creation. Used to create user-visible entries.
0162    std::unique_ptr<RNTupleModel> fUserModel;
0163 
0164    // Cached values of the meta entry pointers.
0165    std::shared_ptr<ROOT::NTupleSize_t> fRangeStartPtr;
0166    std::shared_ptr<ROOT::NTupleSize_t> fRangeLenPtr;
0167 
0168    /// Creates an RNTupleAttrSetWriter associated to the RNTupleWriter owning `mainFillContext` and writing
0169    /// using `sink`. `userModel` is the schema of the AttributeSet.
0170    static std::unique_ptr<RNTupleAttrSetWriter> Create(const RNTupleFillContext &mainFillContext,
0171                                                        std::unique_ptr<ROOT::Internal::RPageSink> sink,
0172                                                        std::unique_ptr<RNTupleModel> userModel);
0173 
0174    RNTupleAttrSetWriter(const RNTupleFillContext &mainFillContext, std::unique_ptr<ROOT::Internal::RPageSink> sink,
0175                         std::unique_ptr<RNTupleModel> metaModel, std::unique_ptr<RNTupleModel> userModel,
0176                         std::shared_ptr<ROOT::NTupleSize_t> rangeStartPtr,
0177                         std::shared_ptr<ROOT::NTupleSize_t> rangeLenPtr);
0178 
0179    /// Commits the attributes written so far to disk and disables writing any new ones.
0180    ROOT::Internal::RNTupleLink Commit();
0181 
0182 public:
0183    /// Returns the descriptor of the underlying attribute RNTuple. This is **NOT** the same descriptor as the
0184    /// main RNTuple being written!
0185    const ROOT::RNTupleDescriptor &GetDescriptor() const { return fFillContext.fSink->GetDescriptor(); }
0186    /// Returns the user-defined model used to create this attribute set.
0187    const ROOT::RNTupleModel &GetModel() const { return *fUserModel; }
0188 
0189    /// Begins an attribute range. All entries filled in the main RNTupleWriter between BeginRange and CommitRange
0190    /// will be associated with the set of values of the fields of this attribute set at the moment of CommitRange.
0191    /// Note that every attribute range must be explicitly committed for it to be stored on disk.
0192    /// \return An object describing the pending range, which must be passed back to CommitRange to end the attribute
0193    /// range
0194    [[nodiscard]] RNTupleAttrPendingRange BeginRange();
0195    /// Ends an attribute range and associates the current values of the fields of the attribute model's default entry
0196    /// with all the main RNTuple entries filled since the BeginRange that created the given `range`.
0197    /// This is only valid if the model used to create this attribute set is not bare.
0198    void CommitRange(RNTupleAttrPendingRange range);
0199    /// Like CommitRange(RNTupleAttrPendingRange range) but uses the given entry rather than the default entry.
0200    /// The given entry must have been created by CreateEntry().
0201    void CommitRange(RNTupleAttrPendingRange range, REntry &entry);
0202 
0203    /// Creates an REntry fit to pass to CommitRange(RNTupleAttrPendingRange range, REntry entry).
0204    std::unique_ptr<REntry> CreateEntry() { return fUserModel->CreateEntry(); }
0205 };
0206 
0207 // clang-format off
0208 /**
0209 \class ROOT::Experimental::RNTupleAttrSetWriterHandle
0210 \ingroup NTuple
0211 \brief Non-owning handle to an RNTupleAttrSetWriter
0212 
0213 RNTupleAttrSetWriter can only be used through an RNTupleAttrSetWriterHandle, a weak_ptr-like object that allows safe
0214 access to it. The lifetime of an attribute set writer is tied to its parent RNTupleWriter, so the handle handed out
0215 by RNTupleWriter::CreateAttributeSet is invalidated as soon as the parent writer is destructed.
0216 
0217 */
0218 // clang-format on
0219 class RNTupleAttrSetWriterHandle final {
0220    friend class ROOT::RNTupleWriter;
0221 
0222    std::weak_ptr<RNTupleAttrSetWriter> fWriter;
0223 
0224    explicit RNTupleAttrSetWriterHandle(const std::shared_ptr<RNTupleAttrSetWriter> &range) : fWriter(range) {}
0225 
0226 public:
0227    RNTupleAttrSetWriterHandle(const RNTupleAttrSetWriterHandle &) = delete;
0228    RNTupleAttrSetWriterHandle &operator=(const RNTupleAttrSetWriterHandle &) = delete;
0229    RNTupleAttrSetWriterHandle(RNTupleAttrSetWriterHandle &&) = default;
0230    RNTupleAttrSetWriterHandle &operator=(RNTupleAttrSetWriterHandle &&other) = default;
0231 
0232    /// Retrieves the underlying pointer to the AttrSetWriter, throwing if it's invalid.
0233    RNTupleAttrSetWriter *operator->()
0234    {
0235       auto ptr = fWriter.lock();
0236       if (R__unlikely(!ptr))
0237          throw ROOT::RException(R__FAIL("Tried to access invalid RNTupleAttrSetWriterHandle"));
0238       return ptr.get();
0239    }
0240 };
0241 
0242 } // namespace Experimental
0243 } // namespace ROOT
0244 
0245 #endif