1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-05-05 03:23:49 +08:00

refactor(cqcode): drop unsafe for cqcode deserialize

name                          old time/op    new time/op    delta
CQBot_ConvertStringMessage-8    1.22µs ± 5%    1.14µs ± 4%  -6.17%  (p=0.000 n=21+18)

name                          old speed      new speed      delta
CQBot_ConvertStringMessage-8  81.2MB/s ± 6%  86.7MB/s ± 3%  +6.84%  (p=0.000 n=20+18)
This commit is contained in:
wdvxdr 2021-05-02 13:33:57 +08:00
parent 111ac7f865
commit 2fbaff8e72
No known key found for this signature in database
GPG Key ID: 55FF1414A69CEBA6
2 changed files with 58 additions and 87 deletions

View File

@ -14,12 +14,10 @@ import (
"net/url"
"os"
"path"
"reflect"
"runtime"
"strconv"
"strings"
"time"
"unsafe"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/message"
@ -49,19 +47,6 @@ var IgnoreInvalidCQCode = false
// SplitURL 是否分割URL
var SplitURL = false
// magicCQ 代表 uint32([]byte("[CQ:"))
var magicCQ = uint32(0)
func init() {
CQHeader := "[CQ:"
magicCQ = *(*uint32)(unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&CQHeader)).Data))
}
// add 指针运算
func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(ptr) + offset)
}
const (
maxImageSize = 1024 * 1024 * 30 // 30MB
maxVideoSize = 1024 * 1024 * 100 // 100MB
@ -397,12 +382,9 @@ func ToStringMessage(e []message.IMessageElement, id int64, isRaw ...bool) (r st
}
// ConvertStringMessage 将消息字符串转为消息元素数组
func (bot *CQBot) ConvertStringMessage(s string, isGroup bool) (r []message.IMessageElement) {
func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IMessageElement) {
var t, key string
d := map[string]string{}
ptr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&s)).Data)
l := len(s)
i, j, CQBegin := 0, 0, 0
saveCQCode := func() {
if t == "reply" { // reply 特殊处理
@ -487,7 +469,11 @@ func (bot *CQBot) ConvertStringMessage(s string, isGroup bool) (r []message.IMes
}
elem, err := bot.ToElement(t, d, isGroup)
if err != nil {
org := s[CQBegin:i]
org := "[CQ:" + t
for k, v := range d {
org += "," + k + "=" + v
}
org += "]"
if !IgnoreInvalidCQCode {
log.Warnf("转换CQ码 %v 时出现错误: %v 将原样发送.", org, err)
r = append(r, message.NewText(org))
@ -504,81 +490,65 @@ func (bot *CQBot) ConvertStringMessage(s string, isGroup bool) (r []message.IMes
}
}
S1: // Plain Text
for ; i < l; i++ {
if *(*byte)(add(ptr, uintptr(i))) == '[' && i+4 < l &&
*(*uint32)(add(ptr, uintptr(i))) == magicCQ { // Magic :uint32([]byte("[CQ:"))
if i > j {
if SplitURL {
for _, str := range global.SplitURL(CQCodeUnescapeText(s[j:i])) {
r = append(r, message.NewText(str))
}
} else {
r = append(r, message.NewText(CQCodeUnescapeText(s[j:i])))
for raw != "" {
i := 0
for i < len(raw) && !(raw[i] == '[' && i+4 < len(raw) && raw[i:i+4] == "[CQ:") {
i++
}
if i > 0 {
if SplitURL {
for _, txt := range global.SplitURL(CQCodeUnescapeText(raw[:i])) {
r = append(r, message.NewText(txt))
}
} else {
r = append(r, message.NewText(CQCodeUnescapeText(raw[:i])))
}
CQBegin = i
i += 4
j = i
goto S2
}
}
goto End
S2: // CQCode Type
for k := range d { // 内存复用减小GC压力
delete(d, k)
}
for ; i < l; i++ {
switch *(*byte)(add(ptr, uintptr(i))) {
case ',': // CQ Code with params
t = s[j:i]
i++
j = i
goto S3
case ']': // CQ Code without params
t = s[j:i]
i++
j = i
saveCQCode()
goto S1
if i+4 > len(raw) {
return
}
}
goto End
S3: // CQCode param key
for ; i < l; i++ {
if *(*byte)(add(ptr, uintptr(i))) == '=' {
key = s[j:i]
raw = raw[i+4:] // skip "[CQ:"
i = 0
for i < len(raw) && raw[i] != ',' && raw[i] != ']' {
i++
j = i
goto S4
}
}
goto End
S4: // CQCode param value
for ; i < l; i++ {
switch *(*byte)(add(ptr, uintptr(i))) {
case ',': // more param
d[key] = CQCodeUnescapeValue(s[j:i])
i++
j = i
goto S3
case ']':
d[key] = CQCodeUnescapeValue(s[j:i])
i++
j = i
saveCQCode()
goto S1
if i+1 > len(raw) {
return
}
}
goto End
End:
if i > j {
if SplitURL {
for _, str := range global.SplitURL(CQCodeUnescapeText(s[j:i])) {
r = append(r, message.NewText(str))
t = raw[:i]
for k := range d { // clear the map, reuse it
delete(d, k)
}
raw = raw[i:]
i = 0
for {
if raw[0] == ']' {
saveCQCode()
raw = raw[1:]
break
}
} else {
r = append(r, message.NewText(CQCodeUnescapeText(s[j:i])))
raw = raw[1:]
for i < len(raw) && raw[i] != '=' {
i++
}
if i+1 > len(raw) {
return
}
key = raw[:i]
raw = raw[i+1:] // skip "="
i = 0
for i < len(raw) && raw[i] != ',' && raw[i] != ']' {
i++
}
if i+1 > len(raw) {
return
}
d[key] = CQCodeUnescapeValue(raw[:i])
raw = raw[i:]
i = 0
}
}
return

View File

@ -22,6 +22,7 @@ func BenchmarkCQBot_ConvertStringMessage(b *testing.B) {
for i := 0; i < b.N; i++ {
bot.ConvertStringMessage(bench, false)
}
b.SetBytes(int64(len(bench)))
}
func BenchmarkCQBot_ConvertObjectMessage(b *testing.B) {