Blender V4.3
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
5#pragma once
6
7#include <cmath>
8
9#include "BLI_string_ref.hh"
10#include "BLI_unroll.hh"
11
13
23template<typename T, int S> struct UIntF {
24 static_assert(std::is_unsigned_v<T>);
25 static_assert(S >= 1);
26
31 std::array<T, S> v;
32
34 UIntF() = default;
35
37 explicit UIntF(uint64_t value);
38
40 explicit UIntF(StringRefNull str, int base = 10);
41
43 explicit operator uint64_t() const;
44
46 explicit operator double() const;
47 explicit operator float() const;
48
49/* See `BLI_fixed_width_int_str.hh`. */
50#ifdef WITH_GMP
52 void set_from_str(StringRefNull str, int base = 10);
53
55 std::string to_string(int base = 10) const;
56#endif
57};
58
62template<typename T, int S> struct IntF {
63 static_assert(std::is_unsigned_v<T>);
64 static_assert(S >= 1);
65
70 std::array<T, S> v;
71
73 IntF() = default;
74
76 explicit IntF(int64_t value);
77
79 explicit IntF(const UIntF<T, S> &value);
80
82 explicit IntF(StringRefNull str, int base = 10);
83
85 explicit operator int64_t() const;
86
88 explicit operator double() const;
89 explicit operator float() const;
90
92 explicit operator UIntF<T, S>() const;
93
94/* See `BLI_fixed_width_int_str.hh`. */
95#ifdef WITH_GMP
97 void set_from_str(const StringRefNull str, const int base = 10);
98
100 std::string to_string(int base = 10) const;
101#endif
102};
103
104template<typename T> struct DoubleUIntType {
105 using type = void;
106};
107template<> struct DoubleUIntType<uint8_t> {
108 using type = uint16_t;
109};
110template<> struct DoubleUIntType<uint16_t> {
111 using type = uint32_t;
112};
113template<> struct DoubleUIntType<uint32_t> {
114 using type = uint64_t;
115};
116#ifndef _MSC_VER
117template<> struct DoubleUIntType<uint64_t> {
118 using type = __uint128_t;
119};
120#endif
121
123template<typename T> using double_uint_type = typename DoubleUIntType<T>::type;
124
128
132
137
142
147
152
153#ifdef _MSC_VER
154using UInt128 = UInt128_32;
155using UInt256 = UInt256_32;
156using Int128 = Int128_32;
157using Int256 = Int256_32;
158#else
163#endif
164
165template<typename T, int S> inline UIntF<T, S>::UIntF(const uint64_t value)
166{
167 constexpr int Count = std::min(S, int(sizeof(decltype(value)) / sizeof(T)));
168 constexpr int BitsPerT = 8 * sizeof(T);
169
170 for (int i = 0; i < Count; i++) {
171 this->v[i] = T(value >> (BitsPerT * i));
172 }
173 for (int i = Count; i < S; i++) {
174 this->v[i] = 0;
175 }
176}
177
178template<typename T, int S> inline IntF<T, S>::IntF(const int64_t value)
179{
180 constexpr int Count = std::min(S, int(sizeof(decltype(value)) / sizeof(T)));
181 constexpr int BitsPerT = 8 * sizeof(T);
182
183 for (int i = 0; i < Count; i++) {
184 this->v[i] = T(value >> (BitsPerT * i));
185 }
186 const T sign_extend_fill = value < 0 ? T(-1) : T(0);
187 for (int i = Count; i < S; i++) {
188 this->v[i] = sign_extend_fill;
189 }
190}
191
192template<typename T, int S> inline IntF<T, S>::IntF(const UIntF<T, S> &value) : v(value.v) {}
193
194template<typename T, int S> UIntF<T, S>::UIntF(const StringRefNull str, const int base)
195{
196 this->set_from_str(str, base);
197}
198
199template<typename T, int S> IntF<T, S>::IntF(const StringRefNull str, const int base)
200{
201 this->set_from_str(str, base);
202}
203
204template<typename T, int S> inline UIntF<T, S>::operator uint64_t() const
205{
206 constexpr int Count = std::min(S, int(sizeof(uint64_t) / sizeof(T)));
207 constexpr int BitsPerT = 8 * sizeof(T);
208
209 uint64_t result = 0;
210 for (int i = 0; i < Count; i++) {
211 result |= uint64_t(this->v[i]) << (BitsPerT * i);
212 }
213 return result;
214}
215
216template<typename T, int S> inline UIntF<T, S>::operator double() const
217{
218 double result = double(this->v[0]);
219 for (int i = 1; i < S; i++) {
220 const T a = this->v[i];
221 if (a == 0) {
222 continue;
223 }
224 result += ldexp(a, 8 * sizeof(T) * i);
225 }
226 return result;
227}
228
229template<typename T, int S> inline UIntF<T, S>::operator float() const
230{
231 return float(double(*this));
232}
233
234template<typename T, int S> inline IntF<T, S>::operator int64_t() const
235{
236 return int64_t(uint64_t(UIntF<T, S>(*this)));
237}
238
239template<typename T, int S> inline IntF<T, S>::operator double() const
240{
241 if (is_negative(*this)) {
242 return -double(-*this);
243 }
244 double result = double(this->v[0]);
245 for (int i = 1; i < S; i++) {
246 const T a = this->v[i];
247 if (a == 0) {
248 continue;
249 }
250 result += ldexp(a, 8 * sizeof(T) * i);
251 }
252 return result;
253}
254
255template<typename T, int S> inline IntF<T, S>::operator float() const
256{
257 return float(double(*this));
258}
259
260template<typename T, int S> inline IntF<T, S>::operator UIntF<T, S>() const
261{
263 result.v = this->v;
264 return result;
265}
266
278template<typename T, typename T2, int S>
279inline void generic_add(T *__restrict dst, const T *a, const T *b)
280{
281 constexpr int shift = 8 * sizeof(T);
282 T2 carry = 0;
283 unroll<S>([&](auto i) {
284 const T2 ai = T2(a[i]);
285 const T2 bi = T2(b[i]);
286 const T2 ri = ai + bi + carry;
287 dst[i] = T(ri);
288 carry = ri >> shift;
289 });
290}
291
295template<typename T, typename T2, int S>
296inline void generic_sub(T *__restrict dst, const T *a, const T *b)
297{
298 T2 carry = 0;
299 unroll<S>([&](auto i) {
300 const T2 ai = T2(a[i]);
301 const T2 bi = T2(b[i]);
302 const T2 ri = ai - bi - carry;
303 dst[i] = T(ri);
304 carry = ri > ai;
305 });
306}
307
309template<typename T, typename T2, int S>
310inline void generic_unsigned_mul(T *__restrict dst, const T *a, const T *b)
311{
312 constexpr int shift = 8 * sizeof(T);
313
314 T2 r[S] = {};
315
316 for (int i = 0; i < S; i++) {
317 const T2 bi = T2(b[i]);
318 T2 carry = 0;
319 for (int j = 0; j < S - i; j++) {
320 const T2 rji = T2(a[j]) * bi + carry;
321 carry = rji >> shift;
322 r[i + j] += T2(T(rji));
323 }
324 }
325
326 T2 carry = 0;
327 for (int i = 0; i < S; i++) {
328 const T2 ri = r[i] + carry;
329 carry = ri >> shift;
330 dst[i] = T(ri);
331 }
332}
333
334template<typename T, int Size, BLI_ENABLE_IF((!std::is_void_v<double_uint_type<T>>))>
336{
338 generic_add<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
339 return result;
340}
341
342template<typename T, int Size, BLI_ENABLE_IF((!std::is_void_v<double_uint_type<T>>))>
344{
346 generic_add<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
347 return result;
348}
349
350template<typename T, int Size>
352{
354 generic_sub<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
355 return result;
356}
357
358template<typename T, int Size>
360{
362 generic_sub<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
363 return result;
364}
365
366template<typename T, int Size, BLI_ENABLE_IF((!std::is_void_v<double_uint_type<T>>))>
368{
370 generic_unsigned_mul<T, double_uint_type<T>, Size>(result.v.data(), a.v.data(), b.v.data());
371 return result;
372}
373
378template<typename T, int Size> bool is_negative(const IntF<T, Size> &a)
379{
380 return (a.v[Size - 1] & (T(1) << (sizeof(T) * 8 - 1))) != 0;
381}
382
383template<typename T, int Size> inline bool is_zero(const UIntF<T, Size> &a)
384{
385 bool result = true;
386 unroll<Size>([&](auto i) { result &= (a.v[i] == 0); });
387 return result;
388}
389
390template<typename T, int Size> inline bool is_zero(const IntF<T, Size> &a)
391{
392 bool result = true;
393 unroll<Size>([&](auto i) { result &= (a.v[i] == 0); });
394 return result;
395}
396
397template<typename T, int Size, BLI_ENABLE_IF((!std::is_void_v<double_uint_type<T>>))>
399{
400 using UIntF = UIntF<T, Size>;
401 using IntF = IntF<T, Size>;
402
403 /* Signed multiplication is implemented in terms of unsigned multiplication. */
404 const bool is_negative_a = is_negative(a);
405 const bool is_negative_b = is_negative(b);
406 if (is_negative_a && is_negative_b) {
407 return IntF(UIntF(-a) * UIntF(-b));
408 }
409 if (is_negative_a) {
410 return -IntF(UIntF(-a) * UIntF(b));
411 }
412 if (is_negative_b) {
413 return -IntF(UIntF(a) * UIntF(-b));
414 }
415 return IntF(UIntF(a) * UIntF(b));
416}
417
418template<typename T, int Size> inline IntF<T, Size> operator-(const IntF<T, Size> &a)
419{
421 for (int i = 0; i < Size; i++) {
422 result.v[i] = ~a.v[i];
423 }
424 return result + IntF<T, Size>(1);
425}
426
427template<typename T, int Size> inline void operator+=(UIntF<T, Size> &a, const UIntF<T, Size> &b)
428{
429 a = a + b;
430}
431
432template<typename T, int Size> inline void operator+=(IntF<T, Size> &a, const IntF<T, Size> &b)
433{
434 a = a + b;
435}
436
437template<typename T, int Size> inline void operator-=(UIntF<T, Size> &a, const UIntF<T, Size> &b)
438{
439 a = a - b;
440}
441
442template<typename T, int Size> inline void operator-=(IntF<T, Size> &a, const IntF<T, Size> &b)
443{
444 a = a - b;
445}
446
447template<typename T, int Size> inline void operator*=(UIntF<T, Size> &a, const UIntF<T, Size> &b)
448{
449 a = a * b;
450}
451
452template<typename T, int Size> inline void operator*=(IntF<T, Size> &a, const IntF<T, Size> &b)
453{
454 a = a * b;
455}
456
457template<typename T, int Size>
458inline bool operator==(const IntF<T, Size> &a, const IntF<T, Size> &b)
459{
460 return a.v == b.v;
461}
462
463template<typename T, int Size>
464inline bool operator==(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
465{
466 return a.v == b.v;
467}
468
469template<typename T, int Size>
470inline bool operator!=(const IntF<T, Size> &a, const IntF<T, Size> &b)
471{
472 return a.v != b.v;
473}
474
475template<typename T, int Size>
476inline bool operator!=(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
477{
478 return a.v != b.v;
479}
480
481template<typename T, size_t Size>
482inline int compare_reversed_order(const std::array<T, Size> &a, const std::array<T, Size> &b)
483{
484 for (int i = Size - 1; i >= 0; i--) {
485 if (a[i] < b[i]) {
486 return -1;
487 }
488 if (a[i] > b[i]) {
489 return 1;
490 }
491 }
492 return 0;
493}
494
495template<typename T, int Size>
496inline bool operator<(const IntF<T, Size> &a, const IntF<T, Size> &b)
497{
498 const bool is_negative_a = is_negative(a);
499 const bool is_negative_b = is_negative(b);
500 if (is_negative_a == is_negative_b) {
501 return compare_reversed_order(a.v, b.v) < 0;
502 }
503 return is_negative_a;
504}
505
506template<typename T, int Size>
507inline bool operator<=(const IntF<T, Size> &a, const IntF<T, Size> &b)
508{
509 const bool is_negative_a = is_negative(a);
510 const bool is_negative_b = is_negative(b);
511 if (is_negative_a == is_negative_b) {
512 return compare_reversed_order(a.v, b.v) <= 0;
513 }
514 return is_negative_a;
515}
516
517template<typename T, int Size>
518inline bool operator>(const IntF<T, Size> &a, const IntF<T, Size> &b)
519{
520 const bool is_negative_a = is_negative(a);
521 const bool is_negative_b = is_negative(b);
522 if (is_negative_a == is_negative_b) {
523 return compare_reversed_order(a.v, b.v) > 0;
524 }
525 return is_negative_b;
526}
527
528template<typename T, int Size>
529inline bool operator>=(const IntF<T, Size> &a, const IntF<T, Size> &b)
530{
531 const bool is_negative_a = is_negative(a);
532 const bool is_negative_b = is_negative(b);
533 if (is_negative_a == is_negative_b) {
534 return compare_reversed_order(a.v, b.v) >= 0;
535 }
536 return is_negative_b;
537}
538
539template<typename T, int Size>
540inline bool operator<(const UIntF<T, Size> &a, const UIntF<T, Size> &b)
541{
542 return compare_reversed_order(a.v, b.v) < 0;
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
563} // namespace blender::fixed_width_int
typedef double(DMatrix)[4][4]
ATTR_WARN_UNUSED_RESULT const BMVert * v
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
#define str(s)
static const char * to_string(const Interpolation &interp)
Definition gl_shader.cc:82
#define T
#define T2
Definition md5.cpp:19
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
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)
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< 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)
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:21
unsigned short uint16_t
Definition stdint.h:79
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
unsigned char uint8_t
Definition stdint.h:78
unsigned __int64 uint64_t
Definition stdint.h:90