Patch for concurrent iterator & others (onto v1.11.6) #386

Closed
roysc wants to merge 1565 commits from v1.11.6-statediff-v5 into master
5 changed files with 101 additions and 47 deletions
Showing only changes of commit 32c576bd3c - Show all commits

View File

@ -379,7 +379,7 @@ func decodeByteArray(s *Stream, val reflect.Value) error {
if err != nil { if err != nil {
return err return err
} }
slice := byteArrayBytes(val) slice := byteArrayBytes(val, val.Len())
switch kind { switch kind {
case Byte: case Byte:
if len(slice) == 0 { if len(slice) == 0 {

View File

@ -432,7 +432,20 @@ func makeByteArrayWriter(typ reflect.Type) writer {
case 1: case 1:
return writeLengthOneByteArray return writeLengthOneByteArray
default: default:
return writeByteArray length := typ.Len()
return func(val reflect.Value, w *encbuf) error {
if !val.CanAddr() {
// Getting the byte slice of val requires it to be addressable. Make it
// addressable by copying.
copy := reflect.New(val.Type()).Elem()
copy.Set(val)
val = copy
}
slice := byteArrayBytes(val, length)
w.encodeStringHeader(len(slice))
w.str = append(w.str, slice...)
return nil
}
} }
} }
@ -451,21 +464,6 @@ func writeLengthOneByteArray(val reflect.Value, w *encbuf) error {
return nil return nil
} }
func writeByteArray(val reflect.Value, w *encbuf) error {
if !val.CanAddr() {
// Getting the byte slice of val requires it to be addressable. Make it
// addressable by copying.
copy := reflect.New(val.Type()).Elem()
copy.Set(val)
val = copy
}
slice := byteArrayBytes(val)
w.encodeStringHeader(len(slice))
w.str = append(w.str, slice...)
return nil
}
func writeString(val reflect.Value, w *encbuf) error { func writeString(val reflect.Value, w *encbuf) error {
s := val.String() s := val.String()
if len(s) == 1 && s[0] <= 0x7f { if len(s) == 1 && s[0] <= 0x7f {
@ -499,10 +497,12 @@ func makeSliceWriter(typ reflect.Type, ts tags) (writer, error) {
if etypeinfo.writerErr != nil { if etypeinfo.writerErr != nil {
return nil, etypeinfo.writerErr return nil, etypeinfo.writerErr
} }
writer := func(val reflect.Value, w *encbuf) error {
if !ts.tail { var wfn writer
defer w.listEnd(w.list()) if ts.tail {
} // This is for struct tail slices.
// w.list is not called for them.
wfn = func(val reflect.Value, w *encbuf) error {
vlen := val.Len() vlen := val.Len()
for i := 0; i < vlen; i++ { for i := 0; i < vlen; i++ {
if err := etypeinfo.writer(val.Index(i), w); err != nil { if err := etypeinfo.writer(val.Index(i), w); err != nil {
@ -511,7 +511,25 @@ func makeSliceWriter(typ reflect.Type, ts tags) (writer, error) {
} }
return nil return nil
} }
return writer, nil } else {
// This is for regular slices and arrays.
wfn = func(val reflect.Value, w *encbuf) error {
vlen := val.Len()
if vlen == 0 {
w.str = append(w.str, 0xC0)
return nil
}
listOffset := w.list()
for i := 0; i < vlen; i++ {
if err := etypeinfo.writer(val.Index(i), w); err != nil {
return err
}
}
w.listEnd(listOffset)
return nil
}
}
return wfn, nil
} }
func makeStructWriter(typ reflect.Type) (writer, error) { func makeStructWriter(typ reflect.Type) (writer, error) {
@ -562,12 +580,8 @@ func makeStructWriter(typ reflect.Type) (writer, error) {
return writer, nil return writer, nil
} }
func makePtrWriter(typ reflect.Type, ts tags) (writer, error) { // nilEncoding returns the encoded value of a nil pointer.
etypeinfo := theTC.infoWhileGenerating(typ.Elem(), tags{}) func nilEncoding(typ reflect.Type, ts tags) uint8 {
if etypeinfo.writerErr != nil {
return nil, etypeinfo.writerErr
}
// Determine how to encode nil pointers.
var nilKind Kind var nilKind Kind
if ts.nilOK { if ts.nilOK {
nilKind = ts.nilKind // use struct tag if provided nilKind = ts.nilKind // use struct tag if provided
@ -575,17 +589,30 @@ func makePtrWriter(typ reflect.Type, ts tags) (writer, error) {
nilKind = defaultNilKind(typ.Elem()) nilKind = defaultNilKind(typ.Elem())
} }
switch nilKind {
case String:
return 0x80
case List:
return 0xC0
default:
panic(fmt.Errorf("rlp: invalid nil kind %d", nilKind))
}
}
func makePtrWriter(typ reflect.Type, ts tags) (writer, error) {
etypeinfo := theTC.infoWhileGenerating(typ.Elem(), tags{})
if etypeinfo.writerErr != nil {
return nil, etypeinfo.writerErr
}
nilEncoding := nilEncoding(typ, ts)
writer := func(val reflect.Value, w *encbuf) error { writer := func(val reflect.Value, w *encbuf) error {
if val.IsNil() { if ev := val.Elem(); ev.IsValid() {
if nilKind == String { return etypeinfo.writer(ev, w)
w.str = append(w.str, 0x80)
} else {
w.listEnd(w.list())
} }
w.str = append(w.str, nilEncoding)
return nil return nil
} }
return etypeinfo.writer(val.Elem(), w)
}
return writer, nil return writer, nil
} }

View File

@ -540,3 +540,31 @@ func BenchmarkEncodeByteArrayStruct(b *testing.B) {
} }
} }
} }
type structSliceElem struct {
X uint64
Y uint64
Z uint64
}
type structPtrSlice []*structSliceElem
func BenchmarkEncodeStructPtrSlice(b *testing.B) {
var out bytes.Buffer
var value = structPtrSlice{
&structSliceElem{1, 1, 1},
&structSliceElem{2, 2, 2},
&structSliceElem{3, 3, 3},
&structSliceElem{5, 5, 5},
&structSliceElem{6, 6, 6},
&structSliceElem{7, 7, 7},
}
b.ReportAllocs()
for i := 0; i < b.N; i++ {
out.Reset()
if err := Encode(&out, &value); err != nil {
b.Fatal(err)
}
}
}

View File

@ -22,6 +22,6 @@ package rlp
import "reflect" import "reflect"
// byteArrayBytes returns a slice of the byte array v. // byteArrayBytes returns a slice of the byte array v.
func byteArrayBytes(v reflect.Value) []byte { func byteArrayBytes(v reflect.Value, length int) []byte {
return v.Slice(0, v.Len()).Bytes() return v.Slice(0, length).Bytes()
} }

View File

@ -25,12 +25,11 @@ import (
) )
// byteArrayBytes returns a slice of the byte array v. // byteArrayBytes returns a slice of the byte array v.
func byteArrayBytes(v reflect.Value) []byte { func byteArrayBytes(v reflect.Value, length int) []byte {
len := v.Len()
var s []byte var s []byte
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s)) hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))
hdr.Data = v.UnsafeAddr() hdr.Data = v.UnsafeAddr()
hdr.Cap = len hdr.Cap = length
hdr.Len = len hdr.Len = length
return s return s
} }