forked from TrueCloudLab/neoneo-go
stackitem: cache serialized results in EncodeBinary
``` name old time/op new time/op delta EncodeBinary-8 8.39ms ± 1% 0.05ms ±21% -99.44% (p=0.000 n=10+9) name old alloc/op new alloc/op delta EncodeBinary-8 2.24MB ± 0% 0.33MB ± 0% -85.29% (p=0.000 n=9+10) name old allocs/op new allocs/op delta EncodeBinary-8 65.6k ± 0% 0.0k ± 0% -99.95% (p=0.000 n=10+10) ``` Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
17a3f17c74
commit
8fdc7e32f5
1 changed files with 17 additions and 9 deletions
|
@ -22,14 +22,14 @@ type serContext struct {
|
||||||
uv [9]byte
|
uv [9]byte
|
||||||
data []byte
|
data []byte
|
||||||
allowInvalid bool
|
allowInvalid bool
|
||||||
seen map[Item]bool
|
seen map[Item]sliceNoPointer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize encodes given Item into the byte slice.
|
// Serialize encodes given Item into the byte slice.
|
||||||
func Serialize(item Item) ([]byte, error) {
|
func Serialize(item Item) ([]byte, error) {
|
||||||
sc := serContext{
|
sc := serContext{
|
||||||
allowInvalid: false,
|
allowInvalid: false,
|
||||||
seen: make(map[Item]bool),
|
seen: make(map[Item]sliceNoPointer),
|
||||||
}
|
}
|
||||||
err := sc.serialize(item)
|
err := sc.serialize(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,7 +58,7 @@ func EncodeBinary(item Item, w *io.BinWriter) {
|
||||||
func EncodeBinaryProtected(item Item, w *io.BinWriter) {
|
func EncodeBinaryProtected(item Item, w *io.BinWriter) {
|
||||||
sc := serContext{
|
sc := serContext{
|
||||||
allowInvalid: true,
|
allowInvalid: true,
|
||||||
seen: make(map[Item]bool),
|
seen: make(map[Item]sliceNoPointer),
|
||||||
}
|
}
|
||||||
err := sc.serialize(item)
|
err := sc.serialize(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -69,10 +69,18 @@ func EncodeBinaryProtected(item Item, w *io.BinWriter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *serContext) serialize(item Item) error {
|
func (w *serContext) serialize(item Item) error {
|
||||||
if w.seen[item] {
|
if v, ok := w.seen[item]; ok {
|
||||||
return ErrRecursive
|
if v.start == v.end {
|
||||||
|
return ErrRecursive
|
||||||
|
}
|
||||||
|
if len(w.data)+v.end-v.start > MaxSize {
|
||||||
|
return ErrTooBig
|
||||||
|
}
|
||||||
|
w.data = append(w.data, w.data[v.start:v.end]...)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start := len(w.data)
|
||||||
switch t := item.(type) {
|
switch t := item.(type) {
|
||||||
case *ByteArray:
|
case *ByteArray:
|
||||||
w.data = append(w.data, byte(ByteArrayT))
|
w.data = append(w.data, byte(ByteArrayT))
|
||||||
|
@ -103,7 +111,7 @@ func (w *serContext) serialize(item Item) error {
|
||||||
return fmt.Errorf("%w: Interop", ErrUnserializable)
|
return fmt.Errorf("%w: Interop", ErrUnserializable)
|
||||||
}
|
}
|
||||||
case *Array, *Struct:
|
case *Array, *Struct:
|
||||||
w.seen[item] = true
|
w.seen[item] = sliceNoPointer{}
|
||||||
|
|
||||||
_, isArray := t.(*Array)
|
_, isArray := t.(*Array)
|
||||||
if isArray {
|
if isArray {
|
||||||
|
@ -119,9 +127,9 @@ func (w *serContext) serialize(item Item) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(w.seen, item)
|
w.seen[item] = sliceNoPointer{start, len(w.data)}
|
||||||
case *Map:
|
case *Map:
|
||||||
w.seen[item] = true
|
w.seen[item] = sliceNoPointer{}
|
||||||
|
|
||||||
elems := t.Value().([]MapElement)
|
elems := t.Value().([]MapElement)
|
||||||
w.data = append(w.data, byte(MapT))
|
w.data = append(w.data, byte(MapT))
|
||||||
|
@ -134,7 +142,7 @@ func (w *serContext) serialize(item Item) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(w.seen, item)
|
w.seen[item] = sliceNoPointer{start, len(w.data)}
|
||||||
case Null:
|
case Null:
|
||||||
w.data = append(w.data, byte(AnyT))
|
w.data = append(w.data, byte(AnyT))
|
||||||
case nil:
|
case nil:
|
||||||
|
|
Loading…
Reference in a new issue