Merge PR #1388: types/int: Switch Int, Uint to use pointers internally

* types/int: Switch Int, Uint to use pointers internally
This reduces the amount of pointer refs & derefs.
* Fix nil pointers on unmarshalling amino
* Fix elusive bug in marshalling with unitialized big int
* Remove debug code
* Switch big.rat to use pointers internally
This commit is contained in:
Dev Ojha 2018-06-26 18:10:34 -07:00 committed by Christopher Goes
parent 9ca3a16bb3
commit d6df6b07d1
4 changed files with 95 additions and 66 deletions

View File

@ -26,6 +26,8 @@ FEATURES
* [tools] Add checking for misspellings and for incorrectly formatted files in circle CI
* [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates
* [tests] Add WaitForNextNBlocksTM helper method
* [types] Switches internal representation of Int/Uint/Rat to use pointers
* [gaiad] unsafe_reset_all now resets addrbook.json
FIXES
* \#1259 - fix bug where certain tests that could have a nil pointer in defer

View File

@ -60,17 +60,17 @@ func unmarshalJSON(i *big.Int, bz []byte) error {
// Checks overflow, underflow and division by zero
// Exists in range from -(2^255-1) to 2^255-1
type Int struct {
i big.Int
i *big.Int
}
// BigInt converts Int to big.Int
func (i Int) BigInt() *big.Int {
return new(big.Int).Set(&(i.i))
return new(big.Int).Set(i.i)
}
// NewInt constructs Int from int64
func NewInt(n int64) Int {
return Int{*big.NewInt(n)}
return Int{big.NewInt(n)}
}
// NewIntFromBigInt constructs Int from big.Int
@ -78,7 +78,7 @@ func NewIntFromBigInt(i *big.Int) Int {
if i.BitLen() > 255 {
panic("NewIntFromBigInt() out of bound")
}
return Int{*i}
return Int{i}
}
// NewIntFromString constructs Int from string
@ -92,7 +92,7 @@ func NewIntFromString(s string) (res Int, ok bool) {
ok = false
return
}
return Int{*i}, true
return Int{i}, true
}
// NewIntWithDecimal constructs Int with decimal
@ -103,14 +103,14 @@ func NewIntWithDecimal(n int64, dec int) Int {
if i.BitLen() > 255 {
panic("NewIntWithDecimal() out of bound")
}
return Int{*i}
return Int{i}
}
// ZeroInt returns Int value with zero
func ZeroInt() Int { return Int{*big.NewInt(0)} }
func ZeroInt() Int { return Int{big.NewInt(0)} }
// OneInt returns Int value with one
func OneInt() Int { return Int{*big.NewInt(1)} }
func OneInt() Int { return Int{big.NewInt(1)} }
// Int64 converts Int to int64
// Panics if the value is out of range
@ -133,22 +133,22 @@ func (i Int) Sign() int {
// Equal compares two Ints
func (i Int) Equal(i2 Int) bool {
return equal(&(i.i), &(i2.i))
return equal(i.i, i2.i)
}
// GT returns true if first Int is greater than second
func (i Int) GT(i2 Int) bool {
return gt((&i.i), &(i2.i))
return gt(i.i, i2.i)
}
// LT returns true if first Int is lesser than second
func (i Int) LT(i2 Int) bool {
return lt((&i.i), &(i2.i))
return lt(i.i, i2.i)
}
// Add adds Int from another
func (i Int) Add(i2 Int) (res Int) {
res = Int{*add(&(i.i), &(i2.i))}
res = Int{add(i.i, i2.i)}
// Check overflow
if res.i.BitLen() > 255 {
panic("Int overflow")
@ -163,7 +163,7 @@ func (i Int) AddRaw(i2 int64) Int {
// Sub subtracts Int from another
func (i Int) Sub(i2 Int) (res Int) {
res = Int{*sub(&(i.i), &(i2.i))}
res = Int{sub(i.i, i2.i)}
// Check overflow
if res.i.BitLen() > 255 {
panic("Int overflow")
@ -182,7 +182,7 @@ func (i Int) Mul(i2 Int) (res Int) {
if i.i.BitLen()+i2.i.BitLen()-1 > 255 {
panic("Int overflow")
}
res = Int{*mul(&(i.i), &(i2.i))}
res = Int{mul(i.i, i2.i)}
// Check overflow if sign of both are same
if res.i.BitLen() > 255 {
panic("Int overflow")
@ -201,7 +201,7 @@ func (i Int) Div(i2 Int) (res Int) {
if i2.i.Sign() == 0 {
panic("Division by zero")
}
return Int{*div(&(i.i), &(i2.i))}
return Int{div(i.i, i2.i)}
}
// DivRaw divides Int with int64
@ -211,46 +211,58 @@ func (i Int) DivRaw(i2 int64) Int {
// Neg negates Int
func (i Int) Neg() (res Int) {
return Int{*neg(&(i.i))}
return Int{neg(i.i)}
}
// MarshalAmino defines custom encoding scheme
func (i Int) MarshalAmino() (string, error) {
return marshalAmino(&(i.i))
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return marshalAmino(i.i)
}
// UnmarshalAmino defines custom decoding scheme
func (i *Int) UnmarshalAmino(text string) error {
return unmarshalAmino(&(i.i), text)
if i.i == nil { // Necessary since default Int initialization has i.i as nil
i.i = new(big.Int)
}
return unmarshalAmino(i.i, text)
}
// MarshalJSON defines custom encoding scheme
func (i Int) MarshalJSON() ([]byte, error) {
return marshalJSON(&(i.i))
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return marshalJSON(i.i)
}
// UnmarshalJSON defines custom decoding scheme
func (i *Int) UnmarshalJSON(bz []byte) error {
return unmarshalJSON(&(i.i), bz)
if i.i == nil { // Necessary since default Int initialization has i.i as nil
i.i = new(big.Int)
}
return unmarshalJSON(i.i, bz)
}
// Int wraps integer with 256 bit range bound
// Checks overflow, underflow and division by zero
// Exists in range from 0 to 2^256-1
type Uint struct {
i big.Int
i *big.Int
}
// BigInt converts Uint to big.Unt
func (i Uint) BigInt() *big.Int {
return new(big.Int).Set(&(i.i))
return new(big.Int).Set(i.i)
}
// NewUint constructs Uint from int64
func NewUint(n uint64) Uint {
i := new(big.Int)
i.SetUint64(n)
return Uint{*i}
return Uint{i}
}
// NewUintFromBigUint constructs Uint from big.Uint
@ -259,7 +271,7 @@ func NewUintFromBigInt(i *big.Int) Uint {
if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 {
panic("Uint overflow")
}
return Uint{*i}
return Uint{i}
}
// NewUintFromString constructs Uint from string
@ -273,7 +285,7 @@ func NewUintFromString(s string) (res Uint, ok bool) {
ok = false
return
}
return Uint{*i}, true
return Uint{i}, true
}
// NewUintWithDecimal constructs Uint with decimal
@ -284,14 +296,14 @@ func NewUintWithDecimal(n int64, dec int) Uint {
if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 {
panic("NewUintWithDecimal() out of bound")
}
return Uint{*i}
return Uint{i}
}
// ZeroUint returns Uint value with zero
func ZeroUint() Uint { return Uint{*big.NewInt(0)} }
func ZeroUint() Uint { return Uint{big.NewInt(0)} }
// OneUint returns Uint value with one
func OneUint() Uint { return Uint{*big.NewInt(1)} }
func OneUint() Uint { return Uint{big.NewInt(1)} }
// Uint64 converts Uint to uint64
// Panics if the value is out of range
@ -314,22 +326,22 @@ func (i Uint) Sign() int {
// Equal compares two Uints
func (i Uint) Equal(i2 Uint) bool {
return equal(&(i.i), &(i2.i))
return equal(i.i, i2.i)
}
// GT returns true if first Uint is greater than second
func (i Uint) GT(i2 Uint) bool {
return gt(&(i.i), &(i2.i))
return gt(i.i, i2.i)
}
// LT returns true if first Uint is lesser than second
func (i Uint) LT(i2 Uint) bool {
return lt(&(i.i), &(i2.i))
return lt(i.i, i2.i)
}
// Add adds Uint from another
func (i Uint) Add(i2 Uint) (res Uint) {
res = Uint{*add(&(i.i), &(i2.i))}
res = Uint{add(i.i, i2.i)}
// Check overflow
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
panic("Uint overflow")
@ -344,7 +356,7 @@ func (i Uint) AddRaw(i2 uint64) Uint {
// Sub subtracts Uint from another
func (i Uint) Sub(i2 Uint) (res Uint) {
res = Uint{*sub(&(i.i), &(i2.i))}
res = Uint{sub(i.i, i2.i)}
// Check overflow
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
panic("Uint overflow")
@ -363,7 +375,7 @@ func (i Uint) Mul(i2 Uint) (res Uint) {
if i.i.BitLen()+i2.i.BitLen()-1 > 256 {
panic("Uint overflow")
}
res = Uint{*mul(&(i.i), &(i2.i))}
res = Uint{mul(i.i, i2.i)}
// Check overflow
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
panic("Uint overflow")
@ -382,7 +394,7 @@ func (i Uint) Div(i2 Uint) (res Uint) {
if i2.Sign() == 0 {
panic("division-by-zero")
}
return Uint{*div(&(i.i), &(i2.i))}
return Uint{div(i.i, i2.i)}
}
// Div divides Uint with int64
@ -392,20 +404,32 @@ func (i Uint) DivRaw(i2 uint64) Uint {
// MarshalAmino defines custom encoding scheme
func (i Uint) MarshalAmino() (string, error) {
return marshalAmino(&(i.i))
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return marshalAmino(i.i)
}
// UnmarshalAmino defines custom decoding scheme
func (i *Uint) UnmarshalAmino(text string) error {
return unmarshalAmino(&(i.i), text)
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return unmarshalAmino(i.i, text)
}
// MarshalJSON defines custom encoding scheme
func (i Uint) MarshalJSON() ([]byte, error) {
return marshalJSON(&(i.i))
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return marshalJSON(i.i)
}
// UnmarshalJSON defines custom decoding scheme
func (i *Uint) UnmarshalJSON(bz []byte) error {
return unmarshalJSON(&(i.i), bz)
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return unmarshalJSON(i.i, bz)
}

View File

@ -18,20 +18,20 @@ import (
// we will panic unmarshalling into the
// nil embedded big.Rat
type Rat struct {
big.Rat `json:"rat"`
*big.Rat `json:"rat"`
}
// nolint - common values
func ZeroRat() Rat { return Rat{*big.NewRat(0, 1)} }
func OneRat() Rat { return Rat{*big.NewRat(1, 1)} }
func ZeroRat() Rat { return Rat{big.NewRat(0, 1)} }
func OneRat() Rat { return Rat{big.NewRat(1, 1)} }
// New - create a new Rat from integers
func NewRat(Numerator int64, Denominator ...int64) Rat {
switch len(Denominator) {
case 0:
return Rat{*big.NewRat(Numerator, 1)}
return Rat{big.NewRat(Numerator, 1)}
case 1:
return Rat{*big.NewRat(Numerator, Denominator[0])}
return Rat{big.NewRat(Numerator, Denominator[0])}
default:
panic("improper use of New, can only have one denominator")
}
@ -84,9 +84,9 @@ func NewRatFromDecimal(decimalStr string) (f Rat, err Error) {
func NewRatFromBigInt(num *big.Int, denom ...*big.Int) Rat {
switch len(denom) {
case 0:
return Rat{*new(big.Rat).SetInt(num)}
return Rat{new(big.Rat).SetInt(num)}
case 1:
return Rat{*new(big.Rat).SetFrac(num, denom[0])}
return Rat{new(big.Rat).SetFrac(num, denom[0])}
default:
panic("improper use of NewRatFromBigInt, can only have one denominator")
}
@ -96,26 +96,26 @@ func NewRatFromBigInt(num *big.Int, denom ...*big.Int) Rat {
func NewRatFromInt(num Int, denom ...Int) Rat {
switch len(denom) {
case 0:
return Rat{*new(big.Rat).SetInt(num.BigInt())}
return Rat{new(big.Rat).SetInt(num.BigInt())}
case 1:
return Rat{*new(big.Rat).SetFrac(num.BigInt(), denom[0].BigInt())}
return Rat{new(big.Rat).SetFrac(num.BigInt(), denom[0].BigInt())}
default:
panic("improper use of NewRatFromBigInt, can only have one denominator")
}
}
//nolint
func (r Rat) Num() int64 { return r.Rat.Num().Int64() } // Num - return the numerator
func (r Rat) Denom() int64 { return r.Rat.Denom().Int64() } // Denom - return the denominator
func (r Rat) IsZero() bool { return r.Num() == 0 } // IsZero - Is the Rat equal to zero
func (r Rat) Equal(r2 Rat) bool { return (&(r.Rat)).Cmp(&(r2.Rat)) == 0 }
func (r Rat) GT(r2 Rat) bool { return (&(r.Rat)).Cmp(&(r2.Rat)) == 1 } // greater than
func (r Rat) LT(r2 Rat) bool { return (&(r.Rat)).Cmp(&(r2.Rat)) == -1 } // less than
func (r Rat) Mul(r2 Rat) Rat { return Rat{*new(big.Rat).Mul(&(r.Rat), &(r2.Rat))} } // Mul - multiplication
func (r Rat) Quo(r2 Rat) Rat { return Rat{*new(big.Rat).Quo(&(r.Rat), &(r2.Rat))} } // Quo - quotient
func (r Rat) Add(r2 Rat) Rat { return Rat{*new(big.Rat).Add(&(r.Rat), &(r2.Rat))} } // Add - addition
func (r Rat) Sub(r2 Rat) Rat { return Rat{*new(big.Rat).Sub(&(r.Rat), &(r2.Rat))} } // Sub - subtraction
func (r Rat) String() string { return r.Rat.String() }
func (r Rat) Num() int64 { return r.Rat.Num().Int64() } // Num - return the numerator
func (r Rat) Denom() int64 { return r.Rat.Denom().Int64() } // Denom - return the denominator
func (r Rat) IsZero() bool { return r.Num() == 0 } // IsZero - Is the Rat equal to zero
func (r Rat) Equal(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == 0 }
func (r Rat) GT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == 1 } // greater than
func (r Rat) LT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == -1 } // less than
func (r Rat) Mul(r2 Rat) Rat { return Rat{new(big.Rat).Mul(r.Rat, r2.Rat)} } // Mul - multiplication
func (r Rat) Quo(r2 Rat) Rat { return Rat{new(big.Rat).Quo(r.Rat, r2.Rat)} } // Quo - quotient
func (r Rat) Add(r2 Rat) Rat { return Rat{new(big.Rat).Add(r.Rat, r2.Rat)} } // Add - addition
func (r Rat) Sub(r2 Rat) Rat { return Rat{new(big.Rat).Sub(r.Rat, r2.Rat)} } // Sub - subtraction
func (r Rat) String() string { return r.Rat.String() }
func (r Rat) FloatString() string { return r.Rat.FloatString(10) } // a human-friendly string format. The last digit is rounded to nearest, with halves rounded away from zero.
var (
@ -169,8 +169,8 @@ func (r Rat) EvaluateInt() Int {
// round Rat with the provided precisionFactor
func (r Rat) Round(precisionFactor int64) Rat {
rTen := Rat{*new(big.Rat).Mul(&(r.Rat), big.NewRat(precisionFactor, 1))}
return Rat{*big.NewRat(rTen.Evaluate(), precisionFactor)}
rTen := Rat{new(big.Rat).Mul(r.Rat, big.NewRat(precisionFactor, 1))}
return Rat{big.NewRat(rTen.Evaluate(), precisionFactor)}
}
// TODO panic if negative or if totalDigits < len(initStr)???
@ -185,7 +185,10 @@ func (r Rat) ToLeftPadded(totalDigits int8) string {
//Wraps r.MarshalText().
func (r Rat) MarshalAmino() (string, error) {
bz, err := (&(r.Rat)).MarshalText()
if r.Rat == nil {
r.Rat = new(big.Rat)
}
bz, err := r.Rat.MarshalText()
return string(bz), err
}
@ -196,7 +199,7 @@ func (r *Rat) UnmarshalAmino(text string) (err error) {
if err != nil {
return err
}
r.Rat = *tempRat
r.Rat = tempRat
return nil
}

View File

@ -180,8 +180,8 @@ func TestRound(t *testing.T) {
precFactor int64
}{
{NewRat(333, 777), NewRat(429, 1000), 1000},
{Rat{*new(big.Rat).SetFrac(big3, big7)}, NewRat(429, 1000), 1000},
{Rat{*new(big.Rat).SetFrac(big3, big7)}, Rat{*big.NewRat(4285714286, 10000000000)}, 10000000000},
{Rat{new(big.Rat).SetFrac(big3, big7)}, NewRat(429, 1000), 1000},
{Rat{new(big.Rat).SetFrac(big3, big7)}, Rat{big.NewRat(4285714286, 10000000000)}, 10000000000},
{NewRat(1, 2), NewRat(1, 2), 1000},
}
@ -229,7 +229,7 @@ func TestSerializationText(t *testing.T) {
bz, err := r.MarshalText()
require.NoError(t, err)
var r2 Rat
var r2 Rat = Rat{new(big.Rat)}
err = r2.UnmarshalText(bz)
require.NoError(t, err)
assert.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2)