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