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 300003579 : fd_uint128_sat_add( __uint128_t x, __uint128_t y ) {
22 300003579 : __uint128_t res = x + y;
23 300003579 : return fd_uint128_if( res < x, UINT128_MAX, res );
24 300003579 : }
25 :
26 : FD_FN_CONST static inline __uint128_t
27 300000210 : fd_uint128_sat_mul( __uint128_t x, __uint128_t y ) {
28 300000210 : __uint128_t res = x * y;
29 300000210 : uchar overflow = ( x != 0 ) && ( y != 0 ) && ( ( res < x ) || ( res < y ) || ( ( res / x ) != y ) );
30 300000210 : return fd_uint128_if( overflow, UINT128_MAX, res );
31 300000210 : }
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 300200166 : fd_ulong_sat_add( ulong x, ulong y ) {
43 300200166 : ulong res;
44 300200166 : int cf = __builtin_uaddl_overflow ( x, y, &res );
45 300200166 : return fd_ulong_if( cf, ULONG_MAX, res );
46 300200166 : }
47 :
48 : FD_FN_CONST static inline ulong
49 300062304 : fd_ulong_sat_mul( ulong x, ulong y ) {
50 300062304 : ulong res;
51 300062304 : int cf = __builtin_umull_overflow ( x, y, &res );
52 300062304 : return fd_ulong_if( cf, ULONG_MAX, res );
53 300062304 : }
54 :
55 : FD_FN_CONST static inline ulong
56 300120552 : fd_ulong_sat_sub( ulong x, ulong y ) {
57 300120552 : ulong res;
58 300120552 : int cf = __builtin_usubl_overflow ( x, y, &res );
59 300120552 : return fd_ulong_if( cf, 0UL, res );
60 300120552 : }
61 :
62 : FD_FN_CONST static inline long
63 300041673 : fd_long_sat_add( long x, long y ) {
64 300041673 : long res;
65 300041673 : int cf = __builtin_saddl_overflow ( x, y, &res );
66 : /* https://stackoverflow.com/a/56531252
67 : x + y overflows => x, y have the same sign
68 : we can use either to determine the result,
69 : with the trick described in the SO answe.
70 : We chose x because it works also for sub. */
71 300041673 : return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
72 300041673 : }
73 :
74 : FD_FN_CONST static inline long
75 300529348 : fd_long_sat_sub( long x, long y ) {
76 300529348 : long res;
77 300529348 : int cf = __builtin_ssubl_overflow ( x, y, &res );
78 300529348 : return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
79 300529348 : }
80 :
81 : FD_FN_CONST static inline long
82 12138 : fd_long_sat_mul( long x, long y ) {
83 12138 : long res;
84 12138 : int cf = __builtin_smull_overflow ( x, y, &res );
85 12138 : return fd_long_if( cf, (long)((ulong)((x ^ y) >> 63)) + LONG_MAX, res );
86 12138 : }
87 :
88 : FD_FN_CONST static inline uint
89 300001446 : fd_uint_sat_add( uint x, uint y ) {
90 300001446 : uint res;
91 300001446 : int cf = __builtin_uadd_overflow ( x, y, &res );
92 300001446 : return fd_uint_if( cf, UINT_MAX, res );
93 300001446 : }
94 :
95 : FD_FN_CONST static inline uint
96 300001197 : fd_uint_sat_mul( uint x, uint y ) {
97 300001197 : uint res;
98 300001197 : int cf = __builtin_umul_overflow ( x, y, &res );
99 300001197 : return fd_uint_if( cf, UINT_MAX, res );
100 300001197 : }
101 :
102 : FD_FN_CONST static inline uint
103 300000402 : fd_uint_sat_sub( uint x, uint y ) {
104 300000402 : uint res;
105 300000402 : int cf = __builtin_usub_overflow ( x, y, &res );
106 300000402 : return fd_uint_if( cf, 0U, res );
107 300000402 : }
108 :
109 : FD_FN_CONST static inline ushort
110 0 : fd_ushort_sat_add( ushort x, ushort y ) {
111 0 : uint res = (uint)x + (uint)y;
112 0 : return fd_ushort_if( res>USHORT_MAX, USHORT_MAX, (ushort)res );
113 0 : }
114 :
115 : FD_FN_CONST static inline ushort
116 0 : fd_ushort_sat_mul( ushort x, ushort y ) {
117 0 : uint res = (uint)x * (uint)y;
118 0 : return fd_ushort_if( res>USHORT_MAX, USHORT_MAX, (ushort)res );
119 0 : }
120 :
121 : FD_FN_CONST static inline double
122 0 : fd_double_sat_add( double x, double y ) {
123 0 : // What does rust do here?
124 0 : return x + y;
125 0 : }
126 :
127 : FD_FN_CONST static inline double
128 0 : fd_double_sat_mul( double x, double y ) {
129 0 : // What does rust do here?
130 0 : return x * y;
131 0 : }
132 :
133 : FD_FN_CONST static inline double
134 0 : fd_double_sat_sub( double x, double y ) {
135 0 : // What does rust do here?
136 0 : return x - y;
137 0 : }
138 :
139 : FD_PROTOTYPES_END
140 :
141 : #endif /* HEADER_fd_src_util_bits_fd_sat_h */
|