stackitem: make BigInteger alias to big.Int

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 <evgeniy@nspcc.ru>
This commit is contained in:
Evgeniy Stratonikov 2021-08-04 16:41:13 +03:00
parent cff8b1c24e
commit a5516e8c96
3 changed files with 42 additions and 61 deletions

View file

@ -2,7 +2,6 @@ package stackitem
import ( import (
"bytes" "bytes"
"encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
@ -90,33 +89,17 @@ func mkInvConversion(from Item, to Type) error {
func Make(v interface{}) Item { func Make(v interface{}) Item {
switch val := v.(type) { switch val := v.(type) {
case int: case int:
return &BigInteger{ return (*BigInteger)(big.NewInt(int64(val)))
value: big.NewInt(int64(val)),
}
case int64: case int64:
return &BigInteger{ return (*BigInteger)(big.NewInt(val))
value: big.NewInt(val),
}
case uint8: case uint8:
return &BigInteger{ return (*BigInteger)(big.NewInt(int64(val)))
value: big.NewInt(int64(val)),
}
case uint16: case uint16:
return &BigInteger{ return (*BigInteger)(big.NewInt(int64(val)))
value: big.NewInt(int64(val)),
}
case uint32: case uint32:
return &BigInteger{ return (*BigInteger)(big.NewInt(int64(val)))
value: big.NewInt(int64(val)),
}
case uint64: case uint64:
b := make([]byte, 8) return (*BigInteger)(new(big.Int).SetUint64(val))
binary.BigEndian.PutUint64(b, val)
bigInt := big.NewInt(0)
bigInt.SetBytes(b)
return &BigInteger{
value: bigInt,
}
case []byte: case []byte:
return &ByteArray{ return &ByteArray{
value: val, value: val,
@ -400,9 +383,7 @@ func (i Null) Convert(typ Type) (Item, error) {
} }
// BigInteger represents a big integer on the stack. // BigInteger represents a big integer on the stack.
type BigInteger struct { type BigInteger big.Int
value *big.Int
}
// NewBigInteger returns an new BigInteger object. // NewBigInteger returns an new BigInteger object.
func NewBigInteger(value *big.Int) *BigInteger { func NewBigInteger(value *big.Int) *BigInteger {
@ -418,19 +399,22 @@ func NewBigInteger(value *big.Int) *BigInteger {
panic(errTooBigInteger) panic(errTooBigInteger)
} }
} }
return &BigInteger{ return (*BigInteger)(value)
value: 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. // Bytes converts i to a slice of bytes.
func (i *BigInteger) Bytes() []byte { func (i *BigInteger) Bytes() []byte {
return bigint.ToBytes(i.value) return bigint.ToBytes(i.Big())
} }
// TryBool implements Item interface. // TryBool implements Item interface.
func (i *BigInteger) TryBool() (bool, error) { func (i *BigInteger) TryBool() (bool, error) {
return i.value.Sign() != 0, nil return i.Big().Sign() != 0, nil
} }
// TryBytes implements Item interface. // TryBytes implements Item interface.
@ -440,7 +424,7 @@ func (i *BigInteger) TryBytes() ([]byte, error) {
// TryInteger implements Item interface. // TryInteger implements Item interface.
func (i *BigInteger) TryInteger() (*big.Int, error) { func (i *BigInteger) TryInteger() (*big.Int, error) {
return i.value, nil return i.Big(), nil
} }
// Equals implements Item interface. // Equals implements Item interface.
@ -451,12 +435,12 @@ func (i *BigInteger) Equals(s Item) bool {
return false return false
} }
val, ok := s.(*BigInteger) val, ok := s.(*BigInteger)
return ok && i.value.Cmp(val.value) == 0 return ok && i.Big().Cmp(val.Big()) == 0
} }
// Value implements Item interface. // Value implements Item interface.
func (i *BigInteger) Value() interface{} { func (i *BigInteger) Value() interface{} {
return i.value return i.Big()
} }
func (i *BigInteger) String() string { func (i *BigInteger) String() string {
@ -466,7 +450,7 @@ func (i *BigInteger) String() string {
// Dup implements Item interface. // Dup implements Item interface.
func (i *BigInteger) Dup() Item { func (i *BigInteger) Dup() Item {
n := new(big.Int) n := new(big.Int)
return &BigInteger{n.Set(i.value)} return (*BigInteger)(n.Set(i.Big()))
} }
// Type implements Item interface. // Type implements Item interface.
@ -479,7 +463,7 @@ func (i *BigInteger) Convert(typ Type) (Item, error) {
// MarshalJSON implements the json.Marshaler interface. // MarshalJSON implements the json.Marshaler interface.
func (i *BigInteger) MarshalJSON() ([]byte, error) { func (i *BigInteger) MarshalJSON() ([]byte, error) {
return json.Marshal(i.value) return json.Marshal(i.Big())
} }
// Bool represents a boolean Item. // Bool represents a boolean Item.
@ -1156,11 +1140,8 @@ func deepCopy(item Item, seen map[Item]Item) Item {
} }
return m return m
case *BigInteger: case *BigInteger:
bi := new(big.Int).SetBytes(it.value.Bytes()) bi := new(big.Int).Set(it.Big())
if it.value.Sign() == -1 { return (*BigInteger)(bi)
bi.Neg(bi)
}
return NewBigInteger(bi)
case *ByteArray: case *ByteArray:
return NewByteArray(slice.Copy(it.value)) return NewByteArray(slice.Copy(it.value))
case *Buffer: case *Buffer:

View file

@ -15,35 +15,35 @@ var makeStackItemTestCases = []struct {
}{ }{
{ {
input: int64(3), input: int64(3),
result: &BigInteger{value: big.NewInt(3)}, result: (*BigInteger)(big.NewInt(3)),
}, },
{ {
input: int16(3), input: int16(3),
result: &BigInteger{value: big.NewInt(3)}, result: (*BigInteger)(big.NewInt(3)),
}, },
{ {
input: 3, input: 3,
result: &BigInteger{value: big.NewInt(3)}, result: (*BigInteger)(big.NewInt(3)),
}, },
{ {
input: uint8(3), input: uint8(3),
result: &BigInteger{value: big.NewInt(3)}, result: (*BigInteger)(big.NewInt(3)),
}, },
{ {
input: uint16(3), input: uint16(3),
result: &BigInteger{value: big.NewInt(3)}, result: (*BigInteger)(big.NewInt(3)),
}, },
{ {
input: uint32(3), input: uint32(3),
result: &BigInteger{value: big.NewInt(3)}, result: (*BigInteger)(big.NewInt(3)),
}, },
{ {
input: uint64(3), input: uint64(3),
result: &BigInteger{value: big.NewInt(3)}, result: (*BigInteger)(big.NewInt(3)),
}, },
{ {
input: big.NewInt(3), input: big.NewInt(3),
result: &BigInteger{value: big.NewInt(3)}, result: (*BigInteger)(big.NewInt(3)),
}, },
{ {
input: []byte{1, 2, 3, 4}, input: []byte{1, 2, 3, 4},
@ -70,12 +70,12 @@ var makeStackItemTestCases = []struct {
result: Bool(false), result: Bool(false),
}, },
{ {
input: []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{value: 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}, 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, result: false,
}, },
{ {
item1: 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)}}), item2: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}),
result: false, result: false,
}, },
{ {
item1: NewArray([]Item{&BigInteger{big.NewInt(1)}}), item1: NewArray([]Item{(*BigInteger)(big.NewInt(1))}),
item2: NewBigInteger(big.NewInt(1)), item2: NewBigInteger(big.NewInt(1)),
result: false, result: false,
}, },
{ {
item1: 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(4)}}), item2: NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(4))}),
result: false, result: false,
}, },
}, },
@ -441,7 +441,7 @@ var marshalJSONTestCases = []struct {
result: []byte(`"010203"`), 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"]`), result: []byte(`[3,"010203"]`),
}, },
{ {

View file

@ -110,10 +110,10 @@ func toJSON(data []byte, seen map[Item]sliceNoPointer, item Item) ([]byte, error
data = append(data, '}') data = append(data, '}')
seen[item] = sliceNoPointer{start, len(data)} seen[item] = sliceNoPointer{start, len(data)}
case *BigInteger: 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) return nil, fmt.Errorf("%w (MaxAllowedInteger)", ErrInvalidValue)
} }
data = append(data, it.value.String()...) data = append(data, it.Big().String()...)
case *ByteArray, *Buffer: case *ByteArray, *Buffer:
raw, err := itemToJSONString(it) raw, err := itemToJSONString(it)
if err != nil { if err != nil {
@ -293,7 +293,7 @@ func toJSONWithTypes(item Item, seen map[Item]bool) (interface{}, error) {
case *Buffer, *ByteArray: case *Buffer, *ByteArray:
value = base64.StdEncoding.EncodeToString(it.Value().([]byte)) value = base64.StdEncoding.EncodeToString(it.Value().([]byte))
case *BigInteger: case *BigInteger:
value = it.value.String() value = it.Big().String()
case *Map: case *Map:
if seen[item] { if seen[item] {
return "", ErrRecursive return "", ErrRecursive