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