LCOV - code coverage report
Current view: top level - util/bits - fd_sat.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 43 78 55.1 %
Date: 2026-03-19 18:19:27 Functions: 77 15674 0.5 %

          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        4401 : fd_uint128_sat_add( __uint128_t x, __uint128_t y ) {
      22        4401 :   __uint128_t res = x + y;
      23        4401 :   return fd_uint128_if( res < x, UINT128_MAX, res );
      24        4401 : }
      25             : 
      26             : FD_FN_CONST static inline __uint128_t
      27        4101 : fd_uint128_sat_mul( __uint128_t x, __uint128_t y ) {
      28        4101 :   __uint128_t res = x * y;
      29        4101 :   uchar overflow = ( x != 0 ) && ( y != 0 ) && ( ( res < x ) || ( res < y ) || ( ( res / x ) != y ) );
      30        4101 :   return fd_uint128_if( overflow, UINT128_MAX, res );
      31        4101 : }
      32             : 
      33             : FD_FN_CONST static inline __uint128_t
      34           0 : fd_uint128_sat_sub( __uint128_t x, __uint128_t y ) {
      35           0 :   __uint128_t res = x - y;
      36           0 :   return fd_uint128_if( res > x, 0, res );
      37           0 : }
      38             : 
      39             : #endif /* FD_HAS_INT128 */
      40             : 
      41             : FD_FN_CONST static inline ulong
      42    26753023 : fd_ulong_sat_add( ulong x, ulong y ) {
      43    26753023 :   ulong res;
      44    26753023 :   int cf = __builtin_uaddl_overflow ( x, y, &res );
      45    26753023 :   return fd_ulong_if( cf, ULONG_MAX, res );
      46    26753023 : }
      47             : 
      48             : FD_FN_CONST static inline ulong
      49     3514255 : fd_ulong_sat_mul( ulong x, ulong y ) {
      50     3514255 :   ulong res;
      51     3514255 :   int cf = __builtin_umull_overflow ( x, y, &res );
      52     3514255 :   return fd_ulong_if( cf, ULONG_MAX, res );
      53     3514255 : }
      54             : 
      55             : FD_FN_CONST static inline ulong
      56     1010391 : fd_ulong_sat_sub( ulong x, ulong y ) {
      57     1010391 :   ulong res;
      58     1010391 :   int cf = __builtin_usubl_overflow ( x, y, &res );
      59     1010391 :   return fd_ulong_if( cf, 0UL, res );
      60     1010391 : }
      61             : 
      62             : FD_FN_CONST static inline long
      63     6825510 : fd_long_sat_add( long x, long y ) {
      64     6825510 :   long res;
      65     6825510 :   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     6825510 :   return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
      72     6825510 : }
      73             : 
      74             : FD_FN_CONST static inline long
      75        4738 : fd_long_sat_sub( long x, long y ) {
      76        4738 :   long res;
      77        4738 :   int cf = __builtin_ssubl_overflow ( x, y, &res );
      78        4738 :   return fd_long_if( cf, (long)((ulong)x >> 63) + LONG_MAX, res );
      79        4738 : }
      80             : 
      81             : FD_FN_CONST static inline long
      82           0 : fd_long_sat_mul( long x, long y ) {
      83           0 :   long res;
      84           0 :   int cf = __builtin_smull_overflow ( x, y, &res );
      85           0 :   return fd_long_if( cf, (long)((ulong)((x ^ y) >> 63)) + LONG_MAX, res );
      86           0 : }
      87             : 
      88             : FD_FN_CONST static inline uint
      89           6 : fd_uint_sat_add( uint x, uint y ) {
      90           6 :   uint res;
      91           6 :   int cf = __builtin_uadd_overflow ( x, y, &res );
      92           6 :   return fd_uint_if( cf, UINT_MAX, res );
      93           6 : }
      94             : 
      95             : FD_FN_CONST static inline uint
      96           0 : fd_uint_sat_mul( uint x, uint y ) {
      97           0 :   uint res;
      98           0 :   int cf = __builtin_umul_overflow ( x, y, &res );
      99           0 :   return fd_uint_if( cf, UINT_MAX, res );
     100           0 : }
     101             : 
     102             : FD_FN_CONST static inline uint
     103           0 : fd_uint_sat_sub( uint x, uint y ) {
     104           0 :   uint res;
     105           0 :   int cf = __builtin_usub_overflow ( x, y, &res );
     106           0 :   return fd_uint_if( cf, 0U, res );
     107           0 : }
     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           1 : fd_ushort_sat_mul( ushort x, ushort y ) {
     117           1 :   uint res = (uint)x * (uint)y;
     118           1 :   return fd_ushort_if( res>USHORT_MAX, USHORT_MAX, (ushort)res );
     119           1 : }
     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 */

Generated by: LCOV version 1.14