package structure import ( "bytes" "encoding/binary" "gitee.com/timedb/wheatCache/pkg/errorx" "math" "strconv" ) // Value 提供一个基础的 动态类型 type Value struct { val []byte length int onType DynamicType } func NewValue() *Value { return &Value{ val: make([]byte, defaultLen), length: 0, onType: DynamicNull, } } func (v *Value) GetLength() int { return len(v.val) } func (v *Value) GetDynamicType() DynamicType { return v.onType } func (v *Value) SetString(str string) { v.onType = DynamicString if len(v.val) >= len(str) { copy(v.val, str) v.length = len(str) v.val = v.val[:v.length] return } // 超过 cap if len(str) > cap(v.val) { v.val = make([]byte, len(str)) copy(v.val, str) v.length = len(str) return } // 在 cap 以内 copy(v.val, str[:v.length]) v.val = append(v.val, str[v.length:]...) } func (v *Value) ToString() string { switch v.onType { case DynamicNull: return "" case DynamicString: return string(v.val[:v.length]) case DynamicInt: i, _ := v.ToInt() return strconv.FormatInt(i, 10) case DynamicFloat: f, _ := v.ToFloat64() return strconv.FormatFloat(f, 'f', 2, 64) } return string(v.val[:v.length]) } // SetInt 使用高位存储 func (v *Value) SetInt(i int64) { byteBuf := bytes.NewBuffer([]byte{}) binary.Write(byteBuf, binary.BigEndian, i) v.val = byteBuf.Bytes() v.length = len(v.val) v.onType = DynamicInt } func (v *Value) ToInt() (reI int64, err error) { if v.onType != DynamicInt { return 0, errorx.New("can only be resolved from dynamic int") } byteBuff := bytes.NewBuffer(v.val) err = binary.Read(byteBuff, binary.BigEndian, &reI) if err != nil { return 0, err } return reI, nil } func (v *Value) SetFloat64(f float64) { bits := math.Float64bits(f) v.length = 8 binary.LittleEndian.PutUint64(v.val[:v.length], bits) v.val = v.val[:v.length] v.onType = DynamicFloat } func (v *Value) ToFloat64() (float64, error) { if v.onType != DynamicFloat { return 0, errorx.New("can only be resolved from dynamic float") } bits := binary.LittleEndian.Uint64(v.val[:v.length]) return math.Float64frombits(bits), nil } // InferValue 通过字符串来自动推导类型,性能较低 func (v *Value) InferValue(str string) { rInt, err := strconv.Atoi(str) if err == nil { v.SetInt(int64(rInt)) return } rf, err := strconv.ParseFloat(str, 64) if err == nil { v.SetFloat64(rf) return } v.SetString(str) } // ChangeValueLength 根据类型推断 change 的大小, 只用于 Set 操作不发生错误 func (v *Value) ChangeValueLength(f func()) UpdateLength { startLen := v.GetLength() f() return UpdateLength(v.GetLength() - startLen) } func (v *Value) SetByte(offset int, val bool) { v.onType = DynamicNull // 位图使用无类型 b := byte(0) if val { b = byte(1) } if v.length >= offset { v.val[offset] = b return } newByte := make([]byte, offset+1) newByte[offset] = b copy(newByte, v.val[:v.length]) v.val = newByte v.length = len(newByte) } func (v *Value) GetByte(offset int) (bool, error) { if v.length >= offset { return v.val[offset] == byte(1), nil } return false, errorx.New("the maximum length is exceeded") }