All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
feat(socket): 优化TCP连接处理性能 - 添加最小可读长度检查,避免无效Peek操作 - 修复数据部分解析逻辑,避免空切片分配 perf(utils): 优化并发哈希映射性能 - 将分段数量调整为CPU核心数 - 重写Range方法,移除channel和goroutine开销 - 添加原子标志控制遍历终止 perf(utils): 优化结构体序列化缓存机制 - 添加sync.Map缓存预处理结果 - 支持结构体、自定义类型、二进制类型分别缓存 - 减少重复反射
186 lines
4.3 KiB
Go
186 lines
4.3 KiB
Go
package struc
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"reflect"
|
|
"sync"
|
|
)
|
|
|
|
type Options struct {
|
|
ByteAlign int
|
|
PtrSize int
|
|
Order binary.ByteOrder
|
|
}
|
|
|
|
func (o *Options) Validate() error {
|
|
if o.PtrSize == 0 {
|
|
o.PtrSize = 32
|
|
} else {
|
|
switch o.PtrSize {
|
|
case 8, 16, 32, 64:
|
|
default:
|
|
return fmt.Errorf("Invalid Options.PtrSize: %d. Must be in (8, 16, 32, 64)", o.PtrSize)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var emptyOptions = &Options{}
|
|
|
|
func init() {
|
|
// fill default values to avoid data race to be reported by race detector.
|
|
emptyOptions.Validate()
|
|
}
|
|
|
|
var prepCache = sync.Map{}
|
|
|
|
// cacheKey 缓存键:区分 结构体/自定义类型/二进制类型,保证缓存唯一性
|
|
type cacheKey struct {
|
|
typ reflect.Type // 数据的基础类型
|
|
kind uint8 // 0=结构体, 1=自定义类型, 2=二进制类型
|
|
}
|
|
|
|
// prep 优化版:带完整缓存,缓存处理后的最终 Packer
|
|
func prep(data interface{}) (reflect.Value, Packer, error) {
|
|
// 1. 提前判空
|
|
if data == nil {
|
|
return reflect.Value{}, nil, fmt.Errorf("Invalid reflect.Value for nil")
|
|
}
|
|
|
|
// 2. 初始反射值处理(和原逻辑一致)
|
|
value := reflect.ValueOf(data)
|
|
elemValue := value
|
|
for elemValue.Kind() == reflect.Ptr {
|
|
next := elemValue.Elem().Kind()
|
|
if next == reflect.Struct || next == reflect.Ptr {
|
|
elemValue = elemValue.Elem()
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
// 3. 构建缓存键的基础类型(取解引用后的类型)
|
|
baseType := elemValue.Type()
|
|
var packer Packer
|
|
var err error
|
|
|
|
// 4. 按类型分支处理,优先查缓存
|
|
switch elemValue.Kind() {
|
|
case reflect.Struct:
|
|
// 缓存键:结构体类型
|
|
key := cacheKey{typ: baseType, kind: 0}
|
|
if cacheVal, ok := prepCache.Load(key); ok {
|
|
// 缓存命中:直接返回缓存的 Packer
|
|
return elemValue, cacheVal.(Packer), nil
|
|
}
|
|
// 缓存未命中:执行原逻辑解析 fields
|
|
packer, err = parseFields(elemValue)
|
|
if err != nil {
|
|
return elemValue, nil, err
|
|
}
|
|
// 缓存处理后的 Packer
|
|
prepCache.Store(key, packer)
|
|
|
|
default:
|
|
// 非结构体类型:检查有效性
|
|
if !elemValue.IsValid() {
|
|
return reflect.Value{}, nil, fmt.Errorf("Invalid reflect.Value for %+v", data)
|
|
}
|
|
|
|
// 自定义类型分支
|
|
if c, ok := data.(Custom); ok {
|
|
// 缓存键:自定义类型
|
|
key := cacheKey{typ: baseType, kind: 1}
|
|
if cacheVal, ok := prepCache.Load(key); ok {
|
|
return elemValue, cacheVal.(Packer), nil
|
|
}
|
|
// 构建 customFallback 并缓存
|
|
// 仅用 custom Custom 构建,完全匹配你的定义
|
|
packer = customFallback{custom: c}
|
|
prepCache.Store(key, packer)
|
|
} else {
|
|
// 二进制类型分支
|
|
// 缓存键:二进制类型
|
|
key := cacheKey{typ: baseType, kind: 2}
|
|
if cacheVal, ok := prepCache.Load(key); ok {
|
|
return elemValue, cacheVal.(Packer), nil
|
|
}
|
|
// 构建 binaryFallback 并缓存
|
|
packer = binaryFallback(elemValue)
|
|
prepCache.Store(key, packer)
|
|
}
|
|
}
|
|
|
|
// 5. 返回和原逻辑完全一致的结果
|
|
return elemValue, packer, err
|
|
}
|
|
func Pack(w io.Writer, data interface{}) error {
|
|
return PackWithOptions(w, data, nil)
|
|
}
|
|
|
|
func PackWithOptions(w io.Writer, data interface{}, options *Options) error {
|
|
if options == nil {
|
|
options = emptyOptions
|
|
}
|
|
if err := options.Validate(); err != nil {
|
|
return err
|
|
}
|
|
val, packer, err := prep(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if val.Type().Kind() == reflect.String {
|
|
val = val.Convert(reflect.TypeOf([]byte{}))
|
|
}
|
|
size := packer.Sizeof(val, options)
|
|
// if size == 0 {
|
|
|
|
// fmt.Println("size==0")
|
|
|
|
// }
|
|
buf := make([]byte, size)
|
|
if _, err := packer.Pack(buf, val, options); err != nil {
|
|
return err
|
|
}
|
|
_, err = w.Write(buf)
|
|
return err
|
|
}
|
|
|
|
func Unpack(r io.Reader, data interface{}) error {
|
|
return UnpackWithOptions(r, data, nil)
|
|
}
|
|
|
|
func UnpackWithOptions(r io.Reader, data interface{}, options *Options) error {
|
|
if options == nil {
|
|
options = emptyOptions
|
|
}
|
|
if err := options.Validate(); err != nil {
|
|
return err
|
|
}
|
|
val, packer, err := prep(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return packer.Unpack(r, val, options)
|
|
}
|
|
|
|
func Sizeof(data interface{}) (int, error) {
|
|
return SizeofWithOptions(data, nil)
|
|
}
|
|
|
|
func SizeofWithOptions(data interface{}, options *Options) (int, error) {
|
|
if options == nil {
|
|
options = emptyOptions
|
|
}
|
|
if err := options.Validate(); err != nil {
|
|
return 0, err
|
|
}
|
|
val, packer, err := prep(data)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return packer.Sizeof(val, options), nil
|
|
}
|