Blender V5.0
BLI_fixed_width_int.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include <cmath>
12
13#include "BLI_string_ref.hh"
14#include "BLI_unroll.hh"
15
17
27template<typename T, int S> struct UIntF {
28 static_assert(std::is_unsigned_v<T>);
29 static_assert(S >= 1);
30
35 std::array<T, S> v;
36
38 UIntF() = default;
39
41 explicit UIntF(uint64_t value);
42
44 explicit UIntF(StringRefNull str, int base = 10);
45
47 explicit operator uint64_t() const;
48
50 explicit operator double() const;
51 explicit operator float() const;
52
53/* See `BLI_fixed_width_int_str.hh`. */
54#ifdef WITH_GMP
56 void set_from_str(StringRefNull str, int base = 10);
57
59 std::string to_string(int base = 10) const;
60#endif
61};
62
66template<typename T, int S> struct IntF {
67 static_assert(std::is_unsigned_v<T>);
68 static_assert(S >= 1);
69
74 std::array<T, S> v;
75
77 IntF() = default;
78
80 explicit IntF(int64_t value);
81
83 explicit IntF(const UIntF<T, S> &value);
84
86 explicit IntF(StringRefNull str, int base = 10);
87
89 explicit operator int64_t() const;
90
92 explicit operator double() const;
93 explicit operator float() const;
94
96 explicit operator UIntF<T, S>() const;
97
98/* See `BLI_fixed_width_int_str.hh`. */
99#ifdef WITH_GMP
101 void set_from_str(const StringRefNull str, const int base = 10);
102
104 std::string to_string(int base = 10) const;
105#endif
106};
107
108template<typename T> struct DoubleUIntType {
109 using type = void;
110};
111template<> struct DoubleUIntType<uint8_t> {
112 using type = uint16_t;
113};
114template<> struct DoubleUIntType<uint16_t> {
115 using type = uint32_t;
116};
117template<> struct DoubleUIntType<uint32_t> {
118 using type = uint64_t;
119};
120#ifndef _MSC_VER
121template<> struct DoubleUIntType<uint64_t> {
122 using type = __uint128_t;
123};
124#endif
125
127template<typename T> using double_uint_type = typename DoubleUIntType<T>::type;
128
132
136
141
146
151
156
157#ifdef _MSC_VER
158using UInt128 = UInt128_32;
159using UInt256 = UInt256_32;
160using Int128 = Int128_32;
161using Int256 = Int256_32;
162#else
167#endif
168
169template<typename T, int S> inline UIntF<T, S>::UIntF(const uint64_t value)
170{
171 constexpr int Count = std::min(S, int(sizeof(decltype(value)) / sizeof(T)));
172 constexpr int BitsPerT = 8 * sizeof(T);
173
174 for (int i = 0; i < Count; i++) {
175 this->v[i] = T(value >> (BitsPerT * i));
176 }
177 for (int i = Count; i < S; i++) {
178 this->v[i] = 0;
179 }
180}
181
182template<typename T, int S> inline IntF<T, S>::IntF(const int64_t value)
183{
184 constexpr int Count = std::min(S, int(sizeof(decltype(value)) / sizeof(T)));
185 constexpr int BitsPerT = 8 * sizeof(T);
186
187 for (int i = 0; i < Count; i++) {
188 this->v[i] = T(value >> (BitsPerT * i));
189 }
190 const T sign_extend_fill = value < 0 ? T(-1) : T(0);
191 for (int i = Count; i < S; i++) {
192 this->v[i] = sign_extend_fill;
193 }
194}
195
196template<typename T, int S> inline IntF<T, S>::IntF(const UIntF<T, S> &value) : v(value.v) {}
197
198#ifdef WITH_GMP
199template<typename T, int S> UIntF<T, S>::UIntF(const StringRefNull str, const int base)
200{
201 this->set_from_str(str, base);
202}
203
204template<typename T, int S> IntF<T, S>::IntF(const StringRefNull str, const int base)
205{
206 this->set_from_str(str, base);
207}
208#endif /* WITH_GMP */
209
210template<typename T, int S> inline UIntF<T, S>::operator uint64_t() const
211{
212 constexpr int Count = std::min(S, int(sizeof(uint64_t) / sizeof(T)));
213 constexpr int BitsPerT = 8 * sizeof(T);
214
215 uint64_t result = 0;
216 for (int i = 0; i < Count; i++) {
217 result |= uint64_t(this->v[i]) << (BitsPerT * i);
218 }
219 return result;
220}
221
222template<typename T, int S> inline UIntF<T, S>::operator double() const
223{
224 double result = double(this->v[0]);
225 for (int i = 1; i < S; i++) {
226 const T a = this->v[i];
227 if (a == 0) {
228 continue;
229 }
230 result += ldexp(a, 8 * sizeof(T) * i);
231 }
232 return result;
233}
234
235template<typename T, int S> inline UIntF<T, S>::operator float() const
236{
237 return float(double(*this));
238}
239
240template<typename T, int S> inline IntF<T, S>::operator int64_t() const
241{
242 return int64_t(uint64_t(UIntF<T, S>(*this)));
243}
244
245template<typename T, int S> inline IntF<T, S>::operator double() const
246{
247 if (is_negative(*this)) {
248 return -double(-*this);
249 }
250 double result = double(this->v[0]);
251 for (int i = 1; i < S; i++) {
252 const T a = this->v[i];
253 if (a == 0) {
254 continue;
255 }
256 result += ldexp(a, 8 * sizeof(T) * i);
257 }
258 return result;
259}
260
261template<typename T, int S> inline IntF<T, S>::operator float() const
262{
263 return float(double(*this));
264}
265
266template<typename T, int S> inline IntF<T, S>::operator UIntF<T, S>() const
267{
269 result.v = this->v;
270 return result;
271}
272
284template<typename T, typename T2, int S>
285inline void generic_add(T *__restrict dst, const T *a, const T *b)
286{
287 constexpr int shift = 8 * sizeof(T);
288 T2 carry = 0;
289 unroll<S>([&](auto i) {
290 const T2 ai = T2(a[i]);
291 const T2 bi = T2(b[i]);
292 const T2 ri = ai + bi + carry;
293 dst[i] = T(ri);
294 carry = ri >> shift;
295 });
296}
297
301template<typename T, typename T2, int S>
302inline void generic_sub(T *__restrict dst, const T *a, const T *b)
303{
304 T2 carry = 0;
305 unroll<S>([&](auto i) {
306 const T2 ai = T2(a[i]);
307 const T2 bi = T2(b[i]);
308 const T2 ri = ai - bi - carry;
309 dst[i] = T(ri);
310 carry = ri > ai;
311 });
312}
313
315template<typename T, typename T2, int S>
316inline void generic_unsigned_mul(T *__restrict dst, const T *a, const T *b)
317{
318 constexpr int shift = 8 * sizeof(T);
319
320 T2 r[S] = {};
321
322 for (int i = 0; i < S; i++) {
323 const T2 bi = T2(b[i]);
324 T2 carry = 0;
325 for (int j = 0; j < S - i; j++) {
326 const T2 rji = T2(a[j]) * bi + carry;
327 carry = rji >> shift;
328 r[i + j] += T2(T(rji));
329 }
330 }
331
332 T2 carry = 0;
333 for (int i = 0; i < S; i++) {
334 const T2 ri = r[i] + carry;
335 carry = ri >> shift;
336 dst[i] = T(ri);
337 }
338}
339
340template<typename T, int Size, BLI_ENABLE_IF((!std::is_void_v<double_uint_type<T>>))>
342{
344 generic_add<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
345 return result;
346}
347
348template<typename T, int Size, BLI_ENABLE_IF((!std::is_void_v<double_uint_type<T>>))>
350{
352 generic_add<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
353 return result;
354}
355
356template<typename T, int Size>
358{
360 generic_sub<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
361 return result;
362}
363
364template<typename T, int Size>
366{
368 generic_sub<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
369 return result;
370}
371
372template<typename T, int Size, BLI_ENABLE_IF((!std::is_void_v<double_uint_type<T>>))>
374{
376 generic_unsigned_mul<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
377 return result;
378}
379
384template<typename T, int Size> bool is_negative(const IntF<T, Size> &a)
385{
386 return (a.v[Size - 1] & (T(1) << (sizeof(T) * 8 - 1))) != 0;
387}
388
389template<typename T, int Size> inline bool is_zero(const UIntF<T, Size> &a)
390{
391 bool result = true;
392 unroll<Size>([&](auto i) { result &= (a.v[i] == 0); });
393 return result;
394}
395
396template<typename T, int Size> inline bool is_zero(const IntF<T, Size> &a)
397{
398 bool result = true;
399 unroll<Size>([&](auto i) { result &= (a.v[i] == 0); });
400 return result;
401}
402
403template<typename T, int Size, BLI_ENABLE_IF((!std::is_void_v<double_uint_type<T>>))>
405{
406 using UIntF = UIntF<T, Size>;
407 using IntF = IntF<T, Size>;
408
409 /* Signed multiplication is implemented in terms of unsigned multiplication. */
410 const bool is_negative_a = is_negative(a);
411 const bool is_negative_b = is_negative(b);
412 if (is_negative_a && is_negative_b) {
413 return IntF(UIntF(-a) * UIntF(-b));
414 }
415 if (is_negative_a) {
416 return -IntF(UIntF(-a) * UIntF(b));
417 }
418 if (is_negative_b) {
419 return -IntF(UIntF(a) * UIntF(-b));
420 }
421 return IntF(UIntF(a) * UIntF(b));
422}
423
424template<typename T, int Size> inline IntF<T, Size> operator-(const IntF<T, Size> &a)
425{
427 for (int i = 0; i < Size; i++) {
428 result.v[i] = ~a.v[i];
429 }
430 return result + IntF<T, Size>(1);
431}
432
433template<typename T, int Size> inline void operator+=(UIntF<T, Size> &a, const UIntF<T, Size> &b)
434{
435 a = a + b;
436}
437
438template<typename T, int Size> inline void operator+=(IntF<T, Size> &a, const IntF<T, Size> &b)
439{
440 a = a + b;
441}
442
443template<typename T, int Size> inline void operator-=(UIntF<T, Size> &a, const UIntF<T, Size> &b)
444{
445 a = a - b;
446}
447
448template<typename T, int Size> inline void operator-=(IntF<T, Size> &a, const IntF<T, Size> &b)
449{
450 a = a - b;
451}
452
453template<typename T, int Size> inline void operator*=(UIntF<T, Size> &a, const UIntF<T, Size> &b)
454{
455 a = a * b;
456}
457
458template<typename T, int Size> inline void operator*=(IntF<T, Size> &a, const IntF<T, Size> &b)
459{
460 a = a * b;
461}
462
463template<typename T, int Size>
464inline bool operator==(const IntF<T, Size> &a, const IntF<T, Size> &b)
465{
466 return a.v == b.v;
467}
468
469template<typename T, int Size>
470inline bool operator==(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
471{
472 return a.v == b.v;
473}
474
475template<typename T, int Size>
476inline bool operator!=(const IntF<T, Size> &a, const IntF<T, Size> &b)
477{
478 return a.v != b.v;
479}
480
481template<typename T, int Size>
482inline bool operator!=(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
483{
484 return a.v != b.v;
485}
486
487template<typename T, size_t Size>
488inline int compare_reversed_order(const std::array<T, Size> &a, const std::array<T, Size> &b)
489{
490 for (int i = Size - 1; i >= 0; i--) {
491 if (a[i] < b[i]) {
492 return -1;
493 }
494 if (a[i] > b[i]) {
495 return 1;
496 }
497 }
498 return 0;
499}
500
501template<typename T, int Size>
502inline bool operator<(const IntF<T, Size> &a, const IntF<T, Size> &b)
503{
504 const bool is_negative_a = is_negative(a);
505 const bool is_negative_b = is_negative(b);
506 if (is_negative_a == is_negative_b) {
507 return compare_reversed_order(a.v, b.v) < 0;
508 }
509 return is_negative_a;
510}
511
512template<typename T, int Size>
513inline bool operator<=(const IntF<T, Size> &a, const IntF<T, Size> &b)
514{
515 const bool is_negative_a = is_negative(a);
516 const bool is_negative_b = is_negative(b);
517 if (is_negative_a == is_negative_b) {
518 return compare_reversed_order(a.v, b.v) <= 0;
519 }
520 return is_negative_a;
521}
522
523template<typename T, int Size>
524inline bool operator>(const IntF<T, Size> &a, const IntF<T, Size> &b)
525{
526 const bool is_negative_a = is_negative(a);
527 const bool is_negative_b = is_negative(b);
528 if (is_negative_a == is_negative_b) {
529 return compare_reversed_order(a.v, b.v) > 0;
530 }
531 return is_negative_b;
532}
533
534template<typename T, int Size>
535inline bool operator>=(const IntF<T, Size> &a, const IntF<T, Size> &b)
536{
537 const bool is_negative_a = is_negative(a);
538 const bool is_negative_b = is_negative(b);
539 if (is_negative_a == is_negative_b) {
540 return compare_reversed_order(a.v, b.v) >= 0;
541 }
542 return is_negative_b;
543}
544
545template<typename T, int Size>
546inline bool operator<(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
547{
548 return compare_reversed_order(a.v, b.v) < 0;
549}
550
551template<typename T, int Size>
552inline bool operator<=(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
553{
554 return compare_reversed_order(a.v, b.v) <= 0;
555}
556
557template<typename T, int Size>
558inline bool operator>(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
559{
560 return compare_reversed_order(a.v, b.v) > 0;
561}
562
563template<typename T, int Size>
564inline bool operator>=(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
565{
566 return compare_reversed_order(a.v, b.v) >= 0;
567}
568
569} // namespace blender::fixed_width_int
long long int int64_t
unsigned long long int uint64_t
nullptr float
#define str(s)
static const char * to_string(const Interpolation &interp)
Definition gl_shader.cc:103
#define ldexp
#define T
#define T2
Definition md5.cpp:21
void operator*=(UIntF< T, Size > &a, const UIntF< T, Size > &b)
UIntF< T, Size > operator*(const UIntF< T, Size > &a, const UIntF< T, Size > &b)
bool is_zero(const UIntF< T, Size > &a)
void operator+=(UIntF< T, Size > &a, const UIntF< T, Size > &b)
bool operator!=(const IntF< T, Size > &a, const IntF< T, Size > &b)
UIntF< T, Size > operator-(const UIntF< T, Size > &a, const UIntF< T, Size > &b)
UIntF< uint32_t, 4 > UInt128_32
IntF< uint16_t, 16 > Int256_16
UIntF< T, Size > operator+(const UIntF< T, Size > &a, const UIntF< T, Size > &b)
int compare_reversed_order(const std::array< T, Size > &a, const std::array< T, Size > &b)
UIntF< uint16_t, 16 > UInt256_16
UIntF< uint32_t, 2 > UInt64_32
UIntF< uint16_t, 8 > UInt128_16
bool operator==(const IntF< T, Size > &a, const IntF< T, Size > &b)
bool operator>(const IntF< T, Size > &a, const IntF< T, Size > &b)
void generic_unsigned_mul(T *__restrict dst, const T *a, const T *b)
UIntF< uint8_t, 16 > UInt128_8
UIntF< uint16_t, 4 > UInt64_16
UIntF< uint32_t, 8 > UInt256_32
typename DoubleUIntType< T >::type double_uint_type
bool operator>=(const IntF< T, Size > &a, const IntF< T, Size > &b)
void generic_add(T *__restrict dst, const T *a, const T *b)
void generic_sub(T *__restrict dst, const T *a, const T *b)
UIntF< uint64_t, 4 > UInt256_64
UIntF< uint64_t, 2 > UInt128_64
bool operator<(const IntF< T, Size > &a, const IntF< T, Size > &b)
bool operator<=(const IntF< T, Size > &a, const IntF< T, Size > &b)
UIntF< uint8_t, 32 > UInt256_8
bool is_negative(const IntF< T, Size > &a)
void operator-=(UIntF< T, Size > &a, const UIntF< T, Size > &b)
void unroll(Fn fn)
Definition BLI_unroll.hh:25
IntF(const UIntF< T, S > &value)
IntF(StringRefNull str, int base=10)
UIntF(StringRefNull str, int base=10)
i
Definition text_draw.cc:230