Project
Loading...
Searching...
No Matches
pack.h
Go to the documentation of this file.
1// Copyright 2019-2023 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15
16#ifndef RANS_INTERNAL_PACK_PACK_H_
17#define RANS_INTERNAL_PACK_PACK_H_
18
19#include <cstdint>
20#include <cstring>
21#include <array>
22#include <type_traits>
23
24#include <iostream>
25
29
30namespace o2::rans
31{
32
33template <typename storageBuffer_T = uint8_t>
34[[nodiscard]] constexpr size_t computePackingBufferSize(size_t extent, size_t packingWidthBits) noexcept
35{
36 using namespace internal;
37 using namespace utils;
38 if (extent > 0) {
39 constexpr size_t PackingBufferBits = toBits<packing_type>();
40 const size_t packedSizeBits = extent * packingWidthBits;
41
42 const size_t packingBufferElems = packedSizeBits / PackingBufferBits + 1;
43 const size_t packingBufferBytes = packingBufferElems * sizeof(packing_type);
44 const size_t storageBufferElems = utils::nBytesTo<storageBuffer_T>(packingBufferBytes);
45 return storageBufferElems;
46 } else {
47 return 0;
48 }
49}
50
51namespace internal
52{
53
54inline BitPtr packShort(BitPtr pos, uint64_t data, size_t packingWidth)
55{
56 assert(pos != BitPtr{});
57 assert(packingWidth <= 58);
58 uint8_t* posPtr = pos.toPtr<uint8_t>();
59 const size_t posBitOffset = pos.getOffset<uint8_t>();
60
61 packing_type buffer = load64(reinterpret_cast<void*>(posPtr));
62 buffer |= data << posBitOffset;
63 write64(posPtr, buffer);
64
65 return pos += packingWidth;
66};
67
68inline BitPtr pack(BitPtr pos, uint64_t data, size_t packingWidth)
69{
70 return packShort(pos, data, packingWidth);
71}
72
73inline BitPtr packLong(BitPtr pos, uint64_t data, size_t packingWidth)
74{
75 assert(pos != BitPtr{});
76 uint8_t* posPtr = pos.toPtr<uint8_t>();
77 const size_t posBitOffset = pos.getOffset<uint8_t>();
78
79 const size_t bitOffsetEnd = posBitOffset + packingWidth;
80 packing_type buffer = load64(reinterpret_cast<void*>(posPtr));
81
82 constexpr size_t PackingBufferBits = utils::toBits<packing_type>();
83
84 if (bitOffsetEnd <= PackingBufferBits) {
85 buffer |= data << posBitOffset;
86 write64(posPtr, buffer);
87 } else {
88 const size_t tailBits = PackingBufferBits - posBitOffset;
89 buffer |= bitExtract(data, 0, tailBits) << posBitOffset;
90 write64(posPtr, buffer);
91 posPtr += sizeof(packing_type);
92 buffer = load64(reinterpret_cast<void*>(posPtr));
93 buffer |= data >> tailBits;
94 write64(posPtr, buffer);
95 }
96
97 return pos += packingWidth;
98};
99
100template <typename T>
101inline T unpack(BitPtr pos, size_t packingWidth)
102{
103 assert(pos != BitPtr{});
104 assert(packingWidth <= utils::toBits<T>());
105 assert(packingWidth <= 58);
106
107 uint8_t* posPtr = pos.toPtr<uint8_t>();
108 size_t posBitOffset = pos.getOffset<uint8_t>();
109
110 packing_type buffer = load64(reinterpret_cast<void*>(posPtr));
111 return static_cast<T>(bitExtract(buffer, posBitOffset, packingWidth));
112};
113
114inline uint64_t unpackLong(BitPtr pos, size_t packingWidth)
115{
116 assert(pos != BitPtr{});
117 assert(packingWidth < 64);
118
119 uint8_t* posPtr = pos.toPtr<uint8_t>();
120 size_t bitOffset = pos.getOffset<uint8_t>();
121
122 constexpr size_t PackingBufferBits = utils::toBits<packing_type>();
123 const size_t bitOffsetEnd = bitOffset + packingWidth;
124 packing_type buffer = load64(reinterpret_cast<void*>(posPtr));
125 uint64_t ret{};
126 if (bitOffsetEnd <= PackingBufferBits) {
127 ret = bitExtract(buffer, bitOffset, packingWidth);
128 } else {
129 // first part
130 ret = bitExtract(buffer, bitOffset, PackingBufferBits - bitOffset);
131 // second part
132 bitOffset = bitOffsetEnd - PackingBufferBits;
133 posPtr += sizeof(packing_type);
134 buffer = load64(reinterpret_cast<void*>(posPtr));
135 ret |= bitExtract(buffer, 0, bitOffset) << (packingWidth - bitOffset);
136 }
137
138 return ret;
139};
140
141template <typename input_T, typename output_T, size_t width_V>
142constexpr BitPtr packStreamImpl(const input_T* __restrict inputBegin, size_t extent, output_T* outputBegin, input_T offset)
143{
144 assert(inputBegin != nullptr);
145 assert(outputBegin != nullptr);
146
147 constexpr size_t PackingBufferBits = utils::toBits<packing_type>();
148 constexpr size_t PackingWidth = width_V;
149
150 constexpr size_t NPackAtOnce = PackingBufferBits / PackingWidth;
151
152 uint8_t* outputIter = reinterpret_cast<uint8_t*>(outputBegin);
153 size_t outputIterBitOffset = {};
154
155 const size_t nIterations = extent / NPackAtOnce;
156 const size_t nRemainderIterations = extent % NPackAtOnce;
157
158 auto inputIter = inputBegin;
159 const auto iterEnd = inputIter + NPackAtOnce * nIterations;
160 packing_type overflowBuffer{0};
161
162 for (; inputIter < iterEnd; inputIter += NPackAtOnce) {
163 packing_type packed = packMultiple<input_T, width_V>(inputIter, offset);
164
165 const size_t tail = PackingBufferBits - outputIterBitOffset;
166 overflowBuffer |= packed << outputIterBitOffset;
167 outputIterBitOffset += NPackAtOnce * PackingWidth;
168
169 if constexpr (PackingBufferBits % PackingWidth == 0) {
170 write64(outputIter, overflowBuffer);
171 overflowBuffer = 0;
172 outputIterBitOffset = 0;
173 outputIter += sizeof(packing_type);
174 } else {
175 if (outputIterBitOffset >= PackingBufferBits) {
176 write64(outputIter, overflowBuffer);
177 outputIter += sizeof(packing_type);
178 overflowBuffer = packed >> tail;
179 }
180 outputIterBitOffset %= PackingBufferBits;
181 }
182 }
183 write64(outputIter, overflowBuffer);
184
185 BitPtr bitPos{outputIter, static_cast<intptr_t>(outputIterBitOffset)};
186 for (size_t i = 0; i < nRemainderIterations; ++i) {
187 const int64_t adjustedValue = static_cast<int64_t>(inputIter[i]) - offset;
188 bitPos = pack(bitPos, adjustedValue, PackingWidth);
189 }
190
191 return bitPos;
192};
193} // namespace internal
194
195template <typename input_T, typename output_T>
196inline constexpr BitPtr pack(const input_T* __restrict inputBegin, size_t extent, output_T* __restrict outputBegin, size_t packingWidth, input_T offset = static_cast<input_T>(0))
197{
198 using namespace internal;
199 using namespace utils;
200
201 assert(inputBegin != nullptr);
202 assert(outputBegin != nullptr);
203
204 switch (packingWidth) {
205 case 0:
206 if (extent > 0) {
207 throw PackingError("Cannot pack data into 0 Bit wide blocks");
208 } else {
209 return BitPtr(outputBegin);
210 }
211 break;
212 case 1:
213 return packStreamImpl<input_T, output_T, 1>(inputBegin, extent, outputBegin, offset);
214 break;
215 case 2:
216 return packStreamImpl<input_T, output_T, 2>(inputBegin, extent, outputBegin, offset);
217 break;
218 case 3:
219 return packStreamImpl<input_T, output_T, 3>(inputBegin, extent, outputBegin, offset);
220 break;
221 case 4:
222 return packStreamImpl<input_T, output_T, 4>(inputBegin, extent, outputBegin, offset);
223 break;
224 case 5:
225 return packStreamImpl<input_T, output_T, 5>(inputBegin, extent, outputBegin, offset);
226 break;
227 case 6:
228 return packStreamImpl<input_T, output_T, 6>(inputBegin, extent, outputBegin, offset);
229 break;
230 case 7:
231 return packStreamImpl<input_T, output_T, 7>(inputBegin, extent, outputBegin, offset);
232 break;
233 case 8:
234 return packStreamImpl<input_T, output_T, 8>(inputBegin, extent, outputBegin, offset);
235 break;
236 case 9:
237 return packStreamImpl<input_T, output_T, 9>(inputBegin, extent, outputBegin, offset);
238 break;
239 case 10:
240 return packStreamImpl<input_T, output_T, 10>(inputBegin, extent, outputBegin, offset);
241 break;
242 case 11:
243 return packStreamImpl<input_T, output_T, 11>(inputBegin, extent, outputBegin, offset);
244 break;
245 case 12:
246 return packStreamImpl<input_T, output_T, 12>(inputBegin, extent, outputBegin, offset);
247 break;
248 case 13:
249 return packStreamImpl<input_T, output_T, 13>(inputBegin, extent, outputBegin, offset);
250 break;
251 case 14:
252 return packStreamImpl<input_T, output_T, 14>(inputBegin, extent, outputBegin, offset);
253 break;
254 case 15:
255 return packStreamImpl<input_T, output_T, 15>(inputBegin, extent, outputBegin, offset);
256 break;
257 case 16:
258 return packStreamImpl<input_T, output_T, 16>(inputBegin, extent, outputBegin, offset);
259 break;
260 case 17:
261 return packStreamImpl<input_T, output_T, 17>(inputBegin, extent, outputBegin, offset);
262 break;
263 case 18:
264 return packStreamImpl<input_T, output_T, 18>(inputBegin, extent, outputBegin, offset);
265 break;
266 case 19:
267 return packStreamImpl<input_T, output_T, 19>(inputBegin, extent, outputBegin, offset);
268 break;
269 case 20:
270 return packStreamImpl<input_T, output_T, 20>(inputBegin, extent, outputBegin, offset);
271 break;
272 case 21:
273 return packStreamImpl<input_T, output_T, 21>(inputBegin, extent, outputBegin, offset);
274 break;
275 case 22:
276 return packStreamImpl<input_T, output_T, 22>(inputBegin, extent, outputBegin, offset);
277 break;
278 case 23:
279 return packStreamImpl<input_T, output_T, 23>(inputBegin, extent, outputBegin, offset);
280 break;
281 case 24:
282 return packStreamImpl<input_T, output_T, 24>(inputBegin, extent, outputBegin, offset);
283 break;
284 case 25:
285 return packStreamImpl<input_T, output_T, 25>(inputBegin, extent, outputBegin, offset);
286 break;
287 case 26:
288 return packStreamImpl<input_T, output_T, 26>(inputBegin, extent, outputBegin, offset);
289 break;
290 case 27:
291 return packStreamImpl<input_T, output_T, 27>(inputBegin, extent, outputBegin, offset);
292 break;
293 case 28:
294 return packStreamImpl<input_T, output_T, 28>(inputBegin, extent, outputBegin, offset);
295 break;
296 case 29:
297 return packStreamImpl<input_T, output_T, 29>(inputBegin, extent, outputBegin, offset);
298 break;
299 case 30:
300 return packStreamImpl<input_T, output_T, 30>(inputBegin, extent, outputBegin, offset);
301 break;
302 case 31:
303 return packStreamImpl<input_T, output_T, 31>(inputBegin, extent, outputBegin, offset);
304 break;
305 case 32:
306 return packStreamImpl<input_T, output_T, 32>(inputBegin, extent, outputBegin, offset);
307 break;
308 default:
309 BitPtr iter{outputBegin};
310 for (size_t i = 0; i < extent; ++i) {
311 const int64_t adjustedValue = static_cast<int64_t>(inputBegin[i]) - offset;
312 iter = packLong(iter, adjustedValue, packingWidth);
313 }
314 return iter;
315 break;
316 }
317 return {};
318};
319
320template <typename input_IT, typename output_T>
321inline constexpr BitPtr pack(input_IT inputBegin, size_t extent, output_T* __restrict outputBegin, size_t packingWidth,
322 typename std::iterator_traits<input_IT>::value_type offset = 0)
323{
324 using namespace internal;
325 using namespace utils;
326 using source_type = typename std::iterator_traits<input_IT>::value_type;
327 input_IT inputEnd = advanceIter(inputBegin, extent);
328 BitPtr outputIter{outputBegin};
329
330 auto packImpl = [](input_IT inputBegin, input_IT inputEnd, BitPtr outputIter, source_type offset, size_t packingWidth, auto packingFunctor) -> BitPtr {
331 for (auto inputIter = inputBegin; inputIter != inputEnd; ++inputIter) {
332 const int64_t adjustedValue = static_cast<int64_t>(*inputIter) - offset;
333 outputIter = packingFunctor(outputIter, adjustedValue, packingWidth);
334 }
335 return outputIter;
336 };
337
338 if (packingWidth <= 58) {
339 return packImpl(inputBegin, inputEnd, outputIter, offset, packingWidth, packShort);
340 } else {
341 return packImpl(inputBegin, inputEnd, outputIter, offset, packingWidth, packLong);
342 }
343}
344
345template <typename input_T, typename output_IT>
346inline void unpack(const input_T* __restrict inputBegin, size_t extent, output_IT outputBegin, size_t packingWidth, typename std::iterator_traits<output_IT>::value_type offset = static_cast<typename std::iterator_traits<output_IT>::value_type>(0))
347{
348 using namespace internal;
349 using namespace utils;
350 using dst_type = typename std::iterator_traits<output_IT>::value_type;
351
352 // cannot unpack into 0 bits
353 if (packingWidth == 0) {
354 if (extent == 0) {
355 return;
356 } else {
357 throw PackingError("Cannot unpack into 0 Bit wide data");
358 }
359 }
360
361 auto unpackImpl = [&](auto packer) {
362 output_IT outputIt = outputBegin;
363 BitPtr iter{inputBegin};
364 for (size_t i = 0; i < extent; ++i) {
365 auto unpacked = packer(iter, packingWidth) + offset;
366 *outputIt++ = unpacked;
367 iter += packingWidth;
368 }
369 };
370
371 if (packingWidth <= 58) {
372 unpackImpl(unpack<dst_type>);
373 } else {
374 unpackImpl(unpackLong);
375 }
376};
377
378} // namespace o2::rans
379
380#endif /* RANS_INTERNAL_PACK_PACK_H_ */
Pointer type helper class for bitwise Packing.
int32_t i
uint16_t pos
Definition RawData.h:3
common helper classes and functions
helper functionalities useful for packing operations
uint32_t source_type
GLuint buffer
Definition glcorearb.h:655
GLboolean * data
Definition glcorearb.h:298
GLintptr offset
Definition glcorearb.h:660
uint64_t load64(const void *__restrict src)
Definition utils.h:74
void write64(void *__restrict dest, uint64_t src)
Definition utils.h:81
BitPtr packShort(BitPtr pos, uint64_t data, size_t packingWidth)
Definition pack.h:54
uint64_t packing_type
Definition utils.h:33
constexpr BitPtr packStreamImpl(const input_T *__restrict inputBegin, size_t extent, output_T *outputBegin, input_T offset)
Definition pack.h:142
uint64_t bitExtract(uint64_t data, uint32_t start, uint32_t length) noexcept
Definition utils.h:58
uint64_t unpackLong(BitPtr pos, size_t packingWidth)
Definition pack.h:114
T unpack(BitPtr pos, size_t packingWidth)
Definition pack.h:101
BitPtr packLong(BitPtr pos, uint64_t data, size_t packingWidth)
Definition pack.h:73
constexpr size_t computePackingBufferSize(size_t extent, size_t packingWidthBits) noexcept
Definition pack.h:34
void unpack(const input_T *__restrict inputBegin, size_t extent, output_IT outputBegin, size_t packingWidth, typename std::iterator_traits< output_IT >::value_type offset=static_cast< typename std::iterator_traits< output_IT >::value_type >(0))
Definition pack.h:346
Common utility functions.