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