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