Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldFundamental.hxx
Go to the documentation of this file.
1/// \file ROOT/RField/Fundamental.hxx
2/// \ingroup NTuple
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-09
5
6/*************************************************************************
7 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#ifndef ROOT_RField_Fundamental
15#define ROOT_RField_Fundamental
16
17#ifndef ROOT_RField
18#error "Please include RField.hxx!"
19#endif
20
21#include <ROOT/RColumn.hxx>
22#include <ROOT/RFieldBase.hxx>
23#include <ROOT/RNTupleUtil.hxx>
24
25#include <cstddef>
26#include <memory>
27#include <string>
28#include <string_view>
29#include <type_traits>
30
31namespace ROOT {
32namespace Experimental {
33
34namespace Detail {
35class RFieldVisitor;
36} // namespace Detail
37
38} // namespace Experimental
39
40////////////////////////////////////////////////////////////////////////////////
41/// Template specializations for concrete C++ fundamental types
42////////////////////////////////////////////////////////////////////////////////
43
44template <>
45class RField<void> : public RFieldBase {
46public:
47 static std::string TypeName() { return "void"; }
48 // RField<void> should never be constructed.
49 RField() = delete;
50 RField(const RField &) = delete;
51 RField &operator=(const RField &) = delete;
52};
53
54////////////////////////////////////////////////////////////////////////////////
55/// Template specializations for integral types
56////////////////////////////////////////////////////////////////////////////////
57
58// bool and char are somewhat special, handle them first
59
60extern template class RSimpleField<bool>;
61
62template <>
64protected:
65 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
66 {
67 return std::make_unique<RField>(newName);
68 }
69
70 const RColumnRepresentations &GetColumnRepresentations() const final;
71
72public:
73 static std::string TypeName() { return "bool"; }
74 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
75 RField(RField &&other) = default;
78
79 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
80};
81
83
84template <>
86protected:
87 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
88 {
89 return std::make_unique<RField>(newName);
90 }
91
92 const RColumnRepresentations &GetColumnRepresentations() const final;
93
94public:
95 static std::string TypeName() { return "char"; }
96 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
97 RField(RField &&other) = default;
100
101 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
102};
103
104// For other integral types, we introduce an intermediate RIntegralField. It is specialized for fixed-width integer
105// types (from std::[u]int8_t to std::[u]int64_t). RField<T> for integral types T is specialized by mapping to the
106// corresponding fixed-width integer type (see RIntegralTypeMap).
107
110 // Instantiating this base template definition should never happen and is an error!
111 RIntegralField() = delete;
112};
113
114extern template class RSimpleField<std::int8_t>;
115
116template <>
118protected:
119 const RColumnRepresentations &GetColumnRepresentations() const final;
120
121public:
122 static std::string TypeName() { return "std::int8_t"; }
123 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
124 RIntegralField(RIntegralField &&other) = default;
125 RIntegralField &operator=(RIntegralField &&other) = default;
126 ~RIntegralField() override = default;
127
128 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
129};
130
131extern template class RSimpleField<std::uint8_t>;
132
133template <>
135protected:
136 const RColumnRepresentations &GetColumnRepresentations() const final;
137
138public:
139 static std::string TypeName() { return "std::uint8_t"; }
140 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
141 RIntegralField(RIntegralField &&other) = default;
142 RIntegralField &operator=(RIntegralField &&other) = default;
143 ~RIntegralField() override = default;
144
145 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
146};
147
148extern template class RSimpleField<std::int16_t>;
149
150template <>
152protected:
153 const RColumnRepresentations &GetColumnRepresentations() const final;
154
155public:
156 static std::string TypeName() { return "std::int16_t"; }
157 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
158 RIntegralField(RIntegralField &&other) = default;
159 RIntegralField &operator=(RIntegralField &&other) = default;
160 ~RIntegralField() override = default;
161
162 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
163};
164
165extern template class RSimpleField<std::uint16_t>;
166
167template <>
169protected:
170 const RColumnRepresentations &GetColumnRepresentations() const final;
171
172public:
173 static std::string TypeName() { return "std::uint16_t"; }
174 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
175 RIntegralField(RIntegralField &&other) = default;
176 RIntegralField &operator=(RIntegralField &&other) = default;
177 ~RIntegralField() override = default;
178
179 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
180};
181
182extern template class RSimpleField<std::int32_t>;
183
184template <>
186protected:
187 const RColumnRepresentations &GetColumnRepresentations() const final;
188
189public:
190 static std::string TypeName() { return "std::int32_t"; }
191 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
192 RIntegralField(RIntegralField &&other) = default;
193 RIntegralField &operator=(RIntegralField &&other) = default;
194 ~RIntegralField() override = default;
195
196 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
197};
198
199extern template class RSimpleField<std::uint32_t>;
200
201template <>
203protected:
204 const RColumnRepresentations &GetColumnRepresentations() const final;
205
206public:
207 static std::string TypeName() { return "std::uint32_t"; }
208 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
209 RIntegralField(RIntegralField &&other) = default;
210 RIntegralField &operator=(RIntegralField &&other) = default;
211 ~RIntegralField() override = default;
212
213 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
214};
215
216extern template class RSimpleField<std::int64_t>;
217
218template <>
220protected:
221 const RColumnRepresentations &GetColumnRepresentations() const final;
222
223public:
224 static std::string TypeName() { return "std::int64_t"; }
225 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
226 RIntegralField(RIntegralField &&other) = default;
227 RIntegralField &operator=(RIntegralField &&other) = default;
228 ~RIntegralField() override = default;
229
230 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
231};
232
233extern template class RSimpleField<std::uint64_t>;
234
235template <>
237protected:
238 const RColumnRepresentations &GetColumnRepresentations() const final;
239
240public:
241 static std::string TypeName() { return "std::uint64_t"; }
242 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
243 RIntegralField(RIntegralField &&other) = default;
244 RIntegralField &operator=(RIntegralField &&other) = default;
245 ~RIntegralField() override = default;
246
247 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
248};
249
250namespace Internal {
251// Map standard integer types to fixed width equivalents.
252template <typename T>
254 using type = T;
255};
256
257// RField<char> has its own specialization, we should not need a specialization of RIntegralTypeMap.
258// From https://en.cppreference.com/w/cpp/language/types:
259// char has the same representation and alignment as either signed char or
260// unsigned char, but is always a distinct type.
261template <>
263 static_assert(sizeof(signed char) == sizeof(std::int8_t));
264 using type = std::int8_t;
265};
266template <>
268 static_assert(sizeof(unsigned char) == sizeof(std::uint8_t));
269 using type = std::uint8_t;
270};
271template <>
273 static_assert(sizeof(short) == sizeof(std::int16_t));
274 using type = std::int16_t;
275};
276template <>
278 static_assert(sizeof(unsigned short) == sizeof(std::uint16_t));
279 using type = std::uint16_t;
280};
281template <>
283 static_assert(sizeof(int) == sizeof(std::int32_t));
284 using type = std::int32_t;
285};
286template <>
288 static_assert(sizeof(unsigned int) == sizeof(std::uint32_t));
289 using type = std::uint32_t;
290};
291template <>
293 static_assert(sizeof(long) == sizeof(std::int32_t) || sizeof(long) == sizeof(std::int64_t));
294 using type = std::conditional_t<sizeof(long) == sizeof(std::int32_t), std::int32_t, std::int64_t>;
295};
296template <>
297struct RIntegralTypeMap<unsigned long> {
298 static_assert(sizeof(unsigned long) == sizeof(std::uint32_t) || sizeof(unsigned long) == sizeof(std::uint64_t));
299 using type = std::conditional_t<sizeof(unsigned long) == sizeof(std::uint32_t), std::uint32_t, std::uint64_t>;
300};
301template <>
302struct RIntegralTypeMap<long long> {
303 static_assert(sizeof(long long) == sizeof(std::int64_t));
304 using type = std::int64_t;
305};
306template <>
307struct RIntegralTypeMap<unsigned long long> {
308 static_assert(sizeof(unsigned long long) == sizeof(std::uint64_t));
309 using type = std::uint64_t;
310};
311} // namespace Internal
312
313template <typename T>
314class RField<T, typename std::enable_if<std::is_integral_v<T>>::type> final
315 : public RIntegralField<typename Internal::RIntegralTypeMap<T>::type> {
316 using MappedType = typename Internal::RIntegralTypeMap<T>::type;
317 static_assert(sizeof(T) == sizeof(MappedType), "invalid size of mapped type");
318 static_assert(std::is_signed_v<T> == std::is_signed_v<MappedType>, "invalid signedness of mapped type");
319 using BaseType = RIntegralField<MappedType>;
320
321protected:
322 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
323 {
324 return std::make_unique<RField>(newName);
325 }
326
327public:
328 RField(std::string_view name) : RIntegralField<MappedType>(name) {}
329 RField(RField &&other) = default;
330 RField &operator=(RField &&other) = default;
332
333 T *Map(ROOT::NTupleSize_t globalIndex) { return reinterpret_cast<T *>(this->BaseType::Map(globalIndex)); }
334 T *Map(RNTupleLocalIndex localIndex) { return reinterpret_cast<T *>(this->BaseType::Map(localIndex)); }
336 {
337 return reinterpret_cast<T *>(this->BaseType::MapV(globalIndex, nItems));
338 }
339 T *MapV(RNTupleLocalIndex localIndex, ROOT::NTupleSize_t &nItems)
340 {
341 return reinterpret_cast<T *>(this->BaseType::MapV(localIndex, nItems));
342 }
343};
344
345////////////////////////////////////////////////////////////////////////////////
346/// Template specializations for floating-point types
347////////////////////////////////////////////////////////////////////////////////
348
349extern template class RSimpleField<double>;
350extern template class RSimpleField<float>;
351
352template <typename T>
355
356 using Base::fAvailableColumns;
357 using Base::fColumnRepresentatives;
358 using Base::fPrincipalColumn;
359
360 std::size_t fBitWidth = sizeof(T) * 8;
361 double fValueMin = std::numeric_limits<T>::min();
362 double fValueMax = std::numeric_limits<T>::max();
363
364protected:
365 /// Called by derived fields' CloneImpl()
366 RRealField(std::string_view name, const RRealField &source)
367 : RSimpleField<T>(name, source.GetTypeName()),
368 fBitWidth(source.fBitWidth),
369 fValueMin(source.fValueMin),
370 fValueMax(source.fValueMax)
371 {
372 }
373
375 {
376 const auto r = Base::GetColumnRepresentatives();
377 const auto n = r.size();
378 fAvailableColumns.reserve(n);
379 for (std::uint16_t i = 0; i < n; ++i) {
380 auto &column = fAvailableColumns.emplace_back(ROOT::Internal::RColumn::Create<T>(r[i][0], 0, i));
382 column->SetBitsOnStorage(fBitWidth);
383 } else if (r[i][0] == ROOT::ENTupleColumnType::kReal32Quant) {
384 column->SetBitsOnStorage(fBitWidth);
385 column->SetValueRange(fValueMin, fValueMax);
386 }
387 }
388 fPrincipalColumn = fAvailableColumns[0].get();
389 }
390
392 {
393 std::uint16_t representationIndex = 0;
394 do {
395 const auto &onDiskTypes = Base::EnsureCompatibleColumnTypes(desc, representationIndex);
396 if (onDiskTypes.empty())
397 break;
398
399 auto &column =
400 fAvailableColumns.emplace_back(ROOT::Internal::RColumn::Create<T>(onDiskTypes[0], 0, representationIndex));
402 const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
403 const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[0]);
404 column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
406 const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
407 const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[0]);
408 assert(coldesc.GetValueRange().has_value());
409 const auto [valMin, valMax] = *coldesc.GetValueRange();
410 column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
411 column->SetValueRange(valMin, valMax);
412 }
413 fColumnRepresentatives.emplace_back(onDiskTypes);
414 if (representationIndex > 0) {
415 fAvailableColumns[0]->MergeTeams(*fAvailableColumns[representationIndex]);
416 }
417
419 } while (true);
420 fPrincipalColumn = fAvailableColumns[0].get();
421 }
422
423 ~RRealField() override = default;
424
425public:
426 using Base::SetColumnRepresentatives;
427
428 RRealField(std::string_view name, std::string_view typeName) : RSimpleField<T>(name, typeName) {}
431
432 /// Sets this field to use a half precision representation, occupying half as much storage space (16 bits:
433 /// 1 sign bit, 5 exponent bits, 10 mantissa bits) on disk.
434 /// This is mutually exclusive with SetTruncated() and SetQuantized() and supersedes them if called after them.
435 void SetHalfPrecision() { SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal16}}); }
436
437 /// Set the on-disk representation of this field to a single-precision float truncated to `nBits`.
438 /// The remaining (32 - `nBits`) bits will be truncated from the number's mantissa.
439 /// `nBits` must be $10 <= nBits <= 31$ (this means that at least 1 bit
440 /// of mantissa is always preserved). Note that this effectively rounds the number towards 0.
441 /// For a double-precision field, this implies first a cast to single-precision, then the truncation.
442 /// This is mutually exclusive with SetHalfPrecision() and SetQuantized() and supersedes them if called after them.
443 void SetTruncated(std::size_t nBits)
444 {
445 const auto &[minBits, maxBits] =
448 throw RException(R__FAIL("SetTruncated() argument nBits = " + std::to_string(nBits) +
449 " is out of valid range [" + std::to_string(minBits) + ", " +
450 std::to_string(maxBits) + "])"));
451 }
452 SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal32Trunc}});
453 fBitWidth = nBits;
454 }
455
456 /// Sets this field to use a quantized integer representation using `nBits` per value.
457 /// It must be $1 <= nBits <= 32$.
458 /// `minValue` and `maxValue` must not be infinity, `NaN` or denormal floats.
459 /// Calling this function establishes a promise by the caller to RNTuple that this field will only contain values
460 /// contained in `[minValue, maxValue]` inclusive. If a value outside this range is assigned to this field, the
461 /// behavior is undefined.
462 /// This is mutually exclusive with SetTruncated() and SetHalfPrecision() and supersedes them if called after them.
463 void SetQuantized(T minValue, T maxValue, std::size_t nBits)
464 {
465 const auto &[minBits, maxBits] =
468 throw RException(R__FAIL("SetQuantized() argument nBits = " + std::to_string(nBits) +
469 " is out of valid range [" + std::to_string(minBits) + ", " +
470 std::to_string(maxBits) + "])"));
471 }
472 SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal32Quant}});
473 fBitWidth = nBits;
474 fValueMin = minValue;
475 fValueMax = maxValue;
476 }
477};
478
479template <>
481 const RColumnRepresentations &GetColumnRepresentations() const final;
482
483 RField(std::string_view name, const RField &source) : RRealField<float>(name, source) {}
484
485 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
486 {
487 return std::unique_ptr<RField>(new RField(newName, *this));
488 }
489
490public:
491 static std::string TypeName() { return "float"; }
492
493 explicit RField(std::string_view name) : RRealField<float>(name, TypeName()) {}
494
495 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
496};
497
498template <>
500 const RColumnRepresentations &GetColumnRepresentations() const final;
501
502 RField(std::string_view name, const RField &source) : RRealField<double>(name, source) {}
503
504 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
505 {
506 return std::unique_ptr<RField>(new RField(newName, *this));
507 }
508
509public:
510 static std::string TypeName() { return "double"; }
511
512 explicit RField(std::string_view name) : RRealField<double>(name, TypeName()) {}
513
514 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
515
516 // Set the column representation to 32 bit floating point and the type alias to `Double32_t`
517 void SetDouble32();
518};
519
520} // namespace ROOT
521
522#endif
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:299
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
void operator=(const TProof &)
Abstract base class for classes implementing the visitor design pattern.
static std::pair< std::uint16_t, std::uint16_t > GetValidBitRange(ROOT::ENTupleColumnType type)
Most types have a fixed on-disk bit width.
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
The list of column representations a field can have.
A field translates read and write calls from/to underlying columns to/from tree values.
~RField() final=default
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
RField(std::string_view name)
RField & operator=(RField &&other)=default
RField(RField &&other)=default
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
RField(RField &&other)=default
RField & operator=(RField &&other)=default
~RField() final=default
RField(std::string_view name)
RField(std::string_view name, const RField &source)
RField(std::string_view name)
static std::string TypeName()
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
static std::string TypeName()
RField(std::string_view name)
RField(std::string_view name, const RField &source)
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
static std::string TypeName()
RField & operator=(const RField &)=delete
RField(const RField &)=delete
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:285
~RField() final=default
RField & operator=(RField &&other)=default
RField(std::string_view name)
Definition RField.hxx:288
The on-storage metadata of an RNTuple.
~RRealField() override=default
RRealField(std::string_view name, const RRealField &source)
Called by derived fields' CloneImpl()
RRealField(std::string_view name, std::string_view typeName)
void SetQuantized(T minValue, T maxValue, std::size_t nBits)
Sets this field to use a quantized integer representation using nBits per value.
void SetHalfPrecision()
Sets this field to use a half precision representation, occupying half as much storage space (16 bits...
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
void SetTruncated(std::size_t nBits)
Set the on-disk representation of this field to a single-precision float truncated to nBits.
RRealField & operator=(RRealField &&other)=default
void GenerateColumns(const ROOT::RNTupleDescriptor &desc) final
Implementations in derived classes should create the backing columns corresponding to the field type ...
RRealField(RRealField &&other)=default
auto Map(Args &&... args)
Create new collection applying a callable to the elements of the input collection.
Definition RVec.hxx:2146
const Int_t n
Definition legend1.C:16
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
std::conditional_t< sizeof(long)==sizeof(std::int32_t), std::int32_t, std::int64_t > type
std::conditional_t< sizeof(unsigned long)==sizeof(std::uint32_t), std::uint32_t, std::uint64_t > type