Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RColumnElement.cxx
Go to the documentation of this file.
1/// \file RColumnElement.cxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2019-08-11
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#include "ROOT/RColumn.hxx"
15
16#include "RColumnElement.hxx"
17
18#include <algorithm>
19#include <bitset>
20#include <cassert>
21#include <cstdint>
22#include <memory>
23#include <utility>
24
27
29{
30 switch (type) {
31 case ENTupleColumnType::kIndex64: return std::make_pair(64, 64);
32 case ENTupleColumnType::kIndex32: return std::make_pair(32, 32);
33 case ENTupleColumnType::kSwitch: return std::make_pair(96, 96);
34 case ENTupleColumnType::kByte: return std::make_pair(8, 8);
35 case ENTupleColumnType::kChar: return std::make_pair(8, 8);
36 case ENTupleColumnType::kBit: return std::make_pair(1, 1);
37 case ENTupleColumnType::kReal64: return std::make_pair(64, 64);
38 case ENTupleColumnType::kReal32: return std::make_pair(32, 32);
39 case ENTupleColumnType::kReal16: return std::make_pair(16, 16);
40 case ENTupleColumnType::kInt64: return std::make_pair(64, 64);
41 case ENTupleColumnType::kUInt64: return std::make_pair(64, 64);
42 case ENTupleColumnType::kInt32: return std::make_pair(32, 32);
43 case ENTupleColumnType::kUInt32: return std::make_pair(32, 32);
44 case ENTupleColumnType::kInt16: return std::make_pair(16, 16);
45 case ENTupleColumnType::kUInt16: return std::make_pair(16, 16);
46 case ENTupleColumnType::kInt8: return std::make_pair(8, 8);
47 case ENTupleColumnType::kUInt8: return std::make_pair(8, 8);
48 case ENTupleColumnType::kSplitIndex64: return std::make_pair(64, 64);
49 case ENTupleColumnType::kSplitIndex32: return std::make_pair(32, 32);
50 case ENTupleColumnType::kSplitReal64: return std::make_pair(64, 64);
51 case ENTupleColumnType::kSplitReal32: return std::make_pair(32, 32);
52 case ENTupleColumnType::kSplitInt64: return std::make_pair(64, 64);
53 case ENTupleColumnType::kSplitUInt64: return std::make_pair(64, 64);
54 case ENTupleColumnType::kSplitInt32: return std::make_pair(32, 32);
55 case ENTupleColumnType::kSplitUInt32: return std::make_pair(32, 32);
56 case ENTupleColumnType::kSplitInt16: return std::make_pair(16, 16);
57 case ENTupleColumnType::kSplitUInt16: return std::make_pair(16, 16);
58 case ENTupleColumnType::kReal32Trunc: return std::make_pair(10, 31);
59 case ENTupleColumnType::kReal32Quant: return std::make_pair(1, 32);
60 default:
61 if (type == kTestFutureColumnType)
62 return std::make_pair(32, 32);
63 R__ASSERT(false);
64 }
65 // never here
66 return std::make_pair(0, 0);
67}
68
70{
71 switch (type) {
72 case ENTupleColumnType::kIndex64: return "Index64";
73 case ENTupleColumnType::kIndex32: return "Index32";
74 case ENTupleColumnType::kSwitch: return "Switch";
75 case ENTupleColumnType::kByte: return "Byte";
76 case ENTupleColumnType::kChar: return "Char";
77 case ENTupleColumnType::kBit: return "Bit";
78 case ENTupleColumnType::kReal64: return "Real64";
79 case ENTupleColumnType::kReal32: return "Real32";
80 case ENTupleColumnType::kReal16: return "Real16";
81 case ENTupleColumnType::kInt64: return "Int64";
82 case ENTupleColumnType::kUInt64: return "UInt64";
83 case ENTupleColumnType::kInt32: return "Int32";
84 case ENTupleColumnType::kUInt32: return "UInt32";
85 case ENTupleColumnType::kInt16: return "Int16";
86 case ENTupleColumnType::kUInt16: return "UInt16";
87 case ENTupleColumnType::kInt8: return "Int8";
88 case ENTupleColumnType::kUInt8: return "UInt8";
89 case ENTupleColumnType::kSplitIndex64: return "SplitIndex64";
90 case ENTupleColumnType::kSplitIndex32: return "SplitIndex32";
91 case ENTupleColumnType::kSplitReal64: return "SplitReal64";
92 case ENTupleColumnType::kSplitReal32: return "SplitReal32";
93 case ENTupleColumnType::kSplitInt64: return "SplitInt64";
94 case ENTupleColumnType::kSplitUInt64: return "SplitUInt64";
95 case ENTupleColumnType::kSplitInt32: return "SplitInt32";
96 case ENTupleColumnType::kSplitUInt32: return "SplitUInt32";
97 case ENTupleColumnType::kSplitInt16: return "SplitInt16";
98 case ENTupleColumnType::kSplitUInt16: return "SplitUInt16";
99 case ENTupleColumnType::kReal32Trunc: return "Real32Trunc";
100 case ENTupleColumnType::kReal32Quant: return "Real32Quant";
101 default:
102 if (type == kTestFutureColumnType)
103 return "TestFutureType";
104 return "UNKNOWN";
105 }
106}
107
108std::unique_ptr<ROOT::Internal::RColumnElementBase>
110{
111 const auto onDiskType = onDisk.GetType();
112 std::unique_ptr<ROOT::Internal::RColumnElementBase> elem;
113
114 //clang-format off
115 switch (onDiskType) {
116 case ENTupleColumnType::kIndex64: elem = std::make_unique<RColumnElement<RColumnIndex, ENTupleColumnType::kIndex64>>(); break;
117 case ENTupleColumnType::kIndex32: elem = std::make_unique<RColumnElement<RColumnIndex, ENTupleColumnType::kIndex32>>(); break;
118 case ENTupleColumnType::kSwitch: elem = std::make_unique<RColumnElement<RColumnSwitch, ENTupleColumnType::kSwitch>>(); break;
119 case ENTupleColumnType::kByte: elem = std::make_unique<RColumnElement<std::byte, ENTupleColumnType::kByte>>(); break;
120 case ENTupleColumnType::kChar: elem = std::make_unique<RColumnElement<char, ENTupleColumnType::kChar>>(); break;
121 case ENTupleColumnType::kBit: elem = std::make_unique<RColumnElement<bool, ENTupleColumnType::kBit>>(); break;
122 case ENTupleColumnType::kReal64: elem = std::make_unique<RColumnElement<double, ENTupleColumnType::kReal64>>(); break;
123 case ENTupleColumnType::kReal32: elem = std::make_unique<RColumnElement<float, ENTupleColumnType::kReal32>>(); break;
124 // TODO: Change to std::float16_t in-memory type once available (from C++23).
125 case ENTupleColumnType::kReal16: elem = std::make_unique<RColumnElement<float, ENTupleColumnType::kReal16>>(); break;
126 case ENTupleColumnType::kInt64: elem = std::make_unique<RColumnElement<std::int64_t, ENTupleColumnType::kInt64>>(); break;
127 case ENTupleColumnType::kUInt64: elem = std::make_unique<RColumnElement<std::uint64_t, ENTupleColumnType::kUInt64>>(); break;
128 case ENTupleColumnType::kInt32: elem = std::make_unique<RColumnElement<std::int32_t, ENTupleColumnType::kInt32>>(); break;
129 case ENTupleColumnType::kUInt32: elem = std::make_unique<RColumnElement<std::uint32_t, ENTupleColumnType::kUInt32>>(); break;
130 case ENTupleColumnType::kInt16: elem = std::make_unique<RColumnElement<std::int16_t, ENTupleColumnType::kInt16>>(); break;
131 case ENTupleColumnType::kUInt16: elem = std::make_unique<RColumnElement<std::uint16_t, ENTupleColumnType::kUInt16>>(); break;
132 case ENTupleColumnType::kInt8: elem = std::make_unique<RColumnElement<std::int8_t, ENTupleColumnType::kInt8>>(); break;
133 case ENTupleColumnType::kUInt8: elem = std::make_unique<RColumnElement<std::uint8_t, ENTupleColumnType::kUInt8>>(); break;
134 case ENTupleColumnType::kSplitIndex64: elem = std::make_unique<RColumnElement<RColumnIndex, ENTupleColumnType::kSplitIndex64>>(); break;
135 case ENTupleColumnType::kSplitIndex32: elem = std::make_unique<RColumnElement<RColumnIndex, ENTupleColumnType::kSplitIndex32>>(); break;
136 case ENTupleColumnType::kSplitReal64: elem = std::make_unique<RColumnElement<double, ENTupleColumnType::kSplitReal64>>(); break;
137 case ENTupleColumnType::kSplitReal32: elem = std::make_unique<RColumnElement<float, ENTupleColumnType::kSplitReal32>>(); break;
138 case ENTupleColumnType::kSplitInt64: elem = std::make_unique<RColumnElement<std::int64_t, ENTupleColumnType::kSplitInt64>>(); break;
139 case ENTupleColumnType::kSplitUInt64: elem = std::make_unique<RColumnElement<std::uint64_t, ENTupleColumnType::kSplitUInt64>>(); break;
140 case ENTupleColumnType::kSplitInt32: elem = std::make_unique<RColumnElement<std::int32_t, ENTupleColumnType::kSplitInt32>>(); break;
141 case ENTupleColumnType::kSplitUInt32: elem = std::make_unique<RColumnElement<std::uint32_t, ENTupleColumnType::kSplitUInt32>>(); break;
142 case ENTupleColumnType::kSplitInt16: elem = std::make_unique<RColumnElement<std::int16_t, ENTupleColumnType::kSplitInt16>>(); break;
143 case ENTupleColumnType::kSplitUInt16: elem = std::make_unique<RColumnElement<std::uint16_t, ENTupleColumnType::kSplitUInt16>>(); break;
144 case ENTupleColumnType::kReal32Trunc: elem = std::make_unique<RColumnElement<float, ENTupleColumnType::kReal32Trunc>>(); break;
145 case ENTupleColumnType::kReal32Quant: elem = std::make_unique<RColumnElement<float, ENTupleColumnType::kReal32Quant>>(); break;
146 default:
147 if (onDiskType == kTestFutureColumnType)
148 return std::make_unique<RColumnElement<Internal::RTestFutureColumn, kTestFutureColumnType>>();
149 R__ASSERT(false);
150 }
151 //clang-format on
152
153 elem->SetBitsOnStorage(onDisk.GetBitsOnStorage());
154 if (auto range = onDisk.GetValueRange())
155 elem->SetValueRange(range->fMin, range->fMax);
156
157 return elem;
158}
159
160std::unique_ptr<ROOT::Internal::RColumnElementBase>
161ROOT::Internal::GenerateColumnElement(std::type_index inMemoryType, ENTupleColumnType onDiskType)
162{
163 if (inMemoryType == std::type_index(typeid(char))) {
164 return GenerateColumnElementInternal<char>(onDiskType);
165 } else if (inMemoryType == std::type_index(typeid(bool))) {
166 return GenerateColumnElementInternal<bool>(onDiskType);
167 } else if (inMemoryType == std::type_index(typeid(std::byte))) {
168 return GenerateColumnElementInternal<std::byte>(onDiskType);
169 } else if (inMemoryType == std::type_index(typeid(std::uint8_t))) {
170 return GenerateColumnElementInternal<std::uint8_t>(onDiskType);
171 } else if (inMemoryType == std::type_index(typeid(std::uint16_t))) {
172 return GenerateColumnElementInternal<std::uint16_t>(onDiskType);
173 } else if (inMemoryType == std::type_index(typeid(std::uint32_t))) {
174 return GenerateColumnElementInternal<std::uint32_t>(onDiskType);
175 } else if (inMemoryType == std::type_index(typeid(std::uint64_t))) {
176 return GenerateColumnElementInternal<std::uint64_t>(onDiskType);
177 } else if (inMemoryType == std::type_index(typeid(std::int8_t))) {
178 return GenerateColumnElementInternal<std::int8_t>(onDiskType);
179 } else if (inMemoryType == std::type_index(typeid(std::int16_t))) {
180 return GenerateColumnElementInternal<std::int16_t>(onDiskType);
181 } else if (inMemoryType == std::type_index(typeid(std::int32_t))) {
182 return GenerateColumnElementInternal<std::int32_t>(onDiskType);
183 } else if (inMemoryType == std::type_index(typeid(std::int64_t))) {
184 return GenerateColumnElementInternal<std::int64_t>(onDiskType);
185 } else if (inMemoryType == std::type_index(typeid(float))) {
186 return GenerateColumnElementInternal<float>(onDiskType);
187 } else if (inMemoryType == std::type_index(typeid(double))) {
188 return GenerateColumnElementInternal<double>(onDiskType);
189 } else if (inMemoryType == std::type_index(typeid(RColumnIndex))) {
190 return GenerateColumnElementInternal<RColumnIndex>(onDiskType);
191 } else if (inMemoryType == std::type_index(typeid(RColumnSwitch))) {
192 return GenerateColumnElementInternal<RColumnSwitch>(onDiskType);
193 } else if (inMemoryType == std::type_index(typeid(RTestFutureColumn))) {
194 return GenerateColumnElementInternal<RTestFutureColumn>(onDiskType);
195 } else {
196 R__ASSERT(!"Invalid memory type in GenerateColumnElement");
197 }
198 // never here
199 return nullptr;
200}
201
202std::unique_ptr<ROOT::Internal::RColumnElementBase>
203ROOT::Internal::GenerateColumnElement(std::type_index inMemoryType, const ROOT::RColumnDescriptor &onDisk)
204{
205 auto elem = GenerateColumnElement(inMemoryType, onDisk.GetType());
206 elem->SetBitsOnStorage(onDisk.GetBitsOnStorage());
207 if (auto range = onDisk.GetValueRange())
208 elem->SetValueRange(range->fMin, range->fMax);
209 return elem;
210}
211
212std::unique_ptr<ROOT::Internal::RColumnElementBase>
217
218void ROOT::Internal::BitPacking::PackBits(void *dst, const void *src, std::size_t count, std::size_t sizeofSrc,
219 std::size_t nDstBits)
220{
221 assert(sizeofSrc <= sizeof(Word_t));
222 assert(0 < nDstBits && nDstBits <= sizeofSrc * 8);
223
224 const unsigned char *srcArray = reinterpret_cast<const unsigned char *>(src);
225 Word_t *dstArray = reinterpret_cast<Word_t *>(dst);
226 Word_t accum = 0;
227 std::size_t bitsUsed = 0;
228 std::size_t dstIdx = 0;
229 for (std::size_t i = 0; i < count; ++i) {
230 Word_t packedWord = 0;
231#if R__LITTLE_ENDIAN == 0
232 memcpy(reinterpret_cast<unsigned char *>(&packedWord) + (sizeof(Word_t) - sizeofSrc), srcArray + i * sizeofSrc,
233 sizeofSrc);
234#else
235 memcpy(&packedWord, srcArray + i * sizeofSrc, sizeofSrc);
236#endif
237 // truncate the LSB of the item
238 packedWord >>= sizeofSrc * 8 - nDstBits;
239
240 const std::size_t bitsRem = kBitsPerWord - bitsUsed;
241 if (bitsRem >= nDstBits) {
242 // append the entire item to the accumulator
243 accum |= (packedWord << bitsUsed);
244 bitsUsed += nDstBits;
245 } else {
246 // chop up the item into its `bitsRem` LSB bits + `nDstBits - bitsRem` MSB bits.
247 // The LSB bits will be saved in the current word and the MSB will be saved in the next one.
248 if (bitsRem > 0) {
249 Word_t packedWordLsb = packedWord;
250 packedWordLsb <<= (kBitsPerWord - bitsRem);
251 packedWordLsb >>= (kBitsPerWord - bitsRem);
252 accum |= (packedWordLsb << bitsUsed);
253 }
254
255 ByteSwapIfNecessary(accum);
256 memcpy(&dstArray[dstIdx++], &accum, sizeof(accum));
257 accum = 0;
258 bitsUsed = 0;
259
260 if (bitsRem > 0) {
261 Word_t packedWordMsb = packedWord;
262 packedWordMsb >>= bitsRem;
263 accum |= packedWordMsb;
264 bitsUsed += nDstBits - bitsRem;
265 } else {
266 // we realigned to a word boundary: append the entire item
267 accum = packedWord;
268 bitsUsed += nDstBits;
269 }
270 }
271 }
272
273 if (bitsUsed) {
274 ByteSwapIfNecessary(accum);
275 memcpy(&dstArray[dstIdx++], &accum, (bitsUsed + 7) / 8);
276 }
277
278 [[maybe_unused]] auto expDstCount = (count * nDstBits + kBitsPerWord - 1) / kBitsPerWord;
279 assert(dstIdx == expDstCount);
280}
281
282void ROOT::Internal::BitPacking::UnpackBits(void *dst, const void *src, std::size_t count, std::size_t sizeofDst,
283 std::size_t nSrcBits)
284{
285 assert(sizeofDst <= sizeof(Word_t));
286 assert(0 < nSrcBits && nSrcBits <= sizeofDst * 8);
287
288 unsigned char *dstArray = reinterpret_cast<unsigned char *>(dst);
289 const Word_t *srcArray = reinterpret_cast<const Word_t *>(src);
290 const auto nWordsToLoad = (count * nSrcBits + kBitsPerWord - 1) / kBitsPerWord;
291
292 // bit offset of the next packed item inside the currently loaded word
293 int offInWord = 0;
294 std::size_t dstIdx = 0;
295 Word_t prevWordLsb = 0;
296 std::size_t remBytesToLoad = (count * nSrcBits + 7) / 8;
297 for (std::size_t i = 0; i < nWordsToLoad; ++i) {
298 assert(dstIdx < count);
299
300 // load the next word, containing some packed items
301 Word_t packedBytes = 0;
302 std::size_t bytesLoaded = std::min(remBytesToLoad, sizeof(Word_t));
303 memcpy(&packedBytes, &srcArray[i], bytesLoaded);
304 ByteSwapIfNecessary(packedBytes);
305
306 assert(remBytesToLoad >= bytesLoaded);
307 remBytesToLoad -= bytesLoaded;
308
309 // If `offInWord` is negative, it means that the last item was split
310 // across 2 words and we need to recombine it.
311 if (offInWord < 0) {
312 std::size_t nMsb = nSrcBits + offInWord;
313 std::uint32_t msb = packedBytes << (8 * sizeofDst - nMsb);
314 Word_t packedWord = msb | prevWordLsb;
315 prevWordLsb = 0;
316#if R__LITTLE_ENDIAN == 0
317 memcpy(dstArray + dstIdx * sizeofDst,
318 reinterpret_cast<unsigned char *>(&packedWord) + sizeof(Word_t) - sizeofDst, sizeofDst);
319#else
320 memcpy(dstArray + dstIdx * sizeofDst, &packedWord, sizeofDst);
321#endif
322 ++dstIdx;
323 offInWord = nMsb;
324 }
325
326 // isolate each item in the loaded word
327 while (dstIdx < count) {
328 // Check if we need to load a split item or a full one
329 if (offInWord > static_cast<int>(kBitsPerWord - nSrcBits)) {
330 // save the LSB of the next item, next `for` loop will merge them with the MSB in the next word.
331 assert(offInWord <= static_cast<int>(kBitsPerWord));
332 std::size_t nLsbNext = kBitsPerWord - offInWord;
333 if (nLsbNext)
334 prevWordLsb = (packedBytes >> offInWord) << (8 * sizeofDst - nSrcBits);
335 offInWord -= kBitsPerWord;
336 break;
337 }
338
339 Word_t packedWord = packedBytes;
340 assert(nSrcBits + offInWord <= kBitsPerWord);
341 packedWord >>= offInWord;
342 packedWord <<= 8 * sizeofDst - nSrcBits;
343#if R__LITTLE_ENDIAN == 0
344 memcpy(dstArray + dstIdx * sizeofDst,
345 reinterpret_cast<unsigned char *>(&packedWord) + sizeof(Word_t) - sizeofDst, sizeofDst);
346#else
347 memcpy(dstArray + dstIdx * sizeofDst, &packedWord, sizeofDst);
348#endif
349 ++dstIdx;
350 offInWord += nSrcBits;
351 }
352 }
353
354 assert(prevWordLsb == 0);
355 assert(dstIdx == count);
356}
double * dst
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:139
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
static const char * GetColumnTypeName(ROOT::ENTupleColumnType type)
static std::pair< std::uint16_t, std::uint16_t > GetValidBitRange(ROOT::ENTupleColumnType type)
Most types have a fixed on-disk bit width.
static std::unique_ptr< RColumnElementBase > Generate(ENTupleColumnType onDiskType)
The in-memory representation of a 32bit or 64bit on-disk index column.
Holds the index and the tag of a kSwitch column.
Metadata stored for every column of an RNTuple.
std::optional< RValueRange > GetValueRange() const
ROOT::ENTupleColumnType GetType() const
std::uint16_t GetBitsOnStorage() const
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.
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::unique_ptr< RColumnElementBase > GenerateColumnElement(std::type_index inMemoryType, ROOT::ENTupleColumnType onDiskType)
ENTupleColumnType
Every concrete RColumnElement type is identified by its on-disk type (column type) and the in-memory ...