github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/math/checked/checked.go (about)

     1  /*
     2  Package checked implements basic arithmetic operations
     3  with underflow and overflow checks.
     4  */
     5  package checked
     6  
     7  import (
     8  	"errors"
     9  	"math"
    10  	"math/big"
    11  
    12  	"github.com/holiman/uint256"
    13  )
    14  
    15  var ErrOverflow = errors.New("arithmetic overflow")
    16  
    17  // AddInt64 returns a + b
    18  // with an integer overflow check.
    19  func AddInt64(a, b int64) (sum int64, ok bool) {
    20  	if (b > 0 && a > math.MaxInt64-b) ||
    21  		(b < 0 && a < math.MinInt64-b) {
    22  		return 0, false
    23  	}
    24  	return a + b, true
    25  }
    26  
    27  // SubInt64 returns a - b
    28  // with an integer overflow check.
    29  func SubInt64(a, b int64) (diff int64, ok bool) {
    30  	if (b > 0 && a < math.MinInt64+b) ||
    31  		(b < 0 && a > math.MaxInt64+b) {
    32  		return 0, false
    33  	}
    34  	return a - b, true
    35  }
    36  
    37  // MulInt64 returns a * b
    38  // with an integer overflow check.
    39  func MulInt64(a, b int64) (product int64, ok bool) {
    40  	if (a > 0 && b > 0 && a > math.MaxInt64/b) ||
    41  		(a > 0 && b <= 0 && b < math.MinInt64/a) ||
    42  		(a <= 0 && b > 0 && a < math.MinInt64/b) ||
    43  		(a < 0 && b <= 0 && b < math.MaxInt64/a) {
    44  		return 0, false
    45  	}
    46  	return a * b, true
    47  }
    48  
    49  // DivInt64 returns a / b
    50  // with an integer overflow check.
    51  func DivInt64(a, b int64) (quotient int64, ok bool) {
    52  	if b == 0 || (a == math.MinInt64 && b == -1) {
    53  		return 0, false
    54  	}
    55  	return a / b, true
    56  }
    57  
    58  // ModInt64 returns a % b
    59  // with an integer overflow check.
    60  func ModInt64(a, b int64) (remainder int64, ok bool) {
    61  	if b == 0 || (a == math.MinInt64 && b == -1) {
    62  		return 0, false
    63  	}
    64  	return a % b, true
    65  }
    66  
    67  // NegateInt64 returns -a
    68  // with an integer overflow check.
    69  func NegateInt64(a int64) (negated int64, ok bool) {
    70  	if a == math.MinInt64 {
    71  		return 0, false
    72  	}
    73  	return -a, true
    74  }
    75  
    76  // LshiftInt64 returns a << b
    77  // with an integer overflow check.
    78  func LshiftInt64(a, b int64) (result int64, ok bool) {
    79  	if b < 0 || b >= 64 {
    80  		return 0, false
    81  	}
    82  	if (a >= 0 && a > math.MaxInt64>>uint(b)) || (a < 0 && a < math.MinInt64>>uint(b)) {
    83  		return 0, false
    84  	}
    85  	return a << uint(b), true
    86  }
    87  
    88  // AddInt32 returns a + b
    89  // with an integer overflow check.
    90  func AddInt32(a, b int32) (sum int32, ok bool) {
    91  	if (b > 0 && a > math.MaxInt32-b) ||
    92  		(b < 0 && a < math.MinInt32-b) {
    93  		return 0, false
    94  	}
    95  	return a + b, true
    96  }
    97  
    98  // SubInt32 returns a - b
    99  // with an integer overflow check.
   100  func SubInt32(a, b int32) (diff int32, ok bool) {
   101  	if (b > 0 && a < math.MinInt32+b) ||
   102  		(b < 0 && a > math.MaxInt32+b) {
   103  		return 0, false
   104  	}
   105  	return a - b, true
   106  }
   107  
   108  // MulInt32 returns a * b
   109  // with an integer overflow check.
   110  func MulInt32(a, b int32) (product int32, ok bool) {
   111  	if (a > 0 && b > 0 && a > math.MaxInt32/b) ||
   112  		(a > 0 && b <= 0 && b < math.MinInt32/a) ||
   113  		(a <= 0 && b > 0 && a < math.MinInt32/b) ||
   114  		(a < 0 && b <= 0 && b < math.MaxInt32/a) {
   115  		return 0, false
   116  	}
   117  	return a * b, true
   118  }
   119  
   120  // DivInt32 returns a / b
   121  // with an integer overflow check.
   122  func DivInt32(a, b int32) (quotient int32, ok bool) {
   123  	if b == 0 || (a == math.MinInt32 && b == -1) {
   124  		return 0, false
   125  	}
   126  	return a / b, true
   127  }
   128  
   129  // ModInt32 returns a % b
   130  // with an integer overflow check.
   131  func ModInt32(a, b int32) (remainder int32, ok bool) {
   132  	if b == 0 || (a == math.MinInt32 && b == -1) {
   133  		return 0, false
   134  	}
   135  	return a % b, true
   136  }
   137  
   138  // NegateInt32 returns -a
   139  // with an integer overflow check.
   140  func NegateInt32(a int32) (negated int32, ok bool) {
   141  	if a == math.MinInt32 {
   142  		return 0, false
   143  	}
   144  	return -a, true
   145  }
   146  
   147  // LshiftInt32 returns a << b
   148  // with an integer overflow check.
   149  func LshiftInt32(a, b int32) (result int32, ok bool) {
   150  	if b < 0 || b >= 32 {
   151  		return 0, false
   152  	}
   153  	if (a >= 0 && a > math.MaxInt32>>uint(b)) || (a < 0 && a < math.MinInt32>>uint(b)) {
   154  		return 0, false
   155  	}
   156  	return a << uint(b), true
   157  }
   158  
   159  // AddUint64 returns a + b
   160  // with an integer overflow check.
   161  func AddUint64(a, b uint64) (sum uint64, ok bool) {
   162  	if math.MaxUint64-a < b {
   163  		return 0, false
   164  	}
   165  	return a + b, true
   166  }
   167  
   168  // SubUint64 returns a - b
   169  // with an integer overflow check.
   170  func SubUint64(a, b uint64) (diff uint64, ok bool) {
   171  	if a < b {
   172  		return 0, false
   173  	}
   174  	return a - b, true
   175  }
   176  
   177  // MulUint64 returns a * b
   178  // with an integer overflow check.
   179  func MulUint64(a, b uint64) (product uint64, ok bool) {
   180  	if b > 0 && a > math.MaxUint64/b {
   181  		return 0, false
   182  	}
   183  	return a * b, true
   184  }
   185  
   186  // DivUint64 returns a / b
   187  // with an integer overflow check.
   188  func DivUint64(a, b uint64) (quotient uint64, ok bool) {
   189  	if b == 0 {
   190  		return 0, false
   191  	}
   192  	return a / b, true
   193  }
   194  
   195  // ModUint64 returns a % b
   196  // with an integer overflow check.
   197  func ModUint64(a, b uint64) (remainder uint64, ok bool) {
   198  	if b == 0 {
   199  		return 0, false
   200  	}
   201  	return a % b, true
   202  }
   203  
   204  // LshiftUint64 returns a << b
   205  // with an integer overflow check.
   206  func LshiftUint64(a, b uint64) (result uint64, ok bool) {
   207  	if b >= 64 {
   208  		return 0, false
   209  	}
   210  	if a > math.MaxUint64>>uint(b) {
   211  		return 0, false
   212  	}
   213  	return a << uint(b), true
   214  }
   215  
   216  // AddUint32 returns a + b
   217  // with an integer overflow check.
   218  func AddUint32(a, b uint32) (sum uint32, ok bool) {
   219  	if math.MaxUint32-a < b {
   220  		return 0, false
   221  	}
   222  	return a + b, true
   223  }
   224  
   225  // SubUint32 returns a - b
   226  // with an integer overflow check.
   227  func SubUint32(a, b uint32) (diff uint32, ok bool) {
   228  	if a < b {
   229  		return 0, false
   230  	}
   231  	return a - b, true
   232  }
   233  
   234  // MulUint32 returns a * b
   235  // with an integer overflow check.
   236  func MulUint32(a, b uint32) (product uint32, ok bool) {
   237  	if b > 0 && a > math.MaxUint32/b {
   238  		return 0, false
   239  	}
   240  	return a * b, true
   241  }
   242  
   243  // DivUint32 returns a / b
   244  // with an integer overflow check.
   245  func DivUint32(a, b uint32) (quotient uint32, ok bool) {
   246  	if b == 0 {
   247  		return 0, false
   248  	}
   249  	return a / b, true
   250  }
   251  
   252  // ModUint32 returns a % b
   253  // with an integer overflow check.
   254  func ModUint32(a, b uint32) (remainder uint32, ok bool) {
   255  	if b == 0 {
   256  		return 0, false
   257  	}
   258  	return a % b, true
   259  }
   260  
   261  // LshiftUint32 returns a << b
   262  // with an integer overflow check.
   263  func LshiftUint32(a, b uint32) (result uint32, ok bool) {
   264  	if b >= 32 {
   265  		return 0, false
   266  	}
   267  	if a > math.MaxUint32>>uint(b) {
   268  		return 0, false
   269  	}
   270  	return a << uint(b), true
   271  }
   272  
   273  // NewUInt256 returns uint256
   274  // with an integer overflow check.
   275  func NewUInt256(a string) (num *uint256.Int, ok bool) {
   276  	bigIntNum, ok := new(big.Int).SetString(a, 10)
   277  	if !ok {
   278  		return nil, false
   279  	}
   280  
   281  	uint256Num, overflow := uint256.FromBig(bigIntNum)
   282  	if overflow {
   283  		return nil, false
   284  	}
   285  
   286  	return uint256Num, true
   287  }