Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RColumnElement.hxx
Go to the documentation of this file.
1/// \file ROOT/RColumnElement.hxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-09
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#ifndef ROOT7_RColumnElement
17#define ROOT7_RColumnElement
18
19#include <ROOT/RColumnModel.hxx>
20#include <ROOT/RConfig.hxx>
21#include <ROOT/RError.hxx>
22#include <ROOT/RFloat16.hxx>
23#include <ROOT/RNTupleUtil.hxx>
24
25#include <Byteswap.h>
26#include <TError.h>
27
28#include <cstring> // for memcpy
29#include <cstddef> // for std::byte
30#include <cstdint>
31#include <memory>
32#include <string>
33#include <type_traits>
34#include <typeinfo>
35#include <utility>
36
37#ifndef R__LITTLE_ENDIAN
38#ifdef R__BYTESWAP
39// `R__BYTESWAP` is defined in RConfig.hxx for little-endian architectures; undefined otherwise
40#define R__LITTLE_ENDIAN 1
41#else
42#define R__LITTLE_ENDIAN 0
43#endif
44#endif /* R__LITTLE_ENDIAN */
45
46namespace {
47
48// In this namespace, common routines are defined for element packing and unpacking of ints and floats.
49// The following conversions and encodings exist:
50//
51// - Byteswap: on big endian machines, ints and floats are byte-swapped to the little endian on-disk format
52// - Cast: in-memory values can be stored in narrower on-disk columns. Currently without bounds checks.
53// For instance, for Double32_t, an in-memory double value is stored as a float on disk.
54// - Split: rearranges the bytes of an array of elements such that all the first bytes are stored first,
55// followed by all the second bytes, etc. This often clusters similar values, e.g. all the zero bytes
56// for arrays of small integers.
57// - Delta: Delta encoding stores on disk the delta to the previous element. This is useful for offsets,
58// because it transforms potentially large offset values into small deltas, which are then better
59// suited for split encoding.
60// - Zigzag: Zigzag encoding is used on signed integers only. It maps x to 2x if x is positive and to -(2x+1) if
61// x is negative. For series of positive and negative values of small absolute value, it will produce
62// a bit pattern that is favorable for split encoding.
63//
64// Encodings/conversions can be fused:
65//
66// - Delta/Zigzag + Splitting (there is no only-delta/zigzag encoding)
67// - (Delta/Zigzag + ) Splitting + Casting
68// - Everything + Byteswap
69
70/// \brief Copy and byteswap `count` elements of size `N` from `source` to `destination`.
71///
72/// Used on big-endian architectures for packing/unpacking elements whose column type requires
73/// a little-endian on-disk representation.
74template <std::size_t N>
75void CopyBswap(void *destination, const void *source, std::size_t count)
76{
77 auto dst = reinterpret_cast<typename RByteSwap<N>::value_type *>(destination);
78 auto src = reinterpret_cast<const typename RByteSwap<N>::value_type *>(source);
79 for (std::size_t i = 0; i < count; ++i) {
80 dst[i] = RByteSwap<N>::bswap(src[i]);
81 }
82}
83
84/// Casts T to one of the ints used in RByteSwap and back to its original type, which may be float or double
85#if R__LITTLE_ENDIAN == 0
86template <typename T>
87void ByteSwapIfNecessary(T &value)
88{
89 constexpr auto N = sizeof(T);
90 using bswap_value_type = typename RByteSwap<N>::value_type;
91 void *valuePtr = &value;
92 auto swapped = RByteSwap<N>::bswap(*reinterpret_cast<bswap_value_type *>(valuePtr));
93 *reinterpret_cast<bswap_value_type *>(valuePtr) = swapped;
94}
95#else
96#define ByteSwapIfNecessary(x) ((void)0)
97#endif
98
99/// \brief Pack `count` elements into narrower (or wider) type
100///
101/// Used to convert in-memory elements to smaller column types of comatible types
102/// (e.g., double to float, int64 to int32). Takes care of byte swap if necessary.
103template <typename DestT, typename SourceT>
104static void CastPack(void *destination, const void *source, std::size_t count)
105{
106 static_assert(std::is_convertible_v<SourceT, DestT>);
107 auto dst = reinterpret_cast<DestT *>(destination);
108 auto src = reinterpret_cast<const SourceT *>(source);
109 for (std::size_t i = 0; i < count; ++i) {
110 dst[i] = src[i];
111 ByteSwapIfNecessary(dst[i]);
112 }
113}
114
115/// \brief Unpack `count` on-disk elements into wider (or narrower) in-memory array
116///
117/// Used to convert on-disk elements to larger C++ types of comatible types
118/// (e.g., float to double, int32 to int64). Takes care of byte swap if necessary.
119template <typename DestT, typename SourceT>
120static void CastUnpack(void *destination, const void *source, std::size_t count)
121{
122 auto dst = reinterpret_cast<DestT *>(destination);
123 auto src = reinterpret_cast<const SourceT *>(source);
124 for (std::size_t i = 0; i < count; ++i) {
125 SourceT val = src[i];
126 ByteSwapIfNecessary(val);
127 dst[i] = val;
128 }
129}
130
131/// \brief Split encoding of elements, possibly into narrower column
132///
133/// Used to first cast and then split-encode in-memory values to the on-disk column. Swap bytes if necessary.
134template <typename DestT, typename SourceT>
135static void CastSplitPack(void *destination, const void *source, std::size_t count)
136{
137 constexpr std::size_t N = sizeof(DestT);
138 auto splitArray = reinterpret_cast<char *>(destination);
139 auto src = reinterpret_cast<const SourceT *>(source);
140 for (std::size_t i = 0; i < count; ++i) {
141 DestT val = src[i];
142 ByteSwapIfNecessary(val);
143 for (std::size_t b = 0; b < N; ++b) {
144 splitArray[b * count + i] = reinterpret_cast<const char *>(&val)[b];
145 }
146 }
147}
148
149/// \brief Reverse split encoding of elements
150///
151/// Used to first unsplit a column, possibly storing elements in wider C++ types. Swaps bytes if necessary
152template <typename DestT, typename SourceT>
153static void CastSplitUnpack(void *destination, const void *source, std::size_t count)
154{
155 constexpr std::size_t N = sizeof(SourceT);
156 auto dst = reinterpret_cast<DestT *>(destination);
157 auto splitArray = reinterpret_cast<const char *>(source);
158 for (std::size_t i = 0; i < count; ++i) {
159 SourceT val = 0;
160 for (std::size_t b = 0; b < N; ++b) {
161 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
162 }
163 ByteSwapIfNecessary(val);
164 dst[i] = val;
165 }
166}
167
168/// \brief Packing of columns with delta + split encoding
169///
170/// Apply split encoding to delta-encoded values, currently used only for index columns
171template <typename DestT, typename SourceT>
172static void CastDeltaSplitPack(void *destination, const void *source, std::size_t count)
173{
174 constexpr std::size_t N = sizeof(DestT);
175 auto src = reinterpret_cast<const SourceT *>(source);
176 auto splitArray = reinterpret_cast<char *>(destination);
177 for (std::size_t i = 0; i < count; ++i) {
178 DestT val = (i == 0) ? src[0] : src[i] - src[i - 1];
179 ByteSwapIfNecessary(val);
180 for (std::size_t b = 0; b < N; ++b) {
181 splitArray[b * count + i] = reinterpret_cast<char *>(&val)[b];
182 }
183 }
184}
185
186/// \brief Unsplit and unwind delta encoding
187///
188/// Unsplit a column and reverse the delta encoding, currently used only for index columns
189template <typename DestT, typename SourceT>
190static void CastDeltaSplitUnpack(void *destination, const void *source, std::size_t count)
191{
192 constexpr std::size_t N = sizeof(SourceT);
193 auto splitArray = reinterpret_cast<const char *>(source);
194 auto dst = reinterpret_cast<DestT *>(destination);
195 for (std::size_t i = 0; i < count; ++i) {
196 SourceT val = 0;
197 for (std::size_t b = 0; b < N; ++b) {
198 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
199 }
200 ByteSwapIfNecessary(val);
201 dst[i] = (i == 0) ? val : dst[i - 1] + val;
202 }
203}
204
205/// \brief Packing of columns with zigzag + split encoding
206///
207/// Apply split encoding to zigzag-encoded values, used for signed integers
208template <typename DestT, typename SourceT>
209static void CastZigzagSplitPack(void *destination, const void *source, std::size_t count)
210{
211 using UDestT = std::make_unsigned_t<DestT>;
212 constexpr std::size_t kNBitsDestT = sizeof(DestT) * 8;
213 constexpr std::size_t N = sizeof(DestT);
214 auto src = reinterpret_cast<const SourceT *>(source);
215 auto splitArray = reinterpret_cast<char *>(destination);
216 for (std::size_t i = 0; i < count; ++i) {
217 UDestT val = (static_cast<DestT>(src[i]) << 1) ^ (static_cast<DestT>(src[i]) >> (kNBitsDestT - 1));
218 ByteSwapIfNecessary(val);
219 for (std::size_t b = 0; b < N; ++b) {
220 splitArray[b * count + i] = reinterpret_cast<char *>(&val)[b];
221 }
222 }
223}
224
225/// \brief Unsplit and unwind zigzag encoding
226///
227/// Unsplit a column and reverse the zigzag encoding, used for signed integer columns
228template <typename DestT, typename SourceT>
229static void CastZigzagSplitUnpack(void *destination, const void *source, std::size_t count)
230{
231 using USourceT = std::make_unsigned_t<SourceT>;
232 constexpr std::size_t N = sizeof(SourceT);
233 auto splitArray = reinterpret_cast<const char *>(source);
234 auto dst = reinterpret_cast<DestT *>(destination);
235 for (std::size_t i = 0; i < count; ++i) {
236 USourceT val = 0;
237 for (std::size_t b = 0; b < N; ++b) {
238 reinterpret_cast<char *>(&val)[b] = splitArray[b * count + i];
239 }
240 ByteSwapIfNecessary(val);
241 dst[i] = static_cast<SourceT>((val >> 1) ^ -(static_cast<SourceT>(val) & 1));
242 }
243}
244
245} // anonymous namespace
246
247namespace ROOT {
248namespace Experimental {
249namespace Internal {
250
251// clang-format off
252/**
253\class ROOT::Experimental::Internal::RColumnElementBase
254\ingroup NTuple
255\brief A column element encapsulates the translation between basic C++ types and their column representation.
256
257Usually the on-disk element should map bitwise to the in-memory element. Sometimes that's not the case
258though, for instance on big endian platforms or for bools.
259
260There is a template specialization for every valid pair of C++ type and column representation.
261These specialized child classes are responsible for overriding `Pack()` / `Unpack()` for packing / unpacking elements
262as appropriate.
263*/
264// clang-format on
266protected:
267 /// Size of the C++ value that corresponds to the on-disk element
268 std::size_t fSize;
269 std::size_t fBitsOnStorage;
270
271 explicit RColumnElementBase(std::size_t size, std::size_t bitsOnStorage = 0)
272 : fSize(size), fBitsOnStorage(bitsOnStorage ? bitsOnStorage : 8 * size)
273 {
274 }
275
276public:
277 RColumnElementBase(const RColumnElementBase& other) = default;
281 virtual ~RColumnElementBase() = default;
282
283 /// If CppT == void, use the default C++ type for the given column type
284 template <typename CppT = void>
285 static std::unique_ptr<RColumnElementBase> Generate(EColumnType type);
286 static std::size_t GetBitsOnStorage(EColumnType type);
287 static std::string GetTypeName(EColumnType type);
288
289 /// Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout
290 virtual bool IsMappable() const
291 {
292 R__ASSERT(false);
293 return false;
294 }
295
296 /// If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-memory page
297 virtual void Pack(void *destination, void *source, std::size_t count) const
298 {
299 std::memcpy(destination, source, count);
300 }
301
302 /// If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-storage page
303 virtual void Unpack(void *destination, void *source, std::size_t count) const
304 {
305 std::memcpy(destination, source, count);
306 }
307
308 std::size_t GetSize() const { return fSize; }
309 std::size_t GetBitsOnStorage() const { return fBitsOnStorage; }
310 std::size_t GetPackedSize(std::size_t nElements = 1U) const { return (nElements * fBitsOnStorage + 7) / 8; }
311}; // class RColumnElementBase
312
313/**
314 * Base class for columns whose on-storage representation is little-endian.
315 * The implementation of `Pack` and `Unpack` takes care of byteswap if the memory page is big-endian.
316 */
317template <typename CppT>
319protected:
320 explicit RColumnElementLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage) {}
321
322public:
323 static constexpr bool kIsMappable = (R__LITTLE_ENDIAN == 1);
324
325 void Pack(void *dst, void *src, std::size_t count) const final
326 {
327#if R__LITTLE_ENDIAN == 1
328 RColumnElementBase::Pack(dst, src, count);
329#else
330 CopyBswap<sizeof(CppT)>(dst, src, count);
331#endif
332 }
333 void Unpack(void *dst, void *src, std::size_t count) const final
334 {
335#if R__LITTLE_ENDIAN == 1
336 RColumnElementBase::Unpack(dst, src, count);
337#else
338 CopyBswap<sizeof(CppT)>(dst, src, count);
339#endif
340 }
341}; // class RColumnElementLE
342
343/**
344 * Base class for columns storing elements of wider in-memory types,
345 * such as 64bit in-memory offsets to Index32 columns.
346 */
347template <typename CppT, typename NarrowT>
349protected:
350 explicit RColumnElementCastLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage)
351 {
352 }
353
354public:
355 static constexpr bool kIsMappable = false;
356
357 void Pack(void *dst, void *src, std::size_t count) const final { CastPack<NarrowT, CppT>(dst, src, count); }
358 void Unpack(void *dst, void *src, std::size_t count) const final { CastUnpack<CppT, NarrowT>(dst, src, count); }
359}; // class RColumnElementCastLE
360
361/**
362 * Base class for split columns whose on-storage representation is little-endian.
363 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
364 * As part of the splitting, can also narrow down the type to NarrowT.
365 */
366template <typename CppT, typename NarrowT>
368protected:
369 explicit RColumnElementSplitLE(std::size_t size, std::size_t bitsOnStorage) : RColumnElementBase(size, bitsOnStorage)
370 {
371 }
372
373public:
374 static constexpr bool kIsMappable = false;
375
376 void Pack(void *dst, void *src, std::size_t count) const final { CastSplitPack<NarrowT, CppT>(dst, src, count); }
377 void Unpack(void *dst, void *src, std::size_t count) const final { CastSplitUnpack<CppT, NarrowT>(dst, src, count); }
378}; // class RColumnElementSplitLE
379
380/**
381 * Base class for delta + split columns (index columns) whose on-storage representation is little-endian.
382 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
383 * As part of the encoding, can also narrow down the type to NarrowT.
384 */
385template <typename CppT, typename NarrowT>
387protected:
388 explicit RColumnElementDeltaSplitLE(std::size_t size, std::size_t bitsOnStorage)
389 : RColumnElementBase(size, bitsOnStorage)
390 {
391 }
392
393public:
394 static constexpr bool kIsMappable = false;
395
396 void Pack(void *dst, void *src, std::size_t count) const final
397 {
398 CastDeltaSplitPack<NarrowT, CppT>(dst, src, count);
399 }
400 void Unpack(void *dst, void *src, std::size_t count) const final
401 {
402 CastDeltaSplitUnpack<CppT, NarrowT>(dst, src, count);
403 }
404}; // class RColumnElementDeltaSplitLE
405
406/**
407 * Base class for zigzag + split columns (signed integer columns) whose on-storage representation is little-endian.
408 * The implementation of `Pack` and `Unpack` takes care of splitting and, if necessary, byteswap.
409 * The NarrowT target type should be an signed integer, which can be smaller than the CppT source type.
410 */
411template <typename CppT, typename NarrowT>
413protected:
414 explicit RColumnElementZigzagSplitLE(std::size_t size, std::size_t bitsOnStorage)
415 : RColumnElementBase(size, bitsOnStorage)
416 {
417 }
418
419public:
420 static constexpr bool kIsMappable = false;
421
422 void Pack(void *dst, void *src, std::size_t count) const final
423 {
424 CastZigzagSplitPack<NarrowT, CppT>(dst, src, count);
425 }
426 void Unpack(void *dst, void *src, std::size_t count) const final
427 {
428 CastZigzagSplitUnpack<CppT, NarrowT>(dst, src, count);
429 }
430}; // class RColumnElementZigzagSplitLE
431
432////////////////////////////////////////////////////////////////////////////////
433// Pairs of C++ type and column type, like float and EColumnType::kReal32
434////////////////////////////////////////////////////////////////////////////////
435
436////////////////////////////////////////////////////////////////////////////////
437// Part 1: C++ type --> unknown column type
438////////////////////////////////////////////////////////////////////////////////
439
440template <typename CppT, EColumnType ColumnT = EColumnType::kUnknown>
442public:
444 {
445 throw RException(R__FAIL(std::string("internal error: no column mapping for this C++ type: ") +
446 typeid(CppT).name() + " --> " + GetTypeName(ColumnT)));
447 }
448};
449
450template <>
452public:
453 static constexpr std::size_t kSize = sizeof(bool);
455};
456
457template <>
458class RColumnElement<std::byte, EColumnType::kUnknown> : public RColumnElementBase {
459public:
460 static constexpr std::size_t kSize = sizeof(std::byte);
461 RColumnElement() : RColumnElementBase(kSize) {}
462};
463
464template <>
466public:
467 static constexpr std::size_t kSize = sizeof(char);
469};
470
471template <>
472class RColumnElement<std::int8_t, EColumnType::kUnknown> : public RColumnElementBase {
473public:
474 static constexpr std::size_t kSize = sizeof(std::int8_t);
475 RColumnElement() : RColumnElementBase(kSize) {}
476};
477
478template <>
479class RColumnElement<std::uint8_t, EColumnType::kUnknown> : public RColumnElementBase {
480public:
481 static constexpr std::size_t kSize = sizeof(std::uint8_t);
482 RColumnElement() : RColumnElementBase(kSize) {}
483};
484
485template <>
486class RColumnElement<std::int16_t, EColumnType::kUnknown> : public RColumnElementBase {
487public:
488 static constexpr std::size_t kSize = sizeof(std::int16_t);
490};
491
492template <>
493class RColumnElement<std::uint16_t, EColumnType::kUnknown> : public RColumnElementBase {
494public:
495 static constexpr std::size_t kSize = sizeof(std::uint16_t);
497};
498
499template <>
500class RColumnElement<std::int32_t, EColumnType::kUnknown> : public RColumnElementBase {
501public:
502 static constexpr std::size_t kSize = sizeof(std::int32_t);
504};
505
506template <>
507class RColumnElement<std::uint32_t, EColumnType::kUnknown> : public RColumnElementBase {
508public:
509 static constexpr std::size_t kSize = sizeof(std::uint32_t);
511};
512
513template <>
514class RColumnElement<std::int64_t, EColumnType::kUnknown> : public RColumnElementBase {
515public:
516 static constexpr std::size_t kSize = sizeof(std::int64_t);
518};
519
520template <>
521class RColumnElement<std::uint64_t, EColumnType::kUnknown> : public RColumnElementBase {
522public:
523 static constexpr std::size_t kSize = sizeof(std::uint64_t);
525};
526
527template <>
529public:
530 static constexpr std::size_t kSize = sizeof(float);
532};
533
534template <>
536public:
537 static constexpr std::size_t kSize = sizeof(double);
539};
540
541template <>
543public:
544 static constexpr std::size_t kSize = sizeof(ClusterSize_t);
546};
547
548template <>
550public:
551 static constexpr std::size_t kSize = sizeof(RColumnSwitch);
553};
554
555////////////////////////////////////////////////////////////////////////////////
556// Part 2: C++ type --> supported column representations,
557// ordered by C++ type
558////////////////////////////////////////////////////////////////////////////////
559
560template <>
562private:
563 struct RSwitchElement {
564 std::uint64_t fIndex;
565 std::uint32_t fTag;
566 };
567
568public:
569 static constexpr bool kIsMappable = false;
570 static constexpr std::size_t kSize = sizeof(ROOT::Experimental::RColumnSwitch);
571 static constexpr std::size_t kBitsOnStorage = 96;
573 bool IsMappable() const final { return kIsMappable; }
574
575 void Pack(void *dst, void *src, std::size_t count) const final
576 {
577 auto srcArray = reinterpret_cast<ROOT::Experimental::RColumnSwitch *>(src);
578 auto dstArray = reinterpret_cast<unsigned char *>(dst);
579 for (std::size_t i = 0; i < count; ++i) {
580 RSwitchElement element{srcArray[i].GetIndex(), srcArray[i].GetTag()};
581#if R__LITTLE_ENDIAN == 0
582 element.fIndex = RByteSwap<8>::bswap(element.fIndex);
583 element.fTag = RByteSwap<8>::bswap(element.fTag);
584#endif
585 memcpy(dstArray + i * 12, &element, 12);
586 }
587 }
588
589 void Unpack(void *dst, void *src, std::size_t count) const final
590 {
591 auto srcArray = reinterpret_cast<unsigned char *>(src);
592 auto dstArray = reinterpret_cast<ROOT::Experimental::RColumnSwitch *>(dst);
593 for (std::size_t i = 0; i < count; ++i) {
594 RSwitchElement element;
595 memcpy(&element, srcArray + i * 12, 12);
596#if R__LITTLE_ENDIAN == 0
597 element.fIndex = RByteSwap<8>::bswap(element.fIndex);
598 element.fTag = RByteSwap<8>::bswap(element.fTag);
599#endif
600 dstArray[i] = ROOT::Experimental::RColumnSwitch(ClusterSize_t{element.fIndex}, element.fTag);
601 }
602 }
603};
604
605template <>
607public:
608 static constexpr bool kIsMappable = false;
609 static constexpr std::size_t kSize = sizeof(bool);
610 static constexpr std::size_t kBitsOnStorage = 1;
612 bool IsMappable() const final { return kIsMappable; }
613
614 void Pack(void *dst, void *src, std::size_t count) const final;
615 void Unpack(void *dst, void *src, std::size_t count) const final;
616};
617
618template <>
620public:
621 static constexpr bool kIsMappable = false;
622 static constexpr std::size_t kSize = sizeof(float);
623 static constexpr std::size_t kBitsOnStorage = 16;
625 bool IsMappable() const final { return kIsMappable; }
626
627 void Pack(void *dst, void *src, std::size_t count) const final
628 {
629 float *floatArray = reinterpret_cast<float *>(src);
630 std::uint16_t *uint16Array = reinterpret_cast<std::uint16_t *>(dst);
631
632 for (std::size_t i = 0; i < count; ++i) {
633 uint16Array[i] = FloatToHalf(floatArray[i]);
634 ByteSwapIfNecessary(uint16Array[i]);
635 }
636 }
637
638 void Unpack(void *dst, void *src, std::size_t count) const final
639 {
640 float *floatArray = reinterpret_cast<float *>(dst);
641 std::uint16_t *uint16Array = reinterpret_cast<std::uint16_t *>(src);
642
643 for (std::size_t i = 0; i < count; ++i) {
644 ByteSwapIfNecessary(floatArray[i]);
645 floatArray[i] = HalfToFloat(uint16Array[i]);
646 }
647 }
648};
649
650#define __RCOLUMNELEMENT_SPEC_BODY(CppT, BaseT, BitsOnStorage) \
651 static constexpr std::size_t kSize = sizeof(CppT); \
652 static constexpr std::size_t kBitsOnStorage = BitsOnStorage; \
653 RColumnElement() : BaseT(kSize, kBitsOnStorage) {} \
654 bool IsMappable() const final \
655 { \
656 return kIsMappable; \
657 }
658/// These macros are used to declare `RColumnElement` template specializations below. Additional arguments can be used
659/// to forward template parameters to the base class, e.g.
660/// ```
661/// DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kInt32, 32,
662/// RColumnElementCastLE, <std::int64_t, std::int32_t>);
663/// ```
664#define DECLARE_RCOLUMNELEMENT_SPEC(CppT, ColumnT, BitsOnStorage, BaseT, ...) \
665 template <> \
666 class RColumnElement<CppT, ColumnT> : public BaseT __VA_ARGS__ { \
667 public: \
668 __RCOLUMNELEMENT_SPEC_BODY(CppT, BaseT, BitsOnStorage) \
669 }
670#define DECLARE_RCOLUMNELEMENT_SPEC_SIMPLE(CppT, ColumnT, BitsOnStorage) \
671 template <> \
672 class RColumnElement<CppT, ColumnT> : public RColumnElementBase { \
673 public: \
674 static constexpr bool kIsMappable = true; \
675 __RCOLUMNELEMENT_SPEC_BODY(CppT, RColumnElementBase, BitsOnStorage) \
676 }
677
679
682
686
690
691DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, EColumnType::kInt16, 16, RColumnElementLE, <std::int16_t>);
692DECLARE_RCOLUMNELEMENT_SPEC(std::int16_t, EColumnType::kUInt16, 16, RColumnElementLE, <std::int16_t>);
694 <std::int16_t, std::int16_t>);
696 <std::int16_t, std::uint16_t>);
697
698DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, EColumnType::kUInt16, 16, RColumnElementLE, <std::uint16_t>);
699DECLARE_RCOLUMNELEMENT_SPEC(std::uint16_t, EColumnType::kInt16, 16, RColumnElementLE, <std::uint16_t>);
701 <std::uint16_t, std::uint16_t>);
703 <std::uint16_t, std::int16_t>);
704
705DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, EColumnType::kInt32, 32, RColumnElementLE, <std::int32_t>);
706DECLARE_RCOLUMNELEMENT_SPEC(std::int32_t, EColumnType::kUInt32, 32, RColumnElementLE, <std::int32_t>);
708 <std::int32_t, std::int32_t>);
710 <std::int32_t, std::uint32_t>);
711
712DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, EColumnType::kUInt32, 32, RColumnElementLE, <std::uint32_t>);
713DECLARE_RCOLUMNELEMENT_SPEC(std::uint32_t, EColumnType::kInt32, 32, RColumnElementLE, <std::uint32_t>);
715 <std::uint32_t, std::uint32_t>);
717 <std::uint32_t, std::int32_t>);
718
719DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kInt64, 64, RColumnElementLE, <std::int64_t>);
720DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kUInt64, 64, RColumnElementLE, <std::int64_t>);
722 <std::int64_t, std::int64_t>);
724 <std::int64_t, std::uint64_t>);
725DECLARE_RCOLUMNELEMENT_SPEC(std::int64_t, EColumnType::kInt32, 32, RColumnElementCastLE, <std::int64_t, std::int32_t>);
727 <std::int64_t, std::uint32_t>);
729 <std::int64_t, std::int32_t>);
731 <std::int64_t, std::uint32_t>);
732
733DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, EColumnType::kUInt64, 64, RColumnElementLE, <std::uint64_t>);
734DECLARE_RCOLUMNELEMENT_SPEC(std::uint64_t, EColumnType::kInt64, 64, RColumnElementLE, <std::uint64_t>);
736 <std::uint64_t, std::uint64_t>);
738 <std::uint64_t, std::int64_t>);
739
742
747
750 <std::uint64_t, std::uint32_t>);
752 <std::uint64_t, std::uint64_t>);
754 <std::uint64_t, std::uint32_t>);
755
756template <typename CppT>
757std::unique_ptr<RColumnElementBase> RColumnElementBase::Generate(EColumnType type)
758{
759 switch (type) {
760 case EColumnType::kIndex64: return std::make_unique<RColumnElement<CppT, EColumnType::kIndex64>>();
761 case EColumnType::kIndex32: return std::make_unique<RColumnElement<CppT, EColumnType::kIndex32>>();
762 case EColumnType::kSwitch: return std::make_unique<RColumnElement<CppT, EColumnType::kSwitch>>();
763 case EColumnType::kByte: return std::make_unique<RColumnElement<CppT, EColumnType::kByte>>();
764 case EColumnType::kChar: return std::make_unique<RColumnElement<CppT, EColumnType::kChar>>();
765 case EColumnType::kBit: return std::make_unique<RColumnElement<CppT, EColumnType::kBit>>();
766 case EColumnType::kReal64: return std::make_unique<RColumnElement<CppT, EColumnType::kReal64>>();
767 case EColumnType::kReal32: return std::make_unique<RColumnElement<CppT, EColumnType::kReal32>>();
768 case EColumnType::kReal16: return std::make_unique<RColumnElement<CppT, EColumnType::kReal16>>();
769 case EColumnType::kInt64: return std::make_unique<RColumnElement<CppT, EColumnType::kInt64>>();
770 case EColumnType::kUInt64: return std::make_unique<RColumnElement<CppT, EColumnType::kUInt64>>();
771 case EColumnType::kInt32: return std::make_unique<RColumnElement<CppT, EColumnType::kInt32>>();
772 case EColumnType::kUInt32: return std::make_unique<RColumnElement<CppT, EColumnType::kUInt32>>();
773 case EColumnType::kInt16: return std::make_unique<RColumnElement<CppT, EColumnType::kInt16>>();
774 case EColumnType::kUInt16: return std::make_unique<RColumnElement<CppT, EColumnType::kUInt16>>();
775 case EColumnType::kInt8: return std::make_unique<RColumnElement<CppT, EColumnType::kInt8>>();
776 case EColumnType::kUInt8: return std::make_unique<RColumnElement<CppT, EColumnType::kUInt8>>();
777 case EColumnType::kSplitIndex64: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitIndex64>>();
778 case EColumnType::kSplitIndex32: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitIndex32>>();
779 case EColumnType::kSplitReal64: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitReal64>>();
780 case EColumnType::kSplitReal32: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitReal32>>();
781 case EColumnType::kSplitInt64: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitInt64>>();
782 case EColumnType::kSplitUInt64: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitUInt64>>();
783 case EColumnType::kSplitInt32: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitInt32>>();
784 case EColumnType::kSplitUInt32: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitUInt32>>();
785 case EColumnType::kSplitInt16: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitInt16>>();
786 case EColumnType::kSplitUInt16: return std::make_unique<RColumnElement<CppT, EColumnType::kSplitUInt16>>();
787 default: R__ASSERT(false);
788 }
789 // never here
790 return nullptr;
791}
792
793template <>
794std::unique_ptr<RColumnElementBase> RColumnElementBase::Generate<void>(EColumnType type);
795
796} // namespace Internal
797} // namespace Experimental
798} // namespace ROOT
799
800#endif
#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)
Definition TError.h:118
#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
A column element encapsulates the translation between basic C++ types and their column representation...
RColumnElementBase & operator=(const RColumnElementBase &other)=delete
RColumnElementBase(std::size_t size, std::size_t bitsOnStorage=0)
virtual void Pack(void *destination, void *source, std::size_t count) const
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
virtual void Unpack(void *destination, void *source, std::size_t count) const
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
virtual bool IsMappable() const
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
static std::string GetTypeName(EColumnType type)
std::size_t fSize
Size of the C++ value that corresponds to the on-disk element.
RColumnElementBase(const RColumnElementBase &other)=default
static std::unique_ptr< RColumnElementBase > Generate(EColumnType type)
If CppT == void, use the default C++ type for the given column type.
std::size_t GetPackedSize(std::size_t nElements=1U) const
RColumnElementBase(RColumnElementBase &&other)=default
Base class for columns storing elements of wider in-memory types, such as 64bit in-memory offsets to ...
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
RColumnElementCastLE(std::size_t size, std::size_t bitsOnStorage)
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
Base class for delta + split columns (index columns) whose on-storage representation is little-endian...
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
RColumnElementDeltaSplitLE(std::size_t size, std::size_t bitsOnStorage)
Base class for columns whose on-storage representation is little-endian.
RColumnElementLE(std::size_t size, std::size_t bitsOnStorage)
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
Base class for split columns whose on-storage representation is little-endian.
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
RColumnElementSplitLE(std::size_t size, std::size_t bitsOnStorage)
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
Base class for zigzag + split columns (signed integer columns) whose on-storage representation is lit...
RColumnElementZigzagSplitLE(std::size_t size, std::size_t bitsOnStorage)
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
void Unpack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, unpacking creates a memory page from an on-...
void Pack(void *dst, void *src, std::size_t count) const final
If the on-storage layout and the in-memory layout differ, packing creates an on-disk page from an in-...
bool IsMappable() const final
Derived, typed classes tell whether the on-storage layout is bitwise identical to the memory layout.
Holds the index and the tag of a kSwitch column.
ClusterSize_t GetIndex() const
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
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
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