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