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 300766515 : fd_ulong_sat_add( ulong x, ulong y ) {
43 300766515 : ulong res;
44 300766515 : int cf = __builtin_uaddl_overflow ( x, y, &res );
45 300766515 : return fd_ulong_if( cf, ULONG_MAX, res );
46 300766515 : }
47 :
48 : FD_FN_CONST static inline ulong
49 300012795 : fd_ulong_sat_mul( ulong x, ulong y ) {
50 300012795 : ulong res;
51 300012795 : int cf = __builtin_umull_overflow ( x, y, &res );
52 300012795 : return fd_ulong_if( cf, ULONG_MAX, res );
53 300012795 : }
54 :
55 : FD_FN_CONST static inline ulong
56 301950864 : fd_ulong_sat_sub( ulong x, ulong y ) {
57 301950864 : ulong res;
58 301950864 : int cf = __builtin_usubl_overflow ( x, y, &res );
59 301950864 : return fd_ulong_if( cf, 0UL, res );
60 301950864 : }
61 :
62 : FD_FN_CONST static inline long
63 300000009 : fd_long_sat_add( long x, long y ) {
64 300000009 : long res;
65 300000009 : 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 300000009 : return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
72 300000009 : }
73 :
74 : FD_FN_CONST static inline long
75 300000006 : fd_long_sat_sub( long x, long y ) {
76 300000006 : long res;
77 300000006 : int cf = __builtin_ssubl_overflow ( x, y, &res );
78 300000006 : return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
79 300000006 : }
80 :
81 : /* fd_long_sat_mul is left as an exercise to the reader */
82 :
83 : FD_FN_CONST static inline uint
84 300000027 : fd_uint_sat_add( uint x, uint y ) {
85 300000027 : uint res;
86 300000027 : int cf = __builtin_uadd_overflow ( x, y, &res );
87 300000027 : return fd_uint_if( cf, UINT_MAX, res );
88 300000027 : }
89 :
90 : FD_FN_CONST static inline uint
91 300006771 : fd_uint_sat_mul( uint x, uint y ) {
92 300006771 : uint res;
93 300006771 : int cf = __builtin_umul_overflow ( x, y, &res );
94 300006771 : return fd_uint_if( cf, UINT_MAX, res );
95 300006771 : }
96 :
97 : FD_FN_CONST static inline uint
98 300000114 : fd_uint_sat_sub( uint x, uint y ) {
99 300000114 : uint res;
100 300000114 : int cf = __builtin_usub_overflow ( x, y, &res );
101 300000114 : return fd_uint_if( cf, 0U, res );
102 300000114 : }
103 :
104 : FD_FN_CONST static inline double
105 0 : fd_double_sat_add( double x, double y ) {
106 0 : // What does rust do here?
107 0 : return x + y;
108 0 : }
109 :
110 : FD_FN_CONST static inline double
111 0 : fd_double_sat_mul( double x, double y ) {
112 0 : // What does rust do here?
113 0 : return x * y;
114 0 : }
115 :
116 : FD_FN_CONST static inline double
117 0 : fd_double_sat_sub( double x, double y ) {
118 0 : // What does rust do here?
119 0 : return x - y;
120 0 : }
121 :
122 : FD_PROTOTYPES_END
123 :
124 : #endif /* HEADER_fd_src_util_bits_fd_sat_h */
|