wheat-cache/pkg/structure/value.go

188 lines
3.7 KiB
Go
Raw Normal View History

2021-09-24 22:48:08 +08:00
package structure
import (
"bytes"
"encoding/binary"
"math"
"strconv"
2021-10-20 21:35:15 +08:00
"gitee.com/timedb/wheatCache/pkg/errorx"
2021-09-24 22:48:08 +08:00
)
// Value 提供一个基础的 动态类型
type Value struct {
val []byte
length int
onType DynamicType
}
2021-10-22 15:36:25 +08:00
func NewValue(val ...string) *Value {
stcValue := &Value{
2021-09-24 22:48:08 +08:00
val: make([]byte, defaultLen),
length: 0,
onType: DynamicNull,
}
2021-10-22 15:36:25 +08:00
if len(val) > 0 {
stcValue.InferValue(val[0])
}
return stcValue
2021-09-24 22:48:08 +08:00
}
func (v *Value) GetLength() int {
2021-10-22 15:36:25 +08:00
return v.length
2021-09-24 22:48:08 +08:00
}
2021-10-20 21:35:15 +08:00
func (v *Value) GetSize() int {
2021-10-22 15:36:25 +08:00
return len(v.val) + 16
2021-10-20 21:35:15 +08:00
}
2021-09-24 22:48:08 +08:00
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)
2021-09-26 16:47:54 +08:00
v.val = v.val[:v.length]
2021-09-24 22:48:08 +08:00
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 {
2021-09-26 16:47:54 +08:00
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)
}
2021-09-24 22:48:08 +08:00
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)
2021-09-26 16:47:54 +08:00
v.val = v.val[:v.length]
2021-09-24 22:48:08 +08:00
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)
}
2021-09-25 16:21:28 +08:00
2021-09-26 16:47:54 +08:00
// ChangeValueLength 根据类型推断 change 的大小, 只用于 Set 操作不发生错误
func (v *Value) ChangeValueLength(f func()) UpdateLength {
2021-09-25 16:21:28 +08:00
startLen := v.GetLength()
f()
return UpdateLength(v.GetLength() - startLen)
2021-09-25 16:21:28 +08:00
}
2021-09-26 16:47:54 +08:00
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")
}
2021-10-20 21:35:15 +08:00
func (v *Value) SliceByString(start, end int) ([]byte, error) {
if v.onType != DynamicString {
return nil, errorx.New("not is string")
}
if start > end {
return nil, errorx.New("the end cannot be greater than the beginning")
}
if end > v.length {
return nil, errorx.New("the maximum index is exceeded, max index: %d", v.length)
}
return v.val[start:end], nil
}