Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RColumnElement.hxx
Go to the documentation of this file.
1// RColumnElement concrete implementations
2//
3// Note that this file is in the src directory and not in the inc directory because we need the ability
4// to override R__LITTLE_ENDIAN for testing purposes.
5// This is not a particularly clean or correct solution, as the tests that do this will end up with two different
6// definitions of some RColumnElements, so we might want to change this mechanism in the future. In any case, these
7// definitions are implementation details and should not be exposed to a public interface.
8
10#include <ROOT/RNTupleTypes.hxx>
11#include <ROOT/RNTupleUtils.hxx>
12#include <ROOT/RConfig.hxx>
13#include <ROOT/RError.hxx>
14#include <Byteswap.h>
15
16#include <bitset>
17#include <cassert>
18#include <limits>
19#include <type_traits>
20#include <cmath>
21
22// NOTE: some tests might define R__LITTLE_ENDIAN to simulate a different-endianness machine
23#ifndef R__LITTLE_ENDIAN
24#ifdef R__BYTESWAP
25// `R__BYTESWAP` is defined in RConfig.hxx for little-endian architectures; undefined otherwise
26#define R__LITTLE_ENDIAN 1
27#else
28#define R__LITTLE_ENDIAN 0
29#endif
30#endif /* R__LITTLE_ENDIAN */
31
33
34using Word_t = std::uintmax_t;
35inline constexpr std::size_t kBitsPerWord = sizeof(Word_t) * 8;
36
37/// Returns the minimum safe size (in bytes) of a buffer that is intended to be used as a destination for PackBits
38/// or a source for UnpackBits.
39/// Passing a buffer that's less than this size will cause invalid memory reads and writes.
40constexpr std::size_t MinBufSize(std::size_t count, std::size_t nDstBits)
41{
42 return (count * nDstBits + 7) / 8;
43}
44
45/// Tightly packs `count` items of size `sizeofSrc` contained in `src` into `dst` using `nDstBits` per item.
46/// It must be `0 < sizeofSrc <= 8` and `0 < nDstBits <= sizeofSrc * 8`.
47/// The extra least significant bits are dropped (assuming LE ordering of the items in `src`).
48/// Note that this function doesn't do any byte reordering for you.
49/// IMPORTANT: the size of `dst` must be at least `MinBufSize(count, nBitBits)`
50void PackBits(void *dst, const void *src, std::size_t count, std::size_t sizeofSrc, std::size_t nDstBits);
51
52/// Undoes the effect of `PackBits`. The bits that were truncated in the packed representation
53/// are filled with zeroes.
54/// `src` must be at least `MinBufSize(count, nDstBits)` bytes long.
55/// `dst` must be at least `count * sizeofDst` bytes long.
56void UnpackBits(void *dst, const void *src, std::size_t count, std::size_t sizeofDst, std::size_t nSrcBits);
57
58} // namespace ROOT::Internal::BitPacking
59
60namespace {
61
62// In this namespace, common routines are defined for element packing and unpacking of ints and floats.
63// The following conversions and encodings exist:
64//
65// - Byteswap: on big endian machines, ints and floats are byte-swapped to the little endian on-disk format
66// - Cast: in-memory values can be stored in narrower on-disk columns. Currently without bounds checks.
67// For instance, for Double32_t, an in-memory double value is stored as a float on disk.
68// - Split: rearranges the bytes of an array of elements such that all the first bytes are stored first,
69// followed by all the second bytes, etc. This often clusters similar values, e.g. all the zero bytes
70// for arrays of small integers.
71// - Delta: Delta encoding stores on disk the delta to the previous element. This is useful for offsets,
72// because it transforms potentially large offset values into small deltas, which are then better
73// suited for split encoding.
74// - Zigzag: Zigzag encoding is used on signed integers only. It maps x to 2x if x is positive and to -(2x+1) if
75// x is negative. For series of positive and negative values of small absolute value, it will produce
76// a bit pattern that is favorable for split encoding.
77//
78// Encodings/conversions can be fused:
79//
80// - Delta/Zigzag + Splitting (there is no only-delta/zigzag encoding)
81// - (Delta/Zigzag + ) Splitting + Casting
82// - Everything + Byteswap
83
84/// \brief Copy and byteswap `count` elements of size `N` from `source` to `destination`.
85///
86/// Used on big-endian architectures for packing/unpacking elements whose column type requires
87/// a little-endian on-disk representation.
88template <std::size_t N>
89inline void CopyBswap(void *destination, const void *source, std::size_t count)
90{
91 auto dst = reinterpret_cast<typename RByteSwap<N>::value_type *>(destination);
92 auto src = reinterpret_cast<const typename RByteSwap<N>::value_type *>(source);
93 for (std::size_t i = 0; i < count; ++i) {
95 }
96}
97
98template <std::size_t N>
99void InPlaceBswap(void *array, std::size_t count)
100{
101 auto arr = reinterpret_cast<typename RByteSwap<N>::value_type *>(array);
102 for (std::size_t i = 0; i < count; ++i) {
103 arr[i] = RByteSwap<N>::bswap(arr[i]);
104 }
105}
106
107/// Casts T to one of the ints used in RByteSwap and back to its original type, which may be float or double
108#if R__LITTLE_ENDIAN == 0
109template <typename T>
110inline void ByteSwapIfNecessary(T &value)
111{
112 constexpr auto N = sizeof(T);
114 void *valuePtr = &value;
115 auto swapped = RByteSwap<N>::bswap(*reinterpret_cast<bswap_value_type *>(valuePtr));
116 *reinterpret_cast<bswap_value_type *>(valuePtr) = swapped;
117}
118template <>
119inline void ByteSwapIfNecessary<char>(char &)
120{
121}
122template <>
123inline void ByteSwapIfNecessary<signed char>(signed char &)
124{
125}
126template <>
127inline void ByteSwapIfNecessary<unsigned char>(unsigned char &)
128{
129}
130#else
131#define ByteSwapIfNecessary(x) ((void)0)
132#endif
133
134/// For integral types, ensures that the value of type SourceT is representable as DestT
135template <typename DestT, typename SourceT>
136inline void EnsureValidRange(SourceT val [[maybe_unused]])
137{
138 using ROOT::RException;
139
140 if constexpr (!std::is_integral_v<DestT> || !std::is_integral_v<SourceT>)
141 return;
142
143 if constexpr (static_cast<double>(std::numeric_limits<SourceT>::min()) <
144 static_cast<double>(std::numeric_limits<DestT>::min())) {
145 if constexpr (!std::is_signed_v<DestT>) {
146 if (val < 0) {
147 throw RException(R__FAIL(std::string("value out of range: ") + std::to_string(val) + " for type " +
148 typeid(DestT).name()));
149 }
150 } else if (val < std::numeric_limits<DestT>::min()) {
151 throw RException(
152 R__FAIL(std::string("value out of range: ") + std::to_string(val) + " for type " + typeid(DestT).name()));
153 }
154 }
155
156 if constexpr (static_cast<double>(std::numeric_limits<SourceT>::max()) >
157 static_cast<double>(std::numeric_limits<DestT>::max())) {
158 if (val > std::numeric_limits<DestT>::max()) {
159 throw RException(
160 R__FAIL(std::string("value out of range: ") + std::to_string(val) + " for type " + typeid(DestT).name()));
161 }
162 }
163}
164
165/// Currently ensures that the floating point class doesn't change in double --> float conversion
166template <typename DestT, typename SourceT>
168{
169 if constexpr (std::is_same_v<DestT, float> && std::is_same_v<SourceT, double>) {
170 if (std::fpclassify(src) != std::fpclassify(dst)) {
171 throw ROOT::RException(R__FAIL(std::string("floating point class mismatch: ") + std::to_string(src) +
172 " on disk to " + std::to_string(dst) + " in memory"));
173 }
174 }
175}
176
177/// \brief Pack `count` elements into narrower (or wider) type
178///
179/// Used to convert in-memory elements to smaller column types of comatible types
180/// (e.g., double to float, int64 to int32). Takes care of byte swap if necessary.
181template <typename DestT, typename SourceT>
182inline void CastPack(void *destination, const void *source, std::size_t count)
183{
184 static_assert(std::is_convertible_v<SourceT, DestT>);
185 auto dst = reinterpret_cast<DestT *>(destination);
186 auto src = reinterpret_cast<const SourceT *>(source);
187 for (std::size_t i = 0; i < count; ++i) {
188 dst[i] = src[i];
190 }
191}
192
193/// \brief Unpack `count` on-disk elements into wider (or narrower) in-memory array
194///
195/// Used to convert on-disk elements to larger C++ types of comatible types
196/// (e.g., float to double, int32 to int64). Takes care of byte swap if necessary.
197template <typename DestT, typename SourceT>
198inline void CastUnpack(void *destination, const void *source, std::size_t count)
199{
200 auto dst = reinterpret_cast<DestT *>(destination);
201 auto src = reinterpret_cast<const SourceT *>(source);
202 for (std::size_t i = 0; i < count; ++i) {
203 SourceT val = src[i];
206 dst[i] = val;
208 }
209}
210
211/// \brief Split encoding of elements, possibly into narrower column
212///
213/// Used to first cast and then split-encode in-memory values to the on-disk column. Swap bytes if necessary.
214template <typename DestT, typename SourceT>
215inline void CastSplitPack(void *destination, const void *source, std::size_t count)
216{
217 constexpr std::size_t N = sizeof(DestT);
218 auto splitArray = reinterpret_cast<char *>(destination);
219 auto src = reinterpret_cast<const SourceT *>(source);
220 for (std::size_t i = 0; i < count; ++i) {
221 DestT val = src[i];
223 for (std::size_t b = 0; b < N; ++b) {
224 splitArray[b * count + i] = reinterpret_cast<const char *>(&val)[b];
225 }
226 }
227}
228
229/// \brief Reverse split encoding of elements
230///
231/// Used to first unsplit a column, possibly storing elements in wider C++ types. Swaps bytes if necessary
232template <typename DestT, typename SourceT>
233inline void CastSplitUnpack(void *destination, const void *source, std::size_t count)
234{
235 constexpr std::size_t N = sizeof(SourceT);
236 auto dst = reinterpret_cast<DestT *>(destination);
237 auto splitArray = reinterpret_cast<const char *>(source);
238 for (std::size_t i = 0; i < count; ++i) {
239 SourceT val = 0;
240 for (std::size_t b = 0; b < N; ++b) {
241 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
242 }
245 dst[i] = val;
247 }
248}
249
250/// \brief Packing of columns with delta + split encoding
251///
252/// Apply split encoding to delta-encoded values, currently used only for index columns
253template <typename DestT, typename SourceT>
254inline void CastDeltaSplitPack(void *destination, const void *source, std::size_t count)
255{
256 constexpr std::size_t N = sizeof(DestT);
257 auto src = reinterpret_cast<const SourceT *>(source);
258 auto splitArray = reinterpret_cast<char *>(destination);
259 for (std::size_t i = 0; i < count; ++i) {
260 DestT val = (i == 0) ? src[0] : src[i] - src[i - 1];
262 for (std::size_t b = 0; b < N; ++b) {
263 splitArray[b * count + i] = reinterpret_cast<char *>(&val)[b];
264 }
265 }
266}
267
268/// \brief Unsplit and unwind delta encoding
269///
270/// Unsplit a column and reverse the delta encoding, currently used only for index columns
271template <typename DestT, typename SourceT>
272inline void CastDeltaSplitUnpack(void *destination, const void *source, std::size_t count)
273{
274 constexpr std::size_t N = sizeof(SourceT);
275 auto splitArray = reinterpret_cast<const char *>(source);
276 auto dst = reinterpret_cast<DestT *>(destination);
277 for (std::size_t i = 0; i < count; ++i) {
278 SourceT val = 0;
279 for (std::size_t b = 0; b < N; ++b) {
280 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
281 }
283 val = (i == 0) ? val : val + dst[i - 1];
285 dst[i] = val;
286 }
287}
288
289/// \brief Packing of columns with zigzag + split encoding
290///
291/// Apply split encoding to zigzag-encoded values, used for signed integers
292template <typename DestT, typename SourceT>
293inline void CastZigzagSplitPack(void *destination, const void *source, std::size_t count)
294{
295 using UDestT = std::make_unsigned_t<DestT>;
296 constexpr std::size_t kNBitsDestT = sizeof(DestT) * 8;
297 constexpr std::size_t N = sizeof(DestT);
298 auto src = reinterpret_cast<const SourceT *>(source);
299 auto splitArray = reinterpret_cast<char *>(destination);
300 for (std::size_t i = 0; i < count; ++i) {
301 UDestT val = (static_cast<DestT>(src[i]) << 1) ^ (static_cast<DestT>(src[i]) >> (kNBitsDestT - 1));
303 for (std::size_t b = 0; b < N; ++b) {
304 splitArray[b * count + i] = reinterpret_cast<char *>(&val)[b];
305 }
306 }
307}
308
309/// \brief Unsplit and unwind zigzag encoding
310///
311/// Unsplit a column and reverse the zigzag encoding, used for signed integer columns
312template <typename DestT, typename SourceT>
313inline void CastZigzagSplitUnpack(void *destination, const void *source, std::size_t count)
314{
315 using USourceT = std::make_unsigned_t<SourceT>;
316 constexpr std::size_t N = sizeof(SourceT);
317 auto splitArray = reinterpret_cast<const char *>(source);
318 auto dst = reinterpret_cast<DestT *>(destination);
319 for (std::size_t i = 0; i < count; ++i) {
320 USourceT val = 0;
321 for (std::size_t b = 0; b < N; ++b) {
322 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
323 }
325 SourceT sval = static_cast<SourceT>((val >> 1) ^ -(static_cast<SourceT>(val) & 1));
327 dst[i] = sval;
328 }
329}
330} // namespace
331
332// anonymous namespace because these definitions are not meant to be exported.
333namespace {
334
339
340template <typename CppT, ENTupleColumnType>
341class RColumnElement;
342
343template <typename CppT>
344std::unique_ptr<RColumnElementBase> GenerateColumnElementInternal(ENTupleColumnType onDiskType)
345{
346 switch (onDiskType) {
347 case ENTupleColumnType::kIndex64: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kIndex64>>();
348 case ENTupleColumnType::kIndex32: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kIndex32>>();
349 case ENTupleColumnType::kSwitch: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSwitch>>();
350 case ENTupleColumnType::kByte: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kByte>>();
351 case ENTupleColumnType::kChar: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kChar>>();
352 case ENTupleColumnType::kBit: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kBit>>();
353 case ENTupleColumnType::kReal64: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kReal64>>();
354 case ENTupleColumnType::kReal32: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kReal32>>();
355 case ENTupleColumnType::kReal16: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kReal16>>();
356 case ENTupleColumnType::kInt64: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kInt64>>();
357 case ENTupleColumnType::kUInt64: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kUInt64>>();
358 case ENTupleColumnType::kInt32: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kInt32>>();
359 case ENTupleColumnType::kUInt32: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kUInt32>>();
360 case ENTupleColumnType::kInt16: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kInt16>>();
361 case ENTupleColumnType::kUInt16: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kUInt16>>();
362 case ENTupleColumnType::kInt8: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kInt8>>();
363 case ENTupleColumnType::kUInt8: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kUInt8>>();
364 case ENTupleColumnType::kSplitIndex64:
365 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitIndex64>>();
366 case ENTupleColumnType::kSplitIndex32:
367 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitIndex32>>();
368 case ENTupleColumnType::kSplitReal64:
369 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitReal64>>();
370 case ENTupleColumnType::kSplitReal32:
371 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitReal32>>();
372 case ENTupleColumnType::kSplitInt64: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitInt64>>();
373 case ENTupleColumnType::kSplitUInt64:
374 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitUInt64>>();
375 case ENTupleColumnType::kSplitInt32: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitInt32>>();
376 case ENTupleColumnType::kSplitUInt32:
377 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitUInt32>>();
378 case ENTupleColumnType::kSplitInt16: return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitInt16>>();
379 case ENTupleColumnType::kSplitUInt16:
380 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kSplitUInt16>>();
381 case ENTupleColumnType::kReal32Trunc:
382 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kReal32Trunc>>();
383 case ENTupleColumnType::kReal32Quant:
384 return std::make_unique<RColumnElement<CppT, ENTupleColumnType::kReal32Quant>>();
385 default:
386 if (onDiskType == kTestFutureColumnType)
387 return std::make_unique<RColumnElement<CppT, kTestFutureColumnType>>();
388 R__ASSERT(false);
389 }
390 // never here
391 return nullptr;
392}
393
394/**
395 * Base class for columns whose on-storage representation is little-endian.
396 * The implementation of `Pack` and `Unpack` takes care of byteswap if the memory page is big-endian.
397 */
398template <typename CppT>
399class RColumnElementLE : public RColumnElementBase {
400protected:
401 explicit RColumnElementLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage) {}
402
403public:
404 static constexpr bool kIsMappable = (R__LITTLE_ENDIAN == 1);
405
406 void Pack(void *dst, const void *src, std::size_t count) const final
407 {
408#if R__LITTLE_ENDIAN == 1
409 RColumnElementBase::Pack(dst, src, count);
410#else
412#endif
413 }
414 void Unpack(void *dst, const void *src, std::size_t count) const final
415 {
416#if R__LITTLE_ENDIAN == 1
417 RColumnElementBase::Unpack(dst, src, count);
418#else
420#endif
421 }
422}; // class RColumnElementLE
423
424/**
425 * Base class for columns storing elements of wider in-memory types,
426 * such as 64bit in-memory offsets to Index32 columns.
427 */
428template <typename CppT, typename NarrowT>
429class RColumnElementCastLE : public RColumnElementBase {
430protected:
431 explicit RColumnElementCastLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage)
432 {
433 }
434
435public:
436 static constexpr bool kIsMappable = false;
437
438 void Pack(void *dst, const void *src, std::size_t count) const final { CastPack<NarrowT, CppT>(dst, src, count); }
439 void Unpack(void *dst, const void *src, std::size_t count) const final
440 {
442 }
443}; // class RColumnElementCastLE
444
445/**
446 * Base class for split columns whose on-storage representation is little-endian.
447 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
448 * As part of the splitting, can also narrow down the type to NarrowT.
449 */
450template <typename CppT, typename NarrowT>
451class RColumnElementSplitLE : public RColumnElementBase {
452protected:
453 explicit RColumnElementSplitLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage)
454 {
455 }
456
457public:
458 static constexpr bool kIsMappable = false;
459
460 void Pack(void *dst, const void *src, std::size_t count) const final
461 {
463 }
464 void Unpack(void *dst, const void *src, std::size_t count) const final
465 {
467 }
468}; // class RColumnElementSplitLE
469
470/**
471 * Base class for delta + split columns (index columns) whose on-storage representation is little-endian.
472 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
473 * As part of the encoding, can also narrow down the type to NarrowT.
474 */
475template <typename CppT, typename NarrowT>
476class RColumnElementDeltaSplitLE : public RColumnElementBase {
477protected:
478 explicit RColumnElementDeltaSplitLE(std::size_t size, std::size_t bitsOnStorage)
479 : RColumnElementBase(size, bitsOnStorage)
480 {
481 }
482
483public:
484 static constexpr bool kIsMappable = false;
485
486 void Pack(void *dst, const void *src, std::size_t count) const final
487 {
489 }
490 void Unpack(void *dst, const void *src, std::size_t count) const final
491 {
493 }
494}; // class RColumnElementDeltaSplitLE
495
496/// Reading of unsplit integer columns to boolean
497template <typename CppIntT>
498class RColumnElementBoolAsUnsplitInt : public RColumnElementBase {
499protected:
500 explicit RColumnElementBoolAsUnsplitInt(std::size_t size, std::size_t bitsOnStorage)
501 : RColumnElementBase(size, bitsOnStorage)
502 {
503 }
504
505public:
506 static constexpr bool kIsMappable = false;
507
508 // We don't implement Pack() because integers must not be written to disk as booleans
509 void Pack(void *, const void *, std::size_t) const final { R__ASSERT(false); }
510
511 void Unpack(void *dst, const void *src, std::size_t count) const final
512 {
513 auto *boolArray = reinterpret_cast<bool *>(dst);
514 auto *intArray = reinterpret_cast<const CppIntT *>(src);
515 for (std::size_t i = 0; i < count; ++i) {
516 boolArray[i] = intArray[i] != 0;
517 }
518 }
519}; // class RColumnElementBoolAsUnsplitInt
520
521/// Reading of split integer columns to boolean
522template <typename CppIntT>
523class RColumnElementBoolAsSplitInt : public RColumnElementBase {
524protected:
525 explicit RColumnElementBoolAsSplitInt(std::size_t size, std::size_t bitsOnStorage)
526 : RColumnElementBase(size, bitsOnStorage)
527 {
528 }
529
530public:
531 static constexpr bool kIsMappable = false;
532
533 // We don't implement Pack() because integers must not be written to disk as booleans
534 void Pack(void *, const void *, std::size_t) const final { R__ASSERT(false); }
535
536 void Unpack(void *dst, const void *src, std::size_t count) const final
537 {
538 constexpr std::size_t N = sizeof(CppIntT);
539 auto *boolArray = reinterpret_cast<bool *>(dst);
540 auto *splitArray = reinterpret_cast<const char *>(src);
541 for (std::size_t i = 0; i < count; ++i) {
542 boolArray[i] = false;
543 for (std::size_t b = 0; b < N; ++b) {
544 if (splitArray[b * count + i]) {
545 boolArray[i] = true;
546 break;
547 }
548 }
549 }
550 }
551}; // RColumnElementBoolAsSplitInt
552
553/// Reading of bit columns as integer
554template <typename CppIntT>
555class RColumnElementIntAsBool : public RColumnElementBase {
556protected:
557 explicit RColumnElementIntAsBool(std::size_t size, std::size_t bitsOnStorage)
558 : RColumnElementBase(size, bitsOnStorage)
559 {
560 }
561
562public:
563 static constexpr bool kIsMappable = false;
564
565 // We don't implement Pack() because booleans must not be written as integers to disk
566 void Pack(void *, const void *, std::size_t) const final { R__ASSERT(false); }
567
568 void Unpack(void *dst, const void *src, std::size_t count) const final
569 {
570 auto *intArray = reinterpret_cast<CppIntT *>(dst);
571 const char *charArray = reinterpret_cast<const char *>(src);
572 std::bitset<8> bitSet;
573 for (std::size_t i = 0; i < count; i += 8) {
574 bitSet = charArray[i / 8];
575 for (std::size_t j = i; j < std::min(count, i + 8); ++j) {
576 intArray[j] = bitSet[j % 8];
577 }
578 }
579 }
580}; // RColumnElementIntAsBool
581
582/**
583 * Base class for zigzag + split columns (signed integer columns) whose on-storage representation is little-endian.
584 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
585 * The NarrowT target type should be an signed integer, which can be smaller than the CppT source type.
586 */
587template <typename CppT, typename NarrowT>
588class RColumnElementZigzagSplitLE : public RColumnElementBase {
589protected:
590 explicit RColumnElementZigzagSplitLE(std::size_t size, std::size_t bitsOnStorage)
591 : RColumnElementBase(size, bitsOnStorage)
592 {
593 }
594
595public:
596 static constexpr bool kIsMappable = false;
597
598 void Pack(void *dst, const void *src, std::size_t count) const final
599 {
601 }
602 void Unpack(void *dst, const void *src, std::size_t count) const final
603 {
605 }
606}; // class RColumnElementZigzagSplitLE
607
608////////////////////////////////////////////////////////////////////////////////
609// Pairs of C++ type and column type, like float and ENTupleColumnType::kReal32
610////////////////////////////////////////////////////////////////////////////////
611
612////////////////////////////////////////////////////////////////////////////////
613// Part 1: C++ type --> unknown column type
614////////////////////////////////////////////////////////////////////////////////
615
616template <typename CppT, ENTupleColumnType ColumnT = ENTupleColumnType::kUnknown>
617class RColumnElement : public RColumnElementBase {
618public:
619 RColumnElement() : RColumnElementBase(sizeof(CppT))
620 {
621 throw ROOT::RException(R__FAIL(std::string("internal error: no column mapping for this C++ type: ") +
622 typeid(CppT).name() + " --> " + GetColumnTypeName(ColumnT)));
623 }
624
625 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(CppT), ENTupleColumnType::kUnknown}; }
626};
627
628template <>
629class RColumnElement<bool, ENTupleColumnType::kUnknown> : public RColumnElementBase {
630public:
631 static constexpr std::size_t kSize = sizeof(bool);
632 RColumnElement() : RColumnElementBase(kSize) {}
633 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(bool), ENTupleColumnType::kUnknown}; }
634};
635
636template <>
637class RColumnElement<std::byte, ENTupleColumnType::kUnknown> : public RColumnElementBase {
638public:
639 static constexpr std::size_t kSize = sizeof(std::byte);
640 RColumnElement() : RColumnElementBase(kSize) {}
641 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::byte), ENTupleColumnType::kUnknown}; }
642};
643
644template <>
645class RColumnElement<char, ENTupleColumnType::kUnknown> : public RColumnElementBase {
646public:
647 static constexpr std::size_t kSize = sizeof(char);
648 RColumnElement() : RColumnElementBase(kSize) {}
649 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(char), ENTupleColumnType::kUnknown}; }
650};
651
652template <>
653class RColumnElement<std::int8_t, ENTupleColumnType::kUnknown> : public RColumnElementBase {
654public:
655 static constexpr std::size_t kSize = sizeof(std::int8_t);
656 RColumnElement() : RColumnElementBase(kSize) {}
657 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::int8_t), ENTupleColumnType::kUnknown}; }
658};
659
660template <>
661class RColumnElement<std::uint8_t, ENTupleColumnType::kUnknown> : public RColumnElementBase {
662public:
663 static constexpr std::size_t kSize = sizeof(std::uint8_t);
664 RColumnElement() : RColumnElementBase(kSize) {}
665 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::uint8_t), ENTupleColumnType::kUnknown}; }
666};
667
668template <>
669class RColumnElement<std::int16_t, ENTupleColumnType::kUnknown> : public RColumnElementBase {
670public:
671 static constexpr std::size_t kSize = sizeof(std::int16_t);
672 RColumnElement() : RColumnElementBase(kSize) {}
673 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::int16_t), ENTupleColumnType::kUnknown}; }
674};
675
676template <>
677class RColumnElement<std::uint16_t, ENTupleColumnType::kUnknown> : public RColumnElementBase {
678public:
679 static constexpr std::size_t kSize = sizeof(std::uint16_t);
680 RColumnElement() : RColumnElementBase(kSize) {}
681 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::uint16_t), ENTupleColumnType::kUnknown}; }
682};
683
684template <>
685class RColumnElement<std::int32_t, ENTupleColumnType::kUnknown> : public RColumnElementBase {
686public:
687 static constexpr std::size_t kSize = sizeof(std::int32_t);
688 RColumnElement() : RColumnElementBase(kSize) {}
689 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::int32_t), ENTupleColumnType::kUnknown}; }
690};
691
692template <>
693class RColumnElement<std::uint32_t, ENTupleColumnType::kUnknown> : public RColumnElementBase {
694public:
695 static constexpr std::size_t kSize = sizeof(std::uint32_t);
696 RColumnElement() : RColumnElementBase(kSize) {}
697 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::uint32_t), ENTupleColumnType::kUnknown}; }
698};
699
700template <>
701class RColumnElement<std::int64_t, ENTupleColumnType::kUnknown> : public RColumnElementBase {
702public:
703 static constexpr std::size_t kSize = sizeof(std::int64_t);
704 RColumnElement() : RColumnElementBase(kSize) {}
705 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::int64_t), ENTupleColumnType::kUnknown}; }
706};
707
708template <>
709class RColumnElement<std::uint64_t, ENTupleColumnType::kUnknown> : public RColumnElementBase {
710public:
711 static constexpr std::size_t kSize = sizeof(std::uint64_t);
712 RColumnElement() : RColumnElementBase(kSize) {}
713 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(std::uint64_t), ENTupleColumnType::kUnknown}; }
714};
715
716template <>
717class RColumnElement<float, ENTupleColumnType::kUnknown> : public RColumnElementBase {
718public:
719 static constexpr std::size_t kSize = sizeof(float);
720 RColumnElement() : RColumnElementBase(kSize) {}
721 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(float), ENTupleColumnType::kUnknown}; }
722};
723
724template <>
725class RColumnElement<double, ENTupleColumnType::kUnknown> : public RColumnElementBase {
726public:
727 static constexpr std::size_t kSize = sizeof(double);
728 RColumnElement() : RColumnElementBase(kSize) {}
729 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(double), ENTupleColumnType::kUnknown}; }
730};
731
732template <>
733class RColumnElement<ROOT::Internal::RColumnIndex, ENTupleColumnType::kUnknown> : public RColumnElementBase {
734public:
735 static constexpr std::size_t kSize = sizeof(ROOT::Internal::RColumnIndex);
736 RColumnElement() : RColumnElementBase(kSize) {}
737 RIdentifier GetIdentifier() const final
738 {
739 return RIdentifier{typeid(ROOT::Internal::RColumnIndex), ENTupleColumnType::kUnknown};
740 }
741};
742
743template <>
744class RColumnElement<ROOT::Internal::RColumnSwitch, ENTupleColumnType::kUnknown> : public RColumnElementBase {
745public:
746 static constexpr std::size_t kSize = sizeof(ROOT::Internal::RColumnSwitch);
747 RColumnElement() : RColumnElementBase(kSize) {}
748 RIdentifier GetIdentifier() const final
749 {
750 return RIdentifier{typeid(ROOT::Internal::RColumnSwitch), ENTupleColumnType::kUnknown};
751 }
752};
753
754////////////////////////////////////////////////////////////////////////////////
755// Part 2: C++ type --> supported column representations,
756// ordered by C++ type
757////////////////////////////////////////////////////////////////////////////////
758
759template <>
760class RColumnElement<ROOT::Internal::RColumnSwitch, ENTupleColumnType::kSwitch> : public RColumnElementBase {
761private:
762 struct RSwitchElement {
763 std::uint64_t fIndex;
764 std::uint32_t fTag;
765 };
766
767public:
768 static constexpr bool kIsMappable = false;
769 static constexpr std::size_t kSize = sizeof(ROOT::Internal::RColumnSwitch);
770 static constexpr std::size_t kBitsOnStorage = 96;
771 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
772 bool IsMappable() const final { return kIsMappable; }
773
774 void Pack(void *dst, const void *src, std::size_t count) const final
775 {
776 auto srcArray = reinterpret_cast<const ROOT::Internal::RColumnSwitch *>(src);
777 auto dstArray = reinterpret_cast<unsigned char *>(dst);
778 for (std::size_t i = 0; i < count; ++i) {
779 RSwitchElement element{srcArray[i].GetIndex(), srcArray[i].GetTag()};
780#if R__LITTLE_ENDIAN == 0
781 element.fIndex = RByteSwap<8>::bswap(element.fIndex);
783#endif
784 memcpy(dstArray + i * 12, &element, 12);
785 }
786 }
787
788 void Unpack(void *dst, const void *src, std::size_t count) const final
789 {
790 auto srcArray = reinterpret_cast<const unsigned char *>(src);
791 auto dstArray = reinterpret_cast<ROOT::Internal::RColumnSwitch *>(dst);
792 for (std::size_t i = 0; i < count; ++i) {
794 memcpy(&element, srcArray + i * 12, 12);
795#if R__LITTLE_ENDIAN == 0
796 element.fIndex = RByteSwap<8>::bswap(element.fIndex);
798#endif
800 }
801 }
802
803 RIdentifier GetIdentifier() const final
804 {
805 return RIdentifier{typeid(ROOT::Internal::RColumnSwitch), ENTupleColumnType::kSwitch};
806 }
807};
808
809template <>
810class RColumnElement<bool, ENTupleColumnType::kBit> : public RColumnElementBase {
811public:
812 static constexpr bool kIsMappable = false;
813 static constexpr std::size_t kSize = sizeof(bool);
814 static constexpr std::size_t kBitsOnStorage = 1;
815 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
816 bool IsMappable() const final { return kIsMappable; }
817
818 void Pack(void *dst, const void *src, std::size_t count) const final;
819 void Unpack(void *dst, const void *src, std::size_t count) const final;
820
821 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(bool), ENTupleColumnType::kBit}; }
822};
823
824template <>
825class RColumnElement<float, ENTupleColumnType::kReal16> : public RColumnElementBase {
826public:
827 static constexpr bool kIsMappable = false;
828 static constexpr std::size_t kSize = sizeof(float);
829 static constexpr std::size_t kBitsOnStorage = 16;
830 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
831 bool IsMappable() const final { return kIsMappable; }
832
833 void Pack(void *dst, const void *src, std::size_t count) const final
834 {
835 const float *floatArray = reinterpret_cast<const float *>(src);
836 std::uint16_t *uint16Array = reinterpret_cast<std::uint16_t *>(dst);
837
838 for (std::size_t i = 0; i < count; ++i) {
841 }
842 }
843
844 void Unpack(void *dst, const void *src, std::size_t count) const final
845 {
846 float *floatArray = reinterpret_cast<float *>(dst);
847 const std::uint16_t *uint16Array = reinterpret_cast<const std::uint16_t *>(src);
848
849 for (std::size_t i = 0; i < count; ++i) {
850 std::uint16_t val = uint16Array[i];
853 }
854 }
855
856 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(float), ENTupleColumnType::kReal16}; }
857};
858
859template <>
860class RColumnElement<double, ENTupleColumnType::kReal16> : public RColumnElementBase {
861public:
862 static constexpr bool kIsMappable = false;
863 static constexpr std::size_t kSize = sizeof(double);
864 static constexpr std::size_t kBitsOnStorage = 16;
865 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
866 bool IsMappable() const final { return kIsMappable; }
867
868 void Pack(void *dst, const void *src, std::size_t count) const final
869 {
870 const double *doubleArray = reinterpret_cast<const double *>(src);
871 std::uint16_t *uint16Array = reinterpret_cast<std::uint16_t *>(dst);
872
873 for (std::size_t i = 0; i < count; ++i) {
874 uint16Array[i] = ROOT::Internal::FloatToHalf(static_cast<float>(doubleArray[i]));
876 }
877 }
878
879 void Unpack(void *dst, const void *src, std::size_t count) const final
880 {
881 double *doubleArray = reinterpret_cast<double *>(dst);
882 const std::uint16_t *uint16Array = reinterpret_cast<const std::uint16_t *>(src);
883
884 for (std::size_t i = 0; i < count; ++i) {
885 std::uint16_t val = uint16Array[i];
887 doubleArray[i] = static_cast<double>(ROOT::Internal::HalfToFloat(val));
888 }
889 }
890
891 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(double), ENTupleColumnType::kReal16}; }
892};
893
894template <typename T>
895class RColumnElementTrunc : public RColumnElementBase {
896public:
897 static_assert(std::is_floating_point_v<T>);
898 static constexpr bool kIsMappable = false;
899 static constexpr std::size_t kSize = sizeof(T);
900
901 // NOTE: setting bitsOnStorage == 0 by default. This is an invalid value that helps us
902 // catch misuses where RColumnElement is used without having explicitly set its bit width
903 // (which should never happen).
904 RColumnElementTrunc() : RColumnElementBase(kSize, 0) {}
905
906 void SetBitsOnStorage(std::size_t bitsOnStorage) final
907 {
908 const auto &[minBits, maxBits] = GetValidBitRange(ENTupleColumnType::kReal32Trunc);
910 fBitsOnStorage = bitsOnStorage;
911 }
912
913 bool IsMappable() const final { return kIsMappable; }
914
915 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(T), ENTupleColumnType::kReal32Trunc}; }
916};
917
918template <>
919class RColumnElement<float, ENTupleColumnType::kReal32Trunc> : public RColumnElementTrunc<float> {
920public:
921 void Pack(void *dst, const void *src, std::size_t count) const final
922 {
923 using namespace ROOT::Internal::BitPacking;
924
925 R__ASSERT(GetPackedSize(count) == MinBufSize(count, fBitsOnStorage));
926
927#if R__LITTLE_ENDIAN == 0
928 // TODO(gparolini): to avoid this extra allocation we might want to perform byte swapping
929 // directly in the Pack/UnpackBits functions.
930 auto bswapped = MakeUninitArray<float>(count);
932 const auto *srcLe = bswapped.get();
933#else
934 const auto *srcLe = reinterpret_cast<const float *>(src);
935#endif
936 PackBits(dst, srcLe, count, sizeof(float), fBitsOnStorage);
937 }
938
939 void Unpack(void *dst, const void *src, std::size_t count) const final
940 {
941 using namespace ROOT::Internal::BitPacking;
942
943 R__ASSERT(GetPackedSize(count) == MinBufSize(count, fBitsOnStorage));
944
945 UnpackBits(dst, src, count, sizeof(float), fBitsOnStorage);
946#if R__LITTLE_ENDIAN == 0
948#endif
949 }
950};
951
952template <>
953class RColumnElement<double, ENTupleColumnType::kReal32Trunc> : public RColumnElementTrunc<double> {
954public:
955 void Pack(void *dst, const void *src, std::size_t count) const final
956 {
957 using namespace ROOT::Internal::BitPacking;
958
959 R__ASSERT(GetPackedSize(count) == MinBufSize(count, fBitsOnStorage));
960
961 // Cast doubles to float before packing them
962 // TODO(gparolini): avoid this allocation
963 auto srcFloat = MakeUninitArray<float>(count);
964 const double *srcDouble = reinterpret_cast<const double *>(src);
965 for (std::size_t i = 0; i < count; ++i)
966 srcFloat[i] = static_cast<float>(srcDouble[i]);
967
968#if R__LITTLE_ENDIAN == 0
969 // TODO(gparolini): to avoid this extra allocation we might want to perform byte swapping
970 // directly in the Pack/UnpackBits functions.
971 auto bswapped = MakeUninitArray<float>(count);
972 CopyBswap<sizeof(float)>(bswapped.get(), srcFloat.get(), count);
973 const float *srcLe = bswapped.get();
974#else
975 const float *srcLe = reinterpret_cast<const float *>(srcFloat.get());
976#endif
977 PackBits(dst, srcLe, count, sizeof(float), fBitsOnStorage);
978 }
979
980 void Unpack(void *dst, const void *src, std::size_t count) const final
981 {
982 using namespace ROOT::Internal::BitPacking;
983
984 R__ASSERT(GetPackedSize(count) == MinBufSize(count, fBitsOnStorage));
985
986 // TODO(gparolini): avoid this allocation
987 auto dstFloat = MakeUninitArray<float>(count);
988 UnpackBits(dstFloat.get(), src, count, sizeof(float), fBitsOnStorage);
989#if R__LITTLE_ENDIAN == 0
991#endif
992
993 double *dstDouble = reinterpret_cast<double *>(dst);
994 for (std::size_t i = 0; i < count; ++i)
995 dstDouble[i] = static_cast<double>(dstFloat[i]);
996 }
997};
998
999namespace Quantize {
1000
1001using Quantized_t = std::uint32_t;
1002
1003[[maybe_unused]] inline std::size_t LeadingZeroes(std::uint32_t x)
1004{
1005 if (x == 0)
1006 return 32;
1007
1008#ifdef _MSC_VER
1009 unsigned long idx = 0;
1010 if (_BitScanReverse(&idx, x))
1011 return static_cast<std::size_t>(31 - idx);
1012 return 32;
1013#else
1014 return static_cast<std::size_t>(__builtin_clz(x));
1015#endif
1016}
1017
1018[[maybe_unused]] inline std::size_t TrailingZeroes(std::uint32_t x)
1019{
1020 if (x == 0)
1021 return 32;
1022
1023#ifdef _MSC_VER
1024 unsigned long idx = 0;
1025 if (_BitScanForward(&idx, x))
1026 return static_cast<std::size_t>(idx);
1027 return 32;
1028#else
1029 return static_cast<std::size_t>(__builtin_ctz(x));
1030#endif
1031}
1032
1033/// Converts the array `src` of `count` floating point numbers into an array of their quantized representations.
1034/// Each element of `src` is assumed to be in the inclusive range [min, max].
1035/// The quantized representation will consist of unsigned integers of at most `nQuantBits` (with `nQuantBits <= 8 *
1036/// sizeof(Quantized_t)`). The unused bits are kept in the LSB of the quantized integers, to allow for easy bit packing
1037/// of those integers via BitPacking::PackBits().
1038/// \return The number of values in `src` that were found to be out of range (0 means all values were in range).
1039template <typename T>
1040int QuantizeReals(Quantized_t *dst, const T *src, std::size_t count, double min, double max, std::size_t nQuantBits)
1041{
1042 static_assert(std::is_floating_point_v<T>);
1043 static_assert(sizeof(T) <= sizeof(double));
1044 assert(1 <= nQuantBits && nQuantBits <= 8 * sizeof(Quantized_t));
1045
1046 // `min` and `max` are supposed to be exactly representable by type `T` because we cast them to `T` in
1047 // SetQuantized().
1048 assert(min == static_cast<double>(static_cast<T>(min)));
1049 assert(max == static_cast<double>(static_cast<T>(max)));
1050
1051 const std::size_t quantMax = (1ull << nQuantBits) - 1;
1052 const double scale = quantMax / (max - min);
1053 const std::size_t unusedBits = sizeof(Quantized_t) * 8 - nQuantBits;
1054
1055 int nOutOfRange = 0;
1056
1057 for (std::size_t i = 0; i < count; ++i) {
1058 const T elem = src[i];
1059
1060 bool outOfRange = !(min <= elem && elem <= max);
1062
1063 const double e = 0.5 + (elem - min) * scale;
1064 Quantized_t q = static_cast<Quantized_t>(e);
1066
1067 // double-check we actually used at most `nQuantBits`
1069
1070 // we want to leave zeroes in the LSB, not the MSB, because we'll then drop the LSB
1071 // when bit packing.
1072 dst[i] = q << unusedBits;
1073 }
1074
1075 return nOutOfRange;
1076}
1077
1078/// Undoes the transformation performed by QuantizeReals() (assuming the same `count`, `min`, `max` and `nQuantBits`).
1079/// \return The number of unpacked values that were found to be out of range (0 means all values were in range).
1080template <typename T>
1081int UnquantizeReals(T *dst, const Quantized_t *src, std::size_t count, double min, double max, std::size_t nQuantBits)
1082{
1083 static_assert(std::is_floating_point_v<T>);
1084 static_assert(sizeof(T) <= sizeof(double));
1085 assert(1 <= nQuantBits && nQuantBits <= 8 * sizeof(Quantized_t));
1086
1087 const std::size_t quantMax = (1ull << nQuantBits) - 1;
1088 const double scale = (max - min) / quantMax;
1089 const std::size_t unusedBits = sizeof(Quantized_t) * 8 - nQuantBits;
1090 const double eps = std::numeric_limits<double>::epsilon();
1091 const double emax = max + std::max(1.0, std::abs(max)) * eps;
1092
1093 int nOutOfRange = 0;
1094
1095 for (std::size_t i = 0; i < count; ++i) {
1096 Quantized_t elem = src[i];
1097 // Undo the LSB-preserving shift performed by QuantizeReals
1099 elem >>= unusedBits;
1101
1102 const double fq = static_cast<double>(elem);
1103 double e = fq * scale + min;
1104
1105 // NOTE: `e` must be greater or equal than precisely `min` because the min value is represented
1106 // by a quantized value of 0, meaning there is no floating point error accumulation coming from
1107 // `e = fq * scale + min` (as it just becomes `e = min`).
1108 // For the max value, however, some error is introduced by the operation, therefore we allow for
1109 // some leeway in the out of range check.
1110 nOutOfRange += !(min <= e && e <= emax);
1111
1112 // Since we want to guarantee that the out value is always within `min` and `max`,
1113 // after the bounds check we clamp the value to the stored `max`.
1114 e = std::min(e, max);
1115
1116 dst[i] = static_cast<T>(e);
1117 }
1118
1119 return nOutOfRange;
1120}
1121} // namespace Quantize
1122
1123template <typename T>
1124class RColumnElementQuantized : public RColumnElementBase {
1125 static_assert(std::is_floating_point_v<T>);
1126
1127public:
1128 static constexpr bool kIsMappable = false;
1129 static constexpr std::size_t kSize = sizeof(T);
1130
1131 RColumnElementQuantized() : RColumnElementBase(kSize, 0) {}
1132
1133 void SetBitsOnStorage(std::size_t bitsOnStorage) final
1134 {
1135 const auto [minBits, maxBits] = GetValidBitRange(ENTupleColumnType::kReal32Quant);
1137 fBitsOnStorage = bitsOnStorage;
1138 }
1139
1140 void SetValueRange(double min, double max) final
1141 {
1142 R__ASSERT(min >= std::numeric_limits<T>::lowest());
1143 R__ASSERT(max <= std::numeric_limits<T>::max());
1144 // Disallow denormal, NaN and infinity
1145 R__ASSERT(std::isnormal(min) || min == 0.0);
1146 R__ASSERT(std::isnormal(max) || max == 0.0);
1147 fValueRange = {min, max};
1148 }
1149
1150 bool IsMappable() const final { return kIsMappable; }
1151
1152 void Pack(void *dst, const void *src, std::size_t count) const final
1153 {
1154 using namespace ROOT::Internal;
1155
1156 // TODO(gparolini): see if we can avoid this allocation
1158 assert(fValueRange);
1159 const auto [min, max] = *fValueRange;
1160 const int nOutOfRange =
1161 Quantize::QuantizeReals(quantized.get(), reinterpret_cast<const T *>(src), count, min, max, fBitsOnStorage);
1162 if (nOutOfRange) {
1163 throw ROOT::RException(R__FAIL(std::to_string(nOutOfRange) +
1164 " values were found of of range for quantization while packing (range is [" +
1165 std::to_string(min) + ", " + std::to_string(max) + "])"));
1166 }
1167 BitPacking::PackBits(dst, quantized.get(), count, sizeof(Quantize::Quantized_t), fBitsOnStorage);
1168 }
1169
1170 void Unpack(void *dst, const void *src, std::size_t count) const final
1171 {
1172 using namespace ROOT::Internal;
1173
1174 // TODO(gparolini): see if we can avoid this allocation
1176 assert(fValueRange);
1177 const auto [min, max] = *fValueRange;
1178 BitPacking::UnpackBits(quantized.get(), src, count, sizeof(Quantize::Quantized_t), fBitsOnStorage);
1179 [[maybe_unused]] const int nOutOfRange =
1180 Quantize::UnquantizeReals(reinterpret_cast<T *>(dst), quantized.get(), count, min, max, fBitsOnStorage);
1181 // NOTE: here, differently from Pack(), we don't ever expect to have values out of range, since the quantized
1182 // integers we pass to UnquantizeReals are by construction limited in value to the proper range. In Pack()
1183 // this is not the case, as the user may give us float values that are out of range.
1184 assert(nOutOfRange == 0);
1185 }
1186
1187 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(T), ENTupleColumnType::kReal32Quant}; }
1188};
1189
1190template <>
1191class RColumnElement<float, ENTupleColumnType::kReal32Quant> : public RColumnElementQuantized<float> {};
1192
1193template <>
1194class RColumnElement<double, ENTupleColumnType::kReal32Quant> : public RColumnElementQuantized<double> {};
1195
1196#define __RCOLUMNELEMENT_SPEC_BODY(CppT, ColumnT, BaseT, BitsOnStorage) \
1197 static constexpr std::size_t kSize = sizeof(CppT); \
1198 static constexpr std::size_t kBitsOnStorage = BitsOnStorage; \
1199 RColumnElement() : BaseT(kSize, kBitsOnStorage) {} \
1200 bool IsMappable() const final \
1201 { \
1202 return kIsMappable; \
1203 } \
1204 RIdentifier GetIdentifier() const final \
1205 { \
1206 return RIdentifier{typeid(CppT), ColumnT}; \
1207 }
1208/// These macros are used to declare `RColumnElement` template specializations below. Additional arguments can be used
1209/// to forward template parameters to the base class, e.g.
1210/// ```
1211/// DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt32, 32,
1212/// RColumnElementCastLE, <std::int64_t, std::int32_t>);
1213/// ```
1214#define DECLARE_RCOLUMNELEMENT_SPEC(CppT, ColumnT, BitsOnStorage, BaseT, ...) \
1215 template <> \
1216 class RColumnElement<CppT, ColumnT> : public BaseT __VA_ARGS__ { \
1217 public: \
1218 __RCOLUMNELEMENT_SPEC_BODY(CppT, ColumnT, BaseT, BitsOnStorage) \
1219 }
1220#define DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(CppT, ColumnT, BitsOnStorage) \
1221 template <> \
1222 class RColumnElement<CppT, ColumnT> : public RColumnElementBase { \
1223 public: \
1224 static constexpr bool kIsMappable = true; \
1225 __RCOLUMNELEMENT_SPEC_BODY(CppT, ColumnT, RColumnElementBase, BitsOnStorage) \
1226 }
1227
1228DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kChar, 8, RColumnElementBoolAsUnsplitInt, <char>);
1229DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kInt8, 8, RColumnElementBoolAsUnsplitInt, <std::int8_t>);
1230DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kUInt8, 8, RColumnElementBoolAsUnsplitInt, <std::uint8_t>);
1231DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kInt16, 16, RColumnElementBoolAsUnsplitInt, <std::int16_t>);
1232DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kUInt16, 16, RColumnElementBoolAsUnsplitInt, <std::uint16_t>);
1233DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kInt32, 32, RColumnElementBoolAsUnsplitInt, <std::int32_t>);
1234DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kUInt32, 32, RColumnElementBoolAsUnsplitInt, <std::uint32_t>);
1235DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kInt64, 64, RColumnElementBoolAsUnsplitInt, <std::int64_t>);
1236DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kUInt64, 64, RColumnElementBoolAsUnsplitInt, <std::uint64_t>);
1237DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitInt16, 16, RColumnElementBoolAsSplitInt, <std::int16_t>);
1238DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitUInt16, 16, RColumnElementBoolAsSplitInt, <std::uint16_t>);
1239DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitInt32, 32, RColumnElementBoolAsSplitInt, <std::int32_t>);
1240DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitUInt32, 32, RColumnElementBoolAsSplitInt, <std::uint32_t>);
1241DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitInt64, 64, RColumnElementBoolAsSplitInt, <std::int64_t>);
1242DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitUInt64, 64, RColumnElementBoolAsSplitInt, <std::uint64_t>);
1243
1244DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::byte, ENTupleColumnType::kByte, 8);
1245
1246DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(char, ENTupleColumnType::kChar, 8);
1247DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kInt8, 8, RColumnElementCastLE, <char, std::int8_t>);
1248DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE, <char, std::uint8_t>);
1249DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kInt16, 16, RColumnElementCastLE, <char, std::int16_t>);
1250DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE, <char, std::uint16_t>);
1251DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kInt32, 32, RColumnElementCastLE, <char, std::int32_t>);
1252DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE, <char, std::uint32_t>);
1253DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kInt64, 64, RColumnElementCastLE, <char, std::int64_t>);
1254DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE, <char, std::uint64_t>);
1255DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1256 <char, std::int16_t>);
1257DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE, <char, std::uint16_t>);
1258DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1259 <char, std::int32_t>);
1260DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE, <char, std::uint32_t>);
1261DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1262 <char, std::int64_t>);
1263DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE, <char, std::uint64_t>);
1264DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <char>);
1265
1266DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::int8_t, ENTupleColumnType::kInt8, 8);
1267DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::int8_t, char>);
1268DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1269 <std::int8_t, std::uint8_t>);
1270DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1271 <std::int8_t, std::int16_t>);
1272DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1273 <std::int8_t, std::uint16_t>);
1274DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1275 <std::int8_t, std::int32_t>);
1276DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1277 <std::int8_t, std::uint32_t>);
1278DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1279 <std::int8_t, std::int64_t>);
1280DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1281 <std::int8_t, std::uint64_t>);
1282DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1283 <std::int8_t, std::int16_t>);
1284DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1285 <std::int8_t, std::uint16_t>);
1286DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1287 <std::int8_t, std::int32_t>);
1288DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1289 <std::int8_t, std::uint32_t>);
1290DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1291 <std::int8_t, std::int64_t>);
1292DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1293 <std::int8_t, std::uint64_t>);
1294DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::int8_t>);
1295
1296DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::uint8_t, ENTupleColumnType::kUInt8, 8);
1297DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::uint8_t, char>);
1298DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1299 <std::uint8_t, std::int8_t>);
1300DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1301 <std::uint8_t, std::int16_t>);
1302DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1303 <std::uint8_t, std::uint16_t>);
1304DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1305 <std::uint8_t, std::int32_t>);
1306DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1307 <std::uint8_t, std::uint32_t>);
1308DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1309 <std::uint8_t, std::int64_t>);
1310DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1311 <std::uint8_t, std::uint64_t>);
1312DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1313 <std::uint8_t, std::int16_t>);
1314DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1315 <std::uint8_t, std::uint16_t>);
1316DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1317 <std::uint8_t, std::int32_t>);
1318DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1319 <std::uint8_t, std::uint32_t>);
1320DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1321 <std::uint8_t, std::int64_t>);
1322DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1323 <std::uint8_t, std::uint64_t>);
1324DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::uint8_t>);
1325
1326DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kInt16, 16, RColumnElementLE, <std::int16_t>);
1327DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1328 <std::int16_t, std::int16_t>);
1329DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::int16_t, char>);
1330DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1331 <std::int16_t, std::int8_t>);
1332DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1333 <std::int16_t, std::uint8_t>);
1334DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1335 <std::int16_t, std::uint16_t>);
1336DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1337 <std::int16_t, std::int32_t>);
1338DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1339 <std::int16_t, std::uint32_t>);
1340DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1341 <std::int16_t, std::int64_t>);
1342DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1343 <std::int16_t, std::uint64_t>);
1344DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1345 <std::int16_t, std::uint16_t>);
1346DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1347 <std::int16_t, std::int32_t>);
1348DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1349 <std::int16_t, std::uint32_t>);
1350DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1351 <std::int16_t, std::int64_t>);
1352DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1353 <std::int16_t, std::uint64_t>);
1354DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::int16_t>);
1355
1356DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kUInt16, 16, RColumnElementLE, <std::uint16_t>);
1357DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1358 <std::uint16_t, std::uint16_t>);
1359DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::uint16_t, char>);
1360DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1361 <std::uint16_t, std::int8_t>);
1362DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1363 <std::uint16_t, std::uint8_t>);
1364DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1365 <std::uint16_t, std::int16_t>);
1366DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1367 <std::uint16_t, std::int32_t>);
1368DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1369 <std::uint16_t, std::uint32_t>);
1370DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1371 <std::uint16_t, std::int64_t>);
1372DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1373 <std::uint16_t, std::uint64_t>);
1374DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1375 <std::uint16_t, std::int16_t>);
1376DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1377 <std::uint16_t, std::int32_t>);
1378DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1379 <std::uint16_t, std::uint32_t>);
1380DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1381 <std::uint16_t, std::int64_t>);
1382DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1383 <std::uint16_t, std::uint64_t>);
1384DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::uint16_t>);
1385
1386DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kInt32, 32, RColumnElementLE, <std::int32_t>);
1387DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1388 <std::int32_t, std::int32_t>);
1389DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::int32_t, char>);
1390DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1391 <std::int32_t, std::int8_t>);
1392DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1393 <std::int32_t, std::uint8_t>);
1394DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1395 <std::int32_t, std::int16_t>);
1396DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1397 <std::int32_t, std::uint16_t>);
1398DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1399 <std::int32_t, std::uint32_t>);
1400DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1401 <std::int32_t, std::int64_t>);
1402DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1403 <std::int32_t, std::uint64_t>);
1404DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1405 <std::int32_t, std::int16_t>);
1406DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1407 <std::int32_t, std::uint16_t>);
1408DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1409 <std::int32_t, std::uint32_t>);
1410DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1411 <std::int32_t, std::int64_t>);
1412DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1413 <std::int32_t, std::uint64_t>);
1414DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::int32_t>);
1415
1416DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kUInt32, 32, RColumnElementLE, <std::uint32_t>);
1417DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1418 <std::uint32_t, std::uint32_t>);
1419DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::uint32_t, char>);
1420DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1421 <std::uint32_t, std::int8_t>);
1422DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1423 <std::uint32_t, std::uint8_t>);
1424DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1425 <std::uint32_t, std::int16_t>);
1426DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1427 <std::uint32_t, std::uint16_t>);
1428DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1429 <std::uint32_t, std::int32_t>);
1430DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1431 <std::uint32_t, std::int64_t>);
1432DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1433 <std::uint32_t, std::uint64_t>);
1434DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1435 <std::uint32_t, std::int16_t>);
1436DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1437 <std::uint32_t, std::uint16_t>);
1438DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1439 <std::uint32_t, std::int32_t>);
1440DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1441 <std::uint32_t, std::int64_t>);
1442DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1443 <std::uint32_t, std::uint64_t>);
1444DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::uint32_t>);
1445
1446DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt64, 64, RColumnElementLE, <std::int64_t>);
1447DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1448 <std::int64_t, std::int64_t>);
1449DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::int64_t, char>);
1450DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1451 <std::int64_t, std::int8_t>);
1452DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1453 <std::int64_t, std::uint8_t>);
1454DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1455 <std::int64_t, std::int16_t>);
1456DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1457 <std::int64_t, std::uint16_t>);
1458DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1459 <std::int64_t, std::int32_t>);
1460DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1461 <std::int64_t, std::uint32_t>);
1462DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1463 <std::int64_t, std::uint64_t>);
1464DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1465 <std::int64_t, std::int16_t>);
1466DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1467 <std::int64_t, std::uint16_t>);
1468DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1469 <std::int64_t, std::int32_t>);
1470DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1471 <std::int64_t, std::uint32_t>);
1472DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1473 <std::int64_t, std::uint64_t>);
1474DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::int64_t>);
1475
1476DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kUInt64, 64, RColumnElementLE, <std::uint64_t>);
1477DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1478 <std::uint64_t, std::uint64_t>);
1479DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::uint64_t, char>);
1480DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1481 <std::uint64_t, std::int8_t>);
1482DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1483 <std::uint64_t, std::uint8_t>);
1484DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1485 <std::uint64_t, std::int16_t>);
1486DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1487 <std::uint64_t, std::uint16_t>);
1488DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1489 <std::uint64_t, std::int32_t>);
1490DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1491 <std::uint64_t, std::uint32_t>);
1492DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1493 <std::uint64_t, std::int64_t>);
1494DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1495 <std::uint64_t, std::int16_t>);
1496DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1497 <std::uint64_t, std::uint16_t>);
1498DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1499 <std::uint64_t, std::int32_t>);
1500DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1501 <std::uint64_t, std::uint32_t>);
1502DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1503 <std::uint64_t, std::int64_t>);
1504DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::uint64_t>);
1505
1506DECLARE_RCOLUMNELEMENT_SPEC(float, ENTupleColumnType::kReal32, 32, RColumnElementLE, <float>);
1507DECLARE_RCOLUMNELEMENT_SPEC(float, ENTupleColumnType::kSplitReal32, 32, RColumnElementSplitLE, <float, float>);
1508DECLARE_RCOLUMNELEMENT_SPEC(float, ENTupleColumnType::kReal64, 64, RColumnElementCastLE, <float, double>);
1509DECLARE_RCOLUMNELEMENT_SPEC(float, ENTupleColumnType::kSplitReal64, 64, RColumnElementSplitLE, <float, double>);
1510
1511DECLARE_RCOLUMNELEMENT_SPEC(double, ENTupleColumnType::kReal64, 64, RColumnElementLE, <double>);
1512DECLARE_RCOLUMNELEMENT_SPEC(double, ENTupleColumnType::kSplitReal64, 64, RColumnElementSplitLE, <double, double>);
1513DECLARE_RCOLUMNELEMENT_SPEC(double, ENTupleColumnType::kReal32, 32, RColumnElementCastLE, <double, float>);
1514DECLARE_RCOLUMNELEMENT_SPEC(double, ENTupleColumnType::kSplitReal32, 32, RColumnElementSplitLE, <double, float>);
1515
1516DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Internal::RColumnIndex, ENTupleColumnType::kIndex64, 64, RColumnElementLE,
1517 <std::uint64_t>);
1518DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Internal::RColumnIndex, ENTupleColumnType::kIndex32, 32, RColumnElementCastLE,
1519 <std::uint64_t, std::uint32_t>);
1520DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Internal::RColumnIndex, ENTupleColumnType::kSplitIndex64, 64,
1521 RColumnElementDeltaSplitLE, <std::uint64_t, std::uint64_t>);
1522DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Internal::RColumnIndex, ENTupleColumnType::kSplitIndex32, 32,
1523 RColumnElementDeltaSplitLE, <std::uint64_t, std::uint32_t>);
1524
1525template <>
1526class RColumnElement<ROOT::Internal::RTestFutureColumn, kTestFutureColumnType> final : public RColumnElementBase {
1527public:
1528 static constexpr bool kIsMappable = false;
1529 static constexpr std::size_t kSize = sizeof(ROOT::Internal::RTestFutureColumn);
1530 static constexpr std::size_t kBitsOnStorage = kSize * 8;
1531 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
1532
1533 bool IsMappable() const final { return kIsMappable; }
1534 void Pack(void *, const void *, std::size_t) const final {}
1535 void Unpack(void *, const void *, std::size_t) const final {}
1536
1537 RIdentifier GetIdentifier() const final
1538 {
1539 return RIdentifier{typeid(ROOT::Internal::RTestFutureColumn), kTestFutureColumnType};
1540 }
1541};
1542
1543inline void
1544RColumnElement<bool, ROOT::ENTupleColumnType::kBit>::Pack(void *dst, const void *src, std::size_t count) const
1545{
1546 const bool *boolArray = reinterpret_cast<const bool *>(src);
1547 char *charArray = reinterpret_cast<char *>(dst);
1548 std::bitset<8> bitSet;
1549 std::size_t i = 0;
1550 for (; i < count; ++i) {
1551 bitSet.set(i % 8, boolArray[i]);
1552 if (i % 8 == 7) {
1553 char packed = bitSet.to_ulong();
1554 charArray[i / 8] = packed;
1555 }
1556 }
1557 if (i % 8 != 0) {
1558 char packed = bitSet.to_ulong();
1559 charArray[i / 8] = packed;
1560 }
1561}
1562
1563inline void
1564RColumnElement<bool, ROOT::ENTupleColumnType::kBit>::Unpack(void *dst, const void *src, std::size_t count) const
1565{
1566 bool *boolArray = reinterpret_cast<bool *>(dst);
1567 const char *charArray = reinterpret_cast<const char *>(src);
1568 std::bitset<8> bitSet;
1569 for (std::size_t i = 0; i < count; i += 8) {
1570 bitSet = charArray[i / 8];
1571 for (std::size_t j = i; j < std::min(count, i + 8); ++j) {
1572 boolArray[j] = bitSet[j % 8];
1573 }
1574 }
1575}
1576
1577} // namespace
#define R__LITTLE_ENDIAN
#define DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(CppT, ColumnT, BitsOnStorage)
#define DECLARE_RCOLUMNELEMENT_SPEC(CppT, ColumnT, BitsOnStorage, BaseT,...)
These macros are used to declare RColumnElement template specializations below.
#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:300
#define b(i)
Definition RSha256.hxx:100
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
#define N
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
char name[80]
Definition TGX11.cxx:110
float * q
@ kSize
Definition TStructNode.h:26
@ kUnknown
Definition TStructNode.h:19
The available trivial, native content types of a column.
A column element encapsulates the translation between basic C++ types and their column representation...
The in-memory representation of a 32bit or 64bit on-disk index column.
Holds the index and the tag of a kSwitch column.
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
Double_t x[n]
Definition legend1.C:17
void PackBits(void *dst, const void *src, std::size_t count, std::size_t sizeofSrc, std::size_t nDstBits)
Tightly packs count items of size sizeofSrc contained in src into dst using nDstBits per item.
constexpr std::size_t MinBufSize(std::size_t count, std::size_t nDstBits)
Returns the minimum safe size (in bytes) of a buffer that is intended to be used as a destination for...
void UnpackBits(void *dst, const void *src, std::size_t count, std::size_t sizeofDst, std::size_t nSrcBits)
Undoes the effect of PackBits.
constexpr std::size_t kBitsPerWord
std::uint16_t FloatToHalf(float value)
Convert an IEEE single-precision float to half-precision.
Definition RFloat16.hxx:95
std::unique_ptr< T[]> MakeUninitArray(std::size_t size)
Make an array of default-initialized elements.
constexpr ENTupleColumnType kTestFutureColumnType
float HalfToFloat(std::uint16_t value)
Convert an IEEE half-precision float to single-precision.
Definition RFloat16.hxx:131
Helper templated class for swapping bytes; specializations for N={2,4,8} are provided below.
Definition Byteswap.h:124
unsigned char byte
Definition gifdecode.c:10