LCOV - code coverage report
Current view: top level - util/bits - fd_sat.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 62 78 79.5 %
Date: 2026-10-15 04:28:26 Functions: 114 17799 0.6 %

          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   300020178 : fd_uint128_sat_add( uint128 x, uint128 y ) {
      20   300020178 :   uint128 res = x + y;
      21   300020178 :   return fd_uint128_if( res < x, UINT128_MAX, res );
      22   300020178 : }
      23             : 
      24             : FD_FN_CONST static inline uint128
      25   318015789 : fd_uint128_sat_mul( uint128 x, uint128 y ) {
      26   318015789 :   uint128 res = x * y;
      27   318015789 :   uchar overflow = ( x != 0 ) && ( y != 0 ) && ( ( res < x ) || ( res < y ) || ( ( res / x ) != y ) );
      28   318015789 :   return fd_uint128_if( overflow, UINT128_MAX, res );
      29   318015789 : }
      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  1121027980 : fd_ulong_sat_add( ulong x, ulong y ) {
      39  1121027980 :   ulong res;
      40  1121027980 :   int cf = __builtin_uaddl_overflow ( x, y, &res );
      41  1121027980 :   return fd_ulong_if( cf, ULONG_MAX, res );
      42  1121027980 : }
      43             : 
      44             : FD_FN_CONST static inline ulong
      45   386176597 : fd_ulong_sat_mul( ulong x, ulong y ) {
      46   386176597 :   ulong res;
      47   386176597 :   int cf = __builtin_umull_overflow ( x, y, &res );
      48   386176597 :   return fd_ulong_if( cf, ULONG_MAX, res );
      49   386176597 : }
      50             : 
      51             : FD_FN_CONST static inline ulong
      52  1378238575 : fd_ulong_sat_sub( ulong x, ulong y ) {
      53  1378238575 :   ulong res;
      54  1378238575 :   int cf = __builtin_usubl_overflow ( x, y, &res );
      55  1378238575 :   return fd_ulong_if( cf, 0UL, res );
      56  1378238575 : }
      57             : 
      58             : FD_FN_CONST static inline long
      59   472254347 : fd_long_sat_add( long x, long y ) {
      60   472254347 :   long res;
      61   472254347 :   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 answer.
      66             :      We chose x because it works also for sub.
      67             :      It is not UB because we compile with -fwrapv. */
      68   472254347 :   return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
      69   472254347 : }
      70             : 
      71             : FD_FN_CONST static inline long
      72   300133290 : fd_long_sat_sub( long x, long y ) {
      73   300133290 :   long res;
      74   300133290 :   int cf = __builtin_ssubl_overflow ( x, y, &res );
      75   300133290 :   return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
      76   300133290 : }
      77             : 
      78             : FD_FN_CONST static inline long
      79   300012162 : fd_long_sat_mul( long x, long y ) {
      80   300012162 :   long res;
      81   300012162 :   int cf = __builtin_smull_overflow ( x, y, &res );
      82   300012162 :   return fd_long_if( cf, (long)((ulong)(x ^ y) >> 63) + LONG_MAX, res );
      83   300012162 : }
      84             : 
      85             : FD_FN_CONST static inline uint
      86   300005592 : fd_uint_sat_add( uint x, uint y ) {
      87   300005592 :   uint res;
      88   300005592 :   int cf = __builtin_uadd_overflow ( x, y, &res );
      89   300005592 :   return fd_uint_if( cf, UINT_MAX, res );
      90   300005592 : }
      91             : 
      92             : FD_FN_CONST static inline uint
      93   300003033 : fd_uint_sat_mul( uint x, uint y ) {
      94   300003033 :   uint res;
      95   300003033 :   int cf = __builtin_umul_overflow ( x, y, &res );
      96   300003033 :   return fd_uint_if( cf, UINT_MAX, res );
      97   300003033 : }
      98             : 
      99             : FD_FN_CONST static inline uint
     100   300003702 : fd_uint_sat_sub( uint x, uint y ) {
     101   300003702 :   uint res;
     102   300003702 :   int cf = __builtin_usub_overflow ( x, y, &res );
     103   300003702 :   return fd_uint_if( cf, 0U, res );
     104   300003702 : }
     105             : 
     106             : FD_FN_CONST static inline ushort
     107           0 : fd_ushort_sat_add( ushort x, ushort y ) {
     108           0 :   uint res = (uint)x + (uint)y;
     109           0 :   return fd_ushort_if( res>USHORT_MAX, USHORT_MAX, (ushort)res );
     110           0 : }
     111             : 
     112             : FD_FN_CONST static inline ushort
     113           3 : fd_ushort_sat_mul( ushort x, ushort y ) {
     114           3 :   uint res = (uint)x * (uint)y;
     115           3 :   return fd_ushort_if( res>USHORT_MAX, USHORT_MAX, (ushort)res );
     116           3 : }
     117             : 
     118             : FD_FN_CONST static inline double
     119           0 : fd_double_sat_add( double x, double y ) {
     120           0 :   // What does rust do here?
     121           0 :   return x + y;
     122           0 : }
     123             : 
     124             : FD_FN_CONST static inline double
     125           0 : fd_double_sat_mul( double x, double y ) {
     126           0 :   // What does rust do here?
     127           0 :   return x * y;
     128           0 : }
     129             : 
     130             : FD_FN_CONST static inline double
     131           0 : fd_double_sat_sub( double x, double y ) {
     132           0 :   // What does rust do here?
     133           0 :   return x - y;
     134           0 : }
     135             : 
     136             : FD_PROTOTYPES_END
     137             : 
     138             : #endif /* HEADER_fd_src_util_bits_fd_sat_h */

Generated by: LCOV version 1.14