Line data Source code
1 : #ifndef HEADER_fd_src_util_bits_fd_sat_h
2 : #define HEADER_fd_src_util_bits_fd_sat_h
3 :
4 : #include "fd_bits.h"
5 :
6 : /* Set of primitives for saturating math operations, mimicking the behaviour
7 : of Rust's primitive `saturating_add`, `saturating_sub`, `saturating_mul` operations.
8 : These saturate at the boundaries of the integer representation, instead of overflowing
9 : or underflowing.
10 :
11 : Note that this is a placeholder API, and the implementations will be optimised and
12 : hardened in the future. The intent of this is to provide an abstraction for saturating
13 : operations which can be used throughout the codebase, providing a single place to optimize
14 : these. */
15 :
16 : FD_PROTOTYPES_BEGIN
17 :
18 : #if FD_HAS_INT128
19 :
20 : FD_FN_CONST static inline __uint128_t
21 300000009 : fd_uint128_sat_add( __uint128_t x, __uint128_t y ) {
22 300000009 : __uint128_t res = x + y;
23 300000009 : return fd_uint128_if( res < x, UINT128_MAX, res );
24 300000009 : }
25 :
26 : FD_FN_CONST static inline __uint128_t
27 300000009 : fd_uint128_sat_mul( __uint128_t x, __uint128_t y ) {
28 300000009 : __uint128_t res = x * y;
29 300000009 : uchar overflow = ( x != 0 ) && ( y != 0 ) && ( ( res < x ) || ( res < y ) || ( ( res / x ) != y ) );
30 300000009 : return fd_uint128_if( overflow, UINT128_MAX, res );
31 300000009 : }
32 :
33 : FD_FN_CONST static inline __uint128_t
34 300000006 : fd_uint128_sat_sub( __uint128_t x, __uint128_t y ) {
35 300000006 : __uint128_t res = x - y;
36 300000006 : return fd_uint128_if( res > x, 0, res );
37 300000006 : }
38 :
39 : #endif /* FD_HAS_INT128 */
40 :
41 : FD_FN_CONST static inline ulong
42 300864948 : fd_ulong_sat_add( ulong x, ulong y ) {
43 300864948 : ulong res;
44 300864948 : int cf = __builtin_uaddl_overflow ( x, y, &res );
45 300864948 : return fd_ulong_if( cf, ULONG_MAX, res );
46 300864948 : }
47 :
48 : FD_FN_CONST static inline ulong
49 300022611 : fd_ulong_sat_mul( ulong x, ulong y ) {
50 300022611 : ulong res;
51 300022611 : int cf = __builtin_umull_overflow ( x, y, &res );
52 300022611 : return fd_ulong_if( cf, ULONG_MAX, res );
53 300022611 : }
54 :
55 : FD_FN_CONST static inline ulong
56 388086104 : fd_ulong_sat_sub( ulong x, ulong y ) {
57 388086104 : ulong res;
58 388086104 : int cf = __builtin_usubl_overflow ( x, y, &res );
59 388086104 : return fd_ulong_if( cf, 0UL, res );
60 388086104 : }
61 :
62 : FD_FN_CONST static inline uint
63 300000027 : fd_uint_sat_add( uint x, uint y ) {
64 300000027 : uint res;
65 300000027 : int cf = __builtin_uadd_overflow ( x, y, &res );
66 300000027 : return fd_uint_if( cf, UINT_MAX, res );
67 300000027 : }
68 :
69 : FD_FN_CONST static inline uint
70 300006057 : fd_uint_sat_mul( uint x, uint y ) {
71 300006057 : uint res;
72 300006057 : int cf = __builtin_umul_overflow ( x, y, &res );
73 300006057 : return fd_uint_if( cf, UINT_MAX, res );
74 300006057 : }
75 :
76 : FD_FN_CONST static inline uint
77 300000060 : fd_uint_sat_sub( uint x, uint y ) {
78 300000060 : uint res;
79 300000060 : int cf = __builtin_usub_overflow ( x, y, &res );
80 300000060 : return fd_uint_if( cf, 0U, res );
81 300000060 : }
82 :
83 : FD_FN_CONST static inline double
84 0 : fd_double_sat_add( double x, double y ) {
85 0 : // What does rust do here?
86 0 : return x + y;
87 0 : }
88 :
89 : FD_FN_CONST static inline double
90 0 : fd_double_sat_mul( double x, double y ) {
91 0 : // What does rust do here?
92 0 : return x * y;
93 0 : }
94 :
95 : FD_FN_CONST static inline double
96 0 : fd_double_sat_sub( double x, double y ) {
97 0 : // What does rust do here?
98 0 : return x - y;
99 0 : }
100 :
101 : FD_PROTOTYPES_END
102 :
103 : #endif /* HEADER_fd_src_util_bits_fd_sat_h */
|