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 <Byteswap.h>
13
14#include <bitset>
15
16// NOTE: some tests might define R__LITTLE_ENDIAN to simulate a different-endianness machine
17#ifndef R__LITTLE_ENDIAN
18#ifdef R__BYTESWAP
19// `R__BYTESWAP` is defined in RConfig.hxx for little-endian architectures; undefined otherwise
20#define R__LITTLE_ENDIAN 1
21#else
22#define R__LITTLE_ENDIAN 0
23#endif
24#endif /* R__LITTLE_ENDIAN */
25
26namespace {
27
28// In this namespace, common routines are defined for element packing and unpacking of ints and floats.
29// The following conversions and encodings exist:
30//
31// - Byteswap: on big endian machines, ints and floats are byte-swapped to the little endian on-disk format
32// - Cast: in-memory values can be stored in narrower on-disk columns. Currently without bounds checks.
33// For instance, for Double32_t, an in-memory double value is stored as a float on disk.
34// - Split: rearranges the bytes of an array of elements such that all the first bytes are stored first,
35// followed by all the second bytes, etc. This often clusters similar values, e.g. all the zero bytes
36// for arrays of small integers.
37// - Delta: Delta encoding stores on disk the delta to the previous element. This is useful for offsets,
38// because it transforms potentially large offset values into small deltas, which are then better
39// suited for split encoding.
40// - Zigzag: Zigzag encoding is used on signed integers only. It maps x to 2x if x is positive and to -(2x+1) if
41// x is negative. For series of positive and negative values of small absolute value, it will produce
42// a bit pattern that is favorable for split encoding.
43//
44// Encodings/conversions can be fused:
45//
46// - Delta/Zigzag + Splitting (there is no only-delta/zigzag encoding)
47// - (Delta/Zigzag + ) Splitting + Casting
48// - Everything + Byteswap
49
50/// \brief Copy and byteswap `count` elements of size `N` from `source` to `destination`.
51///
52/// Used on big-endian architectures for packing/unpacking elements whose column type requires
53/// a little-endian on-disk representation.
54template <std::size_t N>
55inline void CopyBswap(void *destination, const void *source, std::size_t count)
56{
57 auto dst = reinterpret_cast<typename RByteSwap<N>::value_type *>(destination);
58 auto src = reinterpret_cast<const typename RByteSwap<N>::value_type *>(source);
59 for (std::size_t i = 0; i < count; ++i) {
60 dst[i] = RByteSwap<N>::bswap(src[i]);
61 }
62}
63
64/// Casts T to one of the ints used in RByteSwap and back to its original type, which may be float or double
65#if R__LITTLE_ENDIAN == 0
66template <typename T>
67inline void ByteSwapIfNecessary(T &value)
68{
69 constexpr auto N = sizeof(T);
70 using bswap_value_type = typename RByteSwap<N>::value_type;
71 void *valuePtr = &value;
72 auto swapped = RByteSwap<N>::bswap(*reinterpret_cast<bswap_value_type *>(valuePtr));
73 *reinterpret_cast<bswap_value_type *>(valuePtr) = swapped;
74}
75#else
76#define ByteSwapIfNecessary(x) ((void)0)
77#endif
78
79/// \brief Pack `count` elements into narrower (or wider) type
80///
81/// Used to convert in-memory elements to smaller column types of comatible types
82/// (e.g., double to float, int64 to int32). Takes care of byte swap if necessary.
83template <typename DestT, typename SourceT>
84inline void CastPack(void *destination, const void *source, std::size_t count)
85{
86 static_assert(std::is_convertible_v<SourceT, DestT>);
87 auto dst = reinterpret_cast<DestT *>(destination);
88 auto src = reinterpret_cast<const SourceT *>(source);
89 for (std::size_t i = 0; i < count; ++i) {
90 dst[i] = src[i];
91 ByteSwapIfNecessary(dst[i]);
92 }
93}
94
95/// \brief Unpack `count` on-disk elements into wider (or narrower) in-memory array
96///
97/// Used to convert on-disk elements to larger C++ types of comatible types
98/// (e.g., float to double, int32 to int64). Takes care of byte swap if necessary.
99template <typename DestT, typename SourceT>
100inline void CastUnpack(void *destination, const void *source, std::size_t count)
101{
102 auto dst = reinterpret_cast<DestT *>(destination);
103 auto src = reinterpret_cast<const SourceT *>(source);
104 for (std::size_t i = 0; i < count; ++i) {
105 SourceT val = src[i];
106 ByteSwapIfNecessary(val);
107 dst[i] = val;
108 }
109}
110
111/// \brief Split encoding of elements, possibly into narrower column
112///
113/// Used to first cast and then split-encode in-memory values to the on-disk column. Swap bytes if necessary.
114template <typename DestT, typename SourceT>
115inline void CastSplitPack(void *destination, const void *source, std::size_t count)
116{
117 constexpr std::size_t N = sizeof(DestT);
118 auto splitArray = reinterpret_cast<char *>(destination);
119 auto src = reinterpret_cast<const SourceT *>(source);
120 for (std::size_t i = 0; i < count; ++i) {
121 DestT val = src[i];
122 ByteSwapIfNecessary(val);
123 for (std::size_t b = 0; b < N; ++b) {
124 splitArray[b * count + i] = reinterpret_cast<const char *>(&val)[b];
125 }
126 }
127}
128
129/// \brief Reverse split encoding of elements
130///
131/// Used to first unsplit a column, possibly storing elements in wider C++ types. Swaps bytes if necessary
132template <typename DestT, typename SourceT>
133inline void CastSplitUnpack(void *destination, const void *source, std::size_t count)
134{
135 constexpr std::size_t N = sizeof(SourceT);
136 auto dst = reinterpret_cast<DestT *>(destination);
137 auto splitArray = reinterpret_cast<const char *>(source);
138 for (std::size_t i = 0; i < count; ++i) {
139 SourceT val = 0;
140 for (std::size_t b = 0; b < N; ++b) {
141 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
142 }
143 ByteSwapIfNecessary(val);
144 dst[i] = val;
145 }
146}
147
148/// \brief Packing of columns with delta + split encoding
149///
150/// Apply split encoding to delta-encoded values, currently used only for index columns
151template <typename DestT, typename SourceT>
152inline void CastDeltaSplitPack(void *destination, const void *source, std::size_t count)
153{
154 constexpr std::size_t N = sizeof(DestT);
155 auto src = reinterpret_cast<const SourceT *>(source);
156 auto splitArray = reinterpret_cast<char *>(destination);
157 for (std::size_t i = 0; i < count; ++i) {
158 DestT val = (i == 0) ? src[0] : src[i] - src[i - 1];
159 ByteSwapIfNecessary(val);
160 for (std::size_t b = 0; b < N; ++b) {
161 splitArray[b * count + i] = reinterpret_cast<char *>(&val)[b];
162 }
163 }
164}
165
166/// \brief Unsplit and unwind delta encoding
167///
168/// Unsplit a column and reverse the delta encoding, currently used only for index columns
169template <typename DestT, typename SourceT>
170inline void CastDeltaSplitUnpack(void *destination, const void *source, std::size_t count)
171{
172 constexpr std::size_t N = sizeof(SourceT);
173 auto splitArray = reinterpret_cast<const char *>(source);
174 auto dst = reinterpret_cast<DestT *>(destination);
175 for (std::size_t i = 0; i < count; ++i) {
176 SourceT val = 0;
177 for (std::size_t b = 0; b < N; ++b) {
178 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
179 }
180 ByteSwapIfNecessary(val);
181 dst[i] = (i == 0) ? val : dst[i - 1] + val;
182 }
183}
184
185/// \brief Packing of columns with zigzag + split encoding
186///
187/// Apply split encoding to zigzag-encoded values, used for signed integers
188template <typename DestT, typename SourceT>
189inline void CastZigzagSplitPack(void *destination, const void *source, std::size_t count)
190{
191 using UDestT = std::make_unsigned_t<DestT>;
192 constexpr std::size_t kNBitsDestT = sizeof(DestT) * 8;
193 constexpr std::size_t N = sizeof(DestT);
194 auto src = reinterpret_cast<const SourceT *>(source);
195 auto splitArray = reinterpret_cast<char *>(destination);
196 for (std::size_t i = 0; i < count; ++i) {
197 UDestT val = (static_cast<DestT>(src[i]) << 1) ^ (static_cast<DestT>(src[i]) >> (kNBitsDestT - 1));
198 ByteSwapIfNecessary(val);
199 for (std::size_t b = 0; b < N; ++b) {
200 splitArray[b * count + i] = reinterpret_cast<char *>(&val)[b];
201 }
202 }
203}
204
205/// \brief Unsplit and unwind zigzag encoding
206///
207/// Unsplit a column and reverse the zigzag encoding, used for signed integer columns
208template <typename DestT, typename SourceT>
209inline void CastZigzagSplitUnpack(void *destination, const void *source, std::size_t count)
210{
211 using USourceT = std::make_unsigned_t<SourceT>;
212 constexpr std::size_t N = sizeof(SourceT);
213 auto splitArray = reinterpret_cast<const char *>(source);
214 auto dst = reinterpret_cast<DestT *>(destination);
215 for (std::size_t i = 0; i < count; ++i) {
216 USourceT val = 0;
217 for (std::size_t b = 0; b < N; ++b) {
218 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
219 }
220 ByteSwapIfNecessary(val);
221 dst[i] = static_cast<SourceT>((val >> 1) ^ -(static_cast<SourceT>(val) & 1));
222 }
223}
224} // namespace
225
226// anonymous namespace because these definitions are not meant to be exported.
227namespace {
228
231
232template <typename CppT, EColumnType>
233class RColumnElement;
234
235template <typename CppT>
236std::unique_ptr<RColumnElementBase> GenerateColumnElementInternal(EColumnType type)
237{
238 switch (type) {
239 case EColumnType::kIndex64: return std::make_unique<RColumnElement<CppT, EColumnType::kIndex64>>();
240 case EColumnType::kIndex32: return std::make_unique<RColumnElement<CppT, EColumnType::kIndex32>>();
241 case EColumnType::kSwitch: return std::make_unique<RColumnElement<CppT, EColumnType::kSwitch>>();
242 case EColumnType::kByte: return std::make_unique<RColumnElement<CppT, EColumnType::kByte>>();
243 case EColumnType::kChar: return std::make_unique<RColumnElement<CppT, EColumnType::kChar>>();
244 case EColumnType::kBit: return std::make_unique<RColumnElement<CppT, EColumnType::kBit>>();
245 case EColumnType::kReal64: return std::make_unique<RColumnElement<CppT, EColumnType::kReal64>>();
246 case EColumnType::kReal32: return std::make_unique<RColumnElement<CppT, EColumnType::kReal32>>();
247 case EColumnType::kReal16: return std::make_unique<RColumnElement<CppT, EColumnType::kReal16>>();
248 case EColumnType::kInt64: return std::make_unique<RColumnElement<CppT, EColumnType::kInt64>>();
249 case EColumnType::kUInt64: return std::make_unique<RColumnElement<CppT, EColumnType::kUInt64>>();
250 case EColumnType::kInt32: return std::make_unique<RColumnElement<CppT, EColumnType::kInt32>>();
251 case EColumnType::kUInt32: return std::make_unique<RColumnElement<CppT, EColumnType::kUInt32>>();
252 case EColumnType::kInt16: return std::make_unique<RColumnElement<CppT, EColumnType::kInt16>>();
253 case EColumnType::kUInt16: return std::make_unique<RColumnElement<CppT, EColumnType::kUInt16>>();
254 case EColumnType::kInt8: return std::make_unique<RColumnElement<CppT, EColumnType::kInt8>>();
255 case EColumnType::kUInt8: return std::make_unique<RColumnElement<CppT, EColumnType::kUInt8>>();
256 case EColumnType::kSplitIndex64: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitIndex64>>();
257 case EColumnType::kSplitIndex32: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitIndex32>>();
258 case EColumnType::kSplitReal64: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitReal64>>();
259 case EColumnType::kSplitReal32: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitReal32>>();
260 case EColumnType::kSplitInt64: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitInt64>>();
261 case EColumnType::kSplitUInt64: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitUInt64>>();
262 case EColumnType::kSplitInt32: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitInt32>>();
263 case EColumnType::kSplitUInt32: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitUInt32>>();
264 case EColumnType::kSplitInt16: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitInt16>>();
265 case EColumnType::kSplitUInt16: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitUInt16>>();
266 default: R__ASSERT(false);
267 }
268 // never here
269 return nullptr;
270}
271
272/**
273 * Base class for columns whose on-storage representation is little-endian.
274 * The implementation of `Pack` and `Unpack` takes care of byteswap if the memory page is big-endian.
275 */
276template <typename CppT>
277class RColumnElementLE : public RColumnElementBase {
278protected:
279 explicit RColumnElementLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage) {}
280
281public:
282 static constexpr bool kIsMappable = (R__LITTLE_ENDIAN == 1);
283
284 void Pack(void *dst, const void *src, std::size_t count) const final
285 {
286#if R__LITTLE_ENDIAN == 1
287 RColumnElementBase::Pack(dst, src, count);
288#else
289 CopyBswap<sizeof(CppT)>(dst, src, count);
290#endif
291 }
292 void Unpack(void *dst, const void *src, std::size_t count) const final
293 {
294#if R__LITTLE_ENDIAN == 1
295 RColumnElementBase::Unpack(dst, src, count);
296#else
297 CopyBswap<sizeof(CppT)>(dst, src, count);
298#endif
299 }
300}; // class RColumnElementLE
301
302/**
303 * Base class for columns storing elements of wider in-memory types,
304 * such as 64bit in-memory offsets to Index32 columns.
305 */
306template <typename CppT, typename NarrowT>
307class RColumnElementCastLE : public RColumnElementBase {
308protected:
309 explicit RColumnElementCastLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage)
310 {
311 }
312
313public:
314 static constexpr bool kIsMappable = false;
315
316 void Pack(void *dst, const void *src, std::size_t count) const final { CastPack<NarrowT, CppT>(dst, src, count); }
317 void Unpack(void *dst, const void *src, std::size_t count) const final
318 {
319 CastUnpack<CppT, NarrowT>(dst, src, count);
320 }
321}; // class RColumnElementCastLE
322
323/**
324 * Base class for split columns whose on-storage representation is little-endian.
325 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
326 * As part of the splitting, can also narrow down the type to NarrowT.
327 */
328template <typename CppT, typename NarrowT>
329class RColumnElementSplitLE : public RColumnElementBase {
330protected:
331 explicit RColumnElementSplitLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage)
332 {
333 }
334
335public:
336 static constexpr bool kIsMappable = false;
337
338 void Pack(void *dst, const void *src, std::size_t count) const final
339 {
340 CastSplitPack<NarrowT, CppT>(dst, src, count);
341 }
342 void Unpack(void *dst, const void *src, std::size_t count) const final
343 {
344 CastSplitUnpack<CppT, NarrowT>(dst, src, count);
345 }
346}; // class RColumnElementSplitLE
347
348/**
349 * Base class for delta + split columns (index columns) whose on-storage representation is little-endian.
350 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
351 * As part of the encoding, can also narrow down the type to NarrowT.
352 */
353template <typename CppT, typename NarrowT>
354class RColumnElementDeltaSplitLE : public RColumnElementBase {
355protected:
356 explicit RColumnElementDeltaSplitLE(std::size_t size, std::size_t bitsOnStorage)
357 : RColumnElementBase(size, bitsOnStorage)
358 {
359 }
360
361public:
362 static constexpr bool kIsMappable = false;
363
364 void Pack(void *dst, const void *src, std::size_t count) const final
365 {
366 CastDeltaSplitPack<NarrowT, CppT>(dst, src, count);
367 }
368 void Unpack(void *dst, const void *src, std::size_t count) const final
369 {
370 CastDeltaSplitUnpack<CppT, NarrowT>(dst, src, count);
371 }
372}; // class RColumnElementDeltaSplitLE
373
374/**
375 * Base class for zigzag + split columns (signed integer columns) whose on-storage representation is little-endian.
376 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
377 * The NarrowT target type should be an signed integer, which can be smaller than the CppT source type.
378 */
379template <typename CppT, typename NarrowT>
380class RColumnElementZigzagSplitLE : public RColumnElementBase {
381protected:
382 explicit RColumnElementZigzagSplitLE(std::size_t size, std::size_t bitsOnStorage)
383 : RColumnElementBase(size, bitsOnStorage)
384 {
385 }
386
387public:
388 static constexpr bool kIsMappable = false;
389
390 void Pack(void *dst, const void *src, std::size_t count) const final
391 {
392 CastZigzagSplitPack<NarrowT, CppT>(dst, src, count);
393 }
394 void Unpack(void *dst, const void *src, std::size_t count) const final
395 {
396 CastZigzagSplitUnpack<CppT, NarrowT>(dst, src, count);
397 }
398}; // class RColumnElementZigzagSplitLE
399
400////////////////////////////////////////////////////////////////////////////////
401// Pairs of C++ type and column type, like float and EColumnType::kReal32
402////////////////////////////////////////////////////////////////////////////////
403
404////////////////////////////////////////////////////////////////////////////////
405// Part 1: C++ type --> unknown column type
406////////////////////////////////////////////////////////////////////////////////
407
408template <typename CppT, EColumnType ColumnT = EColumnType::kUnknown>
409class RColumnElement : public RColumnElementBase {
410public:
411 RColumnElement() : RColumnElementBase(sizeof(CppT))
412 {
414 R__FAIL(std::string("internal error: no column mapping for this C++ type: ") + typeid(CppT).name() + " --> " +
415 GetTypeName(ColumnT)));
416 }
417};
418
419template <>
420class RColumnElement<bool, EColumnType::kUnknown> : public RColumnElementBase {
421public:
422 static constexpr std::size_t kSize = sizeof(bool);
423 RColumnElement() : RColumnElementBase(kSize) {}
424};
425
426template <>
427class RColumnElement<std::byte, EColumnType::kUnknown> : public RColumnElementBase {
428public:
429 static constexpr std::size_t kSize = sizeof(std::byte);
430 RColumnElement() : RColumnElementBase(kSize) {}
431};
432
433template <>
434class RColumnElement<char, EColumnType::kUnknown> : public RColumnElementBase {
435public:
436 static constexpr std::size_t kSize = sizeof(char);
437 RColumnElement() : RColumnElementBase(kSize) {}
438};
439
440template <>
441class RColumnElement<std::int8_t, EColumnType::kUnknown> : public RColumnElementBase {
442public:
443 static constexpr std::size_t kSize = sizeof(std::int8_t);
444 RColumnElement() : RColumnElementBase(kSize) {}
445};
446
447template <>
448class RColumnElement<std::uint8_t, EColumnType::kUnknown> : public RColumnElementBase {
449public:
450 static constexpr std::size_t kSize = sizeof(std::uint8_t);
451 RColumnElement() : RColumnElementBase(kSize) {}
452};
453
454template <>
455class RColumnElement<std::int16_t, EColumnType::kUnknown> : public RColumnElementBase {
456public:
457 static constexpr std::size_t kSize = sizeof(std::int16_t);
458 RColumnElement() : RColumnElementBase(kSize) {}
459};
460
461template <>
462class RColumnElement<std::uint16_t, EColumnType::kUnknown> : public RColumnElementBase {
463public:
464 static constexpr std::size_t kSize = sizeof(std::uint16_t);
465 RColumnElement() : RColumnElementBase(kSize) {}
466};
467
468template <>
469class RColumnElement<std::int32_t, EColumnType::kUnknown> : public RColumnElementBase {
470public:
471 static constexpr std::size_t kSize = sizeof(std::int32_t);
472 RColumnElement() : RColumnElementBase(kSize) {}
473};
474
475template <>
476class RColumnElement<std::uint32_t, EColumnType::kUnknown> : public RColumnElementBase {
477public:
478 static constexpr std::size_t kSize = sizeof(std::uint32_t);
479 RColumnElement() : RColumnElementBase(kSize) {}
480};
481
482template <>
483class RColumnElement<std::int64_t, EColumnType::kUnknown> : public RColumnElementBase {
484public:
485 static constexpr std::size_t kSize = sizeof(std::int64_t);
486 RColumnElement() : RColumnElementBase(kSize) {}
487};
488
489template <>
490class RColumnElement<std::uint64_t, EColumnType::kUnknown> : public RColumnElementBase {
491public:
492 static constexpr std::size_t kSize = sizeof(std::uint64_t);
493 RColumnElement() : RColumnElementBase(kSize) {}
494};
495
496template <>
497class RColumnElement<float, EColumnType::kUnknown> : public RColumnElementBase {
498public:
499 static constexpr std::size_t kSize = sizeof(float);
500 RColumnElement() : RColumnElementBase(kSize) {}
501};
502
503template <>
504class RColumnElement<double, EColumnType::kUnknown> : public RColumnElementBase {
505public:
506 static constexpr std::size_t kSize = sizeof(double);
507 RColumnElement() : RColumnElementBase(kSize) {}
508};
509
510template <>
511class RColumnElement<ROOT::Experimental::ClusterSize_t, EColumnType::kUnknown> : public RColumnElementBase {
512public:
513 static constexpr std::size_t kSize = sizeof(ROOT::Experimental::ClusterSize_t);
514 RColumnElement() : RColumnElementBase(kSize) {}
515};
516
517template <>
518class RColumnElement<ROOT::Experimental::RColumnSwitch, EColumnType::kUnknown> : public RColumnElementBase {
519public:
520 static constexpr std::size_t kSize = sizeof(ROOT::Experimental::RColumnSwitch);
521 RColumnElement() : RColumnElementBase(kSize) {}
522};
523
524////////////////////////////////////////////////////////////////////////////////
525// Part 2: C++ type --> supported column representations,
526// ordered by C++ type
527////////////////////////////////////////////////////////////////////////////////
528
529template <>
530class RColumnElement<ROOT::Experimental::RColumnSwitch, EColumnType::kSwitch> : public RColumnElementBase {
531private:
532 struct RSwitchElement {
533 std::uint64_t fIndex;
534 std::uint32_t fTag;
535 };
536
537public:
538 static constexpr bool kIsMappable = false;
539 static constexpr std::size_t kSize = sizeof(ROOT::Experimental::RColumnSwitch);
540 static constexpr std::size_t kBitsOnStorage = 96;
541 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
542 bool IsMappable() const final { return kIsMappable; }
543
544 void Pack(void *dst, const void *src, std::size_t count) const final
545 {
546 auto srcArray = reinterpret_cast<const ROOT::Experimental::RColumnSwitch *>(src);
547 auto dstArray = reinterpret_cast<unsigned char *>(dst);
548 for (std::size_t i = 0; i < count; ++i) {
549 RSwitchElement element{srcArray[i].GetIndex(), srcArray[i].GetTag()};
550#if R__LITTLE_ENDIAN == 0
551 element.fIndex = RByteSwap<8>::bswap(element.fIndex);
552 element.fTag = RByteSwap<4>::bswap(element.fTag);
553#endif
554 memcpy(dstArray + i * 12, &element, 12);
555 }
556 }
557
558 void Unpack(void *dst, const void *src, std::size_t count) const final
559 {
560 auto srcArray = reinterpret_cast<const unsigned char *>(src);
561 auto dstArray = reinterpret_cast<ROOT::Experimental::RColumnSwitch *>(dst);
562 for (std::size_t i = 0; i < count; ++i) {
563 RSwitchElement element;
564 memcpy(&element, srcArray + i * 12, 12);
565#if R__LITTLE_ENDIAN == 0
566 element.fIndex = RByteSwap<8>::bswap(element.fIndex);
567 element.fTag = RByteSwap<4>::bswap(element.fTag);
568#endif
569 dstArray[i] =
571 }
572 }
573};
574
575template <>
576class RColumnElement<bool, EColumnType::kBit> : public RColumnElementBase {
577public:
578 static constexpr bool kIsMappable = false;
579 static constexpr std::size_t kSize = sizeof(bool);
580 static constexpr std::size_t kBitsOnStorage = 1;
581 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
582 bool IsMappable() const final { return kIsMappable; }
583
584 void Pack(void *dst, const void *src, std::size_t count) const final;
585 void Unpack(void *dst, const void *src, std::size_t count) const final;
586};
587
588template <>
589class RColumnElement<float, EColumnType::kReal16> : public RColumnElementBase {
590public:
591 static constexpr bool kIsMappable = false;
592 static constexpr std::size_t kSize = sizeof(float);
593 static constexpr std::size_t kBitsOnStorage = 16;
594 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
595 bool IsMappable() const final { return kIsMappable; }
596
597 void Pack(void *dst, const void *src, std::size_t count) const final
598 {
599 const float *floatArray = reinterpret_cast<const float *>(src);
600 std::uint16_t *uint16Array = reinterpret_cast<std::uint16_t *>(dst);
601
602 for (std::size_t i = 0; i < count; ++i) {
603 uint16Array[i] = ROOT::Experimental::Internal::FloatToHalf(floatArray[i]);
604 ByteSwapIfNecessary(uint16Array[i]);
605 }
606 }
607
608 void Unpack(void *dst, const void *src, std::size_t count) const final
609 {
610 float *floatArray = reinterpret_cast<float *>(dst);
611 const std::uint16_t *uint16Array = reinterpret_cast<const std::uint16_t *>(src);
612
613 for (std::size_t i = 0; i < count; ++i) {
614 std::uint16_t val = uint16Array[i];
615 ByteSwapIfNecessary(val);
617 }
618 }
619};
620
621template <>
622class RColumnElement<double, EColumnType::kReal16> : public RColumnElementBase {
623public:
624 static constexpr bool kIsMappable = false;
625 static constexpr std::size_t kSize = sizeof(double);
626 static constexpr std::size_t kBitsOnStorage = 16;
627 RColumnElement() : RColumnElementBase(kSize, kBitsOnStorage) {}
628 bool IsMappable() const final { return kIsMappable; }
629
630 void Pack(void *dst, const void *src, std::size_t count) const final
631 {
632 const double *doubleArray = reinterpret_cast<const double *>(src);
633 std::uint16_t *uint16Array = reinterpret_cast<std::uint16_t *>(dst);
634
635 for (std::size_t i = 0; i < count; ++i) {
636 uint16Array[i] = ROOT::Experimental::Internal::FloatToHalf(static_cast<float>(doubleArray[i]));
637 ByteSwapIfNecessary(uint16Array[i]);
638 }
639 }
640
641 void Unpack(void *dst, const void *src, std::size_t count) const final
642 {
643 double *doubleArray = reinterpret_cast<double *>(dst);
644 const std::uint16_t *uint16Array = reinterpret_cast<const std::uint16_t *>(src);
645
646 for (std::size_t i = 0; i < count; ++i) {
647 std::uint16_t val = uint16Array[i];
648 ByteSwapIfNecessary(val);
649 doubleArray[i] = static_cast<double>(ROOT::Experimental::Internal::HalfToFloat(val));
650 }
651 }
652};
653
654#define __RCOLUMNELEMENT_SPEC_BODY(CppT, BaseT, BitsOnStorage) \
655 static constexpr std::size_t kSize = sizeof(CppT); \
656 static constexpr std::size_t kBitsOnStorage = BitsOnStorage; \
657 RColumnElement() : BaseT(kSize, kBitsOnStorage) {} \
658 bool IsMappable() const final \
659 { \
660 return kIsMappable; \
661 }
662/// These macros are used to declare `RColumnElement` template specializations below. Additional arguments can be used
663/// to forward template parameters to the base class, e.g.
664/// ```
665/// DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kInt32, 32,
666/// RColumnElementCastLE, <std::int64_t, std::int32_t>);
667/// ```
668#define DECLARE_RCOLUMNELEMENT_SPEC(CppT, ColumnT, BitsOnStorage, BaseT, ...) \
669 template <> \
670 class RColumnElement<CppT, ColumnT> : public BaseT __VA_ARGS__ { \
671 public: \
672 __RCOLUMNELEMENT_SPEC_BODY(CppT, BaseT, BitsOnStorage) \
673 }
674#define DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(CppT, ColumnT, BitsOnStorage) \
675 template <> \
676 class RColumnElement<CppT, ColumnT> : public RColumnElementBase { \
677 public: \
678 static constexpr bool kIsMappable = true; \
679 __RCOLUMNELEMENT_SPEC_BODY(CppT, RColumnElementBase, BitsOnStorage) \
680 }
681
682DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::byte, EColumnType::kByte, 8);
683
684DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(char, EColumnType::kByte, 8);
685DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(char, EColumnType::kChar, 8);
686
687DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::int8_t, EColumnType::kInt8, 8);
688DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::int8_t, EColumnType::kUInt8, 8);
689DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::int8_t, EColumnType::kByte, 8);
690
691DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::uint8_t, EColumnType::kUInt8, 8);
692DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::uint8_t, EColumnType::kInt8, 8);
693DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(std::uint8_t, EColumnType::kByte, 8);
694
695DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, EColumnType::kInt16, 16, RColumnElementLE, <std::int16_t>);
696DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, EColumnType::kUInt16, 16, RColumnElementLE, <std::int16_t>);
697DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, EColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
698 <std::int16_t, std::int16_t>);
699DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, EColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
700 <std::int16_t, std::uint16_t>);
701
702DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, EColumnType::kUInt16, 16, RColumnElementLE, <std::uint16_t>);
703DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, EColumnType::kInt16, 16, RColumnElementLE, <std::uint16_t>);
704DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, EColumnType::kSplitUInt16, 16, RColumnElementSplitLE,
705 <std::uint16_t, std::uint16_t>);
706DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, EColumnType::kSplitInt16, 16, RColumnElementZigzagSplitLE,
707 <std::uint16_t, std::int16_t>);
708
709DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, EColumnType::kInt32, 32, RColumnElementLE, <std::int32_t>);
710DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, EColumnType::kUInt32, 32, RColumnElementLE, <std::int32_t>);
711DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, EColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
712 <std::int32_t, std::int32_t>);
713DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, EColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
714 <std::int32_t, std::uint32_t>);
715
716DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, EColumnType::kUInt32, 32, RColumnElementLE, <std::uint32_t>);
717DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, EColumnType::kInt32, 32, RColumnElementLE, <std::uint32_t>);
718DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, EColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
719 <std::uint32_t, std::uint32_t>);
720DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, EColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
721 <std::uint32_t, std::int32_t>);
722
723DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kInt64, 64, RColumnElementLE, <std::int64_t>);
724DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kUInt64, 64, RColumnElementLE, <std::int64_t>);
725DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
726 <std::int64_t, std::int64_t>);
727DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
728 <std::int64_t, std::uint64_t>);
729DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kInt32, 32, RColumnElementCastLE, <std::int64_t, std::int32_t>);
730DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kUInt32, 32, RColumnElementCastLE,
731 <std::int64_t, std::uint32_t>);
732DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kSplitInt32, 32, RColumnElementZigzagSplitLE,
733 <std::int64_t, std::int32_t>);
734DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kSplitUInt32, 32, RColumnElementSplitLE,
735 <std::int64_t, std::uint32_t>);
736
737DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, EColumnType::kUInt64, 64, RColumnElementLE, <std::uint64_t>);
738DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, EColumnType::kInt64, 64, RColumnElementLE, <std::uint64_t>);
739DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, EColumnType::kSplitUInt64, 64, RColumnElementSplitLE,
740 <std::uint64_t, std::uint64_t>);
741DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, EColumnType::kSplitInt64, 64, RColumnElementZigzagSplitLE,
742 <std::uint64_t, std::int64_t>);
743
744DECLARE_RCOLUMNELEMENT_SPEC(float, EColumnType::kReal32, 32, RColumnElementLE, <float>);
745DECLARE_RCOLUMNELEMENT_SPEC(float, EColumnType::kSplitReal32, 32, RColumnElementSplitLE, <float, float>);
746
747DECLARE_RCOLUMNELEMENT_SPEC(double, EColumnType::kReal64, 64, RColumnElementLE, <double>);
748DECLARE_RCOLUMNELEMENT_SPEC(double, EColumnType::kSplitReal64, 64, RColumnElementSplitLE, <double, double>);
749DECLARE_RCOLUMNELEMENT_SPEC(double, EColumnType::kReal32, 32, RColumnElementCastLE, <double, float>);
750DECLARE_RCOLUMNELEMENT_SPEC(double, EColumnType::kSplitReal32, 32, RColumnElementSplitLE, <double, float>);
751
752DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Experimental::ClusterSize_t, EColumnType::kIndex64, 64, RColumnElementLE,
753 <std::uint64_t>);
754DECLARE_RCOLUMNELEMENT_SPEC(ROOT::Experimental::ClusterSize_t, EColumnType::kIndex32, 32, RColumnElementCastLE,
755 <std::uint64_t, std::uint32_t>);
757 RColumnElementDeltaSplitLE, <std::uint64_t, std::uint64_t>);
759 RColumnElementDeltaSplitLE, <std::uint64_t, std::uint32_t>);
760
761void RColumnElement<bool, ROOT::Experimental::EColumnType::kBit>::Pack(void *dst, const void *src,
762 std::size_t count) const
763{
764 const bool *boolArray = reinterpret_cast<const bool *>(src);
765 char *charArray = reinterpret_cast<char *>(dst);
766 std::bitset<8> bitSet;
767 std::size_t i = 0;
768 for (; i < count; ++i) {
769 bitSet.set(i % 8, boolArray[i]);
770 if (i % 8 == 7) {
771 char packed = bitSet.to_ulong();
772 charArray[i / 8] = packed;
773 }
774 }
775 if (i % 8 != 0) {
776 char packed = bitSet.to_ulong();
777 charArray[i / 8] = packed;
778 }
779}
780
781void RColumnElement<bool, ROOT::Experimental::EColumnType::kBit>::Unpack(void *dst, const void *src,
782 std::size_t count) const
783{
784 bool *boolArray = reinterpret_cast<bool *>(dst);
785 const char *charArray = reinterpret_cast<const char *>(src);
786 std::bitset<8> bitSet;
787 for (std::size_t i = 0; i < count; i += 8) {
788 bitSet = charArray[i / 8];
789 for (std::size_t j = i; j < std::min(count, i + 8); ++j) {
790 boolArray[j] = bitSet[j % 8];
791 }
792 }
793}
794
795} // 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:290
#define b(i)
Definition RSha256.hxx:100
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#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
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
@ 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...
Holds the index and the tag of a kSwitch column.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
std::uint16_t FloatToHalf(float value)
Convert an IEEE single-precision float to half-precision.
Definition RFloat16.hxx:96
float HalfToFloat(std::uint16_t value)
Convert an IEEE half-precision float to single-precision.
Definition RFloat16.hxx:132
RClusterSize ClusterSize_t
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
Wrap the integer in a struct in order to avoid template specialization clash with std::uint64_t.
unsigned char byte
Definition gifdecode.c:10