Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFieldFundamental.hxx
Go to the documentation of this file.
1/// \file ROOT/RField/Fundamental.hxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2018-10-09
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#ifndef ROOT_RField_Fundamental
14#define ROOT_RField_Fundamental
15
16#ifndef ROOT_RField
17#error "Please include RField.hxx!"
18#endif
19
20#include <ROOT/RColumn.hxx>
21#include <ROOT/RFieldBase.hxx>
22#include <ROOT/RNTupleTypes.hxx>
23
24#include <cstddef>
25#include <memory>
26#include <string>
27#include <string_view>
28#include <type_traits>
29
30namespace ROOT {
31
32////////////////////////////////////////////////////////////////////////////////
33/// Template specializations for concrete C++ fundamental types
34////////////////////////////////////////////////////////////////////////////////
35
36template <>
37class RField<void> : public RFieldBase {
38public:
39 static std::string TypeName() { return "void"; }
40 // RField<void> should never be constructed.
41 RField() = delete;
42 RField(const RField &) = delete;
43 RField &operator=(const RField &) = delete;
44};
45
46////////////////////////////////////////////////////////////////////////////////
47/// Template specializations for integral types
48////////////////////////////////////////////////////////////////////////////////
49
50// bool and char are somewhat special, handle them first
51
52extern template class RSimpleField<bool>;
53
54template <>
56protected:
57 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
58 {
59 return std::make_unique<RField>(newName);
60 }
61
62 const RColumnRepresentations &GetColumnRepresentations() const final;
63
64public:
65 static std::string TypeName() { return "bool"; }
66 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
67 RField(RField &&other) = default;
70
71 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
72};
73
75
76template <>
78protected:
79 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
80 {
81 return std::make_unique<RField>(newName);
82 }
83
84 const RColumnRepresentations &GetColumnRepresentations() const final;
85
86public:
87 static std::string TypeName() { return "char"; }
88 explicit RField(std::string_view name) : RSimpleField(name, TypeName()) {}
89 RField(RField &&other) = default;
92
93 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
94};
95
96// For other integral types, we introduce an intermediate RIntegralField. It is specialized for fixed-width integer
97// types (from std::[u]int8_t to std::[u]int64_t). RField<T> for integral types T is specialized by mapping to the
98// corresponding fixed-width integer type (see RIntegralTypeMap).
99
102 // Instantiating this base template definition should never happen and is an error!
103 RIntegralField() = delete;
104};
105
106extern template class RSimpleField<std::int8_t>;
107
108template <>
110protected:
111 const RColumnRepresentations &GetColumnRepresentations() const final;
112
113public:
114 static std::string TypeName() { return "std::int8_t"; }
115 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
116 RIntegralField(RIntegralField &&other) = default;
117 RIntegralField &operator=(RIntegralField &&other) = default;
118 ~RIntegralField() override = default;
119
120 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
121};
122
123extern template class RSimpleField<std::uint8_t>;
124
125template <>
127protected:
128 const RColumnRepresentations &GetColumnRepresentations() const final;
129
130public:
131 static std::string TypeName() { return "std::uint8_t"; }
132 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
133 RIntegralField(RIntegralField &&other) = default;
134 RIntegralField &operator=(RIntegralField &&other) = default;
135 ~RIntegralField() override = default;
136
137 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
138};
139
140extern template class RSimpleField<std::int16_t>;
141
142template <>
144protected:
145 const RColumnRepresentations &GetColumnRepresentations() const final;
146
147public:
148 static std::string TypeName() { return "std::int16_t"; }
149 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
150 RIntegralField(RIntegralField &&other) = default;
151 RIntegralField &operator=(RIntegralField &&other) = default;
152 ~RIntegralField() override = default;
153
154 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
155};
156
157extern template class RSimpleField<std::uint16_t>;
158
159template <>
161protected:
162 const RColumnRepresentations &GetColumnRepresentations() const final;
163
164public:
165 static std::string TypeName() { return "std::uint16_t"; }
166 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
167 RIntegralField(RIntegralField &&other) = default;
168 RIntegralField &operator=(RIntegralField &&other) = default;
169 ~RIntegralField() override = default;
170
171 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
172};
173
174extern template class RSimpleField<std::int32_t>;
175
176template <>
178protected:
179 const RColumnRepresentations &GetColumnRepresentations() const final;
180
181public:
182 static std::string TypeName() { return "std::int32_t"; }
183 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
184 RIntegralField(RIntegralField &&other) = default;
185 RIntegralField &operator=(RIntegralField &&other) = default;
186 ~RIntegralField() override = default;
187
188 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
189};
190
191extern template class RSimpleField<std::uint32_t>;
192
193template <>
195protected:
196 const RColumnRepresentations &GetColumnRepresentations() const final;
197
198public:
199 static std::string TypeName() { return "std::uint32_t"; }
200 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
201 RIntegralField(RIntegralField &&other) = default;
202 RIntegralField &operator=(RIntegralField &&other) = default;
203 ~RIntegralField() override = default;
204
205 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
206};
207
208extern template class RSimpleField<std::int64_t>;
209
210template <>
212protected:
213 const RColumnRepresentations &GetColumnRepresentations() const final;
214
215public:
216 static std::string TypeName() { return "std::int64_t"; }
217 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
218 RIntegralField(RIntegralField &&other) = default;
219 RIntegralField &operator=(RIntegralField &&other) = default;
220 ~RIntegralField() override = default;
221
222 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
223};
224
225extern template class RSimpleField<std::uint64_t>;
226
227template <>
229protected:
230 const RColumnRepresentations &GetColumnRepresentations() const final;
231
232public:
233 static std::string TypeName() { return "std::uint64_t"; }
234 explicit RIntegralField(std::string_view name) : RSimpleField(name, TypeName()) {}
235 RIntegralField(RIntegralField &&other) = default;
236 RIntegralField &operator=(RIntegralField &&other) = default;
237 ~RIntegralField() override = default;
238
239 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
240};
241
242namespace Internal {
243// Map standard integer types to fixed width equivalents.
244template <typename T>
246 using type = T;
247};
248
249// RField<char> has its own specialization, we should not need a specialization of RIntegralTypeMap.
250// From https://en.cppreference.com/w/cpp/language/types:
251// char has the same representation and alignment as either signed char or
252// unsigned char, but is always a distinct type.
253template <>
255 static_assert(sizeof(signed char) == sizeof(std::int8_t));
256 using type = std::int8_t;
257};
258template <>
260 static_assert(sizeof(unsigned char) == sizeof(std::uint8_t));
261 using type = std::uint8_t;
262};
263template <>
265 static_assert(sizeof(short) == sizeof(std::int16_t));
266 using type = std::int16_t;
267};
268template <>
270 static_assert(sizeof(unsigned short) == sizeof(std::uint16_t));
271 using type = std::uint16_t;
272};
273template <>
275 static_assert(sizeof(int) == sizeof(std::int32_t));
276 using type = std::int32_t;
277};
278template <>
280 static_assert(sizeof(unsigned int) == sizeof(std::uint32_t));
281 using type = std::uint32_t;
282};
283template <>
285 static_assert(sizeof(long) == sizeof(std::int32_t) || sizeof(long) == sizeof(std::int64_t));
286 using type = std::conditional_t<sizeof(long) == sizeof(std::int32_t), std::int32_t, std::int64_t>;
287};
288template <>
289struct RIntegralTypeMap<unsigned long> {
290 static_assert(sizeof(unsigned long) == sizeof(std::uint32_t) || sizeof(unsigned long) == sizeof(std::uint64_t));
291 using type = std::conditional_t<sizeof(unsigned long) == sizeof(std::uint32_t), std::uint32_t, std::uint64_t>;
292};
293template <>
294struct RIntegralTypeMap<long long> {
295 static_assert(sizeof(long long) == sizeof(std::int64_t));
296 using type = std::int64_t;
297};
298template <>
299struct RIntegralTypeMap<unsigned long long> {
300 static_assert(sizeof(unsigned long long) == sizeof(std::uint64_t));
301 using type = std::uint64_t;
302};
303} // namespace Internal
304
305template <typename T>
306class RField<T, typename std::enable_if<std::is_integral_v<T>>::type> final
307 : public RIntegralField<typename Internal::RIntegralTypeMap<T>::type> {
308 using MappedType = typename Internal::RIntegralTypeMap<T>::type;
309 static_assert(sizeof(T) == sizeof(MappedType), "invalid size of mapped type");
310 static_assert(std::is_signed_v<T> == std::is_signed_v<MappedType>, "invalid signedness of mapped type");
311 using BaseType = RIntegralField<MappedType>;
312
313protected:
314 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
315 {
316 return std::make_unique<RField>(newName);
317 }
318
319public:
320 RField(std::string_view name) : RIntegralField<MappedType>(name) {}
321 RField(RField &&other) = default;
322 RField &operator=(RField &&other) = default;
324
325 T *Map(ROOT::NTupleSize_t globalIndex) { return reinterpret_cast<T *>(this->BaseType::Map(globalIndex)); }
326 T *Map(RNTupleLocalIndex localIndex) { return reinterpret_cast<T *>(this->BaseType::Map(localIndex)); }
328 {
329 return reinterpret_cast<T *>(this->BaseType::MapV(globalIndex, nItems));
330 }
331 T *MapV(RNTupleLocalIndex localIndex, ROOT::NTupleSize_t &nItems)
332 {
333 return reinterpret_cast<T *>(this->BaseType::MapV(localIndex, nItems));
334 }
335};
336
337////////////////////////////////////////////////////////////////////////////////
338/// Template specializations for floating-point types
339////////////////////////////////////////////////////////////////////////////////
340
341extern template class RSimpleField<double>;
342extern template class RSimpleField<float>;
343
344template <typename T>
347
348 using Base::fAvailableColumns;
349 using Base::fColumnRepresentatives;
350 using Base::fPrincipalColumn;
351
352 std::size_t fBitWidth = sizeof(T) * 8;
353 double fValueMin = std::numeric_limits<T>::min();
354 double fValueMax = std::numeric_limits<T>::max();
355
356protected:
357 /// Called by derived fields' CloneImpl()
358 RRealField(std::string_view name, const RRealField &source)
359 : RSimpleField<T>(name, source.GetTypeName()),
360 fBitWidth(source.fBitWidth),
361 fValueMin(source.fValueMin),
362 fValueMax(source.fValueMax)
363 {
364 }
365
367 {
368 const auto r = Base::GetColumnRepresentatives();
369 const auto n = r.size();
370 fAvailableColumns.reserve(n);
371 for (std::uint16_t i = 0; i < n; ++i) {
372 auto &column = fAvailableColumns.emplace_back(ROOT::Internal::RColumn::Create<T>(r[i][0], 0, i));
374 column->SetBitsOnStorage(fBitWidth);
375 } else if (r[i][0] == ROOT::ENTupleColumnType::kReal32Quant) {
376 column->SetBitsOnStorage(fBitWidth);
377 column->SetValueRange(fValueMin, fValueMax);
378 }
379 }
380 fPrincipalColumn = fAvailableColumns[0].get();
381 }
382
384 {
385 std::uint16_t representationIndex = 0;
386 do {
387 const auto &onDiskTypes = Base::EnsureCompatibleColumnTypes(desc, representationIndex);
388 if (onDiskTypes.empty())
389 break;
390
391 auto &column =
392 fAvailableColumns.emplace_back(ROOT::Internal::RColumn::Create<T>(onDiskTypes[0], 0, representationIndex));
394 const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
395 const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[representationIndex]);
396 column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
398 const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
399 const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[representationIndex]);
400 assert(coldesc.GetValueRange().has_value());
401 const auto [valMin, valMax] = *coldesc.GetValueRange();
402 column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
403 column->SetValueRange(valMin, valMax);
404 }
405 fColumnRepresentatives.emplace_back(onDiskTypes);
406 if (representationIndex > 0) {
407 fAvailableColumns[0]->MergeTeams(*fAvailableColumns[representationIndex]);
408 }
409
411 } while (true);
412 fPrincipalColumn = fAvailableColumns[0].get();
413 }
414
415public:
416 using Base::SetColumnRepresentatives;
417
418 RRealField(std::string_view name, std::string_view typeName) : RSimpleField<T>(name, typeName) {}
421 ~RRealField() override = default;
422
423 /// Sets this field to use a half precision representation, occupying half as much storage space (16 bits:
424 /// 1 sign bit, 5 exponent bits, 10 mantissa bits) on disk.
425 /// This is mutually exclusive with SetTruncated() and SetQuantized() and supersedes them if called after them.
426 void SetHalfPrecision() { SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal16}}); }
427
428 /// Set the on-disk representation of this field to a single-precision float truncated to `nBits`.
429 /// The remaining (32 - `nBits`) bits will be truncated from the number's mantissa.
430 /// `nBits` must be $10 <= nBits <= 31$ (this means that at least 1 bit
431 /// of mantissa is always preserved). Note that this effectively rounds the number towards 0.
432 /// For a double-precision field, this implies first a cast to single-precision, then the truncation.
433 /// This is mutually exclusive with SetHalfPrecision() and SetQuantized() and supersedes them if called after them.
434 void SetTruncated(std::size_t nBits)
435 {
436 const auto &[minBits, maxBits] =
439 throw RException(R__FAIL("SetTruncated() argument nBits = " + std::to_string(nBits) +
440 " is out of valid range [" + std::to_string(minBits) + ", " +
441 std::to_string(maxBits) + "])"));
442 }
443 SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal32Trunc}});
444 fBitWidth = nBits;
445 }
446
447 /// Sets this field to use a quantized integer representation using `nBits` per value.
448 /// It must be $1 <= nBits <= 32$.
449 /// `valueRange.first` and `valueRange.second` are respectively the min and max value allowed for this field.
450 /// They must not be infinity, `NaN` or denormal floats, and valueRange.second must be greater or equal to
451 /// valueRange.first.
452 /// Calling this function establishes a promise by the caller to RNTuple that this field will only
453 /// contain values contained in `[minValue, maxValue]` inclusive. If a value outside this range is assigned to this
454 /// field, the behavior is undefined. This is mutually exclusive with SetTruncated() and SetHalfPrecision() and
455 /// supersedes them if called after them.
456 void SetQuantized(std::size_t nBits, std::pair<T, T> valueRange)
457 {
458 const auto &[minBits, maxBits] =
460 if (valueRange.second < valueRange.first) {
461 throw RException(R__FAIL("value range given to SetQuantized() has max < min! (" +
462 std::to_string(valueRange.second) + " < " + std::to_string(valueRange.first) + ")"));
463 }
465 throw RException(R__FAIL("SetQuantized() argument nBits = " + std::to_string(nBits) +
466 " is out of valid range [" + std::to_string(minBits) + ", " +
467 std::to_string(maxBits) + "])"));
468 }
469 SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal32Quant}});
470 fBitWidth = nBits;
471 fValueMin = valueRange.first;
472 fValueMax = valueRange.second;
473 }
474};
475
476template <>
478 const RColumnRepresentations &GetColumnRepresentations() const final;
479
480 RField(std::string_view name, const RField &source) : RRealField<float>(name, source) {}
481
482 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
483 {
484 return std::unique_ptr<RField>(new RField(newName, *this));
485 }
486
487public:
488 static std::string TypeName() { return "float"; }
489
490 explicit RField(std::string_view name) : RRealField<float>(name, TypeName()) {}
491
492 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
493};
494
495template <>
497 const RColumnRepresentations &GetColumnRepresentations() const final;
498
499 RField(std::string_view name, const RField &source) : RRealField<double>(name, source) {}
500
501 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
502 {
503 return std::unique_ptr<RField>(new RField(newName, *this));
504 }
505
506public:
507 static std::string TypeName() { return "double"; }
508
509 explicit RField(std::string_view name) : RRealField<double>(name, TypeName()) {}
510
511 void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
512
513 // Set the column representation to 32 bit floating point and the type alias to `Double32_t`
514 void SetDouble32();
515};
516
517} // namespace ROOT
518
519#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:322
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:148
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:78
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:319
~RField() final=default
RField & operator=(RField &&other)=default
RField(std::string_view name)
Definition RField.hxx:322
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 SetHalfPrecision()
Sets this field to use a half precision representation, occupying half as much storage space (16 bits...
void SetQuantized(std::size_t nBits, std::pair< T, T > valueRange)
Sets this field to use a quantized integer representation using nBits per value.
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:2154
const Int_t n
Definition legend1.C:16
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