173 lines
4.2 KiB
Go
173 lines
4.2 KiB
Go
// The safemath package implements helper functions for safe integer arithmetic.
|
|
//
|
|
// This file implements 'checked' integer arithmetic for guarding against integer
|
|
// overflows and division-by-zero errors.
|
|
|
|
package safemath
|
|
|
|
import (
|
|
"errors"
|
|
"math/bits"
|
|
)
|
|
|
|
var (
|
|
ErrOverflowAdd = errors.New("integer overflow in addition")
|
|
ErrOverflowMul = errors.New("integer overflow in multiplication")
|
|
ErrOverflowSub = errors.New("integer overflow in subtraction")
|
|
ErrDivByZero = errors.New("divide by zero")
|
|
)
|
|
|
|
// CheckedAddU8 adds two uint8's together, returning an error
|
|
// in the event of an overflow.
|
|
func CheckedAddU8(a, b uint8) (uint8, error) {
|
|
result := a + b
|
|
if result < a {
|
|
return 0, ErrOverflowAdd
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// CheckedMulU8 multiplies two uint8's together, returning an error
|
|
// in the event of an overflow.
|
|
func CheckedMulU8(a, b uint8) (uint8, error) {
|
|
result := a * b
|
|
if result < a {
|
|
return 0, ErrOverflowMul
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// CheckedSubU8 computes `a - b` for two uint8's returning an error in the event
|
|
// that a is smaller than b
|
|
func CheckedSubU8(a, b uint8) (uint8, error) {
|
|
if a < b {
|
|
return 0, ErrOverflowSub
|
|
}
|
|
return a - b, nil
|
|
}
|
|
|
|
// CheckedDivU8 computes `a / b` for two uint8's, returning an error in the event
|
|
// that b is 0
|
|
func CheckedDivU8(a, b uint8) (uint8, error) {
|
|
if b == 0 {
|
|
return 0, ErrDivByZero
|
|
}
|
|
return a / b, nil
|
|
}
|
|
|
|
// CheckedAddU16 adds two uint16's together, returning an error in the event
|
|
// of an overflow.
|
|
func CheckedAddU16(a, b uint16) (uint16, error) {
|
|
result := a + b
|
|
if result < a {
|
|
return 0, ErrOverflowAdd
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// CheckedMulU16 multiplies two uint16's together, returning an error in the event
|
|
// of an overflow.
|
|
func CheckedMulU16(a, b uint16) (uint16, error) {
|
|
result := a * b
|
|
if result < a {
|
|
return 0, ErrOverflowMul
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// CheckedSubU16 computes `a - b` for two uint16's, returning an error in the event
|
|
// that a is smaller than b
|
|
func CheckedSubU16(a, b uint16) (uint16, error) {
|
|
if a < b {
|
|
return 0, ErrOverflowSub
|
|
}
|
|
return a - b, nil
|
|
}
|
|
|
|
// CheckedDivU16 computes `a / b` for two uint16's, returning an error in the event
|
|
// that b is 0
|
|
func CheckedDivU16(a, b uint16) (uint16, error) {
|
|
if b == 0 {
|
|
return 0, ErrDivByZero
|
|
}
|
|
return a / b, nil
|
|
}
|
|
|
|
// CheckedAddU32 adds two uint32's together, returning an error in the event of an overflow.
|
|
func CheckedAddU32(a, b uint32) (uint32, error) {
|
|
sum, carryOut := bits.Add32(a, b, 0)
|
|
if carryOut == 1 {
|
|
return 0, ErrOverflowAdd
|
|
}
|
|
return sum, nil
|
|
}
|
|
|
|
// CheckedMulU32 multiplies two uint32's together, returning an error in the event
|
|
// of an overflow.
|
|
func CheckedMulU32(a, b uint32) (uint32, error) {
|
|
hi, lo := bits.Mul32(a, b)
|
|
if hi > 0 {
|
|
return 0, ErrOverflowMul
|
|
}
|
|
return lo, nil
|
|
}
|
|
|
|
// CheckedSubU32 computes `a - b` for two uint32's, returning an error in the event that
|
|
// a is smaller than b
|
|
func CheckedSubU32(a, b uint32) (uint32, error) {
|
|
result, borrow := bits.Sub32(a, b, 0)
|
|
if borrow == 1 {
|
|
return 0, ErrOverflowSub
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// CheckedDivU32 computes `a / b` for two uint32's, returning an error in the event
|
|
// that b is 0
|
|
func CheckedDivU32(a, b uint32) (uint32, error) {
|
|
if b == 0 {
|
|
return 0, ErrDivByZero
|
|
}
|
|
result, _ := bits.Div32(0, a, b)
|
|
return result, nil
|
|
}
|
|
|
|
// CheckedAddU64 adds two uint64's together, returning an error in the event of an overflow.
|
|
func CheckedAddU64(a, b uint64) (uint64, error) {
|
|
sum, carryOut := bits.Add64(a, b, 0)
|
|
if carryOut == 1 {
|
|
return 0, ErrOverflowAdd
|
|
}
|
|
return sum, nil
|
|
}
|
|
|
|
// CheckedMulU64 multiplies two uint64's together, returning an error in the event
|
|
// of an overflow.
|
|
func CheckedMulU64(a, b uint64) (uint64, error) {
|
|
hi, lo := bits.Mul64(a, b)
|
|
if hi > 0 {
|
|
return 0, ErrOverflowMul
|
|
}
|
|
return lo, nil
|
|
}
|
|
|
|
// CheckedSubU64 computes `a - b` for two uint64's, returning an error in the event
|
|
// that a is smaller than b
|
|
func CheckedSubU64(a, b uint64) (uint64, error) {
|
|
result, borrow := bits.Sub64(a, b, 0)
|
|
if borrow == 1 {
|
|
return 0, ErrOverflowSub
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// CheckedDivU64 computes `a / b` for two uint64's, returning an error in the event
|
|
// that b is 0
|
|
func CheckedDivU64(a, b uint64) (uint64, error) {
|
|
if b == 0 {
|
|
return 0, ErrDivByZero
|
|
}
|
|
result, _ := bits.Div64(0, a, b)
|
|
return result, nil
|
|
}
|