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////////////////////////////////////////////////////////////////////////////////
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 <>
63class RField<bool> final : public RSimpleField<bool> {
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;
76 RField &operator=(RField &&other) = default;
77 ~RField() final = default;
78
79 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
80};
81
82extern template class RSimpleField<char>;
83
84template <>
85class RField<char> final : public RSimpleField<char> {
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;
98 RField &operator=(RField &&other) = default;
99 ~RField() final = default;
100
101 void AcceptVisitor(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
108template <typename T>
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(Detail::RFieldVisitor &visitor) const final;
129};
130
131extern template class RSimpleField<std::uint8_t>;
132
133template <>
134class RIntegralField<std::uint8_t> : public RSimpleField<std::uint8_t> {
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(Detail::RFieldVisitor &visitor) const final;
146};
147
148extern template class RSimpleField<std::int16_t>;
149
150template <>
151class RIntegralField<std::int16_t> : public RSimpleField<std::int16_t> {
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(Detail::RFieldVisitor &visitor) const final;
163};
164
165extern template class RSimpleField<std::uint16_t>;
166
167template <>
168class RIntegralField<std::uint16_t> : public RSimpleField<std::uint16_t> {
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(Detail::RFieldVisitor &visitor) const final;
180};
181
182extern template class RSimpleField<std::int32_t>;
183
184template <>
185class RIntegralField<std::int32_t> : public RSimpleField<std::int32_t> {
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(Detail::RFieldVisitor &visitor) const final;
197};
198
199extern template class RSimpleField<std::uint32_t>;
200
201template <>
202class RIntegralField<std::uint32_t> : public RSimpleField<std::uint32_t> {
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(Detail::RFieldVisitor &visitor) const final;
214};
215
216extern template class RSimpleField<std::int64_t>;
217
218template <>
219class RIntegralField<std::int64_t> : public RSimpleField<std::int64_t> {
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(Detail::RFieldVisitor &visitor) const final;
231};
232
233extern template class RSimpleField<std::uint64_t>;
234
235template <>
236class RIntegralField<std::uint64_t> : public RSimpleField<std::uint64_t> {
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(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;
331 ~RField() final = default;
332
333 T *Map(NTupleSize_t globalIndex) { return reinterpret_cast<T *>(this->BaseType::Map(globalIndex)); }
334 T *Map(RClusterIndex clusterIndex) { return reinterpret_cast<T *>(this->BaseType::Map(clusterIndex)); }
335 T *MapV(NTupleSize_t globalIndex, NTupleSize_t &nItems)
336 {
337 return reinterpret_cast<T *>(this->BaseType::MapV(globalIndex, nItems));
338 }
339 T *MapV(RClusterIndex clusterIndex, NTupleSize_t &nItems)
340 {
341 return reinterpret_cast<T *>(this->BaseType::MapV(clusterIndex, 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
374 void GenerateColumns() final
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(Internal::RColumn::Create<T>(r[i][0], 0, i));
381 if (r[i][0] == EColumnType::kReal32Trunc) {
382 column->SetBitsOnStorage(fBitWidth);
383 } else if (r[i][0] == EColumnType::kReal32Quant) {
384 column->SetBitsOnStorage(fBitWidth);
385 column->SetValueRange(fValueMin, fValueMax);
386 }
387 }
388 fPrincipalColumn = fAvailableColumns[0].get();
389 }
390
391 void GenerateColumns(const RNTupleDescriptor &desc) final
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(Internal::RColumn::Create<T>(onDiskTypes[0], 0, representationIndex));
401 if (onDiskTypes[0] == EColumnType::kReal32Trunc) {
402 const auto &fdesc = desc.GetFieldDescriptor(Base::GetOnDiskId());
403 const auto &coldesc = desc.GetColumnDescriptor(fdesc.GetLogicalColumnIds()[0]);
404 column->SetBitsOnStorage(coldesc.GetBitsOnStorage());
405 } else if (onDiskTypes[0] == EColumnType::kReal32Quant) {
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
418 representationIndex++;
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) {}
429 RRealField(RRealField &&other) = default;
430 RRealField &operator=(RRealField &&other) = default;
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`.
435 void SetHalfPrecision() { SetColumnRepresentatives({{EColumnType::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`.
443 void SetTruncated(std::size_t nBits)
444 {
446 if (nBits < minBits || nBits > maxBits) {
447 throw RException(R__FAIL("SetTruncated() argument nBits = " + std::to_string(nBits) +
448 " is out of valid range [" + std::to_string(minBits) + ", " +
449 std::to_string(maxBits) + "])"));
450 }
451 SetColumnRepresentatives({{EColumnType::kReal32Trunc}});
452 fBitWidth = nBits;
453 }
454
455 /// Sets this field to use a quantized integer representation using `nBits` per value.
456 /// It must be $1 <= nBits <= 32$.
457 /// This call promises that this field will only contain values contained in `[minValue, maxValue]` inclusive.
458 /// If a value outside this range is assigned to this field, the behavior is undefined.
459 /// This is mutually exclusive with `SetTruncated` and `SetHalfPrecision`.
460 void SetQuantized(double minValue, double maxValue, std::size_t nBits)
461 {
463 if (nBits < minBits || nBits > maxBits) {
464 throw RException(R__FAIL("SetQuantized() argument nBits = " + std::to_string(nBits) +
465 " is out of valid range [" + std::to_string(minBits) + ", " +
466 std::to_string(maxBits) + "])"));
467 }
468 SetColumnRepresentatives({{EColumnType::kReal32Quant}});
469 fBitWidth = nBits;
470 fValueMin = minValue;
471 fValueMax = maxValue;
472 }
473};
474
475template <>
476class RField<float> final : public RRealField<float> {
477 const RColumnRepresentations &GetColumnRepresentations() const final;
478
479 RField(std::string_view name, const RField &source) : RRealField<float>(name, source) {}
480
481 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
482 {
483 return std::unique_ptr<RField>(new RField(newName, *this));
484 }
485
486public:
487 static std::string TypeName() { return "float"; }
488
489 explicit RField(std::string_view name) : RRealField<float>(name, TypeName()) {}
490
491 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
492};
493
494template <>
495class RField<double> final : public RRealField<double> {
496 const RColumnRepresentations &GetColumnRepresentations() const final;
497
498 RField(std::string_view name, const RField &source) : RRealField<double>(name, source) {}
499
500 std::unique_ptr<RFieldBase> CloneImpl(std::string_view newName) const final
501 {
502 return std::unique_ptr<RField>(new RField(newName, *this));
503 }
504
505public:
506 static std::string TypeName() { return "double"; }
507
508 explicit RField(std::string_view name) : RRealField<double>(name, TypeName()) {}
509
510 void AcceptVisitor(Detail::RFieldVisitor &visitor) const final;
511
512 // Set the column representation to 32 bit floating point and the type alias to Double32_t
513 void SetDouble32();
514};
515} // namespace Experimental
516} // namespace ROOT
517
518#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:290
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(EColumnType 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
Some fields have multiple possible column representations, e.g.
A field translates read and write calls from/to underlying columns to/from tree values.
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
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(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.
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.
RField(const RField &)=delete
RField & operator=(const RField &)=delete
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:241
RField & operator=(RField &&other)=default
The on-storage meta-data of an ntuple.
RRealField(RRealField &&other)=default
void GenerateColumns(const RNTupleDescriptor &desc) final
Implementations in derived classes should create the backing columns corresponsing 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
~RRealField() override=default
void SetQuantized(double minValue, double maxValue, std::size_t nBits)
Sets this field to use a quantized integer representation using nBits per value.
RRealField(std::string_view name, std::string_view typeName)
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponsing to the field type ...
void SetHalfPrecision()
Sets this field to use a half precision representation, occupying half as much storage space (16 bits...
RRealField(std::string_view name, const RRealField &source)
Called by derived fields' CloneImpl()
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
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
double T(double x)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
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