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 300000093 : fd_uint128_sat_add( __uint128_t x, __uint128_t y ) {
22 300000093 : __uint128_t res = x + y;
23 300000093 : return fd_uint128_if( res < x, UINT128_MAX, res );
24 300000093 : }
25 :
26 : FD_FN_CONST static inline __uint128_t
27 300000141 : fd_uint128_sat_mul( __uint128_t x, __uint128_t y ) {
28 300000141 : __uint128_t res = x * y;
29 300000141 : uchar overflow = ( x != 0 ) && ( y != 0 ) && ( ( res < x ) || ( res < y ) || ( ( res / x ) != y ) );
30 300000141 : return fd_uint128_if( overflow, UINT128_MAX, res );
31 300000141 : }
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 300069942 : fd_ulong_sat_add( ulong x, ulong y ) {
43 300069942 : ulong res;
44 300069942 : int cf = __builtin_uaddl_overflow ( x, y, &res );
45 300069942 : return fd_ulong_if( cf, ULONG_MAX, res );
46 300069942 : }
47 :
48 : FD_FN_CONST static inline ulong
49 300007344 : fd_ulong_sat_mul( ulong x, ulong y ) {
50 300007344 : ulong res;
51 300007344 : int cf = __builtin_umull_overflow ( x, y, &res );
52 300007344 : return fd_ulong_if( cf, ULONG_MAX, res );
53 300007344 : }
54 :
55 : FD_FN_CONST static inline ulong
56 300008781 : fd_ulong_sat_sub( ulong x, ulong y ) {
57 300008781 : ulong res;
58 300008781 : int cf = __builtin_usubl_overflow ( x, y, &res );
59 300008781 : return fd_ulong_if( cf, 0UL, res );
60 300008781 : }
61 :
62 : FD_FN_CONST static inline long
63 300012456 : fd_long_sat_add( long x, long y ) {
64 300012456 : long res;
65 300012456 : 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 300012456 : return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
72 300012456 : }
73 :
74 : FD_FN_CONST static inline long
75 300393583 : fd_long_sat_sub( long x, long y ) {
76 300393583 : long res;
77 300393583 : int cf = __builtin_ssubl_overflow ( x, y, &res );
78 300393583 : return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
79 300393583 : }
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 300000012 : fd_uint_sat_add( uint x, uint y ) {
90 300000012 : uint res;
91 300000012 : int cf = __builtin_uadd_overflow ( x, y, &res );
92 300000012 : return fd_uint_if( cf, UINT_MAX, res );
93 300000012 : }
94 :
95 : FD_FN_CONST static inline uint
96 300000009 : fd_uint_sat_mul( uint x, uint y ) {
97 300000009 : uint res;
98 300000009 : int cf = __builtin_umul_overflow ( x, y, &res );
99 300000009 : return fd_uint_if( cf, UINT_MAX, res );
100 300000009 : }
101 :
102 : FD_FN_CONST static inline uint
103 300000006 : fd_uint_sat_sub( uint x, uint y ) {
104 300000006 : uint res;
105 300000006 : int cf = __builtin_usub_overflow ( x, y, &res );
106 300000006 : return fd_uint_if( cf, 0U, res );
107 300000006 : }
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 */
|