mq_coder/encoding/pvarint.go

148 lines
3.9 KiB
Go
Raw Normal View History

2022-10-07 15:30:45 +08:00
package encoding
import (
"errors"
)
// SizeOfPVarInt32 return the buffer size after encoding value as PVarInt32
func SizeOfPVarInt32(value int32) int {
return sizeOfPVarInt(int64(value), 32)
}
// EncodePVarInt32 encode value as PVarInt32 to buffer
func (codec *VarCodec) EncodePVarInt32(buffer []byte, value int32) error {
return codec.encodePVarInt(buffer, int64(value))
}
// DecodePVarInt32 decode to value as PVarInt32 from buffer
func (codec *VarCodec) DecodePVarInt32(buffer []byte, value *int32) error {
var val = int64(*value)
var err = codec.decodePVarInt(buffer, &val)
*value = int32(val)
return err
}
// SizeOfPVarUInt32 return the buffer size after encoding value as PVarUInt32
func SizeOfPVarUInt32(value uint32) int {
return sizeOfPVarInt(int64(int32(value)), 32)
}
// EncodePVarUInt32 encode value as PVarUInt32 to buffer
func (codec *VarCodec) EncodePVarUInt32(buffer []byte, value uint32) error {
return codec.encodePVarInt(buffer, int64(int32(value)))
}
// DecodePVarUInt32 decode to value as PVarUInt32 from buffer
func (codec *VarCodec) DecodePVarUInt32(buffer []byte, value *uint32) error {
var val = int64(int32(*value))
var err = codec.decodePVarInt(buffer, &val)
*value = uint32(val)
return err
}
// SizeOfPVarInt64 return the buffer size after encoding value as PVarInt64
func SizeOfPVarInt64(value int64) int {
return sizeOfPVarInt(value, 64)
}
// EncodePVarInt64 encode value as PVarInt64 to buffer
func (codec *VarCodec) EncodePVarInt64(buffer []byte, value int64) error {
return codec.encodePVarInt(buffer, value)
}
// DecodePVarInt64 decode to value as PVarInt64 from buffer
func (codec *VarCodec) DecodePVarInt64(buffer []byte, value *int64) error {
return codec.decodePVarInt(buffer, value)
}
// SizeOfPVarUInt64 return the buffer size after encoding value as PVarUInt64
func SizeOfPVarUInt64(value uint64) int {
return sizeOfPVarInt(int64(value), 64)
}
// EncodePVarUInt64 encode value as PVarUInt64 to buffer
func (codec *VarCodec) EncodePVarUInt64(buffer []byte, value uint64) error {
return codec.encodePVarInt(buffer, int64(value))
}
// DecodePVarUInt64 decode to value as PVarUInt64 from buffer
func (codec *VarCodec) DecodePVarUInt64(buffer []byte, value *uint64) error {
var val = int64(*value)
var err = codec.decodePVarInt(buffer, &val)
*value = uint64(val)
return err
}
func sizeOfPVarInt(value int64, width int) int {
2022-10-07 15:41:18 +08:00
const unit = 7 // a bit width of encoding unit
2022-10-07 15:30:45 +08:00
var lead = value >> (width - 1)
for size := width / unit; size > 0; size-- {
var lookAhead = value >> (size*unit - 1)
if lookAhead != lead {
return size + 1
}
}
return 1
}
func (codec *VarCodec) encodePVarInt(buffer []byte, value int64) error {
if codec == nil || codec.Size == 0 {
return errors.New("nothing to encode")
}
if codec.Ptr >= len(buffer) {
return ErrBufferInsufficient
}
2022-10-07 15:41:18 +08:00
const unit = 7 // a bit width of encoding unit
2022-10-07 15:30:45 +08:00
const more = -1 << 7 // continuation bits
for codec.Size > 1 {
codec.Size--
var part = value >> (codec.Size * unit)
buffer[codec.Ptr] = byte(part | more)
codec.Ptr++
if codec.Ptr >= len(buffer) {
return ErrBufferInsufficient
}
}
const mask = -1 ^ (-1 << unit) // mask for encoding unit
codec.Size = 0
buffer[codec.Ptr] = byte(value & mask)
codec.Ptr++
return nil
}
func (codec *VarCodec) decodePVarInt(buffer []byte, value *int64) error {
if codec == nil {
return errors.New("nothing to decode")
}
if codec.Ptr >= len(buffer) {
return ErrBufferInsufficient
}
2022-10-07 15:41:18 +08:00
const unit = 7 // a bit width of encoding unit
2022-10-07 15:30:45 +08:00
if codec.Size == 0 { // initialize sign bit
2022-10-07 15:41:18 +08:00
const flag = 8 - unit // a bit of width for non-encoding bits
2022-10-07 15:30:45 +08:00
*value = int64(int8(buffer[codec.Ptr]) << flag >> unit)
}
const mask = -1 ^ (-1 << unit) // mask for encoding unit
for {
var part = int8(buffer[codec.Ptr])
codec.Ptr++
codec.Size++
2022-10-07 15:41:18 +08:00
*value = (*value << unit) | int64(mask&part)
2022-10-07 15:30:45 +08:00
if part >= 0 { // it's the last byte
return nil
}
if codec.Ptr >= len(buffer) {
return ErrBufferInsufficient
}
}
}