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 PackBits(dst, src, count, sizeof(float), fBitsOnStorage);
928 }
929
930 void Unpack(void *dst, const void *src, std::size_t count) const final
931 {
932 using namespace ROOT::Internal::BitPacking;
933
934 R__ASSERT(GetPackedSize(count) == MinBufSize(count, fBitsOnStorage));
935
936 UnpackBits(dst, src, count, sizeof(float), fBitsOnStorage);
937 }
938};
939
940template <>
941class RColumnElement<double, ENTupleColumnType::kReal32Trunc> : public RColumnElementTrunc<double> {
942public:
943 void Pack(void *dst, const void *src, std::size_t count) const final
944 {
945 using namespace ROOT::Internal::BitPacking;
946
947 R__ASSERT(GetPackedSize(count) == MinBufSize(count, fBitsOnStorage));
948
949 // Cast doubles to float before packing them
950 // TODO(gparolini): avoid this allocation
951 auto srcFloat = MakeUninitArray<float>(count);
952 const double *srcDouble = reinterpret_cast<const double *>(src);
953 for (std::size_t i = 0; i < count; ++i)
954 srcFloat[i] = static_cast<float>(srcDouble[i]);
955
956 PackBits(dst, reinterpret_cast<const float *>(srcFloat.get()), count, sizeof(float), fBitsOnStorage);
957 }
958
959 void Unpack(void *dst, const void *src, std::size_t count) const final
960 {
961 using namespace ROOT::Internal::BitPacking;
962
963 R__ASSERT(GetPackedSize(count) == MinBufSize(count, fBitsOnStorage));
964
965 // TODO(gparolini): avoid this allocation
966 auto dstFloat = MakeUninitArray<float>(count);
967 UnpackBits(dstFloat.get(), src, count, sizeof(float), fBitsOnStorage);
968
969 double *dstDouble = reinterpret_cast<double *>(dst);
970 for (std::size_t i = 0; i < count; ++i)
971 dstDouble[i] = static_cast<double>(dstFloat[i]);
972 }
973};
974
975namespace Quantize {
976
977using Quantized_t = std::uint32_t;
978
979[[maybe_unused]] inline std::size_t LeadingZeroes(std::uint32_t x)
980{
981 if (x == 0)
982 return 32;
983
984#ifdef _MSC_VER
985 unsigned long idx = 0;
986 if (_BitScanReverse(&idx, x))
987 return static_cast<std::size_t>(31 - idx);
988 return 32;
989#else
990 return static_cast<std::size_t>(__builtin_clz(x));
991#endif
992}
993
994[[maybe_unused]] inline std::size_t TrailingZeroes(std::uint32_t x)
995{
996 if (x == 0)
997 return 32;
998
999#ifdef _MSC_VER
1000 unsigned long idx = 0;
1001 if (_BitScanForward(&idx, x))
1002 return static_cast<std::size_t>(idx);
1003 return 32;
1004#else
1005 return static_cast<std::size_t>(__builtin_ctz(x));
1006#endif
1007}
1008
1009/// Converts the array `src` of `count` floating point numbers into an array of their quantized representations.
1010/// Each element of `src` is assumed to be in the inclusive range [min, max].
1011/// The quantized representation will consist of unsigned integers of at most `nQuantBits` (with `nQuantBits <= 8 *
1012/// sizeof(Quantized_t)`). The unused bits are kept in the LSB of the quantized integers, to allow for easy bit packing
1013/// of those integers via BitPacking::PackBits().
1014/// \return The number of values in `src` that were found to be out of range (0 means all values were in range).
1015template <typename T>
1016int QuantizeReals(Quantized_t *dst, const T *src, std::size_t count, double min, double max, std::size_t nQuantBits)
1017{
1018 static_assert(std::is_floating_point_v<T>);
1019 static_assert(sizeof(T) <= sizeof(double));
1020 assert(1 <= nQuantBits && nQuantBits <= 8 * sizeof(Quantized_t));
1021
1022 // `min` and `max` are supposed to be exactly representable by type `T` because we cast them to `T` in
1023 // SetQuantized().
1024 assert(min == static_cast<double>(static_cast<T>(min)));
1025 assert(max == static_cast<double>(static_cast<T>(max)));
1026
1027 const std::size_t quantMax = (1ull << nQuantBits) - 1;
1028 const double scale = quantMax / (max - min);
1029 const std::size_t unusedBits = sizeof(Quantized_t) * 8 - nQuantBits;
1030
1031 int nOutOfRange = 0;
1032
1033 for (std::size_t i = 0; i < count; ++i) {
1034 const T elem = src[i];
1035
1036 bool outOfRange = !(min <= elem && elem <= max);
1038
1039 const double e = 0.5 + (elem - min) * scale;
1040 Quantized_t q = static_cast<Quantized_t>(e);
1041
1042 // double-check we actually used at most `nQuantBits`
1044
1045 // we want to leave zeroes in the LSB, not the MSB, because we'll then drop the LSB
1046 // when bit packing.
1047 dst[i] = q << unusedBits;
1048 }
1049
1050 return nOutOfRange;
1051}
1052
1053/// Undoes the transformation performed by QuantizeReals() (assuming the same `count`, `min`, `max` and `nQuantBits`).
1054/// \return The number of unpacked values that were found to be out of range (0 means all values were in range).
1055template <typename T>
1056int UnquantizeReals(T *dst, const Quantized_t *src, std::size_t count, double min, double max, std::size_t nQuantBits)
1057{
1058 static_assert(std::is_floating_point_v<T>);
1059 static_assert(sizeof(T) <= sizeof(double));
1060 assert(1 <= nQuantBits && nQuantBits <= 8 * sizeof(Quantized_t));
1061
1062 const std::size_t quantMax = (1ull << nQuantBits) - 1;
1063 const double scale = (max - min) / quantMax;
1064 const std::size_t unusedBits = sizeof(Quantized_t) * 8 - nQuantBits;
1065 const double eps = std::numeric_limits<double>::epsilon();
1066 const double emax = max + std::max(1.0, std::abs(max)) * eps;
1067
1068 int nOutOfRange = 0;
1069
1070 for (std::size_t i = 0; i < count; ++i) {
1071 Quantized_t elem = src[i];
1072 // Undo the LSB-preserving shift performed by QuantizeReals
1074 elem >>= unusedBits;
1075
1076 const double fq = static_cast<double>(elem);
1077 double e = fq * scale + min;
1078
1079 // NOTE: `e` must be greater or equal than precisely `min` because the min value is represented
1080 // by a quantized value of 0, meaning there is no floating point error accumulation coming from
1081 // `e = fq * scale + min` (as it just becomes `e = min`).
1082 // For the max value, however, some error is introduced by the operation, therefore we allow for
1083 // some leeway in the out of range check.
1084 nOutOfRange += !(min <= e && e <= emax);
1085
1086 // Since we want to guarantee that the out value is always within `min` and `max`,
1087 // after the bounds check we clamp the value to the stored `max`.
1088 e = std::min(e, max);
1089
1090 dst[i] = static_cast<T>(e);
1091 }
1092
1093 return nOutOfRange;
1094}
1095} // namespace Quantize
1096
1097template <typename T>
1098class RColumnElementQuantized : public RColumnElementBase {
1099 static_assert(std::is_floating_point_v<T>);
1100
1101public:
1102 static constexpr bool kIsMappable = false;
1103 static constexpr std::size_t kSize = sizeof(T);
1104
1105 RColumnElementQuantized() : RColumnElementBase(kSize, 0) {}
1106
1107 void SetBitsOnStorage(std::size_t bitsOnStorage) final
1108 {
1109 const auto [minBits, maxBits] = GetValidBitRange(ENTupleColumnType::kReal32Quant);
1111 fBitsOnStorage = bitsOnStorage;
1112 }
1113
1114 void SetValueRange(double min, double max) final
1115 {
1116 R__ASSERT(min >= std::numeric_limits<T>::lowest());
1117 R__ASSERT(max <= std::numeric_limits<T>::max());
1118 // Disallow denormal, NaN and infinity
1119 R__ASSERT(std::isnormal(min) || min == 0.0);
1120 R__ASSERT(std::isnormal(max) || max == 0.0);
1121 fValueRange = {min, max};
1122 }
1123
1124 bool IsMappable() const final { return kIsMappable; }
1125
1126 void Pack(void *dst, const void *src, std::size_t count) const final
1127 {
1128 using namespace ROOT::Internal;
1129
1130 // TODO(gparolini): see if we can avoid this allocation
1132 assert(fValueRange);
1133 const auto [min, max] = *fValueRange;
1134 const int nOutOfRange =
1135 Quantize::QuantizeReals(quantized.get(), reinterpret_cast<const T *>(src), count, min, max, fBitsOnStorage);
1136 if (nOutOfRange) {
1137 throw ROOT::RException(R__FAIL(std::to_string(nOutOfRange) +
1138 " values were found of of range for quantization while packing (range is [" +
1139 std::to_string(min) + ", " + std::to_string(max) + "])"));
1140 }
1141 BitPacking::PackBits(dst, quantized.get(), count, sizeof(Quantize::Quantized_t), fBitsOnStorage);
1142 }
1143
1144 void Unpack(void *dst, const void *src, std::size_t count) const final
1145 {
1146 using namespace ROOT::Internal;
1147
1148 // TODO(gparolini): see if we can avoid this allocation
1150 assert(fValueRange);
1151 const auto [min, max] = *fValueRange;
1152 BitPacking::UnpackBits(quantized.get(), src, count, sizeof(Quantize::Quantized_t), fBitsOnStorage);
1153 [[maybe_unused]] const int nOutOfRange =
1154 Quantize::UnquantizeReals(reinterpret_cast<T *>(dst), quantized.get(), count, min, max, fBitsOnStorage);
1155 // NOTE: here, differently from Pack(), we don't ever expect to have values out of range, since the quantized
1156 // integers we pass to UnquantizeReals are by construction limited in value to the proper range. In Pack()
1157 // this is not the case, as the user may give us float values that are out of range.
1158 assert(nOutOfRange == 0);
1159 }
1160
1161 RIdentifier GetIdentifier() const final { return RIdentifier{typeid(T), ENTupleColumnType::kReal32Quant}; }
1162};
1163
1164template <>
1165class RColumnElement<float, ENTupleColumnType::kReal32Quant> : public RColumnElementQuantized<float> {};
1166
1167template <>
1168class RColumnElement<double, ENTupleColumnType::kReal32Quant> : public RColumnElementQuantized<double> {};
1169
1170#define __RCOLUMNELEMENT_SPEC_BODY(CppT, ColumnT, BaseT, BitsOnStorage) \
1171 static constexpr std::size_t kSize = sizeof(CppT); \
1172 static constexpr std::size_t kBitsOnStorage = BitsOnStorage; \
1173 RColumnElement() : BaseT(kSize, kBitsOnStorage) {} \
1174 bool IsMappable() const final \
1175 { \
1176 return kIsMappable; \
1177 } \
1178 RIdentifier GetIdentifier() const final \
1179 { \
1180 return RIdentifier{typeid(CppT), ColumnT}; \
1181 }
1182/// These macros are used to declare `RColumnElement` template specializations below. Additional arguments can be used
1183/// to forward template parameters to the base class, e.g.
1184/// ```
1185/// DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt32, 32,
1186/// RColumnElementCastLE, <std::int64_t, std::int32_t>);
1187/// ```
1188#define DECLARE_RCOLUMNELEMENT_SPEC(CppT, ColumnT, BitsOnStorage, BaseT, ...) \
1189 template <> \
1190 class RColumnElement<CppT, ColumnT> : public BaseT __VA_ARGS__ { \
1191 public: \
1192 __RCOLUMNELEMENT_SPEC_BODY(CppT, ColumnT, BaseT, BitsOnStorage) \
1193 }
1194#define DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(CppT, ColumnT, BitsOnStorage) \
1195 template <> \
1196 class RColumnElement<CppT, ColumnT> : public RColumnElementBase { \
1197 public: \
1198 static constexpr bool kIsMappable = true; \
1199 __RCOLUMNELEMENT_SPEC_BODY(CppT, ColumnT, RColumnElementBase, BitsOnStorage) \
1200 }
1201
1202DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kChar, 8, RColumnElementBoolAsUnsplitInt, <char>);
1203DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kInt8, 8, RColumnElementBoolAsUnsplitInt, <std::int8_t>);
1204DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kUInt8, 8, RColumnElementBoolAsUnsplitInt, <std::uint8_t>);
1205DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kInt16, 16, RColumnElementBoolAsUnsplitInt, <std::int16_t>);
1206DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kUInt16, 16, RColumnElementBoolAsUnsplitInt, <std::uint16_t>);
1207DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kInt32, 32, RColumnElementBoolAsUnsplitInt, <std::int32_t>);
1208DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kUInt32, 32, RColumnElementBoolAsUnsplitInt, <std::uint32_t>);
1209DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kInt64, 64, RColumnElementBoolAsUnsplitInt, <std::int64_t>);
1210DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kUInt64, 64, RColumnElementBoolAsUnsplitInt, <std::uint64_t>);
1211DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitInt16, 16, RColumnElementBoolAsSplitInt, <std::int16_t>);
1212DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitUInt16, 16, RColumnElementBoolAsSplitInt, <std::uint16_t>);
1213DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitInt32, 32, RColumnElementBoolAsSplitInt, <std::int32_t>);
1214DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitUInt32, 32, RColumnElementBoolAsSplitInt, <std::uint32_t>);
1215DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitInt64, 64, RColumnElementBoolAsSplitInt, <std::int64_t>);
1216DECLARE_RCOLUMNELEMENT_SPEC(bool, ENTupleColumnType::kSplitUInt64, 64, RColumnElementBoolAsSplitInt, <std::uint64_t>);
1217
1218DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::byte, ENTupleColumnType::kByte, 8);
1219
1220DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(char, ENTupleColumnType::kChar, 8);
1221DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kInt8, 8, RColumnElementCastLE, <char, std::int8_t>);
1222DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE, <char, std::uint8_t>);
1223DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kInt16, 16, RColumnElementCastLE, <char, std::int16_t>);
1224DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE, <char, std::uint16_t>);
1225DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kInt32, 32, RColumnElementCastLE, <char, std::int32_t>);
1226DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE, <char, std::uint32_t>);
1227DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kInt64, 64, RColumnElementCastLE, <char, std::int64_t>);
1228DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE, <char, std::uint64_t>);
1229DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1230 <char, std::int16_t>);
1231DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE, <char, std::uint16_t>);
1232DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1233 <char, std::int32_t>);
1234DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE, <char, std::uint32_t>);
1235DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1236 <char, std::int64_t>);
1237DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE, <char, std::uint64_t>);
1238DECLARE_RCOLUMNELEMENT_SPEC(char, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <char>);
1239
1240DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::int8_t, ENTupleColumnType::kInt8, 8);
1241DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::int8_t, char>);
1242DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1243 <std::int8_t, std::uint8_t>);
1244DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1245 <std::int8_t, std::int16_t>);
1246DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1247 <std::int8_t, std::uint16_t>);
1248DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1249 <std::int8_t, std::int32_t>);
1250DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1251 <std::int8_t, std::uint32_t>);
1252DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1253 <std::int8_t, std::int64_t>);
1254DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1255 <std::int8_t, std::uint64_t>);
1256DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1257 <std::int8_t, std::int16_t>);
1258DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1259 <std::int8_t, std::uint16_t>);
1260DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1261 <std::int8_t, std::int32_t>);
1262DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1263 <std::int8_t, std::uint32_t>);
1264DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1265 <std::int8_t, std::int64_t>);
1266DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1267 <std::int8_t, std::uint64_t>);
1268DECLARE_RCOLUMNELEMENT_SPEC(std::int8_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::int8_t>);
1269
1270DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::uint8_t, ENTupleColumnType::kUInt8, 8);
1271DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::uint8_t, char>);
1272DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1273 <std::uint8_t, std::int8_t>);
1274DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1275 <std::uint8_t, std::int16_t>);
1276DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1277 <std::uint8_t, std::uint16_t>);
1278DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1279 <std::uint8_t, std::int32_t>);
1280DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1281 <std::uint8_t, std::uint32_t>);
1282DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1283 <std::uint8_t, std::int64_t>);
1284DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1285 <std::uint8_t, std::uint64_t>);
1286DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1287 <std::uint8_t, std::int16_t>);
1288DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1289 <std::uint8_t, std::uint16_t>);
1290DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1291 <std::uint8_t, std::int32_t>);
1292DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1293 <std::uint8_t, std::uint32_t>);
1294DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1295 <std::uint8_t, std::int64_t>);
1296DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1297 <std::uint8_t, std::uint64_t>);
1298DECLARE_RCOLUMNELEMENT_SPEC(std::uint8_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::uint8_t>);
1299
1300DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kInt16, 16, RColumnElementLE, <std::int16_t>);
1301DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1302 <std::int16_t, std::int16_t>);
1303DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::int16_t, char>);
1304DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1305 <std::int16_t, std::int8_t>);
1306DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1307 <std::int16_t, std::uint8_t>);
1308DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1309 <std::int16_t, std::uint16_t>);
1310DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1311 <std::int16_t, std::int32_t>);
1312DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1313 <std::int16_t, std::uint32_t>);
1314DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1315 <std::int16_t, std::int64_t>);
1316DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1317 <std::int16_t, std::uint64_t>);
1318DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1319 <std::int16_t, std::uint16_t>);
1320DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1321 <std::int16_t, std::int32_t>);
1322DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1323 <std::int16_t, std::uint32_t>);
1324DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1325 <std::int16_t, std::int64_t>);
1326DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1327 <std::int16_t, std::uint64_t>);
1328DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::int16_t>);
1329
1330DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kUInt16, 16, RColumnElementLE, <std::uint16_t>);
1331DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1332 <std::uint16_t, std::uint16_t>);
1333DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::uint16_t, char>);
1334DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1335 <std::uint16_t, std::int8_t>);
1336DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1337 <std::uint16_t, std::uint8_t>);
1338DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1339 <std::uint16_t, std::int16_t>);
1340DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1341 <std::uint16_t, std::int32_t>);
1342DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1343 <std::uint16_t, std::uint32_t>);
1344DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1345 <std::uint16_t, std::int64_t>);
1346DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1347 <std::uint16_t, std::uint64_t>);
1348DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1349 <std::uint16_t, std::int16_t>);
1350DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1351 <std::uint16_t, std::int32_t>);
1352DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1353 <std::uint16_t, std::uint32_t>);
1354DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1355 <std::uint16_t, std::int64_t>);
1356DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1357 <std::uint16_t, std::uint64_t>);
1358DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::uint16_t>);
1359
1360DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kInt32, 32, RColumnElementLE, <std::int32_t>);
1361DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1362 <std::int32_t, std::int32_t>);
1363DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::int32_t, char>);
1364DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1365 <std::int32_t, std::int8_t>);
1366DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1367 <std::int32_t, std::uint8_t>);
1368DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1369 <std::int32_t, std::int16_t>);
1370DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1371 <std::int32_t, std::uint16_t>);
1372DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1373 <std::int32_t, std::uint32_t>);
1374DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1375 <std::int32_t, std::int64_t>);
1376DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1377 <std::int32_t, std::uint64_t>);
1378DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1379 <std::int32_t, std::int16_t>);
1380DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1381 <std::int32_t, std::uint16_t>);
1382DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1383 <std::int32_t, std::uint32_t>);
1384DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1385 <std::int32_t, std::int64_t>);
1386DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1387 <std::int32_t, std::uint64_t>);
1388DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::int32_t>);
1389
1390DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kUInt32, 32, RColumnElementLE, <std::uint32_t>);
1391DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1392 <std::uint32_t, std::uint32_t>);
1393DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::uint32_t, char>);
1394DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1395 <std::uint32_t, std::int8_t>);
1396DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1397 <std::uint32_t, std::uint8_t>);
1398DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1399 <std::uint32_t, std::int16_t>);
1400DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1401 <std::uint32_t, std::uint16_t>);
1402DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1403 <std::uint32_t, std::int32_t>);
1404DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1405 <std::uint32_t, std::int64_t>);
1406DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1407 <std::uint32_t, std::uint64_t>);
1408DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1409 <std::uint32_t, std::int16_t>);
1410DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1411 <std::uint32_t, std::uint16_t>);
1412DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1413 <std::uint32_t, std::int32_t>);
1414DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1415 <std::uint32_t, std::int64_t>);
1416DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1417 <std::uint32_t, std::uint64_t>);
1418DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::uint32_t>);
1419
1420DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt64, 64, RColumnElementLE, <std::int64_t>);
1421DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1422 <std::int64_t, std::int64_t>);
1423DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::int64_t, char>);
1424DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1425 <std::int64_t, std::int8_t>);
1426DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1427 <std::int64_t, std::uint8_t>);
1428DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1429 <std::int64_t, std::int16_t>);
1430DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1431 <std::int64_t, std::uint16_t>);
1432DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1433 <std::int64_t, std::int32_t>);
1434DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1435 <std::int64_t, std::uint32_t>);
1436DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kUInt64, 64, RColumnElementCastLE,
1437 <std::int64_t, std::uint64_t>);
1438DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1439 <std::int64_t, std::int16_t>);
1440DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1441 <std::int64_t, std::uint16_t>);
1442DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1443 <std::int64_t, std::int32_t>);
1444DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1445 <std::int64_t, std::uint32_t>);
1446DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1447 <std::int64_t, std::uint64_t>);
1448DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::int64_t>);
1449
1450DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kUInt64, 64, RColumnElementLE, <std::uint64_t>);
1451DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
1452 <std::uint64_t, std::uint64_t>);
1453DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kChar, 8, RColumnElementCastLE, <std::uint64_t, char>);
1454DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kInt8, 8, RColumnElementCastLE,
1455 <std::uint64_t, std::int8_t>);
1456DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kUInt8, 8, RColumnElementCastLE,
1457 <std::uint64_t, std::uint8_t>);
1458DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kInt16, 16, RColumnElementCastLE,
1459 <std::uint64_t, std::int16_t>);
1460DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kUInt16, 16, RColumnElementCastLE,
1461 <std::uint64_t, std::uint16_t>);
1462DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kInt32, 32, RColumnElementCastLE,
1463 <std::uint64_t, std::int32_t>);
1464DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kUInt32, 32, RColumnElementCastLE,
1465 <std::uint64_t, std::uint32_t>);
1466DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kInt64, 64, RColumnElementCastLE,
1467 <std::uint64_t, std::int64_t>);
1468DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
1469 <std::uint64_t, std::int16_t>);
1470DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
1471 <std::uint64_t, std::uint16_t>);
1472DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
1473 <std::uint64_t, std::int32_t>);
1474DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
1475 <std::uint64_t, std::uint32_t>);
1476DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
1477 <std::uint64_t, std::int64_t>);
1478DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, ENTupleColumnType::kBit, 1, RColumnElementIntAsBool, <std::uint64_t>);
1479
1480DECLARE_RCOLUMNELEMENT_SPEC(float, ENTupleColumnType::kReal32, 32, RColumnElementLE, <float>);
1481DECLARE_RCOLUMNELEMENT_SPEC(float, ENTupleColumnType::kSplitReal32, 32, RColumnElementSplitLE, <float, float>);
1482DECLARE_RCOLUMNELEMENT_SPEC(float, ENTupleColumnType::kReal64, 64, RColumnElementCastLE, <float, double>);
1483DECLARE_RCOLUMNELEMENT_SPEC(float, ENTupleColumnType::kSplitReal64, 64, RColumnElementSplitLE, <float, double>);
1484
1485DECLARE_RCOLUMNELEMENT_SPEC(double, ENTupleColumnType::kReal64, 64, RColumnElementLE, <double>);
1486DECLARE_RCOLUMNELEMENT_SPEC(double, ENTupleColumnType::kSplitReal64, 64, RColumnElementSplitLE, <double, double>);
1487DECLARE_RCOLUMNELEMENT_SPEC(double, ENTupleColumnType::kReal32, 32, RColumnElementCastLE, <double, float>);
1488DECLARE_RCOLUMNELEMENT_SPEC(double, ENTupleColumnType::kSplitReal32, 32, RColumnElementSplitLE, <double, float>);
1489
1490DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Internal::RColumnIndex, ENTupleColumnType::kIndex64, 64, RColumnElementLE,
1491 <std::uint64_t>);
1492DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Internal::RColumnIndex, ENTupleColumnType::kIndex32, 32, RColumnElementCastLE,
1493 <std::uint64_t, std::uint32_t>);
1494DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Internal::RColumnIndex, ENTupleColumnType::kSplitIndex64, 64,
1495 RColumnElementDeltaSplitLE, <std::uint64_t, std::uint64_t>);
1496DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Internal::RColumnIndex, ENTupleColumnType::kSplitIndex32, 32,
1497 RColumnElementDeltaSplitLE, <std::uint64_t, std::uint32_t>);
1498
1499template <>
1500class RColumnElement<ROOT::Internal::RTestFutureColumn, kTestFutureColumnType> final : public RColumnElementBase {
1501public:
1502 static constexpr bool kIsMappable = false;
1503 static constexpr std::size_t kSize = sizeof(ROOT::Internal::RTestFutureColumn);
1504 static constexpr std::size_t kBitsOnStorage = kSize * 8;
1505 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
1506
1507 bool IsMappable() const final { return kIsMappable; }
1508 void Pack(void *, const void *, std::size_t) const final {}
1509 void Unpack(void *, const void *, std::size_t) const final {}
1510
1511 RIdentifier GetIdentifier() const final
1512 {
1513 return RIdentifier{typeid(ROOT::Internal::RTestFutureColumn), kTestFutureColumnType};
1514 }
1515};
1516
1517inline void
1518RColumnElement<bool, ROOT::ENTupleColumnType::kBit>::Pack(void *dst, const void *src, std::size_t count) const
1519{
1520 const bool *boolArray = reinterpret_cast<const bool *>(src);
1521 char *charArray = reinterpret_cast<char *>(dst);
1522 std::bitset<8> bitSet;
1523 std::size_t i = 0;
1524 for (; i < count; ++i) {
1525 bitSet.set(i % 8, boolArray[i]);
1526 if (i % 8 == 7) {
1527 char packed = bitSet.to_ulong();
1528 charArray[i / 8] = packed;
1529 }
1530 }
1531 if (i % 8 != 0) {
1532 char packed = bitSet.to_ulong();
1533 charArray[i / 8] = packed;
1534 }
1535}
1536
1537inline void
1538RColumnElement<bool, ROOT::ENTupleColumnType::kBit>::Unpack(void *dst, const void *src, std::size_t count) const
1539{
1540 bool *boolArray = reinterpret_cast<bool *>(dst);
1541 const char *charArray = reinterpret_cast<const char *>(src);
1542 std::bitset<8> bitSet;
1543 for (std::size_t i = 0; i < count; i += 8) {
1544 bitSet = charArray[i / 8];
1545 for (std::size_t j = i; j < std::min(count, i + 8); ++j) {
1546 boolArray[j] = bitSet[j % 8];
1547 }
1548 }
1549}
1550
1551} // 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:145
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