Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RColumnElement.cxx
Go to the documentation of this file.
1/// \file RColumnElement.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2019-08-11
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#include "ROOT/RColumn.hxx"
18
19#include "RColumnElement.hxx"
20
21#include <algorithm>
22#include <bitset>
23#include <cassert>
24#include <cstdint>
25#include <memory>
26#include <utility>
27
28std::pair<std::uint16_t, std::uint16_t>
30{
31 switch (type) {
32 case EColumnType::kIndex64: return std::make_pair(64, 64);
33 case EColumnType::kIndex32: return std::make_pair(32, 32);
34 case EColumnType::kSwitch: return std::make_pair(96, 96);
35 case EColumnType::kByte: return std::make_pair(8, 8);
36 case EColumnType::kChar: return std::make_pair(8, 8);
37 case EColumnType::kBit: return std::make_pair(1, 1);
38 case EColumnType::kReal64: return std::make_pair(64, 64);
39 case EColumnType::kReal32: return std::make_pair(32, 32);
40 case EColumnType::kReal16: return std::make_pair(16, 16);
41 case EColumnType::kInt64: return std::make_pair(64, 64);
42 case EColumnType::kUInt64: return std::make_pair(64, 64);
43 case EColumnType::kInt32: return std::make_pair(32, 32);
44 case EColumnType::kUInt32: return std::make_pair(32, 32);
45 case EColumnType::kInt16: return std::make_pair(16, 16);
46 case EColumnType::kUInt16: return std::make_pair(16, 16);
47 case EColumnType::kInt8: return std::make_pair(8, 8);
48 case EColumnType::kUInt8: return std::make_pair(8, 8);
49 case EColumnType::kSplitIndex64: return std::make_pair(64, 64);
50 case EColumnType::kSplitIndex32: return std::make_pair(32, 32);
51 case EColumnType::kSplitReal64: return std::make_pair(64, 64);
52 case EColumnType::kSplitReal32: return std::make_pair(32, 32);
53 case EColumnType::kSplitInt64: return std::make_pair(64, 64);
54 case EColumnType::kSplitUInt64: return std::make_pair(64, 64);
55 case EColumnType::kSplitInt32: return std::make_pair(32, 32);
56 case EColumnType::kSplitUInt32: return std::make_pair(32, 32);
57 case EColumnType::kSplitInt16: return std::make_pair(16, 16);
58 case EColumnType::kSplitUInt16: return std::make_pair(16, 16);
59 case EColumnType::kReal32Trunc: return std::make_pair(10, 31);
60 case EColumnType::kReal32Quant: return std::make_pair(1, 32);
61 default: assert(false);
62 }
63 // never here
64 return std::make_pair(0, 0);
65}
66
68{
69 switch (type) {
70 case EColumnType::kIndex64: return "Index64";
71 case EColumnType::kIndex32: return "Index32";
72 case EColumnType::kSwitch: return "Switch";
73 case EColumnType::kByte: return "Byte";
74 case EColumnType::kChar: return "Char";
75 case EColumnType::kBit: return "Bit";
76 case EColumnType::kReal64: return "Real64";
77 case EColumnType::kReal32: return "Real32";
78 case EColumnType::kReal16: return "Real16";
79 case EColumnType::kInt64: return "Int64";
80 case EColumnType::kUInt64: return "UInt64";
81 case EColumnType::kInt32: return "Int32";
82 case EColumnType::kUInt32: return "UInt32";
83 case EColumnType::kInt16: return "Int16";
84 case EColumnType::kUInt16: return "UInt16";
85 case EColumnType::kInt8: return "Int8";
86 case EColumnType::kUInt8: return "UInt8";
87 case EColumnType::kSplitIndex64: return "SplitIndex64";
88 case EColumnType::kSplitIndex32: return "SplitIndex32";
89 case EColumnType::kSplitReal64: return "SplitReal64";
90 case EColumnType::kSplitReal32: return "SplitReal32";
91 case EColumnType::kSplitInt64: return "SplitInt64";
92 case EColumnType::kSplitUInt64: return "SplitUInt64";
93 case EColumnType::kSplitInt32: return "SplitInt32";
94 case EColumnType::kSplitUInt32: return "SplitUInt32";
95 case EColumnType::kSplitInt16: return "SplitInt16";
96 case EColumnType::kSplitUInt16: return "SplitUInt16";
97 case EColumnType::kReal32Trunc: return "Real32Trunc";
98 case EColumnType::kReal32Quant: return "Real32Quant";
99 default: return "UNKNOWN";
100 }
101}
102
103template <>
104std::unique_ptr<ROOT::Experimental::Internal::RColumnElementBase>
105ROOT::Experimental::Internal::RColumnElementBase::Generate<void>(EColumnType type)
106{
107 switch (type) {
108 case EColumnType::kIndex64: return std::make_unique<RColumnElement<ClusterSize_t, EColumnType::kIndex64>>();
109 case EColumnType::kIndex32: return std::make_unique<RColumnElement<ClusterSize_t, EColumnType::kIndex32>>();
110 case EColumnType::kSwitch: return std::make_unique<RColumnElement<RColumnSwitch, EColumnType::kSwitch>>();
111 case EColumnType::kByte: return std::make_unique<RColumnElement<std::byte, EColumnType::kByte>>();
112 case EColumnType::kChar: return std::make_unique<RColumnElement<char, EColumnType::kChar>>();
113 case EColumnType::kBit: return std::make_unique<RColumnElement<bool, EColumnType::kBit>>();
114 case EColumnType::kReal64: return std::make_unique<RColumnElement<double, EColumnType::kReal64>>();
115 case EColumnType::kReal32: return std::make_unique<RColumnElement<float, EColumnType::kReal32>>();
116 // TODO: Change to std::float16_t in-memory type once available (from C++23).
117 case EColumnType::kReal16: return std::make_unique<RColumnElement<float, EColumnType::kReal16>>();
118 case EColumnType::kInt64: return std::make_unique<RColumnElement<std::int64_t, EColumnType::kInt64>>();
119 case EColumnType::kUInt64: return std::make_unique<RColumnElement<std::uint64_t, EColumnType::kUInt64>>();
120 case EColumnType::kInt32: return std::make_unique<RColumnElement<std::int32_t, EColumnType::kInt32>>();
121 case EColumnType::kUInt32: return std::make_unique<RColumnElement<std::uint32_t, EColumnType::kUInt32>>();
122 case EColumnType::kInt16: return std::make_unique<RColumnElement<std::int16_t, EColumnType::kInt16>>();
123 case EColumnType::kUInt16: return std::make_unique<RColumnElement<std::uint16_t, EColumnType::kUInt16>>();
124 case EColumnType::kInt8: return std::make_unique<RColumnElement<std::int8_t, EColumnType::kInt8>>();
125 case EColumnType::kUInt8: return std::make_unique<RColumnElement<std::uint8_t, EColumnType::kUInt8>>();
127 return std::make_unique<RColumnElement<ClusterSize_t, EColumnType::kSplitIndex64>>();
129 return std::make_unique<RColumnElement<ClusterSize_t, EColumnType::kSplitIndex32>>();
130 case EColumnType::kSplitReal64: return std::make_unique<RColumnElement<double, EColumnType::kSplitReal64>>();
131 case EColumnType::kSplitReal32: return std::make_unique<RColumnElement<float, EColumnType::kSplitReal32>>();
132 case EColumnType::kSplitInt64: return std::make_unique<RColumnElement<std::int64_t, EColumnType::kSplitInt64>>();
133 case EColumnType::kSplitUInt64: return std::make_unique<RColumnElement<std::uint64_t, EColumnType::kSplitUInt64>>();
134 case EColumnType::kSplitInt32: return std::make_unique<RColumnElement<std::int32_t, EColumnType::kSplitInt32>>();
135 case EColumnType::kSplitUInt32: return std::make_unique<RColumnElement<std::uint32_t, EColumnType::kSplitUInt32>>();
136 case EColumnType::kSplitInt16: return std::make_unique<RColumnElement<std::int16_t, EColumnType::kSplitInt16>>();
137 case EColumnType::kSplitUInt16: return std::make_unique<RColumnElement<std::uint16_t, EColumnType::kSplitUInt16>>();
138 case EColumnType::kReal32Trunc: return std::make_unique<RColumnElement<float, EColumnType::kReal32Trunc>>();
139 case EColumnType::kReal32Quant: return std::make_unique<RColumnElement<float, EColumnType::kReal32Quant>>();
140 default: assert(false);
141 }
142 // never here
143 return nullptr;
144}
145
146std::unique_ptr<ROOT::Experimental::Internal::RColumnElementBase>
148{
149 switch (cppType) {
150 case EColumnCppType::kChar: return GenerateColumnElementInternal<char>(type);
151 case EColumnCppType::kBool: return GenerateColumnElementInternal<bool>(type);
152 case EColumnCppType::kByte: return GenerateColumnElementInternal<std::byte>(type);
153 case EColumnCppType::kUint8: return GenerateColumnElementInternal<std::uint8_t>(type);
154 case EColumnCppType::kUint16: return GenerateColumnElementInternal<std::uint16_t>(type);
155 case EColumnCppType::kUint32: return GenerateColumnElementInternal<std::uint32_t>(type);
156 case EColumnCppType::kUint64: return GenerateColumnElementInternal<std::uint64_t>(type);
157 case EColumnCppType::kInt8: return GenerateColumnElementInternal<std::int8_t>(type);
158 case EColumnCppType::kInt16: return GenerateColumnElementInternal<std::int16_t>(type);
159 case EColumnCppType::kInt32: return GenerateColumnElementInternal<std::int32_t>(type);
160 case EColumnCppType::kInt64: return GenerateColumnElementInternal<std::int64_t>(type);
161 case EColumnCppType::kFloat: return GenerateColumnElementInternal<float>(type);
162 case EColumnCppType::kDouble: return GenerateColumnElementInternal<double>(type);
163 case EColumnCppType::kClusterSize: return GenerateColumnElementInternal<ClusterSize_t>(type);
164 case EColumnCppType::kColumnSwitch: return GenerateColumnElementInternal<RColumnSwitch>(type);
165 default: R__ASSERT(!"Invalid column cpp type");
166 }
167 // never here
168 return nullptr;
169}
170
171void ROOT::Experimental::Internal::BitPacking::PackBits(void *dst, const void *src, std::size_t count,
172 std::size_t sizeofSrc, std::size_t nDstBits)
173{
174 assert(sizeofSrc <= sizeof(Word_t));
175 assert(0 < nDstBits && nDstBits <= sizeofSrc * 8);
176
177 const unsigned char *srcArray = reinterpret_cast<const unsigned char *>(src);
178 Word_t *dstArray = reinterpret_cast<Word_t *>(dst);
179 Word_t accum = 0;
180 std::size_t bitsUsed = 0;
181 std::size_t dstIdx = 0;
182 for (std::size_t i = 0; i < count; ++i) {
183 Word_t packedWord = 0;
184 memcpy(&packedWord, srcArray + i * sizeofSrc, sizeofSrc);
185 // truncate the LSB of the item
186 packedWord >>= sizeofSrc * 8 - nDstBits;
187
188 const std::size_t bitsRem = kBitsPerWord - bitsUsed;
189 if (bitsRem >= nDstBits) {
190 // append the entire item to the accumulator
191 accum |= (packedWord << bitsUsed);
192 bitsUsed += nDstBits;
193 } else {
194 // chop up the item into its `bitsRem` LSB bits + `nDstBits - bitsRem` MSB bits.
195 // The LSB bits will be saved in the current word and the MSB will be saved in the next one.
196 if (bitsRem > 0) {
197 Word_t packedWordLsb = packedWord;
198 packedWordLsb <<= (kBitsPerWord - bitsRem);
199 packedWordLsb >>= (kBitsPerWord - bitsRem);
200 accum |= (packedWordLsb << bitsUsed);
201 }
202
203 memcpy(&dstArray[dstIdx++], &accum, sizeof(accum));
204 accum = 0;
205 bitsUsed = 0;
206
207 if (bitsRem > 0) {
208 Word_t packedWordMsb = packedWord;
209 packedWordMsb >>= bitsRem;
210 accum |= packedWordMsb;
211 bitsUsed += nDstBits - bitsRem;
212 } else {
213 // we realigned to a word boundary: append the entire item
214 accum = packedWord;
215 bitsUsed += nDstBits;
216 }
217 }
218 }
219
220 if (bitsUsed)
221 memcpy(&dstArray[dstIdx++], &accum, (bitsUsed + 7) / 8);
222
223 [[maybe_unused]] auto expDstCount = (count * nDstBits + kBitsPerWord - 1) / kBitsPerWord;
224 assert(dstIdx == expDstCount);
225}
226
227void ROOT::Experimental::Internal::BitPacking::UnpackBits(void *dst, const void *src, std::size_t count,
228 std::size_t sizeofDst, std::size_t nSrcBits)
229{
230 assert(sizeofDst <= sizeof(Word_t));
231 assert(0 < nSrcBits && nSrcBits <= sizeofDst * 8);
232
233 unsigned char *dstArray = reinterpret_cast<unsigned char *>(dst);
234 const Word_t *srcArray = reinterpret_cast<const Word_t *>(src);
235 const auto nWordsToLoad = (count * nSrcBits + kBitsPerWord - 1) / kBitsPerWord;
236
237 // bit offset of the next packed item inside the currently loaded word
238 int offInWord = 0;
239 std::size_t dstIdx = 0;
240 Word_t prevWordLsb = 0;
241 std::size_t remBytesToLoad = (count * nSrcBits + 7) / 8;
242 for (std::size_t i = 0; i < nWordsToLoad; ++i) {
243 assert(dstIdx < count);
244
245 // load the next word, containing some packed items
246 Word_t packedBytes = 0;
247 std::size_t bytesLoaded = std::min(remBytesToLoad, sizeof(Word_t));
248 memcpy(&packedBytes, &srcArray[i], bytesLoaded);
249
250 assert(remBytesToLoad >= bytesLoaded);
251 remBytesToLoad -= bytesLoaded;
252
253 // If `offInWord` is negative, it means that the last item was split
254 // across 2 words and we need to recombine it.
255 if (offInWord < 0) {
256 std::size_t nMsb = nSrcBits + offInWord;
257 std::uint32_t msb = packedBytes << (8 * sizeofDst - nMsb);
258 Word_t packedWord = msb | prevWordLsb;
259 prevWordLsb = 0;
260 memcpy(dstArray + dstIdx * sizeofDst, &packedWord, sizeofDst);
261 ++dstIdx;
262 offInWord = nMsb;
263 }
264
265 // isolate each item in the loaded word
266 while (dstIdx < count) {
267 // Check if we need to load a split item or a full one
268 if (offInWord > static_cast<int>(kBitsPerWord - nSrcBits)) {
269 // save the LSB of the next item, next `for` loop will merge them with the MSB in the next word.
270 assert(offInWord <= static_cast<int>(kBitsPerWord));
271 std::size_t nLsbNext = kBitsPerWord - offInWord;
272 if (nLsbNext)
273 prevWordLsb = (packedBytes >> offInWord) << (8 * sizeofDst - nSrcBits);
274 offInWord -= kBitsPerWord;
275 break;
276 }
277
278 Word_t packedWord = packedBytes;
279 assert(nSrcBits + offInWord <= kBitsPerWord);
280 packedWord >>= offInWord;
281 packedWord <<= 8 * sizeofDst - nSrcBits;
282 memcpy(dstArray + dstIdx * sizeofDst, &packedWord, sizeofDst);
283 ++dstIdx;
284 offInWord += nSrcBits;
285 }
286 }
287
288 assert(prevWordLsb == 0);
289 assert(dstIdx == count);
290}
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
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 std::string GetTypeName(EColumnType type)
static std::pair< std::uint16_t, std::uint16_t > GetValidBitRange(EColumnType type)
Most types have a fixed on-disk bit width.
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.
std::unique_ptr< RColumnElementBase > GenerateColumnElement(EColumnCppType cppType, EColumnType colType)
static char accum[256]
Definition gifencode.c:210