Project
Loading...
Searching...
No Matches
utils.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_COMMON_UTILS_H_
17#define RANS_INTERNAL_COMMON_UTILS_H_
18
19#include <cstddef>
20#include <cmath>
21#include <chrono>
22#include <type_traits>
23#include <iterator>
24#include <sstream>
25#include <vector>
26#include <cstring>
27
28#include <fairlogger/Logger.h>
29
32
33#define rans_likely(x) __builtin_expect((x), 1)
34#define rans_unlikely(x) __builtin_expect((x), 0)
35
36namespace o2::rans
37{
38
39namespace utils
40{
41
42template <typename T>
43constexpr size_t toBits() noexcept;
44
45} // namespace utils
46
47namespace internal
48{
49// taken from https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastlog.h
50[[nodiscard]] inline constexpr float_t fastlog2(float_t x) noexcept
51{
52 union {
53 float_t f;
54 uint32_t i;
55 } vx = {x};
56
57 union {
58 uint32_t i;
59 float_t f;
60 } mx = {(vx.i & 0x007FFFFF) | 0x3f000000};
61
62 float_t y = vx.i;
63 y *= 1.1920928955078125e-7f;
64
65 return y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f);
66};
67
68template <typename T>
69inline size_t itemsPerQWord()
70{
71 return sizeof(uint64_t) / sizeof(T);
72}
73
74inline uint64_t load64(const void* __restrict src)
75{
76 uint64_t ret;
77 std::memcpy(&ret, src, 8);
78 return ret;
79};
80
81inline void write64(void* __restrict dest, uint64_t src) { std::memcpy(dest, &src, 8); };
82
83template <typename T>
84inline constexpr uintptr_t adr2Bits(T* address) noexcept
85{
86 return (reinterpret_cast<uintptr_t>(address) << 3ull);
87};
88
89template <typename T>
90inline constexpr T log2UIntNZ(T x) noexcept
91{
92 static_assert(std::is_integral_v<T>, "Type is not integral");
93 static_assert(std::is_unsigned_v<T>, "only defined for unsigned numbers");
94 assert(x > 0);
95
96 if constexpr (sizeof(T) <= 4) {
97 return static_cast<T>(utils::toBits<uint32_t>() - __builtin_clz(x) - 1);
98 } else {
99 return static_cast<T>(utils::toBits<uint64_t>() - __builtin_clzl(x) - 1);
100 }
101}
102
103template <typename T, std::enable_if_t<std::is_unsigned_v<T>, bool> = true>
104inline constexpr bool isPow2(T x) noexcept
105{
106 return x > 0 && (x & (x - 1)) == 0;
107}
108
109[[nodiscard]] inline count_t roundSymbolFrequency(double_t rescaledFrequency)
110{
111 const count_t roundedDown = static_cast<count_t>(rescaledFrequency);
112 const double_t roundedDownD = roundedDown;
113
114 // rescaledFrequency**2 <= ( floor(rescaledFrequency) * ceil(rescaledFrequency))
115 if (rescaledFrequency * rescaledFrequency <= (roundedDownD * (roundedDownD + 1.0))) {
116 // round down
117 return roundedDown;
118 } else {
119 // round up
120 return roundedDown + 1;
121 }
122};
123
124inline constexpr size_t numSymbolsWithNBits(size_t bits) noexcept
125{
126 return (static_cast<size_t>(1) << (bits + 1)) - 1;
127};
128
129inline constexpr size_t numBitsForNSymbols(size_t nSymbols) noexcept
130{
131 switch (nSymbols) {
132 case 0:
133 return 0; // to represent 0 symbols we need 0 bits
134 break;
135 case 1: // to represent 1 symbol we need 1 bit
136 return 1;
137 break;
138 default: // general case for > 1 symbols
139 return std::ceil(std::log2(nSymbols));
140 break;
141 }
142}
143
144inline uint32_t safeadd(uint32_t a, uint32_t b)
145{
146 uint32_t result;
147 if (rans_unlikely(__builtin_uadd_overflow(a, b, &result))) {
148 throw OverflowError("arithmetic overflow during addition");
149 }
150 return result;
151}
152
153} // namespace internal
154
155inline constexpr std::uint8_t operator"" _u8(unsigned long long int value) { return static_cast<uint8_t>(value); };
156inline constexpr std::int8_t operator"" _i8(unsigned long long int value) { return static_cast<int8_t>(value); };
157
158inline constexpr std::uint16_t operator"" _u16(unsigned long long int value) { return static_cast<uint16_t>(value); };
159inline constexpr std::int16_t operator"" _i16(unsigned long long int value) { return static_cast<int16_t>(value); };
160
161namespace utils
162{
163inline constexpr size_t toBytes(size_t bits) noexcept { return (bits / 8) + (bits % 8 != 0); };
164
165inline constexpr size_t pow2(size_t n) noexcept
166{
167 return 1ull << n;
168}
169
170inline constexpr size_t toBits(size_t bytes) noexcept { return bytes * 8; };
171
172template <typename T>
173inline constexpr size_t toBits() noexcept
174{
175 return toBits(sizeof(T));
176};
177
178template <typename T>
179inline constexpr T log2UInt(T x) noexcept
180{
181 static_assert(std::is_integral_v<T>, "Type is not integral");
182 static_assert(std::is_unsigned_v<T>, "only defined for unsigned numbers");
183 if (x > static_cast<T>(0)) {
184 return internal::log2UIntNZ<T>(x);
185 } else {
186 return static_cast<T>(0);
187 }
188}
189
190template <typename Freq_IT>
191inline Freq_IT advanceIter(Freq_IT iter, std::ptrdiff_t distance)
192{
193 std::advance(iter, distance);
194 return iter;
195}
196
197[[nodiscard]] inline uint32_t symbolLengthBits(uint32_t x) noexcept { return log2UInt(x); };
198
199template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
200[[nodiscard]] inline constexpr uint32_t getRangeBits(T min, T max) noexcept
201{
202 assert(max >= min);
203 const int64_t diff = max - min;
204
205 if (diff == 0) {
206 return 0; // if min==max, we're empty. Compatible with the case that we need 2**0 == 1 Value.
207 } else {
208 return symbolLengthBits(diff) + 1; // otherwise add 1 to cover full interval [min,max]
209 }
210};
211
212[[nodiscard]] inline size_t sanitizeRenormingBitRange(size_t renormPrecision)
213{
214 size_t sanitizedPrecision{};
215 if (renormPrecision != 0) {
216 sanitizedPrecision = std::min(defaults::MaxRenormPrecisionBits, std::max(defaults::MinRenormPrecisionBits, renormPrecision));
217 LOG_IF(debug, (sanitizedPrecision != renormPrecision)) << fmt::format("Renorming precision {} is not in valid interval [{},{}], rounding to {} ",
218 renormPrecision,
221 sanitizedPrecision);
222 } else {
223 // allow 0 as special case to handle empty frequency tables
224 sanitizedPrecision = 0;
225 }
226 return sanitizedPrecision;
227};
228
229template <typename T>
230[[nodiscard]] inline size_t constexpr nBytesTo(size_t nBytes) noexcept
231{
232 const size_t nOthers = nBytes / sizeof(T) + (nBytes % sizeof(T) > 0);
233 return nOthers;
234};
235
236[[nodiscard]] inline constexpr bool isValidRenormingPrecision(size_t renormPrecision)
237{
238 const bool isInInterval = (renormPrecision >= defaults::MinRenormPrecisionBits) && (renormPrecision <= defaults::MaxRenormPrecisionBits);
239 const bool isZeroMessage = renormPrecision == 0;
240 return isInInterval || isZeroMessage;
241};
242
243template <typename IT>
244void checkBounds(IT iteratorPosition, IT upperBound)
245{
246 const auto diff = std::distance(iteratorPosition, upperBound);
247 if (diff < 0) {
248 throw OutOfBoundsError(fmt::format("Bounds of buffer violated by {} elements", std::abs(diff)));
249 }
250}
251
253{
254 public:
255 void start() { mStart = std::chrono::high_resolution_clock::now(); };
256 void stop() { mStop = std::chrono::high_resolution_clock::now(); };
257 inline double getDurationMS() noexcept
258 {
259 std::chrono::duration<double, std::milli> duration = mStop - mStart;
260 return duration.count();
261 }
262
263 inline double getDurationS() noexcept
264 {
265 std::chrono::duration<double, std::ratio<1>> duration = mStop - mStart;
266 return duration.count();
267 }
268
269 private:
270 std::chrono::time_point<std::chrono::high_resolution_clock> mStart;
271 std::chrono::time_point<std::chrono::high_resolution_clock> mStop;
272};
273
274template <class T>
276{
277 public:
278 explicit JSONArrayLogger(bool reverse = false) : mReverse{reverse} {};
279 inline JSONArrayLogger& operator<<(const T& elem)
280 {
281 mElems.emplace_back(elem);
282 return *this;
283 };
284
285 friend std::ostream& operator<<(std::ostream& os, const JSONArrayLogger& logger)
286 {
287 auto printSymbols = [&](auto begin, auto end) {
288 --end;
289 for (auto it = begin; it != end; ++it) {
290 os << +static_cast<T>(*it) << " ,";
291 }
292 os << +static_cast<T>(*end);
293 };
294
295 os << "[";
296 if (!logger.mElems.empty()) {
297 if (logger.mReverse) {
298 printSymbols(logger.mElems.rbegin(), logger.mElems.rend());
299 } else {
300 printSymbols(logger.mElems.begin(), logger.mElems.end());
301 }
302 }
303 os << "]";
304 return os;
305 }
306
307 private:
308 std::vector<T> mElems{};
309 bool mReverse{false};
310};
311
312template <typename T, typename IT>
313inline constexpr bool isCompatibleIter_v = std::is_convertible_v<typename std::iterator_traits<IT>::value_type, T>;
314
315template <typename IT>
316inline constexpr bool isIntegralIter_v = std::is_integral_v<typename std::iterator_traits<IT>::value_type>;
317
318} // namespace utils
319
320} // namespace o2::rans
321
322#endif /* RANS_INTERNAL_COMMON_UTILS_H_ */
int32_t i
std::array< int, 64 > reverse(std::array< int, 64 > a)
#define rans_unlikely(x)
Definition utils.h:34
std::ostringstream debug
JSONArrayLogger & operator<<(const T &elem)
Definition utils.h:279
JSONArrayLogger(bool reverse=false)
Definition utils.h:278
friend std::ostream & operator<<(std::ostream &os, const JSONArrayLogger &logger)
Definition utils.h:285
double getDurationS() noexcept
Definition utils.h:263
double getDurationMS() noexcept
Definition utils.h:257
rans exceptions
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint GLuint64EXT address
Definition glcorearb.h:5846
GLenum src
Definition glcorearb.h:1767
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint GLuint end
Definition glcorearb.h:469
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei GLsizei GLfloat distance
Definition glcorearb.h:5506
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
Definition glcorearb.h:4150
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
constexpr size_t MinRenormPrecisionBits
Definition defaults.h:56
constexpr size_t MaxRenormPrecisionBits
Definition defaults.h:57
constexpr bool isPow2(T x) noexcept
Definition utils.h:104
uint32_t safeadd(uint32_t a, uint32_t b)
Definition utils.h:144
uint64_t load64(const void *__restrict src)
Definition utils.h:74
void write64(void *__restrict dest, uint64_t src)
Definition utils.h:81
size_t itemsPerQWord()
Definition utils.h:69
constexpr uintptr_t adr2Bits(T *address) noexcept
Definition utils.h:84
count_t roundSymbolFrequency(double_t rescaledFrequency)
Definition utils.h:109
constexpr size_t numBitsForNSymbols(size_t nSymbols) noexcept
Definition utils.h:129
constexpr float_t fastlog2(float_t x) noexcept
Definition utils.h:50
constexpr size_t numSymbolsWithNBits(size_t bits) noexcept
Definition utils.h:124
constexpr T log2UIntNZ(T x) noexcept
Definition utils.h:90
uint32_t symbolLengthBits(uint32_t x) noexcept
Definition utils.h:197
constexpr uint32_t getRangeBits(T min, T max) noexcept
Definition utils.h:200
constexpr size_t pow2(size_t n) noexcept
Definition utils.h:165
constexpr T log2UInt(T x) noexcept
Definition utils.h:179
constexpr bool isValidRenormingPrecision(size_t renormPrecision)
Definition utils.h:236
constexpr size_t toBits() noexcept
Definition utils.h:173
size_t constexpr nBytesTo(size_t nBytes) noexcept
Definition utils.h:230
constexpr bool isIntegralIter_v
Definition utils.h:316
void checkBounds(IT iteratorPosition, IT upperBound)
Definition utils.h:244
constexpr size_t toBytes(size_t bits) noexcept
Definition utils.h:163
size_t sanitizeRenormingBitRange(size_t renormPrecision)
Definition utils.h:212
Freq_IT advanceIter(Freq_IT iter, std::ptrdiff_t distance)
Definition utils.h:191
constexpr bool isCompatibleIter_v
Definition utils.h:313
uint32_t count_t
Definition defaults.h:34
Common utility functions.
constexpr size_t min
constexpr size_t max