From a5516e8c96a9203547f17c5d4a9186ae4dc8ab2b Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Wed, 4 Aug 2021 16:41:13 +0300 Subject: [PATCH] stackitem: make `BigInteger` alias to `big.Int` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove one indirection step. `` name old time/op new time/op delta MakeInt-8 79.7ns ± 8% 56.2ns ± 8% -29.44% (p=0.000 n=10+10) name old alloc/op new alloc/op delta MakeInt-8 48.0B ± 0% 40.0B ± 0% -16.67% (p=0.000 n=10+10) name old allocs/op new allocs/op delta MakeInt-8 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=10+10) ``` Signed-off-by: Evgeniy Stratonikov --- pkg/vm/stackitem/item.go | 63 ++++++++++++----------------------- pkg/vm/stackitem/item_test.go | 34 +++++++++---------- pkg/vm/stackitem/json.go | 6 ++-- 3 files changed, 42 insertions(+), 61 deletions(-) diff --git a/pkg/vm/stackitem/item.go b/pkg/vm/stackitem/item.go index f042c0c77..a57dfb30d 100644 --- a/pkg/vm/stackitem/item.go +++ b/pkg/vm/stackitem/item.go @@ -2,7 +2,6 @@ package stackitem import ( "bytes" - "encoding/binary" "encoding/hex" "encoding/json" "errors" @@ -90,33 +89,17 @@ func mkInvConversion(from Item, to Type) error { func Make(v interface{}) Item { switch val := v.(type) { case int: - return &BigInteger{ - value: big.NewInt(int64(val)), - } + return (*BigInteger)(big.NewInt(int64(val))) case int64: - return &BigInteger{ - value: big.NewInt(val), - } + return (*BigInteger)(big.NewInt(val)) case uint8: - return &BigInteger{ - value: big.NewInt(int64(val)), - } + return (*BigInteger)(big.NewInt(int64(val))) case uint16: - return &BigInteger{ - value: big.NewInt(int64(val)), - } + return (*BigInteger)(big.NewInt(int64(val))) case uint32: - return &BigInteger{ - value: big.NewInt(int64(val)), - } + return (*BigInteger)(big.NewInt(int64(val))) case uint64: - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, val) - bigInt := big.NewInt(0) - bigInt.SetBytes(b) - return &BigInteger{ - value: bigInt, - } + return (*BigInteger)(new(big.Int).SetUint64(val)) case []byte: return &ByteArray{ value: val, @@ -400,9 +383,7 @@ func (i Null) Convert(typ Type) (Item, error) { } // BigInteger represents a big integer on the stack. -type BigInteger struct { - value *big.Int -} +type BigInteger big.Int // NewBigInteger returns an new BigInteger object. func NewBigInteger(value *big.Int) *BigInteger { @@ -418,19 +399,22 @@ func NewBigInteger(value *big.Int) *BigInteger { panic(errTooBigInteger) } } - return &BigInteger{ - value: value, - } + return (*BigInteger)(value) +} + +// Big casts i to the big.Int type. +func (i *BigInteger) Big() *big.Int { + return (*big.Int)(i) } // Bytes converts i to a slice of bytes. func (i *BigInteger) Bytes() []byte { - return bigint.ToBytes(i.value) + return bigint.ToBytes(i.Big()) } // TryBool implements Item interface. func (i *BigInteger) TryBool() (bool, error) { - return i.value.Sign() != 0, nil + return i.Big().Sign() != 0, nil } // TryBytes implements Item interface. @@ -440,7 +424,7 @@ func (i *BigInteger) TryBytes() ([]byte, error) { // TryInteger implements Item interface. func (i *BigInteger) TryInteger() (*big.Int, error) { - return i.value, nil + return i.Big(), nil } // Equals implements Item interface. @@ -451,12 +435,12 @@ func (i *BigInteger) Equals(s Item) bool { return false } val, ok := s.(*BigInteger) - return ok && i.value.Cmp(val.value) == 0 + return ok && i.Big().Cmp(val.Big()) == 0 } // Value implements Item interface. func (i *BigInteger) Value() interface{} { - return i.value + return i.Big() } func (i *BigInteger) String() string { @@ -466,7 +450,7 @@ func (i *BigInteger) String() string { // Dup implements Item interface. func (i *BigInteger) Dup() Item { n := new(big.Int) - return &BigInteger{n.Set(i.value)} + return (*BigInteger)(n.Set(i.Big())) } // Type implements Item interface. @@ -479,7 +463,7 @@ func (i *BigInteger) Convert(typ Type) (Item, error) { // MarshalJSON implements the json.Marshaler interface. func (i *BigInteger) MarshalJSON() ([]byte, error) { - return json.Marshal(i.value) + return json.Marshal(i.Big()) } // Bool represents a boolean Item. @@ -1156,11 +1140,8 @@ func deepCopy(item Item, seen map[Item]Item) Item { } return m case *BigInteger: - bi := new(big.Int).SetBytes(it.value.Bytes()) - if it.value.Sign() == -1 { - bi.Neg(bi) - } - return NewBigInteger(bi) + bi := new(big.Int).Set(it.Big()) + return (*BigInteger)(bi) case *ByteArray: return NewByteArray(slice.Copy(it.value)) case *Buffer: diff --git a/pkg/vm/stackitem/item_test.go b/pkg/vm/stackitem/item_test.go index 61d961851..b6b877aec 100644 --- a/pkg/vm/stackitem/item_test.go +++ b/pkg/vm/stackitem/item_test.go @@ -15,35 +15,35 @@ var makeStackItemTestCases = []struct { }{ { input: int64(3), - result: &BigInteger{value: big.NewInt(3)}, + result: (*BigInteger)(big.NewInt(3)), }, { input: int16(3), - result: &BigInteger{value: big.NewInt(3)}, + result: (*BigInteger)(big.NewInt(3)), }, { input: 3, - result: &BigInteger{value: big.NewInt(3)}, + result: (*BigInteger)(big.NewInt(3)), }, { input: uint8(3), - result: &BigInteger{value: big.NewInt(3)}, + result: (*BigInteger)(big.NewInt(3)), }, { input: uint16(3), - result: &BigInteger{value: big.NewInt(3)}, + result: (*BigInteger)(big.NewInt(3)), }, { input: uint32(3), - result: &BigInteger{value: big.NewInt(3)}, + result: (*BigInteger)(big.NewInt(3)), }, { input: uint64(3), - result: &BigInteger{value: big.NewInt(3)}, + result: (*BigInteger)(big.NewInt(3)), }, { input: big.NewInt(3), - result: &BigInteger{value: big.NewInt(3)}, + result: (*BigInteger)(big.NewInt(3)), }, { input: []byte{1, 2, 3, 4}, @@ -70,12 +70,12 @@ var makeStackItemTestCases = []struct { result: Bool(false), }, { - input: []Item{&BigInteger{value: big.NewInt(3)}, &ByteArray{value: []byte{1, 2, 3}}}, - result: &Array{value: []Item{&BigInteger{value: big.NewInt(3)}, &ByteArray{value: []byte{1, 2, 3}}}}, + input: []Item{(*BigInteger)(big.NewInt(3)), &ByteArray{value: []byte{1, 2, 3}}}, + result: &Array{value: []Item{(*BigInteger)(big.NewInt(3)), &ByteArray{value: []byte{1, 2, 3}}}}, }, { input: []int{1, 2, 3}, - result: &Array{value: []Item{&BigInteger{value: big.NewInt(1)}, &BigInteger{value: big.NewInt(2)}, &BigInteger{value: big.NewInt(3)}}}, + result: &Array{value: []Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}}, }, } @@ -281,18 +281,18 @@ var equalsTestCases = map[string][]struct { result: false, }, { - item1: NewArray([]Item{&BigInteger{big.NewInt(1)}, &BigInteger{big.NewInt(2)}, &BigInteger{big.NewInt(3)}}), - item2: NewArray([]Item{&BigInteger{big.NewInt(1)}, &BigInteger{big.NewInt(2)}, &BigInteger{big.NewInt(3)}}), + item1: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}), + item2: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}), result: false, }, { - item1: NewArray([]Item{&BigInteger{big.NewInt(1)}}), + item1: NewArray([]Item{(*BigInteger)(big.NewInt(1))}), item2: NewBigInteger(big.NewInt(1)), result: false, }, { - item1: NewArray([]Item{&BigInteger{big.NewInt(1)}, &BigInteger{big.NewInt(2)}, &BigInteger{big.NewInt(3)}}), - item2: NewArray([]Item{&BigInteger{big.NewInt(1)}, &BigInteger{big.NewInt(2)}, &BigInteger{big.NewInt(4)}}), + item1: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}), + item2: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(4))}), result: false, }, }, @@ -441,7 +441,7 @@ var marshalJSONTestCases = []struct { result: []byte(`"010203"`), }, { - input: &Array{value: []Item{&BigInteger{value: big.NewInt(3)}, &ByteArray{value: []byte{1, 2, 3}}}}, + input: &Array{value: []Item{(*BigInteger)(big.NewInt(3)), &ByteArray{value: []byte{1, 2, 3}}}}, result: []byte(`[3,"010203"]`), }, { diff --git a/pkg/vm/stackitem/json.go b/pkg/vm/stackitem/json.go index 5b346ada1..bb01076b0 100644 --- a/pkg/vm/stackitem/json.go +++ b/pkg/vm/stackitem/json.go @@ -110,10 +110,10 @@ func toJSON(data []byte, seen map[Item]sliceNoPointer, item Item) ([]byte, error data = append(data, '}') seen[item] = sliceNoPointer{start, len(data)} case *BigInteger: - if it.value.CmpAbs(big.NewInt(MaxAllowedInteger)) == 1 { + if it.Big().CmpAbs(big.NewInt(MaxAllowedInteger)) == 1 { return nil, fmt.Errorf("%w (MaxAllowedInteger)", ErrInvalidValue) } - data = append(data, it.value.String()...) + data = append(data, it.Big().String()...) case *ByteArray, *Buffer: raw, err := itemToJSONString(it) if err != nil { @@ -293,7 +293,7 @@ func toJSONWithTypes(item Item, seen map[Item]bool) (interface{}, error) { case *Buffer, *ByteArray: value = base64.StdEncoding.EncodeToString(it.Value().([]byte)) case *BigInteger: - value = it.value.String() + value = it.Big().String() case *Map: if seen[item] { return "", ErrRecursive