From d598466737ff7d9473f4072b844714cc6ff49cb1 Mon Sep 17 00:00:00 2001 From: rwxe Date: Wed, 27 Sep 2023 20:04:04 +0800 Subject: [PATCH 1/7] Add support for uint type overflow detection --- README.md | 5 +- overflow.go | 92 +++++++++++- overflow_impl.go | 340 +++++++++++++++++++++++++++++++++++++++++++ overflow_template.sh | 85 +++++++++++ overflow_test.go | 97 +++++++++++- 5 files changed, 612 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 418e427..a228145 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Build Status](https://travis-ci.org/JohnCGriffin/overflow.png)](https://travis-ci.org/JohnCGriffin/overflow) # overflow -Check for int/int8/int16/int64/int32 integer overflow in Golang arithmetic. +Check for integer overflow in Golang arithmetic. ### Install ``` go get github.com/johncgriffin/overflow @@ -46,8 +46,7 @@ yields the output 9223372036854775802+9 -> (0,false) ``` -For int, int64, and int32 types, provide Add, Add32, Add64, Sub, Sub32, Sub64, etc. -Unsigned types not covered at the moment, but such additions are welcome. +For (u)int types, provide (U)Add, (U)Sub, (U)Mul, (U)Div, (U)Quotient, etc. ### Stay calm and panic diff --git a/overflow.go b/overflow.go index 17e2417..fa41aa9 100644 --- a/overflow.go +++ b/overflow.go @@ -1,4 +1,5 @@ -/*Package overflow offers overflow-checked integer arithmetic operations +/* +Package overflow offers overflow-checked integer arithmetic operations for int, int32, and int64. Each of the operations returns a result,bool combination. This was prompted by the need to know when to flow into higher precision types from the math.big library. @@ -16,7 +17,8 @@ overflow.Add(math.MaxInt64,1) -> (0, false) Add, Sub, Mul, Div are for int. Add64, Add32, etc. are specifically sized. If anybody wishes an unsigned version, submit a pull request for code -and new tests. */ +and new tests. +*/ package overflow //go:generate ./overflow_template.sh @@ -50,6 +52,16 @@ func Add(a, b int) (int, bool) { return int(r32), ok } +// UAdd sums two uints, returning the result and a boolean status. +func UAdd(a, b uint) (uint, bool) { + if _is64Bit() { + r64, ok := UAdd64(uint64(a), uint64(b)) + return uint(r64), ok + } + r32, ok := UAdd32(uint32(a), uint32(b)) + return uint(r32), ok +} + // Sub returns the difference of two ints and a boolean status. func Sub(a, b int) (int, bool) { if _is64Bit() { @@ -60,6 +72,16 @@ func Sub(a, b int) (int, bool) { return int(r32), ok } +// USub returns the difference of two uints and a boolean status. +func USub(a, b uint) (uint, bool) { + if _is64Bit() { + r64, ok := USub64(uint64(a), uint64(b)) + return uint(r64), ok + } + r32, ok := USub32(uint32(a), uint32(b)) + return uint(r32), ok +} + // Mul returns the product of two ints and a boolean status. func Mul(a, b int) (int, bool) { if _is64Bit() { @@ -70,6 +92,16 @@ func Mul(a, b int) (int, bool) { return int(r32), ok } +// UMul returns the product of two uints and a boolean status. +func UMul(a, b uint) (uint, bool) { + if _is64Bit() { + r64, ok := UMul64(uint64(a), uint64(b)) + return uint(r64), ok + } + r32, ok := UMul32(uint32(a), uint32(b)) + return uint(r32), ok +} + // Div returns the quotient of two ints and a boolean status func Div(a, b int) (int, bool) { if _is64Bit() { @@ -80,6 +112,16 @@ func Div(a, b int) (int, bool) { return int(r32), ok } +// UDiv returns the quotient of two uints and a boolean status +func UDiv(a, b uint) (uint, bool) { + if _is64Bit() { + r64, ok := UDiv64(uint64(a), uint64(b)) + return uint(r64), ok + } + r32, ok := UDiv32(uint32(a), uint32(b)) + return uint(r32), ok +} + // Quotient returns the quotient, remainder and status of two ints func Quotient(a, b int) (int, int, bool) { if _is64Bit() { @@ -90,6 +132,16 @@ func Quotient(a, b int) (int, int, bool) { return int(q32), int(r32), ok } +// UQuotient returns the quotient, remainder and status of two uints +func UQuotient(a, b uint) (uint, uint, bool) { + if _is64Bit() { + uq64, ur64, ok := UQuotient64(uint64(a), uint64(b)) + return uint(uq64), uint(ur64), ok + } + uq32, ur32, ok := UQuotient32(uint32(a), uint32(b)) + return uint(uq32), uint(ur32), ok +} + /************* Panic versions for int ****************/ // Addp returns the sum of two ints, panicking on overflow @@ -101,6 +153,15 @@ func Addp(a, b int) int { return r } +// UAddp returns the sum of two uints, panicking on overflow +func UAddp(a, b uint) uint { + r, ok := UAdd(a, b) + if !ok { + panic("addition overflow") + } + return r +} + // Subp returns the difference of two ints, panicking on overflow. func Subp(a, b int) int { r, ok := Sub(a, b) @@ -110,6 +171,15 @@ func Subp(a, b int) int { return r } +// USubp returns the difference of two uints, panicking on overflow. +func USubp(a, b uint) uint { + r, ok := USub(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + // Mulp returns the product of two ints, panicking on overflow. func Mulp(a, b int) int { r, ok := Mul(a, b) @@ -119,6 +189,15 @@ func Mulp(a, b int) int { return r } +// UMulp returns the product of two uints, panicking on overflow. +func UMulp(a, b uint) uint { + r, ok := UMul(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} + // Divp returns the quotient of two ints, panicking on overflow. func Divp(a, b int) int { r, ok := Div(a, b) @@ -127,3 +206,12 @@ func Divp(a, b int) int { } return r } + +// UDivp returns the quotient of two uints, panicking on overflow. +func UDivp(a, b uint) uint { + r, ok := UDiv(a, b) + if !ok { + panic("division failure") + } + return r +} diff --git a/overflow_impl.go b/overflow_impl.go index d1cbe86..c96e8af 100644 --- a/overflow_impl.go +++ b/overflow_impl.go @@ -25,6 +25,25 @@ func Add8p(a, b int8) int8 { return r } +// UAdd8 performs + operation on two uint8 operands +// returning a result and status +func UAdd8(a, b uint8) (uint8, bool) { + c := a + b + if c >= a { + return c, true + } + return c, false +} + +// UAdd8p is the unchecked panicing version of UAdd8 +func UAdd8p(a, b uint8) uint8 { + r, ok := UAdd8(a, b) + if !ok { + panic("addition overflow") + } + return r +} + // Sub8 performs - operation on two int8 operands // returning a result and status @@ -45,6 +64,25 @@ func Sub8p(a, b int8) int8 { return r } +// USub8 performs - operation on two uint8 operands +// returning a result and status +func USub8(a, b uint8) (uint8, bool) { + c := a - b + if a >= b { + return c, true + } + return c, false +} + +// USub8p is the unchecked panicing version of USub8 +func USub8p(a, b uint8) uint8 { + r, ok := USub8(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + // Mul8 performs * operation on two int8 operands // returning a result and status @@ -70,6 +108,27 @@ func Mul8p(a, b int8) int8 { return r } +// UMul8 performs * operation on two uint8 operands +// returning a result and status +func UMul8(a, b uint8) (uint8, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if c/b == a { + return c, true + } + return c, false +} + +// UMul8p is the unchecked panicing version of UMul8 +func UMul8p(a, b uint8) uint8 { + r, ok := UMul8(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} // Div8 performs / operation on two int8 operands @@ -99,6 +158,32 @@ func Quotient8(a, b int8) (int8, int8, bool) { return c, a % b, status } +// UDiv8 performs / operation on two uint8 operands +// returning a result and status +func UDiv8(a, b uint8) (uint8, bool) { + q, _, ok := UQuotient8(a, b) + return q, ok +} + +// UDiv8p is the unchecked panicing version of UDiv8 +func UDiv8p(a, b uint8) uint8 { + r, ok := UDiv8(a, b) + if !ok { + panic("division failure") + } + return r +} + +// UQuotient8 performs + operation on two uint8 operands +// returning a quotient, a remainder and status +func UQuotient8(a, b uint8) (uint8, uint8, bool) { + if b == 0 { + return 0, 0, false + } + c := a / b + return c, a % b, true +} + // Add16 performs + operation on two int16 operands @@ -120,6 +205,25 @@ func Add16p(a, b int16) int16 { return r } +// UAdd16 performs + operation on two uint16 operands +// returning a result and status +func UAdd16(a, b uint16) (uint16, bool) { + c := a + b + if c >= a { + return c, true + } + return c, false +} + +// UAdd16p is the unchecked panicing version of UAdd16 +func UAdd16p(a, b uint16) uint16 { + r, ok := UAdd16(a, b) + if !ok { + panic("addition overflow") + } + return r +} + // Sub16 performs - operation on two int16 operands // returning a result and status @@ -140,6 +244,25 @@ func Sub16p(a, b int16) int16 { return r } +// USub16 performs - operation on two uint16 operands +// returning a result and status +func USub16(a, b uint16) (uint16, bool) { + c := a - b + if a >= b { + return c, true + } + return c, false +} + +// USub16p is the unchecked panicing version of USub16 +func USub16p(a, b uint16) uint16 { + r, ok := USub16(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + // Mul16 performs * operation on two int16 operands // returning a result and status @@ -165,6 +288,27 @@ func Mul16p(a, b int16) int16 { return r } +// UMul16 performs * operation on two uint16 operands +// returning a result and status +func UMul16(a, b uint16) (uint16, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if c/b == a { + return c, true + } + return c, false +} + +// UMul16p is the unchecked panicing version of UMul16 +func UMul16p(a, b uint16) uint16 { + r, ok := UMul16(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} // Div16 performs / operation on two int16 operands @@ -194,6 +338,32 @@ func Quotient16(a, b int16) (int16, int16, bool) { return c, a % b, status } +// UDiv16 performs / operation on two uint16 operands +// returning a result and status +func UDiv16(a, b uint16) (uint16, bool) { + q, _, ok := UQuotient16(a, b) + return q, ok +} + +// UDiv16p is the unchecked panicing version of UDiv16 +func UDiv16p(a, b uint16) uint16 { + r, ok := UDiv16(a, b) + if !ok { + panic("division failure") + } + return r +} + +// UQuotient16 performs + operation on two uint16 operands +// returning a quotient, a remainder and status +func UQuotient16(a, b uint16) (uint16, uint16, bool) { + if b == 0 { + return 0, 0, false + } + c := a / b + return c, a % b, true +} + // Add32 performs + operation on two int32 operands @@ -215,6 +385,25 @@ func Add32p(a, b int32) int32 { return r } +// UAdd32 performs + operation on two uint32 operands +// returning a result and status +func UAdd32(a, b uint32) (uint32, bool) { + c := a + b + if c >= a { + return c, true + } + return c, false +} + +// UAdd32p is the unchecked panicing version of UAdd32 +func UAdd32p(a, b uint32) uint32 { + r, ok := UAdd32(a, b) + if !ok { + panic("addition overflow") + } + return r +} + // Sub32 performs - operation on two int32 operands // returning a result and status @@ -235,6 +424,25 @@ func Sub32p(a, b int32) int32 { return r } +// USub32 performs - operation on two uint32 operands +// returning a result and status +func USub32(a, b uint32) (uint32, bool) { + c := a - b + if a >= b { + return c, true + } + return c, false +} + +// USub32p is the unchecked panicing version of USub32 +func USub32p(a, b uint32) uint32 { + r, ok := USub32(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + // Mul32 performs * operation on two int32 operands // returning a result and status @@ -260,6 +468,27 @@ func Mul32p(a, b int32) int32 { return r } +// UMul32 performs * operation on two uint32 operands +// returning a result and status +func UMul32(a, b uint32) (uint32, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if c/b == a { + return c, true + } + return c, false +} + +// UMul32p is the unchecked panicing version of UMul32 +func UMul32p(a, b uint32) uint32 { + r, ok := UMul32(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} // Div32 performs / operation on two int32 operands @@ -289,6 +518,32 @@ func Quotient32(a, b int32) (int32, int32, bool) { return c, a % b, status } +// UDiv32 performs / operation on two uint32 operands +// returning a result and status +func UDiv32(a, b uint32) (uint32, bool) { + q, _, ok := UQuotient32(a, b) + return q, ok +} + +// UDiv32p is the unchecked panicing version of UDiv32 +func UDiv32p(a, b uint32) uint32 { + r, ok := UDiv32(a, b) + if !ok { + panic("division failure") + } + return r +} + +// UQuotient32 performs + operation on two uint32 operands +// returning a quotient, a remainder and status +func UQuotient32(a, b uint32) (uint32, uint32, bool) { + if b == 0 { + return 0, 0, false + } + c := a / b + return c, a % b, true +} + // Add64 performs + operation on two int64 operands @@ -310,6 +565,25 @@ func Add64p(a, b int64) int64 { return r } +// UAdd64 performs + operation on two uint64 operands +// returning a result and status +func UAdd64(a, b uint64) (uint64, bool) { + c := a + b + if c >= a { + return c, true + } + return c, false +} + +// UAdd64p is the unchecked panicing version of UAdd64 +func UAdd64p(a, b uint64) uint64 { + r, ok := UAdd64(a, b) + if !ok { + panic("addition overflow") + } + return r +} + // Sub64 performs - operation on two int64 operands // returning a result and status @@ -330,6 +604,25 @@ func Sub64p(a, b int64) int64 { return r } +// USub64 performs - operation on two uint64 operands +// returning a result and status +func USub64(a, b uint64) (uint64, bool) { + c := a - b + if a >= b { + return c, true + } + return c, false +} + +// USub64p is the unchecked panicing version of USub64 +func USub64p(a, b uint64) uint64 { + r, ok := USub64(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + // Mul64 performs * operation on two int64 operands // returning a result and status @@ -355,6 +648,27 @@ func Mul64p(a, b int64) int64 { return r } +// UMul64 performs * operation on two uint64 operands +// returning a result and status +func UMul64(a, b uint64) (uint64, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if c/b == a { + return c, true + } + return c, false +} + +// UMul64p is the unchecked panicing version of UMul64 +func UMul64p(a, b uint64) uint64 { + r, ok := UMul64(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} // Div64 performs / operation on two int64 operands @@ -384,3 +698,29 @@ func Quotient64(a, b int64) (int64, int64, bool) { return c, a % b, status } +// UDiv64 performs / operation on two uint64 operands +// returning a result and status +func UDiv64(a, b uint64) (uint64, bool) { + q, _, ok := UQuotient64(a, b) + return q, ok +} + +// UDiv64p is the unchecked panicing version of UDiv64 +func UDiv64p(a, b uint64) uint64 { + r, ok := UDiv64(a, b) + if !ok { + panic("division failure") + } + return r +} + +// UQuotient64 performs + operation on two uint64 operands +// returning a quotient, a remainder and status +func UQuotient64(a, b uint64) (uint64, uint64, bool) { + if b == 0 { + return 0, 0, false + } + c := a / b + return c, a % b, true +} + diff --git a/overflow_template.sh b/overflow_template.sh index b21fb04..ad63c2a 100755 --- a/overflow_template.sh +++ b/overflow_template.sh @@ -33,6 +33,25 @@ func Add${SIZE}p(a, b int${SIZE}) int${SIZE} { return r } +// UAdd${SIZE} performs + operation on two uint${SIZE} operands +// returning a result and status +func UAdd${SIZE}(a, b uint${SIZE}) (uint${SIZE}, bool) { + c := a + b + if c >= a { + return c, true + } + return c, false +} + +// UAdd${SIZE}p is the unchecked panicing version of UAdd${SIZE} +func UAdd${SIZE}p(a, b uint${SIZE}) uint${SIZE} { + r, ok := UAdd${SIZE}(a, b) + if !ok { + panic(\"addition overflow\") + } + return r +} + // Sub${SIZE} performs - operation on two int${SIZE} operands // returning a result and status @@ -53,6 +72,25 @@ func Sub${SIZE}p(a, b int${SIZE}) int${SIZE} { return r } +// USub${SIZE} performs - operation on two uint${SIZE} operands +// returning a result and status +func USub${SIZE}(a, b uint${SIZE}) (uint${SIZE}, bool) { + c := a - b + if a >= b { + return c, true + } + return c, false +} + +// USub${SIZE}p is the unchecked panicing version of USub${SIZE} +func USub${SIZE}p(a, b uint${SIZE}) uint${SIZE} { + r, ok := USub${SIZE}(a, b) + if !ok { + panic(\"subtraction overflow\") + } + return r +} + // Mul${SIZE} performs * operation on two int${SIZE} operands // returning a result and status @@ -78,6 +116,27 @@ func Mul${SIZE}p(a, b int${SIZE}) int${SIZE} { return r } +// UMul${SIZE} performs * operation on two uint${SIZE} operands +// returning a result and status +func UMul${SIZE}(a, b uint${SIZE}) (uint${SIZE}, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if c/b == a { + return c, true + } + return c, false +} + +// UMul${SIZE}p is the unchecked panicing version of UMul${SIZE} +func UMul${SIZE}p(a, b uint${SIZE}) uint${SIZE} { + r, ok := UMul${SIZE}(a, b) + if !ok { + panic(\"multiplication overflow\") + } + return r +} // Div${SIZE} performs / operation on two int${SIZE} operands @@ -106,5 +165,31 @@ func Quotient${SIZE}(a, b int${SIZE}) (int${SIZE}, int${SIZE}, bool) { status := (c < 0) == ((a < 0) != (b < 0)) return c, a % b, status } + +// UDiv${SIZE} performs / operation on two uint${SIZE} operands +// returning a result and status +func UDiv${SIZE}(a, b uint${SIZE}) (uint${SIZE}, bool) { + q, _, ok := UQuotient${SIZE}(a, b) + return q, ok +} + +// UDiv${SIZE}p is the unchecked panicing version of UDiv${SIZE} +func UDiv${SIZE}p(a, b uint${SIZE}) uint${SIZE} { + r, ok := UDiv${SIZE}(a, b) + if !ok { + panic(\"division failure\") + } + return r +} + +// UQuotient${SIZE} performs + operation on two uint${SIZE} operands +// returning a quotient, a remainder and status +func UQuotient${SIZE}(a, b uint${SIZE}) (uint${SIZE}, uint${SIZE}, bool) { + if b == 0 { + return 0, 0, false + } + c := a / b + return c, a % b, true +} " done diff --git a/overflow_test.go b/overflow_test.go index 419191d..f9f15e0 100644 --- a/overflow_test.go +++ b/overflow_test.go @@ -1,15 +1,15 @@ package overflow import ( + "fmt" "math" "testing" ) -import "fmt" // sample all possibilities of 8 bit numbers // by checking against 64 bit numbers -func TestAlgorithms(t *testing.T) { +func TestAlgorithmsInt(t *testing.T) { errors := 0 @@ -95,6 +95,92 @@ func TestAlgorithms(t *testing.T) { } +func TestAlgorithmsUint(t *testing.T) { + + errors := 0 + + for a64 := uint64(0); a64 <= uint64(math.MaxUint8); a64++ { + + for b64 := uint64(0); b64 <= uint64(math.MaxUint8) && errors < 10; b64++ { + + a8 := uint8(a64) + b8 := uint8(b64) + + if uint64(a8) != a64 || uint64(b8) != b64 { + t.Fatal("LOGIC FAILURE IN TEST") + } + + // ADDITION + { + r64 := a64 + b64 + + // now the verification + result, ok := UAdd8(a8, b8) + if ok && uint64(result) != r64 { + t.Errorf("failed to fail on %v + %v = %v instead of %v\n", + a8, b8, result, r64) + errors++ + } + if !ok && uint64(result) == r64 { + t.Fail() + errors++ + } + } + + // SUBTRACTION + { + r64 := a64 - b64 + + // now the verification + result, ok := USub8(a8, b8) + if ok && uint64(result) != r64 { + t.Errorf("failed to fail on %v - %v = %v instead of %v\n", + a8, b8, result, r64) + } + if !ok && uint64(result) == r64 { + t.Fail() + errors++ + } + } + + // MULTIPLICATION + { + r64 := a64 * b64 + + // now the verification + result, ok := UMul8(a8, b8) + if ok && uint64(result) != r64 { + t.Errorf("failed to fail on %v * %v = %v instead of %v\n", + a8, b8, result, r64) + errors++ + } + if !ok && uint64(result) == r64 { + t.Fail() + errors++ + } + } + + // DIVISION + if b8 != 0 { + r64 := a64 / b64 + + // now the verifiggcation + result, _, ok := UQuotient8(a8, b8) + if ok && uint64(result) != r64 { + t.Errorf("failed to fail on %v / %v = %v instead of %v\n", + a8, b8, result, r64) + errors++ + } + if !ok && result != 0 && uint64(result) == r64 { + t.Fail() + errors++ + } + } + } + } + +} + func TestQuotient(t *testing.T) { q, r, ok := Quotient(100, 3) if r != 1 || q != 33 || !ok { @@ -103,6 +189,13 @@ func TestQuotient(t *testing.T) { if _, _, ok = Quotient(1, 0); ok { t.Error("unexpected lack of failure") } + uq, ur, ok := UQuotient(100, 3) + if ur != 1 || uq != 33 || !ok { + t.Errorf("expected 100/3 => 33, r=1") + } + if _, _, ok = UQuotient(1, 0); ok { + t.Error("unexpected lack of failure") + } } //func TestAdditionInt(t *testing.T) { From e5a43412177fe629c1b1b63d381a161daf8537fd Mon Sep 17 00:00:00 2001 From: rwxe Date: Thu, 28 Sep 2023 07:26:49 +0800 Subject: [PATCH 2/7] Add support for (u)int type conversion overflow detection --- README.md | 32 +- overflow.go | 40 +++ overflow_impl.go | 496 +++++++++++++++++++++++++++++++ overflow_template.sh | 90 +++++- overflow_type_conversion_test.go | 392 ++++++++++++++++++++++++ 5 files changed, 1047 insertions(+), 3 deletions(-) create mode 100644 overflow_type_conversion_test.go diff --git a/README.md b/README.md index a228145..fea810f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Build Status](https://travis-ci.org/JohnCGriffin/overflow.png)](https://travis-ci.org/JohnCGriffin/overflow) # overflow -Check for integer overflow in Golang arithmetic. +Check for integer overflow in Golang arithmetic and type conversion. ### Install ``` go get github.com/johncgriffin/overflow @@ -13,6 +13,7 @@ go generate ``` ### Synopsis +#### Arithmetic overflow detection ``` package main @@ -48,6 +49,34 @@ yields the output For (u)int types, provide (U)Add, (U)Sub, (U)Mul, (U)Div, (U)Quotient, etc. + +#### Type conversion overflow detection +``` +func main() { + var i uint + for i = math.MaxInt - 5; i <= math.MaxInt+5; i++ { + ret, ok := overflow.UintToInt(i) + fmt.Printf("%v -> (%v,%v)\n", + i, ret, ok) + } +} +``` +yields the output +``` +9223372036854775802 -> (9223372036854775802,true) +9223372036854775803 -> (9223372036854775803,true) +9223372036854775804 -> (9223372036854775804,true) +9223372036854775805 -> (9223372036854775805,true) +9223372036854775806 -> (9223372036854775806,true) +9223372036854775807 -> (9223372036854775807,true) +9223372036854775808 -> (-9223372036854775808,false) +9223372036854775809 -> (-9223372036854775807,false) +9223372036854775810 -> (-9223372036854775806,false) +9223372036854775811 -> (-9223372036854775805,false) +9223372036854775812 -> (-9223372036854775804,false) +``` +Provide UintToInt, IntToUint, Uint64ToInt32, Int32ToUint64, etc. + ### Stay calm and panic There's a good case to be made that a panic is an unidiomatic but proper response. Iff you @@ -80,4 +109,3 @@ SOFTWARE. - diff --git a/overflow.go b/overflow.go index fa41aa9..3ec0caa 100644 --- a/overflow.go +++ b/overflow.go @@ -142,6 +142,28 @@ func UQuotient(a, b uint) (uint, uint, bool) { return uint(uq32), uint(ur32), ok } +// IntToUint converts an int value to uint. +// returning a converted value and a bool value indicating whether the operation is safe. +func IntToUint(x int) (uint, bool) { + if _is64Bit() { + y64, ok := Int64ToUint64(int64(x)) + return uint(y64), ok + } + y32, ok := Int32ToUint32(int32(x)) + return uint(y32), ok +} + +// UintToInt converts an uint value to int. +// returning a converted value and a bool value indicating whether the operation is safe. +func UintToInt(x uint) (int, bool) { + if _is64Bit() { + y64, ok := Uint64ToInt64(uint64(x)) + return int(y64), ok + } + y32, ok := Uint32ToInt32(uint32(x)) + return int(y32), ok +} + /************* Panic versions for int ****************/ // Addp returns the sum of two ints, panicking on overflow @@ -215,3 +237,21 @@ func UDivp(a, b uint) uint { } return r } + +// IntToUintp converts an uint value to int, panicking on overflow. +func IntToUintp(x int) uint { + r, ok := IntToUint(x) + if !ok { + panic("conversion failure") + } + return r +} + +// UintToIntp converts an uint value to int, panicking on overflow. +func UintToIntp(x uint) int { + r, ok := UintToInt(x) + if !ok { + panic("conversion failure") + } + return r +} diff --git a/overflow_impl.go b/overflow_impl.go index c96e8af..c26de96 100644 --- a/overflow_impl.go +++ b/overflow_impl.go @@ -1,5 +1,7 @@ package overflow +import "math" + // This is generated code, created by overflow_template.sh executed // by "go generate" @@ -724,3 +726,497 @@ func UQuotient64(a, b uint64) (uint64, uint64, bool) { return c, a % b, true } + + +// Int64ToInt32 converts an int64 value to int32. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int64ToInt32(x int64) (int32, bool) { + y := int32(x) + if math.MinInt32 <= x && x <= math.MaxInt32 { + return y, true + } + return y, false +} + + + + +// Int64ToInt16 converts an int64 value to int16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int64ToInt16(x int64) (int16, bool) { + y := int16(x) + if math.MinInt16 <= x && x <= math.MaxInt16 { + return y, true + } + return y, false +} + + + + +// Int64ToInt8 converts an int64 value to int8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int64ToInt8(x int64) (int8, bool) { + y := int8(x) + if math.MinInt8 <= x && x <= math.MaxInt8 { + return y, true + } + return y, false +} + + + + +// Int32ToInt16 converts an int32 value to int16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int32ToInt16(x int32) (int16, bool) { + y := int16(x) + if math.MinInt16 <= x && x <= math.MaxInt16 { + return y, true + } + return y, false +} + + + + +// Int32ToInt8 converts an int32 value to int8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int32ToInt8(x int32) (int8, bool) { + y := int8(x) + if math.MinInt8 <= x && x <= math.MaxInt8 { + return y, true + } + return y, false +} + + + + +// Int16ToInt8 converts an int16 value to int8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int16ToInt8(x int16) (int8, bool) { + y := int8(x) + if math.MinInt8 <= x && x <= math.MaxInt8 { + return y, true + } + return y, false +} + + + + +// Uint64ToUint32 converts an uint64 value to uint32. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint64ToUint32(x uint64) (uint32, bool) { + y := uint32(x) + if x <= math.MaxUint32 { + return y, true + } + return y, false +} + + + + +// Uint64ToUint16 converts an uint64 value to uint16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint64ToUint16(x uint64) (uint16, bool) { + y := uint16(x) + if x <= math.MaxUint16 { + return y, true + } + return y, false +} + + + + +// Uint64ToUint8 converts an uint64 value to uint8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint64ToUint8(x uint64) (uint8, bool) { + y := uint8(x) + if x <= math.MaxUint8 { + return y, true + } + return y, false +} + + + + +// Uint32ToUint16 converts an uint32 value to uint16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint32ToUint16(x uint32) (uint16, bool) { + y := uint16(x) + if x <= math.MaxUint16 { + return y, true + } + return y, false +} + + + + +// Uint32ToUint8 converts an uint32 value to uint8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint32ToUint8(x uint32) (uint8, bool) { + y := uint8(x) + if x <= math.MaxUint8 { + return y, true + } + return y, false +} + + + + +// Uint16ToUint8 converts an uint16 value to uint8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint16ToUint8(x uint16) (uint8, bool) { + y := uint8(x) + if x <= math.MaxUint8 { + return y, true + } + return y, false +} + + + + +// Uint64ToInt64 converts an uint64 value to int64. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint64ToInt64(x uint64) (int64, bool) { + y := int64(x) + if x <= math.MaxInt64 { + return y, true + } + return y, false +} + + + + +// Uint64ToInt32 converts an uint64 value to int32. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint64ToInt32(x uint64) (int32, bool) { + y := int32(x) + if x <= math.MaxInt32 { + return y, true + } + return y, false +} + + + + +// Uint64ToInt16 converts an uint64 value to int16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint64ToInt16(x uint64) (int16, bool) { + y := int16(x) + if x <= math.MaxInt16 { + return y, true + } + return y, false +} + + + + +// Uint64ToInt8 converts an uint64 value to int8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint64ToInt8(x uint64) (int8, bool) { + y := int8(x) + if x <= math.MaxInt8 { + return y, true + } + return y, false +} + + + + +// Uint32ToInt32 converts an uint32 value to int32. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint32ToInt32(x uint32) (int32, bool) { + y := int32(x) + if x <= math.MaxInt32 { + return y, true + } + return y, false +} + + + + +// Uint32ToInt16 converts an uint32 value to int16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint32ToInt16(x uint32) (int16, bool) { + y := int16(x) + if x <= math.MaxInt16 { + return y, true + } + return y, false +} + + + + +// Uint32ToInt8 converts an uint32 value to int8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint32ToInt8(x uint32) (int8, bool) { + y := int8(x) + if x <= math.MaxInt8 { + return y, true + } + return y, false +} + + + + +// Uint16ToInt16 converts an uint16 value to int16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint16ToInt16(x uint16) (int16, bool) { + y := int16(x) + if x <= math.MaxInt16 { + return y, true + } + return y, false +} + + + + +// Uint16ToInt8 converts an uint16 value to int8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint16ToInt8(x uint16) (int8, bool) { + y := int8(x) + if x <= math.MaxInt8 { + return y, true + } + return y, false +} + + + + +// Uint8ToInt8 converts an uint8 value to int8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint8ToInt8(x uint8) (int8, bool) { + y := int8(x) + if x <= math.MaxInt8 { + return y, true + } + return y, false +} + + + + +// Int64ToUint64 converts an int64 value to uint64. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int64ToUint64(x int64) (uint64, bool) { + y := uint64(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int64ToUint32 converts an int64 value to uint32. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int64ToUint32(x int64) (uint32, bool) { + y := uint32(x) + if 0 <= x && x <= math.MaxUint32 { + return y, true + } + return y, false +} + + + + +// Int64ToUint16 converts an int64 value to uint16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int64ToUint16(x int64) (uint16, bool) { + y := uint16(x) + if 0 <= x && x <= math.MaxUint16 { + return y, true + } + return y, false +} + + + + +// Int64ToUint8 converts an int64 value to uint8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int64ToUint8(x int64) (uint8, bool) { + y := uint8(x) + if 0 <= x && x <= math.MaxUint8 { + return y, true + } + return y, false +} + + + + +// Int32ToUint64 converts an int32 value to uint64. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int32ToUint64(x int32) (uint64, bool) { + y := uint64(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int32ToUint32 converts an int32 value to uint32. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int32ToUint32(x int32) (uint32, bool) { + y := uint32(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int32ToUint16 converts an int32 value to uint16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int32ToUint16(x int32) (uint16, bool) { + y := uint16(x) + if 0 <= x && x <= math.MaxUint16 { + return y, true + } + return y, false +} + + + + +// Int32ToUint8 converts an int32 value to uint8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int32ToUint8(x int32) (uint8, bool) { + y := uint8(x) + if 0 <= x && x <= math.MaxUint8 { + return y, true + } + return y, false +} + + + + +// Int16ToUint64 converts an int16 value to uint64. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int16ToUint64(x int16) (uint64, bool) { + y := uint64(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int16ToUint32 converts an int16 value to uint32. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int16ToUint32(x int16) (uint32, bool) { + y := uint32(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int16ToUint16 converts an int16 value to uint16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int16ToUint16(x int16) (uint16, bool) { + y := uint16(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int16ToUint8 converts an int16 value to uint8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int16ToUint8(x int16) (uint8, bool) { + y := uint8(x) + if 0 <= x && x <= math.MaxUint8 { + return y, true + } + return y, false +} + + + + +// Int8ToUint64 converts an int8 value to uint64. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int8ToUint64(x int8) (uint64, bool) { + y := uint64(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int8ToUint32 converts an int8 value to uint32. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int8ToUint32(x int8) (uint32, bool) { + y := uint32(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int8ToUint16 converts an int8 value to uint16. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int8ToUint16(x int8) (uint16, bool) { + y := uint16(x) + if 0 <= x { + return y, true + } + return y, false +} + + + + +// Int8ToUint8 converts an int8 value to uint8. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int8ToUint8(x int8) (uint8, bool) { + y := uint8(x) + if 0 <= x { + return y, true + } + return y, false +} + + diff --git a/overflow_template.sh b/overflow_template.sh index ad63c2a..b2ad7ec 100755 --- a/overflow_template.sh +++ b/overflow_template.sh @@ -1,9 +1,11 @@ -#!/bin/sh +#!/bin/bash exec > overflow_impl.go echo "package overflow +import \"math\" + // This is generated code, created by overflow_template.sh executed // by \"go generate\" @@ -193,3 +195,89 @@ func UQuotient${SIZE}(a, b uint${SIZE}) (uint${SIZE}, uint${SIZE}, bool) { } " done + +SIZE=(64 32 16 8) + +# Int -> Int +for FROM in {0..3}; do +for TO in $(seq $((FROM + 1)) 3); do +echo " + +// Int${SIZE[FROM]}ToInt${SIZE[TO]} converts an int${SIZE[FROM]} value to int${SIZE[TO]}. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int${SIZE[FROM]}ToInt${SIZE[TO]}(x int${SIZE[FROM]}) (int${SIZE[TO]}, bool) { + y := int${SIZE[TO]}(x) + if math.MinInt${SIZE[TO]} <= x && x <= math.MaxInt${SIZE[TO]} { + return y, true + } + return y, false +} + +" +done +done + +# Uint -> Uint +for FROM in {0..3}; do +for TO in $(seq $((FROM + 1)) 3); do +echo " + +// Uint${SIZE[FROM]}ToUint${SIZE[TO]} converts an uint${SIZE[FROM]} value to uint${SIZE[TO]}. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint${SIZE[FROM]}ToUint${SIZE[TO]}(x uint${SIZE[FROM]}) (uint${SIZE[TO]}, bool) { + y := uint${SIZE[TO]}(x) + if x <= math.MaxUint${SIZE[TO]} { + return y, true + } + return y, false +} + +" +done +done + +# Uint -> Int +for FROM in {0..3}; do +for TO in $(seq $((FROM)) 3); do +echo " + +// Uint${SIZE[FROM]}ToInt${SIZE[TO]} converts an uint${SIZE[FROM]} value to int${SIZE[TO]}. +// returning a converted value and a bool value indicating whether the operation is safe. +func Uint${SIZE[FROM]}ToInt${SIZE[TO]}(x uint${SIZE[FROM]}) (int${SIZE[TO]}, bool) { + y := int${SIZE[TO]}(x) + if x <= math.MaxInt${SIZE[TO]} { + return y, true + } + return y, false +} + +" +done +done + + +# Int -> Uint +for FROM in {0..3}; do +for TO in {0..3}; do +echo " + +// Int${SIZE[FROM]}ToUint${SIZE[TO]} converts an int${SIZE[FROM]} value to uint${SIZE[TO]}. +// returning a converted value and a bool value indicating whether the operation is safe. +func Int${SIZE[FROM]}ToUint${SIZE[TO]}(x int${SIZE[FROM]}) (uint${SIZE[TO]}, bool) { + y := uint${SIZE[TO]}(x)" + if [ "$((SIZE[FROM]))" -gt "$((SIZE[TO]))" ]; then + echo "\ + if 0 <= x && x <= math.MaxUint${SIZE[TO]} {" + else + echo "\ + if 0 <= x {" + fi +echo "\ + return y, true + } + return y, false +} + +" +done +done diff --git a/overflow_type_conversion_test.go b/overflow_type_conversion_test.go new file mode 100644 index 0000000..d6f9bf1 --- /dev/null +++ b/overflow_type_conversion_test.go @@ -0,0 +1,392 @@ +package overflow + +import ( + "testing" +) + +/* + +NOTE: +For the convenience of editing, please turn off automatic formatting when modifying this file +Please ignore any meaningless comments, which are residual comments generated automatically and are not easy to clear. + +NOTE: +The following test cases are generated by the following bash script, +and all compiler error lines are deleted, and then the expected OK lines are manually commented. + +```bash +sizes=(64 32 16 8) +signs=("Int" "Uint") +for from_sign in "${signs[@]}"; do +for from_size in "${sizes[@]}"; do +for to_sign in "${signs[@]}"; do +for to_size in "${sizes[@]}"; do +code=" +// ${from_sign}${from_size} -> ${to_sign}${to_size} +if r,ok:=${from_sign}${from_size}To${to_sign}${to_size}(Max${from_sign}${from_size});ok{t.Error(UNEXPECTED_OK,r)} +if r,ok:=${from_sign}${from_size}To${to_sign}${to_size}(Min${from_sign}${from_size});ok{t.Error(UNEXPECTED_OK,r)} +if r,ok:=${from_sign}${from_size}To${to_sign}${to_size}(Max${to_sign}${to_size}+1);ok{t.Error(UNEXPECTED_OK,r)} +if r,ok:=${from_sign}${from_size}To${to_sign}${to_size}(Min${to_sign}${to_size}-1);ok{t.Error(UNEXPECTED_OK,r)} +" +echo "$code" +done +done +done +done +``` +*/ + +// Integer limit values. +const ( + intSize = 32 << (^uint(0) >> 63) // 32 or 64 + + MaxInt = 1<<(intSize-1) - 1 // MaxInt32 or MaxInt64 depending on intSize. + MinInt = -1 << (intSize - 1) // MinInt32 or MinInt64 depending on intSize. + MaxInt8 = 1<<7 - 1 // 127 + MinInt8 = -1 << 7 // -128 + MaxInt16 = 1<<15 - 1 // 32767 + MinInt16 = -1 << 15 // -32768 + MaxInt32 = 1<<31 - 1 // 2147483647 + MinInt32 = -1 << 31 // -2147483648 + MaxInt64 = 1<<63 - 1 // 9223372036854775807 + MinInt64 = -1 << 63 // -9223372036854775808 + MaxUint = 1< Int64 + + + // Int64 -> Int32 + if r,ok:=Int64ToInt32(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt32(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt32(MaxInt32+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt32(MinInt32-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int64 -> Int16 + if r,ok:=Int64ToInt16(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt16(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt16(MinInt16-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int64 -> Int8 + if r,ok:=Int64ToInt8(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt8(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt8(MinInt8-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int64 -> Uint64 + //if r,ok:=Int64ToUint64(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint64(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint64(MinUint64-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int64 -> Uint32 + if r,ok:=Int64ToUint32(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint32(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint32(MaxUint32+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint32(MinUint32-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int64 -> Uint16 + if r,ok:=Int64ToUint16(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint16(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint16(MaxUint16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint16(MinUint16-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int64 -> Uint8 + if r,ok:=Int64ToUint8(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint8(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint8(MinUint8-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int32 -> Int64 + + + // Int32 -> Int32 + + + // Int32 -> Int16 + if r,ok:=Int32ToInt16(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToInt16(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToInt16(MinInt16-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int32 -> Int8 + if r,ok:=Int32ToInt8(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToInt8(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToInt8(MinInt8-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int32 -> Uint64 + //if r,ok:=Int32ToUint64(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint64(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint64(MinUint64-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int32 -> Uint32 + //if r,ok:=Int32ToUint32(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint32(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint32(MinUint32-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int32 -> Uint16 + if r,ok:=Int32ToUint16(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint16(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint16(MaxUint16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint16(MinUint16-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int32 -> Uint8 + if r,ok:=Int32ToUint8(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint8(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint8(MinUint8-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int16 -> Int64 + + + // Int16 -> Int32 + + + // Int16 -> Int16 + + + // Int16 -> Int8 + if r,ok:=Int16ToInt8(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToInt8(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToInt8(MinInt8-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int16 -> Uint64 + //if r,ok:=Int16ToUint64(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint64(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint64(MinUint64-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int16 -> Uint32 + //if r,ok:=Int16ToUint32(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint32(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint32(MinUint32-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int16 -> Uint16 + //if r,ok:=Int16ToUint16(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint16(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint16(MinUint16-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int16 -> Uint8 + if r,ok:=Int16ToUint8(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint8(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint8(MinUint8-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int8 -> Int64 + + + // Int8 -> Int32 + + + // Int8 -> Int16 + + + // Int8 -> Int8 + + + // Int8 -> Uint64 + //if r,ok:=Int8ToUint64(MaxInt8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint64(MinInt8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint64(MinUint64-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int8 -> Uint32 + //if r,ok:=Int8ToUint32(MaxInt8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint32(MinInt8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint32(MinUint32-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int8 -> Uint16 + //if r,ok:=Int8ToUint16(MaxInt8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint16(MinInt8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint16(MinUint16-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Int8 -> Uint8 + //if r,ok:=Int8ToUint8(MaxInt8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint8(MinInt8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint8(MinUint8-1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint64 -> Int64 + if r,ok:=Uint64ToInt64(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint64ToInt64(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt64(MaxInt64+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint64 -> Int32 + if r,ok:=Uint64ToInt32(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint64ToInt32(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt32(MaxInt32+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint64 -> Int16 + if r,ok:=Uint64ToInt16(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint64ToInt16(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint64 -> Int8 + if r,ok:=Uint64ToInt8(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint64ToInt8(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint64 -> Uint64 + + + // Uint64 -> Uint32 + if r,ok:=Uint64ToUint32(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint64ToUint32(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint32(MaxUint32+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint64 -> Uint16 + if r,ok:=Uint64ToUint16(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint64ToUint16(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint16(MaxUint16+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint64 -> Uint8 + if r,ok:=Uint64ToUint8(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint64ToUint8(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint32 -> Int64 + + + // Uint32 -> Int32 + if r,ok:=Uint32ToInt32(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint32ToInt32(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt32(MaxInt32+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint32 -> Int16 + if r,ok:=Uint32ToInt16(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint32ToInt16(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint32 -> Int8 + if r,ok:=Uint32ToInt8(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint32ToInt8(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint32 -> Uint64 + + + // Uint32 -> Uint32 + + + // Uint32 -> Uint16 + if r,ok:=Uint32ToUint16(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint32ToUint16(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToUint16(MaxUint16+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint32 -> Uint8 + if r,ok:=Uint32ToUint8(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint32ToUint8(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint16 -> Int64 + + + // Uint16 -> Int32 + + + // Uint16 -> Int16 + if r,ok:=Uint16ToInt16(MaxUint16);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint16ToInt16(MinUint16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint16 -> Int8 + if r,ok:=Uint16ToInt8(MaxUint16);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint16ToInt8(MinUint16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint16 -> Uint64 + + + // Uint16 -> Uint32 + + + // Uint16 -> Uint16 + + + // Uint16 -> Uint8 + if r,ok:=Uint16ToUint8(MaxUint16);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint16ToUint8(MinUint16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint8 -> Int64 + + + // Uint8 -> Int32 + + + // Uint8 -> Int16 + + + // Uint8 -> Int8 + if r,ok:=Uint8ToInt8(MaxUint8);ok{t.Error(UNEXPECTED_OK,r)} + //if r,ok:=Uint8ToInt8(MinUint8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint8ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + + + // Uint8 -> Uint64 + + + // Uint8 -> Uint32 + + + // Uint8 -> Uint16 + + + // Uint8 -> Uint8 + +} From 06d7f9728145032168b18404ec4b499c73d9c5f9 Mon Sep 17 00:00:00 2001 From: rwxe Date: Thu, 28 Sep 2023 09:00:10 +0800 Subject: [PATCH 3/7] Add readme about new features, improve comments, and add an corner test case --- README.md | 33 +++++++-- overflow.go | 20 +++--- overflow_impl.go | 156 +++++++++++++++++++++---------------------- overflow_template.sh | 28 ++++---- overflow_test.go | 3 + 5 files changed, 132 insertions(+), 108 deletions(-) diff --git a/README.md b/README.md index fea810f..68f9eda 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,19 @@ # overflow Check for integer overflow in Golang arithmetic and type conversion. ### Install -``` +```sh go get github.com/johncgriffin/overflow ``` Note that because Go has no template types, the majority of repetitive code is generated by overflow_template.sh. If you have to change an algorithm, change it there and regenerate the Go code via: -``` +```sh go generate ``` ### Synopsis #### Arithmetic overflow detection -``` +```go package main import "fmt" @@ -34,7 +34,7 @@ func main() { } ``` yields the output -``` +```go 9223372036854775802+0 -> (9223372036854775802,true) 9223372036854775802+1 -> (9223372036854775803,true) 9223372036854775802+2 -> (9223372036854775804,true) @@ -51,7 +51,7 @@ For (u)int types, provide (U)Add, (U)Sub, (U)Mul, (U)Div, (U)Quotient, etc. #### Type conversion overflow detection -``` +```go func main() { var i uint for i = math.MaxInt - 5; i <= math.MaxInt+5; i++ { @@ -62,7 +62,7 @@ func main() { } ``` yields the output -``` +```go 9223372036854775802 -> (9223372036854775802,true) 9223372036854775803 -> (9223372036854775803,true) 9223372036854775804 -> (9223372036854775804,true) @@ -83,6 +83,27 @@ There's a good case to be made that a panic is an unidiomatic but proper respons believe that there's no valid way to continue your program after math goes wayward, you can use the easier Addp, Mulp, Subp, and Divp versions which return the normal result or panic. +### Performance considerations + +Compared with the integer type safety libraries of other languages (such as C++), this +library uses some seemingly slow operations, such as division. But this does not mean that +these methods will be slow, on the contrary, it will be faster than complex implementations +in other languages. The reason is that Go does not allow forced inlining, and any complex +functions will be abandoned for inlining, resulting in additional calling overhead. Short +functions are lightning fast due to automatic inlining. For example, for unsigned 64-bit +integer multiplication overflow detection, when inlining is disabled, division takes five +times as long as long multiplication, but after automatic inlining is allowed, division +takes 1/5 of long multiplication. + +Note that using `//go:noinline` in your business function will not affect the inlining of +the library function. Only disabling global inlining through `-gcflags="-l"` will affect the +inlining of this library function. + +### Basis and dependencies + +This library is based on Go's official compiler implementation and language specification, +which defines the behavior when integer overflow occurs. + - - - MIT License diff --git a/overflow.go b/overflow.go index 3ec0caa..e9b8e0c 100644 --- a/overflow.go +++ b/overflow.go @@ -42,7 +42,7 @@ So, FEEL FREE to carefully review the code visually. // Unspecified size, i.e. normal signed int -// Add sums two ints, returning the result and a boolean status. +// Add sums two ints, returning the result and a ok result indicating whether the operation is safe. func Add(a, b int) (int, bool) { if _is64Bit() { r64, ok := Add64(int64(a), int64(b)) @@ -52,7 +52,7 @@ func Add(a, b int) (int, bool) { return int(r32), ok } -// UAdd sums two uints, returning the result and a boolean status. +// UAdd sums two uints, returning the result and a ok result indicating whether the operation is safe. func UAdd(a, b uint) (uint, bool) { if _is64Bit() { r64, ok := UAdd64(uint64(a), uint64(b)) @@ -62,7 +62,7 @@ func UAdd(a, b uint) (uint, bool) { return uint(r32), ok } -// Sub returns the difference of two ints and a boolean status. +// Sub returns the difference of two ints and a ok result indicating whether the operation is safe. func Sub(a, b int) (int, bool) { if _is64Bit() { r64, ok := Sub64(int64(a), int64(b)) @@ -72,7 +72,7 @@ func Sub(a, b int) (int, bool) { return int(r32), ok } -// USub returns the difference of two uints and a boolean status. +// USub returns the difference of two uints and a ok result indicating whether the operation is safe. func USub(a, b uint) (uint, bool) { if _is64Bit() { r64, ok := USub64(uint64(a), uint64(b)) @@ -82,7 +82,7 @@ func USub(a, b uint) (uint, bool) { return uint(r32), ok } -// Mul returns the product of two ints and a boolean status. +// Mul returns the product of two ints and a ok result indicating whether the operation is safe. func Mul(a, b int) (int, bool) { if _is64Bit() { r64, ok := Mul64(int64(a), int64(b)) @@ -92,7 +92,7 @@ func Mul(a, b int) (int, bool) { return int(r32), ok } -// UMul returns the product of two uints and a boolean status. +// UMul returns the product of two uints and a ok result indicating whether the operation is safe. func UMul(a, b uint) (uint, bool) { if _is64Bit() { r64, ok := UMul64(uint64(a), uint64(b)) @@ -102,7 +102,7 @@ func UMul(a, b uint) (uint, bool) { return uint(r32), ok } -// Div returns the quotient of two ints and a boolean status +// Div returns the quotient of two ints and a ok result indicating whether the operation is safe. func Div(a, b int) (int, bool) { if _is64Bit() { r64, ok := Div64(int64(a), int64(b)) @@ -112,7 +112,7 @@ func Div(a, b int) (int, bool) { return int(r32), ok } -// UDiv returns the quotient of two uints and a boolean status +// UDiv returns the quotient of two uints and a ok result indicating whether the operation is safe. func UDiv(a, b uint) (uint, bool) { if _is64Bit() { r64, ok := UDiv64(uint64(a), uint64(b)) @@ -122,7 +122,7 @@ func UDiv(a, b uint) (uint, bool) { return uint(r32), ok } -// Quotient returns the quotient, remainder and status of two ints +// Quotient returns the quotient, remainder and ok result indicating whether the operation is safe. func Quotient(a, b int) (int, int, bool) { if _is64Bit() { q64, r64, ok := Quotient64(int64(a), int64(b)) @@ -132,7 +132,7 @@ func Quotient(a, b int) (int, int, bool) { return int(q32), int(r32), ok } -// UQuotient returns the quotient, remainder and status of two uints +// UQuotient returns the quotient, remainder and ok result indicating whether the operation is safe. func UQuotient(a, b uint) (uint, uint, bool) { if _is64Bit() { uq64, ur64, ok := UQuotient64(uint64(a), uint64(b)) diff --git a/overflow_impl.go b/overflow_impl.go index c26de96..1362f27 100644 --- a/overflow_impl.go +++ b/overflow_impl.go @@ -9,7 +9,7 @@ import "math" // Add8 performs + operation on two int8 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Add8(a, b int8) (int8, bool) { c := a + b if (c > a) == (b > 0) { @@ -28,7 +28,7 @@ func Add8p(a, b int8) int8 { } // UAdd8 performs + operation on two uint8 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UAdd8(a, b uint8) (uint8, bool) { c := a + b if c >= a { @@ -48,7 +48,7 @@ func UAdd8p(a, b uint8) uint8 { // Sub8 performs - operation on two int8 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Sub8(a, b int8) (int8, bool) { c := a - b if (c < a) == (b > 0) { @@ -67,7 +67,7 @@ func Sub8p(a, b int8) int8 { } // USub8 performs - operation on two uint8 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func USub8(a, b uint8) (uint8, bool) { c := a - b if a >= b { @@ -87,7 +87,7 @@ func USub8p(a, b uint8) uint8 { // Mul8 performs * operation on two int8 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Mul8(a, b int8) (int8, bool) { if a == 0 || b == 0 { return 0, true @@ -111,7 +111,7 @@ func Mul8p(a, b int8) int8 { } // UMul8 performs * operation on two uint8 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UMul8(a, b uint8) (uint8, bool) { if a == 0 || b == 0 { return 0, true @@ -134,7 +134,7 @@ func UMul8p(a, b uint8) uint8 { // Div8 performs / operation on two int8 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Div8(a, b int8) (int8, bool) { q, _, ok := Quotient8(a, b) return q, ok @@ -150,7 +150,7 @@ func Div8p(a, b int8) int8 { } // Quotient8 performs + operation on two int8 operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func Quotient8(a, b int8) (int8, int8, bool) { if b == 0 { return 0, 0, false @@ -161,7 +161,7 @@ func Quotient8(a, b int8) (int8, int8, bool) { } // UDiv8 performs / operation on two uint8 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UDiv8(a, b uint8) (uint8, bool) { q, _, ok := UQuotient8(a, b) return q, ok @@ -177,7 +177,7 @@ func UDiv8p(a, b uint8) uint8 { } // UQuotient8 performs + operation on two uint8 operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func UQuotient8(a, b uint8) (uint8, uint8, bool) { if b == 0 { return 0, 0, false @@ -189,7 +189,7 @@ func UQuotient8(a, b uint8) (uint8, uint8, bool) { // Add16 performs + operation on two int16 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Add16(a, b int16) (int16, bool) { c := a + b if (c > a) == (b > 0) { @@ -208,7 +208,7 @@ func Add16p(a, b int16) int16 { } // UAdd16 performs + operation on two uint16 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UAdd16(a, b uint16) (uint16, bool) { c := a + b if c >= a { @@ -228,7 +228,7 @@ func UAdd16p(a, b uint16) uint16 { // Sub16 performs - operation on two int16 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Sub16(a, b int16) (int16, bool) { c := a - b if (c < a) == (b > 0) { @@ -247,7 +247,7 @@ func Sub16p(a, b int16) int16 { } // USub16 performs - operation on two uint16 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func USub16(a, b uint16) (uint16, bool) { c := a - b if a >= b { @@ -267,7 +267,7 @@ func USub16p(a, b uint16) uint16 { // Mul16 performs * operation on two int16 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Mul16(a, b int16) (int16, bool) { if a == 0 || b == 0 { return 0, true @@ -291,7 +291,7 @@ func Mul16p(a, b int16) int16 { } // UMul16 performs * operation on two uint16 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UMul16(a, b uint16) (uint16, bool) { if a == 0 || b == 0 { return 0, true @@ -314,7 +314,7 @@ func UMul16p(a, b uint16) uint16 { // Div16 performs / operation on two int16 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Div16(a, b int16) (int16, bool) { q, _, ok := Quotient16(a, b) return q, ok @@ -330,7 +330,7 @@ func Div16p(a, b int16) int16 { } // Quotient16 performs + operation on two int16 operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func Quotient16(a, b int16) (int16, int16, bool) { if b == 0 { return 0, 0, false @@ -341,7 +341,7 @@ func Quotient16(a, b int16) (int16, int16, bool) { } // UDiv16 performs / operation on two uint16 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UDiv16(a, b uint16) (uint16, bool) { q, _, ok := UQuotient16(a, b) return q, ok @@ -357,7 +357,7 @@ func UDiv16p(a, b uint16) uint16 { } // UQuotient16 performs + operation on two uint16 operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func UQuotient16(a, b uint16) (uint16, uint16, bool) { if b == 0 { return 0, 0, false @@ -369,7 +369,7 @@ func UQuotient16(a, b uint16) (uint16, uint16, bool) { // Add32 performs + operation on two int32 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Add32(a, b int32) (int32, bool) { c := a + b if (c > a) == (b > 0) { @@ -388,7 +388,7 @@ func Add32p(a, b int32) int32 { } // UAdd32 performs + operation on two uint32 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UAdd32(a, b uint32) (uint32, bool) { c := a + b if c >= a { @@ -408,7 +408,7 @@ func UAdd32p(a, b uint32) uint32 { // Sub32 performs - operation on two int32 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Sub32(a, b int32) (int32, bool) { c := a - b if (c < a) == (b > 0) { @@ -427,7 +427,7 @@ func Sub32p(a, b int32) int32 { } // USub32 performs - operation on two uint32 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func USub32(a, b uint32) (uint32, bool) { c := a - b if a >= b { @@ -447,7 +447,7 @@ func USub32p(a, b uint32) uint32 { // Mul32 performs * operation on two int32 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Mul32(a, b int32) (int32, bool) { if a == 0 || b == 0 { return 0, true @@ -471,7 +471,7 @@ func Mul32p(a, b int32) int32 { } // UMul32 performs * operation on two uint32 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UMul32(a, b uint32) (uint32, bool) { if a == 0 || b == 0 { return 0, true @@ -494,7 +494,7 @@ func UMul32p(a, b uint32) uint32 { // Div32 performs / operation on two int32 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Div32(a, b int32) (int32, bool) { q, _, ok := Quotient32(a, b) return q, ok @@ -510,7 +510,7 @@ func Div32p(a, b int32) int32 { } // Quotient32 performs + operation on two int32 operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func Quotient32(a, b int32) (int32, int32, bool) { if b == 0 { return 0, 0, false @@ -521,7 +521,7 @@ func Quotient32(a, b int32) (int32, int32, bool) { } // UDiv32 performs / operation on two uint32 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UDiv32(a, b uint32) (uint32, bool) { q, _, ok := UQuotient32(a, b) return q, ok @@ -537,7 +537,7 @@ func UDiv32p(a, b uint32) uint32 { } // UQuotient32 performs + operation on two uint32 operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func UQuotient32(a, b uint32) (uint32, uint32, bool) { if b == 0 { return 0, 0, false @@ -549,7 +549,7 @@ func UQuotient32(a, b uint32) (uint32, uint32, bool) { // Add64 performs + operation on two int64 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Add64(a, b int64) (int64, bool) { c := a + b if (c > a) == (b > 0) { @@ -568,7 +568,7 @@ func Add64p(a, b int64) int64 { } // UAdd64 performs + operation on two uint64 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UAdd64(a, b uint64) (uint64, bool) { c := a + b if c >= a { @@ -588,7 +588,7 @@ func UAdd64p(a, b uint64) uint64 { // Sub64 performs - operation on two int64 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Sub64(a, b int64) (int64, bool) { c := a - b if (c < a) == (b > 0) { @@ -607,7 +607,7 @@ func Sub64p(a, b int64) int64 { } // USub64 performs - operation on two uint64 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func USub64(a, b uint64) (uint64, bool) { c := a - b if a >= b { @@ -627,7 +627,7 @@ func USub64p(a, b uint64) uint64 { // Mul64 performs * operation on two int64 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Mul64(a, b int64) (int64, bool) { if a == 0 || b == 0 { return 0, true @@ -651,7 +651,7 @@ func Mul64p(a, b int64) int64 { } // UMul64 performs * operation on two uint64 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UMul64(a, b uint64) (uint64, bool) { if a == 0 || b == 0 { return 0, true @@ -674,7 +674,7 @@ func UMul64p(a, b uint64) uint64 { // Div64 performs / operation on two int64 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Div64(a, b int64) (int64, bool) { q, _, ok := Quotient64(a, b) return q, ok @@ -690,7 +690,7 @@ func Div64p(a, b int64) int64 { } // Quotient64 performs + operation on two int64 operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func Quotient64(a, b int64) (int64, int64, bool) { if b == 0 { return 0, 0, false @@ -701,7 +701,7 @@ func Quotient64(a, b int64) (int64, int64, bool) { } // UDiv64 performs / operation on two uint64 operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UDiv64(a, b uint64) (uint64, bool) { q, _, ok := UQuotient64(a, b) return q, ok @@ -717,7 +717,7 @@ func UDiv64p(a, b uint64) uint64 { } // UQuotient64 performs + operation on two uint64 operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func UQuotient64(a, b uint64) (uint64, uint64, bool) { if b == 0 { return 0, 0, false @@ -729,7 +729,7 @@ func UQuotient64(a, b uint64) (uint64, uint64, bool) { // Int64ToInt32 converts an int64 value to int32. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int64ToInt32(x int64) (int32, bool) { y := int32(x) if math.MinInt32 <= x && x <= math.MaxInt32 { @@ -742,7 +742,7 @@ func Int64ToInt32(x int64) (int32, bool) { // Int64ToInt16 converts an int64 value to int16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int64ToInt16(x int64) (int16, bool) { y := int16(x) if math.MinInt16 <= x && x <= math.MaxInt16 { @@ -755,7 +755,7 @@ func Int64ToInt16(x int64) (int16, bool) { // Int64ToInt8 converts an int64 value to int8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int64ToInt8(x int64) (int8, bool) { y := int8(x) if math.MinInt8 <= x && x <= math.MaxInt8 { @@ -768,7 +768,7 @@ func Int64ToInt8(x int64) (int8, bool) { // Int32ToInt16 converts an int32 value to int16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int32ToInt16(x int32) (int16, bool) { y := int16(x) if math.MinInt16 <= x && x <= math.MaxInt16 { @@ -781,7 +781,7 @@ func Int32ToInt16(x int32) (int16, bool) { // Int32ToInt8 converts an int32 value to int8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int32ToInt8(x int32) (int8, bool) { y := int8(x) if math.MinInt8 <= x && x <= math.MaxInt8 { @@ -794,7 +794,7 @@ func Int32ToInt8(x int32) (int8, bool) { // Int16ToInt8 converts an int16 value to int8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int16ToInt8(x int16) (int8, bool) { y := int8(x) if math.MinInt8 <= x && x <= math.MaxInt8 { @@ -807,7 +807,7 @@ func Int16ToInt8(x int16) (int8, bool) { // Uint64ToUint32 converts an uint64 value to uint32. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint64ToUint32(x uint64) (uint32, bool) { y := uint32(x) if x <= math.MaxUint32 { @@ -820,7 +820,7 @@ func Uint64ToUint32(x uint64) (uint32, bool) { // Uint64ToUint16 converts an uint64 value to uint16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint64ToUint16(x uint64) (uint16, bool) { y := uint16(x) if x <= math.MaxUint16 { @@ -833,7 +833,7 @@ func Uint64ToUint16(x uint64) (uint16, bool) { // Uint64ToUint8 converts an uint64 value to uint8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint64ToUint8(x uint64) (uint8, bool) { y := uint8(x) if x <= math.MaxUint8 { @@ -846,7 +846,7 @@ func Uint64ToUint8(x uint64) (uint8, bool) { // Uint32ToUint16 converts an uint32 value to uint16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint32ToUint16(x uint32) (uint16, bool) { y := uint16(x) if x <= math.MaxUint16 { @@ -859,7 +859,7 @@ func Uint32ToUint16(x uint32) (uint16, bool) { // Uint32ToUint8 converts an uint32 value to uint8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint32ToUint8(x uint32) (uint8, bool) { y := uint8(x) if x <= math.MaxUint8 { @@ -872,7 +872,7 @@ func Uint32ToUint8(x uint32) (uint8, bool) { // Uint16ToUint8 converts an uint16 value to uint8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint16ToUint8(x uint16) (uint8, bool) { y := uint8(x) if x <= math.MaxUint8 { @@ -885,7 +885,7 @@ func Uint16ToUint8(x uint16) (uint8, bool) { // Uint64ToInt64 converts an uint64 value to int64. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint64ToInt64(x uint64) (int64, bool) { y := int64(x) if x <= math.MaxInt64 { @@ -898,7 +898,7 @@ func Uint64ToInt64(x uint64) (int64, bool) { // Uint64ToInt32 converts an uint64 value to int32. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint64ToInt32(x uint64) (int32, bool) { y := int32(x) if x <= math.MaxInt32 { @@ -911,7 +911,7 @@ func Uint64ToInt32(x uint64) (int32, bool) { // Uint64ToInt16 converts an uint64 value to int16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint64ToInt16(x uint64) (int16, bool) { y := int16(x) if x <= math.MaxInt16 { @@ -924,7 +924,7 @@ func Uint64ToInt16(x uint64) (int16, bool) { // Uint64ToInt8 converts an uint64 value to int8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint64ToInt8(x uint64) (int8, bool) { y := int8(x) if x <= math.MaxInt8 { @@ -937,7 +937,7 @@ func Uint64ToInt8(x uint64) (int8, bool) { // Uint32ToInt32 converts an uint32 value to int32. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint32ToInt32(x uint32) (int32, bool) { y := int32(x) if x <= math.MaxInt32 { @@ -950,7 +950,7 @@ func Uint32ToInt32(x uint32) (int32, bool) { // Uint32ToInt16 converts an uint32 value to int16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint32ToInt16(x uint32) (int16, bool) { y := int16(x) if x <= math.MaxInt16 { @@ -963,7 +963,7 @@ func Uint32ToInt16(x uint32) (int16, bool) { // Uint32ToInt8 converts an uint32 value to int8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint32ToInt8(x uint32) (int8, bool) { y := int8(x) if x <= math.MaxInt8 { @@ -976,7 +976,7 @@ func Uint32ToInt8(x uint32) (int8, bool) { // Uint16ToInt16 converts an uint16 value to int16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint16ToInt16(x uint16) (int16, bool) { y := int16(x) if x <= math.MaxInt16 { @@ -989,7 +989,7 @@ func Uint16ToInt16(x uint16) (int16, bool) { // Uint16ToInt8 converts an uint16 value to int8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint16ToInt8(x uint16) (int8, bool) { y := int8(x) if x <= math.MaxInt8 { @@ -1002,7 +1002,7 @@ func Uint16ToInt8(x uint16) (int8, bool) { // Uint8ToInt8 converts an uint8 value to int8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint8ToInt8(x uint8) (int8, bool) { y := int8(x) if x <= math.MaxInt8 { @@ -1015,7 +1015,7 @@ func Uint8ToInt8(x uint8) (int8, bool) { // Int64ToUint64 converts an int64 value to uint64. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int64ToUint64(x int64) (uint64, bool) { y := uint64(x) if 0 <= x { @@ -1028,7 +1028,7 @@ func Int64ToUint64(x int64) (uint64, bool) { // Int64ToUint32 converts an int64 value to uint32. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int64ToUint32(x int64) (uint32, bool) { y := uint32(x) if 0 <= x && x <= math.MaxUint32 { @@ -1041,7 +1041,7 @@ func Int64ToUint32(x int64) (uint32, bool) { // Int64ToUint16 converts an int64 value to uint16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int64ToUint16(x int64) (uint16, bool) { y := uint16(x) if 0 <= x && x <= math.MaxUint16 { @@ -1054,7 +1054,7 @@ func Int64ToUint16(x int64) (uint16, bool) { // Int64ToUint8 converts an int64 value to uint8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int64ToUint8(x int64) (uint8, bool) { y := uint8(x) if 0 <= x && x <= math.MaxUint8 { @@ -1067,7 +1067,7 @@ func Int64ToUint8(x int64) (uint8, bool) { // Int32ToUint64 converts an int32 value to uint64. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int32ToUint64(x int32) (uint64, bool) { y := uint64(x) if 0 <= x { @@ -1080,7 +1080,7 @@ func Int32ToUint64(x int32) (uint64, bool) { // Int32ToUint32 converts an int32 value to uint32. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int32ToUint32(x int32) (uint32, bool) { y := uint32(x) if 0 <= x { @@ -1093,7 +1093,7 @@ func Int32ToUint32(x int32) (uint32, bool) { // Int32ToUint16 converts an int32 value to uint16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int32ToUint16(x int32) (uint16, bool) { y := uint16(x) if 0 <= x && x <= math.MaxUint16 { @@ -1106,7 +1106,7 @@ func Int32ToUint16(x int32) (uint16, bool) { // Int32ToUint8 converts an int32 value to uint8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int32ToUint8(x int32) (uint8, bool) { y := uint8(x) if 0 <= x && x <= math.MaxUint8 { @@ -1119,7 +1119,7 @@ func Int32ToUint8(x int32) (uint8, bool) { // Int16ToUint64 converts an int16 value to uint64. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int16ToUint64(x int16) (uint64, bool) { y := uint64(x) if 0 <= x { @@ -1132,7 +1132,7 @@ func Int16ToUint64(x int16) (uint64, bool) { // Int16ToUint32 converts an int16 value to uint32. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int16ToUint32(x int16) (uint32, bool) { y := uint32(x) if 0 <= x { @@ -1145,7 +1145,7 @@ func Int16ToUint32(x int16) (uint32, bool) { // Int16ToUint16 converts an int16 value to uint16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int16ToUint16(x int16) (uint16, bool) { y := uint16(x) if 0 <= x { @@ -1158,7 +1158,7 @@ func Int16ToUint16(x int16) (uint16, bool) { // Int16ToUint8 converts an int16 value to uint8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int16ToUint8(x int16) (uint8, bool) { y := uint8(x) if 0 <= x && x <= math.MaxUint8 { @@ -1171,7 +1171,7 @@ func Int16ToUint8(x int16) (uint8, bool) { // Int8ToUint64 converts an int8 value to uint64. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int8ToUint64(x int8) (uint64, bool) { y := uint64(x) if 0 <= x { @@ -1184,7 +1184,7 @@ func Int8ToUint64(x int8) (uint64, bool) { // Int8ToUint32 converts an int8 value to uint32. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int8ToUint32(x int8) (uint32, bool) { y := uint32(x) if 0 <= x { @@ -1197,7 +1197,7 @@ func Int8ToUint32(x int8) (uint32, bool) { // Int8ToUint16 converts an int8 value to uint16. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int8ToUint16(x int8) (uint16, bool) { y := uint16(x) if 0 <= x { @@ -1210,7 +1210,7 @@ func Int8ToUint16(x int8) (uint16, bool) { // Int8ToUint8 converts an int8 value to uint8. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int8ToUint8(x int8) (uint8, bool) { y := uint8(x) if 0 <= x { diff --git a/overflow_template.sh b/overflow_template.sh index b2ad7ec..7e473ad 100755 --- a/overflow_template.sh +++ b/overflow_template.sh @@ -17,7 +17,7 @@ do echo " // Add${SIZE} performs + operation on two int${SIZE} operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Add${SIZE}(a, b int${SIZE}) (int${SIZE}, bool) { c := a + b if (c > a) == (b > 0) { @@ -36,7 +36,7 @@ func Add${SIZE}p(a, b int${SIZE}) int${SIZE} { } // UAdd${SIZE} performs + operation on two uint${SIZE} operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UAdd${SIZE}(a, b uint${SIZE}) (uint${SIZE}, bool) { c := a + b if c >= a { @@ -56,7 +56,7 @@ func UAdd${SIZE}p(a, b uint${SIZE}) uint${SIZE} { // Sub${SIZE} performs - operation on two int${SIZE} operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Sub${SIZE}(a, b int${SIZE}) (int${SIZE}, bool) { c := a - b if (c < a) == (b > 0) { @@ -75,7 +75,7 @@ func Sub${SIZE}p(a, b int${SIZE}) int${SIZE} { } // USub${SIZE} performs - operation on two uint${SIZE} operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func USub${SIZE}(a, b uint${SIZE}) (uint${SIZE}, bool) { c := a - b if a >= b { @@ -95,7 +95,7 @@ func USub${SIZE}p(a, b uint${SIZE}) uint${SIZE} { // Mul${SIZE} performs * operation on two int${SIZE} operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Mul${SIZE}(a, b int${SIZE}) (int${SIZE}, bool) { if a == 0 || b == 0 { return 0, true @@ -119,7 +119,7 @@ func Mul${SIZE}p(a, b int${SIZE}) int${SIZE} { } // UMul${SIZE} performs * operation on two uint${SIZE} operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UMul${SIZE}(a, b uint${SIZE}) (uint${SIZE}, bool) { if a == 0 || b == 0 { return 0, true @@ -142,7 +142,7 @@ func UMul${SIZE}p(a, b uint${SIZE}) uint${SIZE} { // Div${SIZE} performs / operation on two int${SIZE} operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func Div${SIZE}(a, b int${SIZE}) (int${SIZE}, bool) { q, _, ok := Quotient${SIZE}(a, b) return q, ok @@ -158,7 +158,7 @@ func Div${SIZE}p(a, b int${SIZE}) int${SIZE} { } // Quotient${SIZE} performs + operation on two int${SIZE} operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func Quotient${SIZE}(a, b int${SIZE}) (int${SIZE}, int${SIZE}, bool) { if b == 0 { return 0, 0, false @@ -169,7 +169,7 @@ func Quotient${SIZE}(a, b int${SIZE}) (int${SIZE}, int${SIZE}, bool) { } // UDiv${SIZE} performs / operation on two uint${SIZE} operands -// returning a result and status +// returning a result and a ok result indicating whether the operation is safe. func UDiv${SIZE}(a, b uint${SIZE}) (uint${SIZE}, bool) { q, _, ok := UQuotient${SIZE}(a, b) return q, ok @@ -185,7 +185,7 @@ func UDiv${SIZE}p(a, b uint${SIZE}) uint${SIZE} { } // UQuotient${SIZE} performs + operation on two uint${SIZE} operands -// returning a quotient, a remainder and status +// returning a quotient, a remainder and a ok result indicating whether the operation is safe. func UQuotient${SIZE}(a, b uint${SIZE}) (uint${SIZE}, uint${SIZE}, bool) { if b == 0 { return 0, 0, false @@ -204,7 +204,7 @@ for TO in $(seq $((FROM + 1)) 3); do echo " // Int${SIZE[FROM]}ToInt${SIZE[TO]} converts an int${SIZE[FROM]} value to int${SIZE[TO]}. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int${SIZE[FROM]}ToInt${SIZE[TO]}(x int${SIZE[FROM]}) (int${SIZE[TO]}, bool) { y := int${SIZE[TO]}(x) if math.MinInt${SIZE[TO]} <= x && x <= math.MaxInt${SIZE[TO]} { @@ -223,7 +223,7 @@ for TO in $(seq $((FROM + 1)) 3); do echo " // Uint${SIZE[FROM]}ToUint${SIZE[TO]} converts an uint${SIZE[FROM]} value to uint${SIZE[TO]}. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint${SIZE[FROM]}ToUint${SIZE[TO]}(x uint${SIZE[FROM]}) (uint${SIZE[TO]}, bool) { y := uint${SIZE[TO]}(x) if x <= math.MaxUint${SIZE[TO]} { @@ -242,7 +242,7 @@ for TO in $(seq $((FROM)) 3); do echo " // Uint${SIZE[FROM]}ToInt${SIZE[TO]} converts an uint${SIZE[FROM]} value to int${SIZE[TO]}. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Uint${SIZE[FROM]}ToInt${SIZE[TO]}(x uint${SIZE[FROM]}) (int${SIZE[TO]}, bool) { y := int${SIZE[TO]}(x) if x <= math.MaxInt${SIZE[TO]} { @@ -262,7 +262,7 @@ for TO in {0..3}; do echo " // Int${SIZE[FROM]}ToUint${SIZE[TO]} converts an int${SIZE[FROM]} value to uint${SIZE[TO]}. -// returning a converted value and a bool value indicating whether the operation is safe. +// returning a converted value and a ok result indicating whether the operation is safe. func Int${SIZE[FROM]}ToUint${SIZE[TO]}(x int${SIZE[FROM]}) (uint${SIZE[TO]}, bool) { y := uint${SIZE[TO]}(x)" if [ "$((SIZE[FROM]))" -gt "$((SIZE[TO]))" ]; then diff --git a/overflow_test.go b/overflow_test.go index f9f15e0..d688966 100644 --- a/overflow_test.go +++ b/overflow_test.go @@ -189,6 +189,9 @@ func TestQuotient(t *testing.T) { if _, _, ok = Quotient(1, 0); ok { t.Error("unexpected lack of failure") } + if _, _, ok = Quotient(math.MinInt, -1); ok { + t.Error("unexpected lack of failure") + } uq, ur, ok := UQuotient(100, 3) if ur != 1 || uq != 33 || !ok { t.Errorf("expected 100/3 => 33, r=1") From ba8a0d7865a4303b230a6283554005fe258e2774 Mon Sep 17 00:00:00 2001 From: Felipe Pinheiro Date: Fri, 2 Jun 2023 11:17:00 -0300 Subject: [PATCH 4/7] Add LICENSE.md file Move license section out of README into LICENSE --- LICENSE.md | 21 +++++++++++++++++++++ README.md | 26 ++------------------------ 2 files changed, 23 insertions(+), 24 deletions(-) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..3f37f2e --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 John C. Griffin, + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 68f9eda..4c44cd9 100644 --- a/README.md +++ b/README.md @@ -104,29 +104,7 @@ inlining of this library function. This library is based on Go's official compiler implementation and language specification, which defines the behavior when integer overflow occurs. +### License -- - - -MIT License - -Copyright (c) 2017 John C. Griffin, - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - +[MIT LICENSE](./LICENSE.md) From 21e93b5de0cda824ed261f9b5e7b24eaf3fcf4a7 Mon Sep 17 00:00:00 2001 From: rwxe Date: Sat, 30 Sep 2023 18:17:43 +0800 Subject: [PATCH 5/7] Add special READMEs before the PR is merged by the upstream --- README.md | 48 ++++++++++------------- README.zh_CN.md | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 27 deletions(-) create mode 100644 README.zh_CN.md diff --git a/README.md b/README.md index 4c44cd9..f408980 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,24 @@ -[![Build Status](https://travis-ci.org/JohnCGriffin/overflow.png)](https://travis-ci.org/JohnCGriffin/overflow) # overflow Check for integer overflow in Golang arithmetic and type conversion. + +Other language README: [中文版](./README.zh_CN.md) ### Install + +*This is a special README before the PR is merged by the upstream.* + +This repository forks from `johncgriffin/overflow` and adds overflow detection for unsigned integer arithmetic and type conversions between integers. + +It has been well tested and benchmarked, and passed the code security scan provided by Github Workflow. + +[![CodeQL](https://github.com/rwxe/overflow/actions/workflows/codeql.yml/badge.svg)](https://github.com/rwxe/overflow/actions/workflows/codeql.yml) + ```sh -go get github.com/johncgriffin/overflow +go get github.com/rwxe/overflow ``` -Note that because Go has no template types, the majority of repetitive code is -generated by overflow_template.sh. If you have to change an -algorithm, change it there and regenerate the Go code via: + +In order to be compatible with the old code and keep the code simple and readable, the new code still does not use generics, but uses templates to generate code. So the majority of repetitive code is generated by `overflow_template.sh`. + +If you have to change an algorithm, change it there and regenerate the Go code via: ```sh go generate ``` @@ -19,18 +30,15 @@ package main import "fmt" import "math" -import "github.com/JohnCGriffin/overflow" +import "github.com/rwxe/overflow" func main() { - addend := math.MaxInt64 - 5 - for i := 0; i < 10; i++ { sum, ok := overflow.Add(addend, i) fmt.Printf("%v+%v -> (%v,%v)\n", addend, i, sum, ok) } - } ``` yields the output @@ -46,7 +54,6 @@ yields the output 9223372036854775802+8 -> (0,false) 9223372036854775802+9 -> (0,false) ``` - For (u)int types, provide (U)Add, (U)Sub, (U)Mul, (U)Div, (U)Quotient, etc. @@ -79,30 +86,17 @@ Provide UintToInt, IntToUint, Uint64ToInt32, Int32ToUint64, etc. ### Stay calm and panic -There's a good case to be made that a panic is an unidiomatic but proper response. Iff you -believe that there's no valid way to continue your program after math goes wayward, you can -use the easier Addp, Mulp, Subp, and Divp versions which return the normal result or panic. +There's a good case to be made that a panic is an unidiomatic but proper response. Iff you believe that there's no valid way to continue your program after math goes wayward, you can use the easier Addp, Mulp, Subp, Divp, IntToUintp, UintToIntp versions which return the normal result or panic. ### Performance considerations -Compared with the integer type safety libraries of other languages (such as C++), this -library uses some seemingly slow operations, such as division. But this does not mean that -these methods will be slow, on the contrary, it will be faster than complex implementations -in other languages. The reason is that Go does not allow forced inlining, and any complex -functions will be abandoned for inlining, resulting in additional calling overhead. Short -functions are lightning fast due to automatic inlining. For example, for unsigned 64-bit -integer multiplication overflow detection, when inlining is disabled, division takes five -times as long as long multiplication, but after automatic inlining is allowed, division -takes 1/5 of long multiplication. +Compared with the integer type safety libraries of other languages (such as C++), this library uses some seemingly slow operations, such as division. But this does not mean that these methods will be slow, on the contrary, it will be faster than complex implementations in other languages. The reason is that Go does not allow forced inlining, and any complex functions will be abandoned for inlining, resulting in additional calling overhead. Short functions are lightning fast due to automatic inlining. For example, for unsigned 64-bit integer multiplication overflow detection, when inlining is disabled, division takes five times as long as long multiplication, but after automatic inlining is allowed, division takes 1/5 of long multiplication. -Note that using `//go:noinline` in your business function will not affect the inlining of -the library function. Only disabling global inlining through `-gcflags="-l"` will affect the -inlining of this library function. +Note that using `//go:noinline` in your business function will not affect the inlining of the library function. Only disabling global inlining through `-gcflags="-l"` will affect the inlining of this library function. ### Basis and dependencies -This library is based on Go's official compiler implementation and language specification, -which defines the behavior when integer overflow occurs. +This library is based on Go's official compiler implementation and language specification, which defines the behavior when integer overflow occurs. ### License diff --git a/README.zh_CN.md b/README.zh_CN.md new file mode 100644 index 0000000..188836f --- /dev/null +++ b/README.zh_CN.md @@ -0,0 +1,102 @@ +# overflow 溢出 +检查 Golang 算术和类型转换中的整数溢出。 +### 安装 + +*这是一份PR被上游合并之前的特殊README。* + +该库从`johncgriffin/overflow`派生而来并添加了无符号整数的算术和整数之间的溢出检测。 + +它经过了良好的测试和基准测试,并通过了由GitHub提供的Workflow代码安全扫描。 + +[![CodeQL](https://github.com/rwxe/overflow/actions/workflows/codeql.yml/badge.svg)](https://github.com/rwxe/overflow/actions/workflows/codeql.yml) + +```sh +go get github.com/rwxe/overflow +``` + +为了兼容旧代码并保持代码简单易读,新的代码仍然不使用泛型,而是使用模板来生成代码。 所以大多数重复代码由`overflow_template.sh`生成。 + +如果您必须更改算法,请在那里更改并通过以下方式重新生成 Go 代码: +```sh +go generate +``` +### 概要 + +#### 算术溢出检测 +```go +package main + +import "fmt" +import "math" +import "github.com/rwxe/overflow" + +func main() { + addend := math.MaxInt64 - 5 + for i := 0; i < 10; i++ { + sum, ok := overflow.Add(addend, i) + fmt.Printf("%v+%v -> (%v,%v)\n", + addend, i, sum, ok) + } +} +``` +输出 +```go +9223372036854775802+0 -> (9223372036854775802,true) +9223372036854775802+1 -> (9223372036854775803,true) +9223372036854775802+2 -> (9223372036854775804,true) +9223372036854775802+3 -> (9223372036854775805,true) +9223372036854775802+4 -> (9223372036854775806,true) +9223372036854775802+5 -> (9223372036854775807,true) +9223372036854775802+6 -> (0,false) +9223372036854775802+7 -> (0,false) +9223372036854775802+8 -> (0,false) +9223372036854775802+9 -> (0,false) +``` +对于 (u)int 类型,提供 (U)Add、(U)Sub、(U)Mul、(U)Div、(U)Quotient 等操作。 + + +#### 类型转换溢出检测 +```go +func main() { + var i uint + for i = math.MaxInt - 5; i <= math.MaxInt+5; i++ { + ret, ok := overflow.UintToInt(i) + fmt.Printf("%v -> (%v,%v)\n", + i, ret, ok) + } +} +``` +输出 +```go +9223372036854775802 -> (9223372036854775802,true) +9223372036854775803 -> (9223372036854775803,true) +9223372036854775804 -> (9223372036854775804,true) +9223372036854775805 -> (9223372036854775805,true) +9223372036854775806 -> (9223372036854775806,true) +9223372036854775807 -> (9223372036854775807,true) +9223372036854775808 -> (-9223372036854775808,false) +9223372036854775809 -> (-9223372036854775807,false) +9223372036854775810 -> (-9223372036854775806,false) +9223372036854775811 -> (-9223372036854775805,false) +9223372036854775812 -> (-9223372036854775804,false) +``` +提供UintToInt、IntToUint、Uint64ToInt32、Int32ToUint64等操作。 + +### 保持冷静并恐慌 + +有充分的证据表明,恐慌是一种不惯用但正确的反应。 如果你相信在算术和转换出现问题后,没有有效的方法可以继续你的程序,你可以使用更简单的 Addp、Mulp、Subp 、Divp、UintToIntp、IntToUintp 版本,它们返回正常结果或恐慌。 + +### 性能考虑 + +与其他语言(例如C++)的整数类型安全库相比,该库使用了一些看似缓慢的操作,例如除法。 但这并不意味着这些方法会很慢,相反,它会比其他语言中的复杂实现更快。 原因是Go不允许强制内联,任何复杂的函数都会被抛弃内联,导致额外的调用开销。 而短函数由于自动内联将快如闪电。 例如,对于无符号64位整数乘法溢出检测,当禁用内联时,除法所需的时间是长乘法的5倍,但允许自动内联后,除法所需的时间是长乘法的1/5。 + +请注意,在业务函数中使用 `//go:noinline` 不会影响本库函数的内联。 只有通过 `-gcflags="-l"` 禁用全局内联才会影响该本库函数的内联。 + +### 基于和依赖 + +该库基于Go的官方编译器实现和语言规范,其定义了整数溢出发生时的行为。 + +### 许可 + +[MIT LICENSE](./LICENSE.md) + From 0e6fb1ff01b5f64d0b3c1722528065283b63a6fd Mon Sep 17 00:00:00 2001 From: rwxe Date: Sun, 1 Oct 2023 03:56:22 +0800 Subject: [PATCH 6/7] Add safe absolute value operation --- README.md | 61 +++++--- README.zh_CN.md | 34 +++- overflow.go | 19 +++ overflow_impl.go | 48 ++++++ overflow_template.sh | 12 ++ overflow_test.go | 18 +++ overflow_type_conversion_test.go | 256 +++++++++++++++---------------- 7 files changed, 301 insertions(+), 147 deletions(-) diff --git a/README.md b/README.md index f408980..c2aa918 100644 --- a/README.md +++ b/README.md @@ -26,19 +26,14 @@ go generate #### Arithmetic overflow detection ```go -package main - -import "fmt" -import "math" import "github.com/rwxe/overflow" func main() { - addend := math.MaxInt64 - 5 - for i := 0; i < 10; i++ { - sum, ok := overflow.Add(addend, i) - fmt.Printf("%v+%v -> (%v,%v)\n", - addend, i, sum, ok) - } + addend := math.MaxInt64 - 5 + for i := 0; i < 10; i++ { + sum, ok := overflow.Add(addend, i) + fmt.Printf("%v+%v -> (%v,%v)\n", addend, i, sum, ok) + } } ``` yields the output @@ -56,16 +51,14 @@ yields the output ``` For (u)int types, provide (U)Add, (U)Sub, (U)Mul, (U)Div, (U)Quotient, etc. - #### Type conversion overflow detection ```go func main() { - var i uint - for i = math.MaxInt - 5; i <= math.MaxInt+5; i++ { - ret, ok := overflow.UintToInt(i) - fmt.Printf("%v -> (%v,%v)\n", - i, ret, ok) - } + var i uint + for i = math.MaxInt - 5; i <= math.MaxInt+5; i++ { + ret, ok := overflow.UintToInt(i) + fmt.Printf("%v -> (%v,%v)\n", i, ret, ok) + } } ``` yields the output @@ -84,9 +77,41 @@ yields the output ``` Provide UintToInt, IntToUint, Uint64ToInt32, Int32ToUint64, etc. +#### Get absolute value +```go +func main() { + normalAbs := func(x int64) int64 { + if x < 0 { + x = -x + } + return x + } + var i1, j1, k1 int64 = -9007199254740993, -9007199254740993, -9007199254740993 + fmt.Println(int64(math.Abs(float64(i1)))) + fmt.Println(normalAbs(j1)) + fmt.Println(overflow.Abs64(k1)) + + var i2, j2, k2 int64 = math.MinInt64, math.MinInt64, math.MinInt64 + fmt.Println(int64(math.Abs(float64(i2)))) + fmt.Println(normalAbs(j2)) + fmt.Println(overflow.Abs64(k2)) +} +``` +yields the output +```go +9007199254740992 // Mantissa overflow, precision lost +9007199254740993 +9007199254740993 true +-9223372036854775808 +-9223372036854775808 +-9223372036854775808 false // Overflow detected +``` + +For int, provides an absolute value including overflow detection. + ### Stay calm and panic -There's a good case to be made that a panic is an unidiomatic but proper response. Iff you believe that there's no valid way to continue your program after math goes wayward, you can use the easier Addp, Mulp, Subp, Divp, IntToUintp, UintToIntp versions which return the normal result or panic. +There's a good case to be made that a panic is an unidiomatic but proper response. If you believe that there's no valid way to continue your program after math goes wayward, you can use the easier Addp, Mulp, Subp, Divp, IntToUintp, Absp etc, which return the normal result or panic. ### Performance considerations diff --git a/README.zh_CN.md b/README.zh_CN.md index 188836f..f4466d9 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -82,9 +82,41 @@ func main() { ``` 提供UintToInt、IntToUint、Uint64ToInt32、Int32ToUint64等操作。 +#### 取绝对值 +```go +func main() { + normalAbs := func(x int64) int64 { + if x < 0 { + x = -x + } + return x + } + var i1, j1, k1 int64 = -9007199254740993, -9007199254740993, -9007199254740993 + fmt.Println(int64(math.Abs(float64(i1)))) + fmt.Println(normalAbs(j1)) + fmt.Println(overflow.Abs64(k1)) + + var i2, j2, k2 int64 = math.MinInt64, math.MinInt64, math.MinInt64 + fmt.Println(int64(math.Abs(float64(i2)))) + fmt.Println(normalAbs(j2)) + fmt.Println(overflow.Abs64(k2)) +} +``` +yields the output +```go +9007199254740992 // Mantissa overflow, precision lost +9007199254740993 +9007199254740993 true +-9223372036854775808 +-9223372036854775808 +-9223372036854775808 false // Overflow detected +``` + +对于整数,提供包含溢出检测的取绝对值操作。 + ### 保持冷静并恐慌 -有充分的证据表明,恐慌是一种不惯用但正确的反应。 如果你相信在算术和转换出现问题后,没有有效的方法可以继续你的程序,你可以使用更简单的 Addp、Mulp、Subp 、Divp、UintToIntp、IntToUintp 版本,它们返回正常结果或恐慌。 +有充分的证据表明,恐慌是一种不惯用但正确的反应。 如果你相信在算术和转换出现问题后,没有有效的方法可以继续你的程序,你可以使用更简单的 Addp、Mulp、Subp 、Divp、UintToIntp、Absp等版本,它们返回正常结果或恐慌。 ### 性能考虑 diff --git a/overflow.go b/overflow.go index e9b8e0c..e5d581e 100644 --- a/overflow.go +++ b/overflow.go @@ -42,6 +42,16 @@ So, FEEL FREE to carefully review the code visually. // Unspecified size, i.e. normal signed int +// Abs get absolute value of an int, returning the result and a ok result indicating whether the operation is safe. +func Abs(x int) (int, bool) { + if _is64Bit() { + r64, ok := Abs64(int64(x)) + return int(r64), ok + } + r32, ok := Abs32(int32(x)) + return int(r32), ok +} + // Add sums two ints, returning the result and a ok result indicating whether the operation is safe. func Add(a, b int) (int, bool) { if _is64Bit() { @@ -166,6 +176,15 @@ func UintToInt(x uint) (int, bool) { /************* Panic versions for int ****************/ +// Absp returns the absolute value, panicking on overflow +func Absp(x int) int { + r, ok := Abs(x) + if !ok { + panic("absolute value overflow") + } + return r +} + // Addp returns the sum of two ints, panicking on overflow func Addp(a, b int) int { r, ok := Add(a, b) diff --git a/overflow_impl.go b/overflow_impl.go index 1362f27..fb7eaae 100644 --- a/overflow_impl.go +++ b/overflow_impl.go @@ -8,6 +8,18 @@ import "math" +// Abs8 performs absolute value operation on an int8 operand +// returning a result and a ok result indicating whether the operation is safe. +func Abs8(x int8) (int8, bool) { + if x == math.MinInt8 { + return x, false + } + if x >= 0 { + return x, true + } + return -x, true +} + // Add8 performs + operation on two int8 operands // returning a result and a ok result indicating whether the operation is safe. func Add8(a, b int8) (int8, bool) { @@ -188,6 +200,18 @@ func UQuotient8(a, b uint8) (uint8, uint8, bool) { +// Abs16 performs absolute value operation on an int16 operand +// returning a result and a ok result indicating whether the operation is safe. +func Abs16(x int16) (int16, bool) { + if x == math.MinInt16 { + return x, false + } + if x >= 0 { + return x, true + } + return -x, true +} + // Add16 performs + operation on two int16 operands // returning a result and a ok result indicating whether the operation is safe. func Add16(a, b int16) (int16, bool) { @@ -368,6 +392,18 @@ func UQuotient16(a, b uint16) (uint16, uint16, bool) { +// Abs32 performs absolute value operation on an int32 operand +// returning a result and a ok result indicating whether the operation is safe. +func Abs32(x int32) (int32, bool) { + if x == math.MinInt32 { + return x, false + } + if x >= 0 { + return x, true + } + return -x, true +} + // Add32 performs + operation on two int32 operands // returning a result and a ok result indicating whether the operation is safe. func Add32(a, b int32) (int32, bool) { @@ -548,6 +584,18 @@ func UQuotient32(a, b uint32) (uint32, uint32, bool) { +// Abs64 performs absolute value operation on an int64 operand +// returning a result and a ok result indicating whether the operation is safe. +func Abs64(x int64) (int64, bool) { + if x == math.MinInt64 { + return x, false + } + if x >= 0 { + return x, true + } + return -x, true +} + // Add64 performs + operation on two int64 operands // returning a result and a ok result indicating whether the operation is safe. func Add64(a, b int64) (int64, bool) { diff --git a/overflow_template.sh b/overflow_template.sh index 7e473ad..96faae7 100755 --- a/overflow_template.sh +++ b/overflow_template.sh @@ -16,6 +16,18 @@ for SIZE in 8 16 32 64 do echo " +// Abs${SIZE} performs absolute value operation on an int${SIZE} operand +// returning a result and a ok result indicating whether the operation is safe. +func Abs${SIZE}(x int${SIZE}) (int${SIZE}, bool) { + if x == math.MinInt${SIZE} { + return x, false + } + if x >= 0 { + return x, true + } + return -x, true +} + // Add${SIZE} performs + operation on two int${SIZE} operands // returning a result and a ok result indicating whether the operation is safe. func Add${SIZE}(a, b int${SIZE}) (int${SIZE}, bool) { diff --git a/overflow_test.go b/overflow_test.go index d688966..c11464a 100644 --- a/overflow_test.go +++ b/overflow_test.go @@ -201,6 +201,24 @@ func TestQuotient(t *testing.T) { } } +func TestAbs(t *testing.T) { + if _, ok := Abs(math.MinInt); ok { + t.Error("unexpected ok, absolute value overflow") + } + if _, ok := Abs64(math.MinInt64); ok { + t.Error("unexpected ok, absolute value overflow") + } + if _, ok := Abs32(math.MinInt32); ok { + t.Error("unexpected ok, absolute value overflow") + } + if _, ok := Abs16(math.MinInt16); ok { + t.Error("unexpected ok, absolute value overflow") + } + if _, ok := Abs8(math.MinInt8); ok { + t.Error("unexpected ok, absolute value overflow") + } +} + //func TestAdditionInt(t *testing.T) { // fmt.Printf("\nminint8 = %v\n", math.MinInt8) // fmt.Printf("maxint8 = %v\n\n", math.MaxInt8) diff --git a/overflow_type_conversion_test.go b/overflow_type_conversion_test.go index d6f9bf1..d58d80d 100644 --- a/overflow_type_conversion_test.go +++ b/overflow_type_conversion_test.go @@ -1,7 +1,7 @@ package overflow import ( - "testing" + "testing" ) /* @@ -38,89 +38,89 @@ done // Integer limit values. const ( - intSize = 32 << (^uint(0) >> 63) // 32 or 64 - - MaxInt = 1<<(intSize-1) - 1 // MaxInt32 or MaxInt64 depending on intSize. - MinInt = -1 << (intSize - 1) // MinInt32 or MinInt64 depending on intSize. - MaxInt8 = 1<<7 - 1 // 127 - MinInt8 = -1 << 7 // -128 - MaxInt16 = 1<<15 - 1 // 32767 - MinInt16 = -1 << 15 // -32768 - MaxInt32 = 1<<31 - 1 // 2147483647 - MinInt32 = -1 << 31 // -2147483648 - MaxInt64 = 1<<63 - 1 // 9223372036854775807 - MinInt64 = -1 << 63 // -9223372036854775808 - MaxUint = 1<> 63) // 32 or 64 + + MaxInt = 1<<(intSize-1) - 1 // MaxInt32 or MaxInt64 depending on intSize. + MinInt = -1 << (intSize - 1) // MinInt32 or MinInt64 depending on intSize. + MaxInt8 = 1<<7 - 1 // 127 + MinInt8 = -1 << 7 // -128 + MaxInt16 = 1<<15 - 1 // 32767 + MinInt16 = -1 << 15 // -32768 + MaxInt32 = 1<<31 - 1 // 2147483647 + MinInt32 = -1 << 31 // -2147483648 + MaxInt64 = 1<<63 - 1 // 9223372036854775807 + MinInt64 = -1 << 63 // -9223372036854775808 + MaxUint = 1< Int64 // Int64 -> Int32 - if r,ok:=Int64ToInt32(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt32(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt32(MaxInt32+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt32(MinInt32-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt32(MaxInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt32(MinInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt32(MaxInt32+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt32(MinInt32-1);ok{t.Error(UnexpectedOk,r)} // Int64 -> Int16 - if r,ok:=Int64ToInt16(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt16(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt16(MinInt16-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt16(MaxInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt16(MinInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt16(MaxInt16+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt16(MinInt16-1);ok{t.Error(UnexpectedOk,r)} // Int64 -> Int8 - if r,ok:=Int64ToInt8(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt8(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToInt8(MinInt8-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToInt8(MaxInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt8(MinInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt8(MaxInt8+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToInt8(MinInt8-1);ok{t.Error(UnexpectedOk,r)} // Int64 -> Uint64 //if r,ok:=Int64ToUint64(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint64(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint64(MinUint64-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint64(MinInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint64(MinUint64-1);ok{t.Error(UnexpectedOk,r)} // Int64 -> Uint32 - if r,ok:=Int64ToUint32(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint32(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint32(MaxUint32+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint32(MinUint32-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint32(MaxInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint32(MinInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint32(MaxUint32+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint32(MinUint32-1);ok{t.Error(UnexpectedOk,r)} // Int64 -> Uint16 - if r,ok:=Int64ToUint16(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint16(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint16(MaxUint16+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint16(MinUint16-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint16(MaxInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint16(MinInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint16(MaxUint16+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint16(MinUint16-1);ok{t.Error(UnexpectedOk,r)} // Int64 -> Uint8 - if r,ok:=Int64ToUint8(MaxInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint8(MinInt64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int64ToUint8(MinUint8-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int64ToUint8(MaxInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint8(MinInt64);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint8(MaxUint8+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int64ToUint8(MinUint8-1);ok{t.Error(UnexpectedOk,r)} // Int32 -> Int64 @@ -130,43 +130,43 @@ func TestTypeConversion(t *testing.T) { // Int32 -> Int16 - if r,ok:=Int32ToInt16(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToInt16(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToInt16(MinInt16-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToInt16(MaxInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToInt16(MinInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToInt16(MaxInt16+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToInt16(MinInt16-1);ok{t.Error(UnexpectedOk,r)} // Int32 -> Int8 - if r,ok:=Int32ToInt8(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToInt8(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToInt8(MinInt8-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToInt8(MaxInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToInt8(MinInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToInt8(MaxInt8+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToInt8(MinInt8-1);ok{t.Error(UnexpectedOk,r)} // Int32 -> Uint64 //if r,ok:=Int32ToUint64(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint64(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint64(MinUint64-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint64(MinInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToUint64(MinUint64-1);ok{t.Error(UnexpectedOk,r)} // Int32 -> Uint32 //if r,ok:=Int32ToUint32(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint32(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint32(MinUint32-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint32(MinInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToUint32(MinUint32-1);ok{t.Error(UnexpectedOk,r)} // Int32 -> Uint16 - if r,ok:=Int32ToUint16(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint16(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint16(MaxUint16+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint16(MinUint16-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint16(MaxInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToUint16(MinInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToUint16(MaxUint16+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToUint16(MinUint16-1);ok{t.Error(UnexpectedOk,r)} // Int32 -> Uint8 - if r,ok:=Int32ToUint8(MaxInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint8(MinInt32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int32ToUint8(MinUint8-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int32ToUint8(MaxInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToUint8(MinInt32);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToUint8(MaxUint8+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int32ToUint8(MinUint8-1);ok{t.Error(UnexpectedOk,r)} // Int16 -> Int64 @@ -179,35 +179,35 @@ func TestTypeConversion(t *testing.T) { // Int16 -> Int8 - if r,ok:=Int16ToInt8(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToInt8(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToInt8(MinInt8-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToInt8(MaxInt16);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToInt8(MinInt16);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToInt8(MaxInt8+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToInt8(MinInt8-1);ok{t.Error(UnexpectedOk,r)} // Int16 -> Uint64 //if r,ok:=Int16ToUint64(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint64(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint64(MinUint64-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint64(MinInt16);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToUint64(MinUint64-1);ok{t.Error(UnexpectedOk,r)} // Int16 -> Uint32 //if r,ok:=Int16ToUint32(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint32(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint32(MinUint32-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint32(MinInt16);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToUint32(MinUint32-1);ok{t.Error(UnexpectedOk,r)} // Int16 -> Uint16 //if r,ok:=Int16ToUint16(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint16(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint16(MinUint16-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint16(MinInt16);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToUint16(MinUint16-1);ok{t.Error(UnexpectedOk,r)} // Int16 -> Uint8 - if r,ok:=Int16ToUint8(MaxInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint8(MinInt16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int16ToUint8(MinUint8-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int16ToUint8(MaxInt16);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToUint8(MinInt16);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToUint8(MaxUint8+1);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int16ToUint8(MinUint8-1);ok{t.Error(UnexpectedOk,r)} // Int8 -> Int64 @@ -224,92 +224,92 @@ func TestTypeConversion(t *testing.T) { // Int8 -> Uint64 //if r,ok:=Int8ToUint64(MaxInt8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int8ToUint64(MinInt8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int8ToUint64(MinUint64-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint64(MinInt8);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int8ToUint64(MinUint64-1);ok{t.Error(UnexpectedOk,r)} // Int8 -> Uint32 //if r,ok:=Int8ToUint32(MaxInt8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int8ToUint32(MinInt8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int8ToUint32(MinUint32-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint32(MinInt8);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int8ToUint32(MinUint32-1);ok{t.Error(UnexpectedOk,r)} // Int8 -> Uint16 //if r,ok:=Int8ToUint16(MaxInt8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int8ToUint16(MinInt8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int8ToUint16(MinUint16-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint16(MinInt8);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int8ToUint16(MinUint16-1);ok{t.Error(UnexpectedOk,r)} // Int8 -> Uint8 //if r,ok:=Int8ToUint8(MaxInt8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int8ToUint8(MinInt8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Int8ToUint8(MinUint8-1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Int8ToUint8(MinInt8);ok{t.Error(UnexpectedOk,r)} + if r,ok:=Int8ToUint8(MinUint8-1);ok{t.Error(UnexpectedOk,r)} // Uint64 -> Int64 - if r,ok:=Uint64ToInt64(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt64(MaxUint64);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint64ToInt64(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint64ToInt64(MaxInt64+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt64(MaxInt64+1);ok{t.Error(UnexpectedOk,r)} // Uint64 -> Int32 - if r,ok:=Uint64ToInt32(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt32(MaxUint64);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint64ToInt32(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint64ToInt32(MaxInt32+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt32(MaxInt32+1);ok{t.Error(UnexpectedOk,r)} // Uint64 -> Int16 - if r,ok:=Uint64ToInt16(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt16(MaxUint64);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint64ToInt16(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint64ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt16(MaxInt16+1);ok{t.Error(UnexpectedOk,r)} // Uint64 -> Int8 - if r,ok:=Uint64ToInt8(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt8(MaxUint64);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint64ToInt8(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint64ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToInt8(MaxInt8+1);ok{t.Error(UnexpectedOk,r)} // Uint64 -> Uint64 // Uint64 -> Uint32 - if r,ok:=Uint64ToUint32(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint32(MaxUint64);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint64ToUint32(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint64ToUint32(MaxUint32+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint32(MaxUint32+1);ok{t.Error(UnexpectedOk,r)} // Uint64 -> Uint16 - if r,ok:=Uint64ToUint16(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint16(MaxUint64);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint64ToUint16(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint64ToUint16(MaxUint16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint16(MaxUint16+1);ok{t.Error(UnexpectedOk,r)} // Uint64 -> Uint8 - if r,ok:=Uint64ToUint8(MaxUint64);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint8(MaxUint64);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint64ToUint8(MinUint64);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint64ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint64ToUint8(MaxUint8+1);ok{t.Error(UnexpectedOk,r)} // Uint32 -> Int64 // Uint32 -> Int32 - if r,ok:=Uint32ToInt32(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt32(MaxUint32);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint32ToInt32(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint32ToInt32(MaxInt32+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt32(MaxInt32+1);ok{t.Error(UnexpectedOk,r)} // Uint32 -> Int16 - if r,ok:=Uint32ToInt16(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt16(MaxUint32);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint32ToInt16(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint32ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt16(MaxInt16+1);ok{t.Error(UnexpectedOk,r)} // Uint32 -> Int8 - if r,ok:=Uint32ToInt8(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt8(MaxUint32);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint32ToInt8(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint32ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToInt8(MaxInt8+1);ok{t.Error(UnexpectedOk,r)} // Uint32 -> Uint64 @@ -319,15 +319,15 @@ func TestTypeConversion(t *testing.T) { // Uint32 -> Uint16 - if r,ok:=Uint32ToUint16(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToUint16(MaxUint32);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint32ToUint16(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint32ToUint16(MaxUint16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToUint16(MaxUint16+1);ok{t.Error(UnexpectedOk,r)} // Uint32 -> Uint8 - if r,ok:=Uint32ToUint8(MaxUint32);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToUint8(MaxUint32);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint32ToUint8(MinUint32);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint32ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint32ToUint8(MaxUint8+1);ok{t.Error(UnexpectedOk,r)} // Uint16 -> Int64 @@ -337,15 +337,15 @@ func TestTypeConversion(t *testing.T) { // Uint16 -> Int16 - if r,ok:=Uint16ToInt16(MaxUint16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToInt16(MaxUint16);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint16ToInt16(MinUint16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint16ToInt16(MaxInt16+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToInt16(MaxInt16+1);ok{t.Error(UnexpectedOk,r)} // Uint16 -> Int8 - if r,ok:=Uint16ToInt8(MaxUint16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToInt8(MaxUint16);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint16ToInt8(MinUint16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint16ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToInt8(MaxInt8+1);ok{t.Error(UnexpectedOk,r)} // Uint16 -> Uint64 @@ -358,9 +358,9 @@ func TestTypeConversion(t *testing.T) { // Uint16 -> Uint8 - if r,ok:=Uint16ToUint8(MaxUint16);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToUint8(MaxUint16);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint16ToUint8(MinUint16);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint16ToUint8(MaxUint8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint16ToUint8(MaxUint8+1);ok{t.Error(UnexpectedOk,r)} // Uint8 -> Int64 @@ -373,9 +373,9 @@ func TestTypeConversion(t *testing.T) { // Uint8 -> Int8 - if r,ok:=Uint8ToInt8(MaxUint8);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint8ToInt8(MaxUint8);ok{t.Error(UnexpectedOk,r)} //if r,ok:=Uint8ToInt8(MinUint8);ok{t.Error(UNEXPECTED_OK,r)} - if r,ok:=Uint8ToInt8(MaxInt8+1);ok{t.Error(UNEXPECTED_OK,r)} + if r,ok:=Uint8ToInt8(MaxInt8+1);ok{t.Error(UnexpectedOk,r)} // Uint8 -> Uint64 From dae5ef875162b41e88385c4fad05ac5a60555580 Mon Sep 17 00:00:00 2001 From: rwxe Date: Mon, 2 Oct 2023 03:28:44 +0800 Subject: [PATCH 7/7] Improve README --- README.md | 20 +++----- README.zh_CN.md | 134 ------------------------------------------------ 2 files changed, 7 insertions(+), 147 deletions(-) delete mode 100644 README.zh_CN.md diff --git a/README.md b/README.md index c2aa918..2a9ed03 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,11 @@ +[![Build Status](https://travis-ci.org/JohnCGriffin/overflow.png)](https://travis-ci.org/JohnCGriffin/overflow) # overflow Check for integer overflow in Golang arithmetic and type conversion. -Other language README: [中文版](./README.zh_CN.md) ### Install -*This is a special README before the PR is merged by the upstream.* - -This repository forks from `johncgriffin/overflow` and adds overflow detection for unsigned integer arithmetic and type conversions between integers. - -It has been well tested and benchmarked, and passed the code security scan provided by Github Workflow. - -[![CodeQL](https://github.com/rwxe/overflow/actions/workflows/codeql.yml/badge.svg)](https://github.com/rwxe/overflow/actions/workflows/codeql.yml) - ```sh -go get github.com/rwxe/overflow +go get github.com/johncgriffin/overflow ``` In order to be compatible with the old code and keep the code simple and readable, the new code still does not use generics, but uses templates to generate code. So the majority of repetitive code is generated by `overflow_template.sh`. @@ -26,7 +18,7 @@ go generate #### Arithmetic overflow detection ```go -import "github.com/rwxe/overflow" +import "github.com/JohnCGriffin/overflow" func main() { addend := math.MaxInt64 - 5 @@ -115,13 +107,15 @@ There's a good case to be made that a panic is an unidiomatic but proper respons ### Performance considerations -Compared with the integer type safety libraries of other languages (such as C++), this library uses some seemingly slow operations, such as division. But this does not mean that these methods will be slow, on the contrary, it will be faster than complex implementations in other languages. The reason is that Go does not allow forced inlining, and any complex functions will be abandoned for inlining, resulting in additional calling overhead. Short functions are lightning fast due to automatic inlining. For example, for unsigned 64-bit integer multiplication overflow detection, when inlining is disabled, division takes five times as long as long multiplication, but after automatic inlining is allowed, division takes 1/5 of long multiplication. +Compared to integer safe libraries in other languages (e.g. C++), this library uses some seemingly slow operations, such as division. But that doesn't mean these methods will be slow. In fact, because of Go's automatic inlining strategy for short functions and compiler optimizations, these operations are actually very fast in benchmark tests, lightning fast. + +In addition, Go defines the overflow behavior of signed integers, making the detection of signed integer overflow simple and efficient. Note that using `//go:noinline` in your business function will not affect the inlining of the library function. Only disabling global inlining through `-gcflags="-l"` will affect the inlining of this library function. ### Basis and dependencies -This library is based on Go's official compiler implementation and language specification, which defines the behavior when integer overflow occurs. +The library is developed based on Go's official compiler implementation (gc) and language specifications. ### License diff --git a/README.zh_CN.md b/README.zh_CN.md deleted file mode 100644 index f4466d9..0000000 --- a/README.zh_CN.md +++ /dev/null @@ -1,134 +0,0 @@ -# overflow 溢出 -检查 Golang 算术和类型转换中的整数溢出。 -### 安装 - -*这是一份PR被上游合并之前的特殊README。* - -该库从`johncgriffin/overflow`派生而来并添加了无符号整数的算术和整数之间的溢出检测。 - -它经过了良好的测试和基准测试,并通过了由GitHub提供的Workflow代码安全扫描。 - -[![CodeQL](https://github.com/rwxe/overflow/actions/workflows/codeql.yml/badge.svg)](https://github.com/rwxe/overflow/actions/workflows/codeql.yml) - -```sh -go get github.com/rwxe/overflow -``` - -为了兼容旧代码并保持代码简单易读,新的代码仍然不使用泛型,而是使用模板来生成代码。 所以大多数重复代码由`overflow_template.sh`生成。 - -如果您必须更改算法,请在那里更改并通过以下方式重新生成 Go 代码: -```sh -go generate -``` -### 概要 - -#### 算术溢出检测 -```go -package main - -import "fmt" -import "math" -import "github.com/rwxe/overflow" - -func main() { - addend := math.MaxInt64 - 5 - for i := 0; i < 10; i++ { - sum, ok := overflow.Add(addend, i) - fmt.Printf("%v+%v -> (%v,%v)\n", - addend, i, sum, ok) - } -} -``` -输出 -```go -9223372036854775802+0 -> (9223372036854775802,true) -9223372036854775802+1 -> (9223372036854775803,true) -9223372036854775802+2 -> (9223372036854775804,true) -9223372036854775802+3 -> (9223372036854775805,true) -9223372036854775802+4 -> (9223372036854775806,true) -9223372036854775802+5 -> (9223372036854775807,true) -9223372036854775802+6 -> (0,false) -9223372036854775802+7 -> (0,false) -9223372036854775802+8 -> (0,false) -9223372036854775802+9 -> (0,false) -``` -对于 (u)int 类型,提供 (U)Add、(U)Sub、(U)Mul、(U)Div、(U)Quotient 等操作。 - - -#### 类型转换溢出检测 -```go -func main() { - var i uint - for i = math.MaxInt - 5; i <= math.MaxInt+5; i++ { - ret, ok := overflow.UintToInt(i) - fmt.Printf("%v -> (%v,%v)\n", - i, ret, ok) - } -} -``` -输出 -```go -9223372036854775802 -> (9223372036854775802,true) -9223372036854775803 -> (9223372036854775803,true) -9223372036854775804 -> (9223372036854775804,true) -9223372036854775805 -> (9223372036854775805,true) -9223372036854775806 -> (9223372036854775806,true) -9223372036854775807 -> (9223372036854775807,true) -9223372036854775808 -> (-9223372036854775808,false) -9223372036854775809 -> (-9223372036854775807,false) -9223372036854775810 -> (-9223372036854775806,false) -9223372036854775811 -> (-9223372036854775805,false) -9223372036854775812 -> (-9223372036854775804,false) -``` -提供UintToInt、IntToUint、Uint64ToInt32、Int32ToUint64等操作。 - -#### 取绝对值 -```go -func main() { - normalAbs := func(x int64) int64 { - if x < 0 { - x = -x - } - return x - } - var i1, j1, k1 int64 = -9007199254740993, -9007199254740993, -9007199254740993 - fmt.Println(int64(math.Abs(float64(i1)))) - fmt.Println(normalAbs(j1)) - fmt.Println(overflow.Abs64(k1)) - - var i2, j2, k2 int64 = math.MinInt64, math.MinInt64, math.MinInt64 - fmt.Println(int64(math.Abs(float64(i2)))) - fmt.Println(normalAbs(j2)) - fmt.Println(overflow.Abs64(k2)) -} -``` -yields the output -```go -9007199254740992 // Mantissa overflow, precision lost -9007199254740993 -9007199254740993 true --9223372036854775808 --9223372036854775808 --9223372036854775808 false // Overflow detected -``` - -对于整数,提供包含溢出检测的取绝对值操作。 - -### 保持冷静并恐慌 - -有充分的证据表明,恐慌是一种不惯用但正确的反应。 如果你相信在算术和转换出现问题后,没有有效的方法可以继续你的程序,你可以使用更简单的 Addp、Mulp、Subp 、Divp、UintToIntp、Absp等版本,它们返回正常结果或恐慌。 - -### 性能考虑 - -与其他语言(例如C++)的整数类型安全库相比,该库使用了一些看似缓慢的操作,例如除法。 但这并不意味着这些方法会很慢,相反,它会比其他语言中的复杂实现更快。 原因是Go不允许强制内联,任何复杂的函数都会被抛弃内联,导致额外的调用开销。 而短函数由于自动内联将快如闪电。 例如,对于无符号64位整数乘法溢出检测,当禁用内联时,除法所需的时间是长乘法的5倍,但允许自动内联后,除法所需的时间是长乘法的1/5。 - -请注意,在业务函数中使用 `//go:noinline` 不会影响本库函数的内联。 只有通过 `-gcflags="-l"` 禁用全局内联才会影响该本库函数的内联。 - -### 基于和依赖 - -该库基于Go的官方编译器实现和语言规范,其定义了整数溢出发生时的行为。 - -### 许可 - -[MIT LICENSE](./LICENSE.md) -