mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 19:17:38 +08:00
jce: speed up read
don't use bytes.Buffer to inline more functions name old time/op new time/op delta JceReader_ReadSlice-8 614µs ±68% 523µs ±70% ~ (p=0.690 n=5+5) RequestDataVersion2_ReadFrom-8 3.98µs ± 1% 3.54µs ± 2% -10.96% (p=0.008 n=5+5) name old speed new speed delta JceReader_ReadSlice-8 104MB/s ± 7% 121MB/s ± 2% +16.68% (p=0.008 n=5+5) RequestDataVersion2_ReadFrom-8 23.4MB/s ± 1% 26.3MB/s ± 2% +12.33% (p=0.008 n=5+5) name old alloc/op new alloc/op delta JceReader_ReadSlice-8 196kB ±67% 184kB ±67% ~ (p=0.690 n=5+5) RequestDataVersion2_ReadFrom-8 2.59kB ± 0% 2.62kB ± 0% +1.04% (p=0.008 n=5+5) name old allocs/op new allocs/op delta JceReader_ReadSlice-8 9.02k ±67% 9.02k ±67% ~ (p=1.000 n=5+5) RequestDataVersion2_ReadFrom-8 46.0 ± 0% 44.0 ± 0% -4.35% (p=0.008 n=5+5)
This commit is contained in:
parent
43b23f4e6f
commit
97dcddb6d4
@ -1,15 +1,16 @@
|
|||||||
package jce
|
package jce
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
goBinary "encoding/binary"
|
goBinary "encoding/binary"
|
||||||
"io"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JceReader struct {
|
type JceReader struct {
|
||||||
buf *bytes.Reader
|
buf []byte
|
||||||
|
off int
|
||||||
}
|
}
|
||||||
|
|
||||||
type HeadData struct {
|
type HeadData struct {
|
||||||
@ -18,25 +19,26 @@ type HeadData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewJceReader(data []byte) *JceReader {
|
func NewJceReader(data []byte) *JceReader {
|
||||||
buf := bytes.NewReader(data)
|
return &JceReader{buf: data}
|
||||||
return &JceReader{buf: buf}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) readHead() (hd HeadData, l int32) {
|
func (r *JceReader) readHead() (hd HeadData, l int32) {
|
||||||
b, _ := r.buf.ReadByte()
|
b := r.buf[r.off]
|
||||||
hd.Type = b & 0xF
|
hd.Type = b & 0xF
|
||||||
hd.Tag = (int(b) & 0xF0) >> 4
|
hd.Tag = (int(b) & 0xF0) >> 4
|
||||||
|
l = 1
|
||||||
if hd.Tag == 15 {
|
if hd.Tag == 15 {
|
||||||
b, _ = r.buf.ReadByte()
|
b = r.buf[r.off+1]
|
||||||
hd.Tag = int(b) & 0xFF
|
hd.Tag = int(b) & 0xFF
|
||||||
return hd, 2
|
l = 2
|
||||||
}
|
}
|
||||||
return hd, 1
|
r.off += int(l)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) peakHead() (h HeadData, l int32) {
|
func (r *JceReader) peakHead() (h HeadData, l int32) {
|
||||||
h, l = r.readHead()
|
h, l = r.readHead()
|
||||||
_, _ = r.buf.Seek(int64(-l), io.SeekCurrent)
|
r.off -= int(l)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +57,7 @@ func (r *JceReader) skipField(t byte) {
|
|||||||
case 3, 5:
|
case 3, 5:
|
||||||
r.skip(8)
|
r.skip(8)
|
||||||
case 6:
|
case 6:
|
||||||
b, _ := r.buf.ReadByte()
|
b := r.readByte()
|
||||||
r.skip(int(b))
|
r.skip(int(b))
|
||||||
case 7:
|
case 7:
|
||||||
r.skip(int(r.readInt32()))
|
r.skip(int(r.readInt32()))
|
||||||
@ -89,33 +91,28 @@ func (r *JceReader) SkipField(c int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) readBytes(len int) []byte {
|
func (r *JceReader) readBytes(n int) []byte {
|
||||||
if len == 0 {
|
if r.off+n > len(r.buf) {
|
||||||
return nil
|
panic("readBytes: EOF")
|
||||||
}
|
|
||||||
b := make([]byte, len)
|
|
||||||
_, err := r.buf.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
b := make([]byte, n)
|
||||||
|
n = copy(b, r.buf[r.off:])
|
||||||
|
r.off += n
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) readByte() byte {
|
func (r *JceReader) readByte() byte {
|
||||||
b, err := r.buf.ReadByte()
|
if r.off >= len(r.buf) {
|
||||||
if err != nil {
|
panic("readByte: EOF")
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
b := r.buf[r.off]
|
||||||
|
r.off++
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) readUInt16() uint16 {
|
func (r *JceReader) readUInt16() uint16 {
|
||||||
f, _ := r.buf.ReadByte()
|
b := r.readBytes(2)
|
||||||
s, err := r.buf.ReadByte()
|
return uint16((int32(b[0]) << 8) + int32(b[1]))
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return uint16((int32(f) << 8) + int32(s))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) readInt32() int32 {
|
func (r *JceReader) readInt32() int32 {
|
||||||
@ -274,9 +271,9 @@ func (r *JceReader) ReadString(tag int) string {
|
|||||||
hd, _ := r.readHead()
|
hd, _ := r.readHead()
|
||||||
switch hd.Type {
|
switch hd.Type {
|
||||||
case 6:
|
case 6:
|
||||||
return string(r.readBytes(int(r.readByte())))
|
return utils.B2S(r.readBytes(int(r.readByte())))
|
||||||
case 7:
|
case 7:
|
||||||
return string(r.readBytes(int(r.readInt32())))
|
return utils.B2S(r.readBytes(int(r.readInt32())))
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -364,35 +361,60 @@ func (r *JceReader) ReadJceStruct(obj IJceStruct, tag int) {
|
|||||||
|
|
||||||
func (r *JceReader) ReadMap(i interface{}, tag int) {
|
func (r *JceReader) ReadMap(i interface{}, tag int) {
|
||||||
v := reflect.ValueOf(i)
|
v := reflect.ValueOf(i)
|
||||||
if v.Kind() != reflect.Map {
|
r.readMap(v, tag)
|
||||||
return
|
}
|
||||||
}
|
|
||||||
if !r.skipToTag(tag) {
|
func (r *JceReader) readMap(v reflect.Value, tag int) {
|
||||||
|
if v.Kind() != reflect.Map || !r.skipToTag(tag) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
|
|
||||||
kt := t.Key()
|
kt := t.Key()
|
||||||
kv := reflect.New(kt)
|
|
||||||
|
|
||||||
vt := t.Elem()
|
vt := t.Elem()
|
||||||
vv := reflect.New(vt)
|
|
||||||
|
|
||||||
r.readHead()
|
r.readHead()
|
||||||
s := r.ReadInt32(0)
|
s := r.ReadInt32(0)
|
||||||
|
|
||||||
|
// map with string key or string value is very common.
|
||||||
|
// specialize for string
|
||||||
|
if kt.Kind() == reflect.String && vt.Kind() == reflect.String {
|
||||||
for i := 0; i < int(s); i++ {
|
for i := 0; i < int(s); i++ {
|
||||||
r.ReadObject(kv.Interface(), 0)
|
kv := reflect.ValueOf(r.ReadString(0))
|
||||||
r.ReadObject(vv.Interface(), 1)
|
vv := reflect.ValueOf(r.ReadString(1))
|
||||||
|
v.SetMapIndex(kv, vv)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if kt.Kind() == reflect.String {
|
||||||
|
vv := reflect.New(vt)
|
||||||
|
for i := 0; i < int(s); i++ {
|
||||||
|
kv := reflect.ValueOf(r.ReadString(0))
|
||||||
|
r.readObject(vv, 1)
|
||||||
|
v.SetMapIndex(kv, vv.Elem())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
kv := reflect.New(kt)
|
||||||
|
vv := reflect.New(vt)
|
||||||
|
for i := 0; i < int(s); i++ {
|
||||||
|
r.readObject(kv, 0)
|
||||||
|
r.readObject(vv, 1)
|
||||||
v.SetMapIndex(kv.Elem(), vv.Elem())
|
v.SetMapIndex(kv.Elem(), vv.Elem())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) ReadSlice(i interface{}, tag int) {
|
func (r *JceReader) ReadSlice(i interface{}, tag int) {
|
||||||
t := reflect.TypeOf(i)
|
r.readSlice(reflect.ValueOf(i), tag)
|
||||||
v := reflect.ValueOf(i).Elem()
|
}
|
||||||
|
|
||||||
|
func (r *JceReader) readSlice(v reflect.Value, tag int) {
|
||||||
|
t := v.Type()
|
||||||
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice {
|
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
v = v.Elem()
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
if !r.skipToTag(tag) {
|
if !r.skipToTag(tag) {
|
||||||
return
|
return
|
||||||
@ -404,7 +426,7 @@ func (r *JceReader) ReadSlice(i interface{}, tag int) {
|
|||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
val := reflect.New(t)
|
val := reflect.New(t)
|
||||||
for i := 0; i < int(s); i++ {
|
for i := 0; i < int(s); i++ {
|
||||||
r.ReadObject(val.Interface(), 0)
|
r.readObject(val, 0)
|
||||||
sv.Index(i).Set(val.Elem())
|
sv.Index(i).Set(val.Elem())
|
||||||
}
|
}
|
||||||
v.Set(sv)
|
v.Set(sv)
|
||||||
@ -417,43 +439,52 @@ func (r *JceReader) ReadSlice(i interface{}, tag int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) ReadObject(i interface{}, tag int) {
|
func (r *JceReader) ReadObject(i interface{}, tag int) {
|
||||||
va := reflect.ValueOf(i)
|
v := reflect.ValueOf(i)
|
||||||
if va.Kind() != reflect.Ptr || va.IsNil() {
|
r.readObject(v, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *JceReader) readObject(v reflect.Value, tag int) {
|
||||||
|
if v.Kind() != reflect.Ptr || v.IsNil() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ve := va.Elem(); ve.Kind() == reflect.Map {
|
elemType := v.Type().Elem()
|
||||||
ve.Set(reflect.MakeMap(ve.Type()))
|
if elemType.Kind() == reflect.Map {
|
||||||
r.ReadMap(ve.Interface(), tag)
|
elem := v.Elem()
|
||||||
|
elem.Set(reflect.MakeMap(elem.Type()))
|
||||||
|
r.readMap(elem, tag)
|
||||||
|
return
|
||||||
|
} else if elemType.Kind() == reflect.Slice && // *[]byte
|
||||||
|
elemType.Elem().Kind() == reflect.Uint8 {
|
||||||
|
elem := v.Elem()
|
||||||
|
elem.SetBytes(r.ReadBytes(tag))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch o := i.(type) {
|
|
||||||
case *byte:
|
switch elemType.Kind() {
|
||||||
*o = r.ReadByte(tag)
|
case reflect.Uint8, reflect.Int8:
|
||||||
case *bool:
|
*(*uint8)(pointerOf(v)) = r.ReadByte(tag)
|
||||||
*o = r.ReadBool(tag)
|
case reflect.Bool:
|
||||||
case *int16:
|
*(*bool)(pointerOf(v)) = r.ReadBool(tag)
|
||||||
*o = r.ReadInt16(tag)
|
case reflect.Uint16, reflect.Int16:
|
||||||
case *int:
|
*(*int16)(pointerOf(v)) = r.ReadInt16(tag)
|
||||||
*o = int(r.ReadInt32(tag))
|
case reflect.Uint32, reflect.Int32:
|
||||||
case *int32:
|
*(*int32)(pointerOf(v)) = r.ReadInt32(tag)
|
||||||
*o = r.ReadInt32(tag)
|
case reflect.Uint64, reflect.Int64:
|
||||||
case *int64:
|
*(*int64)(pointerOf(v)) = r.ReadInt64(tag)
|
||||||
*o = r.ReadInt64(tag)
|
case reflect.String:
|
||||||
case *float32:
|
*(*string)(pointerOf(v)) = r.ReadString(tag)
|
||||||
*o = r.ReadFloat32(tag)
|
|
||||||
case *float64:
|
default:
|
||||||
*o = r.ReadFloat64(tag)
|
// other cases
|
||||||
case *string:
|
switch o := v.Interface().(type) {
|
||||||
*o = r.ReadString(tag)
|
|
||||||
case *[]byte:
|
|
||||||
r.ReadSlice(o, tag)
|
|
||||||
case IJceStruct:
|
case IJceStruct:
|
||||||
r.readHead()
|
r.readHead()
|
||||||
o.ReadFrom(r)
|
o.ReadFrom(r)
|
||||||
r.skipToStructEnd()
|
r.skipToStructEnd()
|
||||||
|
case *float32:
|
||||||
|
*o = r.ReadFloat32(tag)
|
||||||
|
case *float64:
|
||||||
|
*o = r.ReadFloat64(tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JceReader) ReadAvailable() []byte {
|
|
||||||
return r.readBytes(r.buf.Len())
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user