Logo ROOT  
Reference Guide
RTreeColumnReader.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud CERN 09/2020
2
3/*************************************************************************
4 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#ifndef ROOT_RDF_RTREECOLUMNREADER
12#define ROOT_RDF_RTREECOLUMNREADER
13
14#include "RColumnReaderBase.hxx"
15#include <ROOT/RVec.hxx>
16#include <Rtypes.h> // Long64_t, R__CLING_PTRCHECK
17#include <TTreeReader.h>
18#include <TTreeReaderValue.h>
19#include <TTreeReaderArray.h>
20
21#include <memory>
22#include <string>
23
24namespace ROOT {
25namespace Internal {
26namespace RDF {
27
28/// RTreeColumnReader specialization for TTree values read via TTreeReaderValues
29template <typename T>
30class R__CLING_PTRCHECK(off) RTreeColumnReader final : public ROOT::Detail::RDF::RColumnReaderBase {
31 std::unique_ptr<TTreeReaderValue<T>> fTreeValue;
32
33 void *GetImpl(Long64_t) final { return fTreeValue->Get(); }
34public:
35 /// Construct the RTreeColumnReader. Actual initialization is performed lazily by the Init method.
36 RTreeColumnReader(TTreeReader &r, const std::string &colName)
37 : fTreeValue(std::make_unique<TTreeReaderValue<T>>(r, colName.c_str()))
38 {
39 }
40
41 /// The dtor resets the TTreeReaderValue object.
42 //
43 // Otherwise a race condition is present in which a TTreeReader
44 // and its TTreeReader{Value,Array}s can be deleted concurrently:
45 // - Thread #1) a task ends and pushes back processing slot
46 // - Thread #2) a task starts and overwrites thread-local TTreeReaderValues
47 // - Thread #1) first task deletes TTreeReader
48 // See https://github.com/root-project/root/commit/26e8ace6e47de6794ac9ec770c3bbff9b7f2e945
49 ~RTreeColumnReader() { fTreeValue.reset(); }
50};
51
52/// RTreeColumnReader specialization for TTree values read via TTreeReaderArrays.
53///
54/// TTreeReaderArrays are used whenever the RDF column type is RVec<T>.
55template <typename T>
56class R__CLING_PTRCHECK(off) RTreeColumnReader<RVec<T>> final : public ROOT::Detail::RDF::RColumnReaderBase {
57 std::unique_ptr<TTreeReaderArray<T>> fTreeArray;
58
59 /// Enumerator for the memory layout of the branch
60 enum class EStorageType : char { kContiguous, kUnknown, kSparse };
61
62 /// We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory layout.
64
65 /// Signal whether we ever checked that the branch we are reading with a TTreeReaderArray stores array elements
66 /// in contiguous memory.
68
69 /// Whether we already printed a warning about performing a copy of the TTreeReaderArray contents
70 bool fCopyWarningPrinted = false;
71
72 void *GetImpl(Long64_t) final
73 {
74 auto &readerArray = *fTreeArray;
75 // We only use TTreeReaderArrays to read columns that users flagged as type `RVec`, so we need to check
76 // that the branch stores the array as contiguous memory that we can actually wrap in an `RVec`.
77 // Currently we need the first entry to have been loaded to perform the check
78 // TODO Move check to constructor once ROOT-10823 is fixed and TTreeReaderArray itself exposes this information
79 const auto readerArraySize = readerArray.GetSize();
80 if (EStorageType::kUnknown == fStorageType && readerArraySize > 1) {
81 // We can decide since the array is long enough
82 fStorageType = EStorageType::kContiguous;
83 for (auto i = 0u; i < readerArraySize - 1; ++i) {
84 if ((char *)&readerArray[i + 1] - (char *)&readerArray[i] != sizeof(T)) {
85 fStorageType = EStorageType::kSparse;
86 break;
87 }
88 }
89 }
90
91 if (EStorageType::kContiguous == fStorageType ||
92 (EStorageType::kUnknown == fStorageType && readerArray.GetSize() < 2)) {
93 if (readerArraySize > 0) {
94 // trigger loading of the contents of the TTreeReaderArray
95 // the address of the first element in the reader array is not necessarily equal to
96 // the address returned by the GetAddress method
97 auto readerArrayAddr = &readerArray.At(0);
98 RVec<T> rvec(readerArrayAddr, readerArraySize);
99 std::swap(fRVec, rvec);
100 } else {
101 RVec<T> emptyVec{};
102 std::swap(fRVec, emptyVec);
103 }
104 } else {
105 // The storage is not contiguous or we don't know yet: we cannot but copy into the rvec
106#ifndef NDEBUG
107 if (!fCopyWarningPrinted) {
108 Warning("RTreeColumnReader::Get",
109 "Branch %s hangs from a non-split branch. A copy is being performed in order "
110 "to properly read the content.",
111 readerArray.GetBranchName());
112 fCopyWarningPrinted = true;
113 }
114#else
115 (void)fCopyWarningPrinted;
116#endif
117 if (readerArraySize > 0) {
118 RVec<T> rvec(readerArray.begin(), readerArray.end());
119 std::swap(fRVec, rvec);
120 } else {
121 RVec<T> emptyVec{};
122 std::swap(fRVec, emptyVec);
123 }
124 }
125 return &fRVec;
126 }
127
128public:
129 RTreeColumnReader(TTreeReader &r, const std::string &colName)
130 : fTreeArray(std::make_unique<TTreeReaderArray<T>>(r, colName.c_str()))
131 {
132 }
133
134 /// See the other class template specializations for an explanation.
135 ~RTreeColumnReader() { fTreeArray.reset(); }
136};
137
138/// RTreeColumnReader specialization for arrays of boolean values read via TTreeReaderArrays.
139///
140/// TTreeReaderArray<bool> is used whenever the RDF column type is RVec<bool>.
141template <>
142class R__CLING_PTRCHECK(off) RTreeColumnReader<RVec<bool>> final : public ROOT::Detail::RDF::RColumnReaderBase {
143
144 std::unique_ptr<TTreeReaderArray<bool>> fTreeArray;
145
146 /// We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory layout
148
149 // We always copy the contents of TTreeReaderArray<bool> into an RVec<bool> (never take a view into the memory
150 // buffer) because the underlying memory buffer might be the one of a std::vector<bool>, which is not a contiguous
151 // slab of bool values.
152 // Note that this also penalizes the case in which the column type is actually bool[], but the possible performance
153 // gains in this edge case is probably not worth the extra complication required to differentiate the two cases.
154 void *GetImpl(Long64_t) final
155 {
156 auto &readerArray = *fTreeArray;
157 const auto readerArraySize = readerArray.GetSize();
158 if (readerArraySize > 0) {
159 // always perform a copy
160 RVec<bool> rvec(readerArray.begin(), readerArray.end());
161 std::swap(fRVec, rvec);
162 } else {
163 RVec<bool> emptyVec{};
164 std::swap(fRVec, emptyVec);
165 }
166 return &fRVec;
167 }
168
169public:
170 RTreeColumnReader(TTreeReader &r, const std::string &colName)
171 : fTreeArray(std::make_unique<TTreeReaderArray<bool>>(r, colName.c_str()))
172 {
173 }
174
175 /// See the other class template specializations for an explanation.
176 ~RTreeColumnReader() { fTreeArray.reset(); }
177};
178
179} // namespace RDF
180} // namespace Internal
181} // namespace ROOT
182
183#endif
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
ROOT::R::TRInterface & r
Definition: Object.C:4
long long Long64_t
Definition: RtypesCore.h:80
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition: TError.cxx:231
@ kUnknown
Definition: TStructNode.h:19
std::unique_ptr< TTreeReaderArray< T > > fTreeArray
RTreeColumnReader(TTreeReader &r, const std::string &colName)
EStorageType
Enumerator for the memory layout of the branch.
~RTreeColumnReader()
See the other class template specializations for an explanation.
RVec< T > fRVec
We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory la...
RVec< bool > fRVec
We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory la...
~RTreeColumnReader()
See the other class template specializations for an explanation.
std::unique_ptr< TTreeReaderArray< bool > > fTreeArray
RTreeColumnReader(TTreeReader &r, const std::string &colName)
RTreeColumnReader specialization for TTree values read via TTreeReaderValues.
RTreeColumnReader(TTreeReader &r, const std::string &colName)
Construct the RTreeColumnReader. Actual initialization is performed lazily by the Init method.
~RTreeColumnReader()
The dtor resets the TTreeReaderValue object.
std::unique_ptr< TTreeReaderValue< T > > fTreeValue
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition: RVec.hxx:1409
An interface for reading collections stored in ROOT columnar datasets.
An interface for reading values stored in ROOT columnar datasets.
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition: TTreeReader.h:44
void swap(RDirectoryEntry &e1, RDirectoryEntry &e2) noexcept
double T(double x)
Definition: ChebyshevPol.h:34
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.