1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 11:07:40 +08:00
MiraiGo/binary/jce/gen/structs_parser.go
fumiama b041fc20e8 perf(jce): drop most reflect in writer
name                           old time/op    new time/op     delta
JceWriter_WriteMap-8             2.34µs ± 2%     0.69µs ± 4%   -70.63%  (p=0.008 n=5+5)
JceWriter_WriteJceStructRaw-8    1.28µs ± 1%     0.42µs ± 1%   -66.86%  (p=0.008 n=5+5)

name                           old speed      new speed       delta
JceWriter_WriteMap-8           39.7MB/s ± 2%  135.4MB/s ± 4%  +240.56%  (p=0.008 n=5+5)
JceWriter_WriteJceStructRaw-8  82.3MB/s ± 1%  219.9MB/s ± 1%  +167.32%  (p=0.008 n=5+5)

name                           old alloc/op   new alloc/op    delta
JceWriter_WriteMap-8             1.30kB ± 0%     0.21kB ± 0%   -84.05%  (p=0.008 n=5+5)
JceWriter_WriteJceStructRaw-8      640B ± 0%       208B ± 0%   -67.50%  (p=0.008 n=5+5)

name                           old allocs/op  new allocs/op   delta
JceWriter_WriteMap-8               30.0 ± 0%        2.0 ± 0%   -93.33%  (p=0.008 n=5+5)
JceWriter_WriteJceStructRaw-8      15.0 ± 0%        2.0 ± 0%   -86.67%  (p=0.008 n=5+5)
2021-12-09 22:25:53 +08:00

157 lines
4.3 KiB
Go

package main
import (
"flag"
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings"
"sync"
"github.com/Mrs4s/MiraiGo/binary/jce"
)
const head = `// Code generated by structs_parser; DO NOT EDIT.
package jce
`
func main() {
f := flag.String("f", "structs_tobytes.go", "output file.")
flag.Parse()
fmt.Println("gen runs on arg", *f)
w, err := os.Create(*f)
if err != nil {
panic(err)
}
w.WriteString(head)
WriteJceStruct(w, &jce.RequestPacket{})
WriteJceStruct(w, &jce.RequestDataVersion3{})
WriteJceStruct(w, &jce.RequestDataVersion2{})
WriteJceStruct(w, &jce.SvcReqRegister{})
WriteJceStruct(w, &jce.FriendListRequest{})
WriteJceStruct(w, &jce.SummaryCardReq{})
WriteJceStruct(w, &jce.SummaryCardReqSearch{})
WriteJceStruct(w, &jce.TroopListRequest{})
WriteJceStruct(w, &jce.TroopMemberListRequest{})
WriteJceStruct(w, &jce.SvcRespPushMsg{})
WriteJceStruct(w, &jce.ModifyGroupCardRequest{})
WriteJceStruct(w, &jce.SvcReqGetDevLoginInfo{})
WriteJceStruct(w, &jce.SvcReqRegisterNew{})
WriteJceStruct(w, &jce.DelFriendReq{})
err = w.Close()
if err != nil {
panic(err)
}
}
func writeObject(w io.Writer, v reflect.Value, tag byte, name string) {
k := v.Kind()
if k == reflect.Map {
switch v.Interface().(type) {
case map[string]string:
w.Write([]byte(fmt.Sprintf("\tw.writeMapStrStr(pkt.%s, %d)\n", name, tag)))
case map[string][]byte:
w.Write([]byte(fmt.Sprintf("\tw.writeMapStrBytes(pkt.%s, %d)\n", name, tag)))
case map[string]map[string][]byte:
w.Write([]byte(fmt.Sprintf("\tw.writeMapStrMapStrBytes(pkt.%s, %d)\n", name, tag)))
default:
w.Write([]byte(fmt.Sprintf("\tw.writeMap(pkt.%s, %d)\n", name, tag)))
}
return
}
if k == reflect.Slice {
switch v.Interface().(type) {
case []byte:
w.Write([]byte(fmt.Sprintf("\tw.WriteBytes(pkt.%s, %d)\n", name, tag)))
case []int64:
w.Write([]byte(fmt.Sprintf("\tw.WriteInt64Slice(pkt.%s, %d)\n", name, tag)))
case [][]byte:
w.Write([]byte(fmt.Sprintf("\tw.WriteBytesSlice(pkt.%s, %d)\n", name, tag)))
case []jce.IJceStruct:
w.Write([]byte(fmt.Sprintf("\tw.WriteJceStructSlice(pkt.%s, %d)\n", name, tag)))
default:
w.Write([]byte(fmt.Sprintf("\tw.writeSlice(pkt.%s, %d)\n", name, tag)))
}
return
}
switch k {
case reflect.Uint8, reflect.Int8:
w.Write([]byte(fmt.Sprintf("\tw.WriteByte(byte(pkt.%s), %d)\n", name, tag)))
case reflect.Uint16, reflect.Int16:
w.Write([]byte(fmt.Sprintf("\tw.WriteInt16(int16(pkt.%s), %d)\n", name, tag)))
case reflect.Uint32, reflect.Int32:
w.Write([]byte(fmt.Sprintf("\tw.WriteInt32(int32(pkt.%s), %d)\n", name, tag)))
case reflect.Uint64, reflect.Int64:
w.Write([]byte(fmt.Sprintf("\tw.WriteInt64(int64(pkt.%s), %d)\n", name, tag)))
case reflect.String:
w.Write([]byte(fmt.Sprintf("\tw.WriteString(pkt.%s, %d)\n", name, tag)))
default:
switch v.Interface().(type) {
case jce.IJceStruct:
w.Write([]byte(fmt.Sprintf("\tw.WriteJceStruct(pkt.%s, %d)\n", name, tag)))
case float32:
w.Write([]byte(fmt.Sprintf("\tw.WriteFloat32(pkt.%s, %d)\n", name, tag)))
case float64:
w.Write([]byte(fmt.Sprintf("\tw.WriteFloat64(pkt.%s, %d)\n", name, tag)))
}
}
}
type decoder struct {
index int
id int
name string
}
var decoderCache = sync.Map{}
// writeJceStructRaw 写入 Jce 结构体
func writeJceStructRaw(w io.Writer, s interface{}) {
t := reflect.TypeOf(s)
if t.Kind() != reflect.Ptr {
return
}
t = t.Elem()
v := reflect.ValueOf(s).Elem()
var jceDec []decoder
dec, ok := decoderCache.Load(t)
if ok { // 从缓存中加载
jceDec = dec.([]decoder)
} else { // 初次反射
jceDec = make([]decoder, 0, t.NumField())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
strId := field.Tag.Get("jceId")
if strId == "" {
continue
}
id, err := strconv.Atoi(strId)
if err != nil {
continue
}
jceDec = append(jceDec, decoder{
index: i,
id: id,
name: field.Name,
})
}
decoderCache.Store(t, jceDec) // 存入缓存
}
for _, dec := range jceDec {
obj := v.Field(dec.index)
writeObject(w, obj, byte(dec.id), dec.name)
}
}
func WriteJceStruct(w io.Writer, s jce.IJceStruct) {
w.Write([]byte(fmt.Sprintf("func (pkt %s) ToBytes() []byte {\n", strings.ReplaceAll(reflect.TypeOf(s).String(), "jce.", ""))))
w.Write([]byte("\tw := NewJceWriter()\n"))
writeJceStructRaw(w, s)
w.Write([]byte("\treturn w.Bytes()\n"))
w.Write([]byte("}\n\n"))
}