181 lines
4.0 KiB
Go
181 lines
4.0 KiB
Go
package ormfield
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
)
|
|
|
|
// FixedUint32Codec encodes uint32 values as 4-byte big-endian integers.
|
|
type FixedUint32Codec struct{}
|
|
|
|
func (u FixedUint32Codec) FixedBufferSize() int {
|
|
return 4
|
|
}
|
|
|
|
func (u FixedUint32Codec) ComputeBufferSize(protoreflect.Value) (int, error) {
|
|
return u.FixedBufferSize(), nil
|
|
}
|
|
|
|
func (u FixedUint32Codec) IsOrdered() bool {
|
|
return true
|
|
}
|
|
|
|
func (u FixedUint32Codec) Compare(v1, v2 protoreflect.Value) int {
|
|
return compareUint(v1, v2)
|
|
}
|
|
|
|
func (u FixedUint32Codec) Decode(r Reader) (protoreflect.Value, error) {
|
|
var x uint32
|
|
err := binary.Read(r, binary.BigEndian, &x)
|
|
return protoreflect.ValueOfUint32(x), err
|
|
}
|
|
|
|
func (u FixedUint32Codec) Encode(value protoreflect.Value, w io.Writer) error {
|
|
return binary.Write(w, binary.BigEndian, uint32(value.Uint()))
|
|
}
|
|
|
|
// CompactUint32Codec encodes uint32 values using EncodeCompactUint32.
|
|
type CompactUint32Codec struct{}
|
|
|
|
func (c CompactUint32Codec) Decode(r Reader) (protoreflect.Value, error) {
|
|
x, err := DecodeCompactUint32(r)
|
|
return protoreflect.ValueOfUint32(x), err
|
|
}
|
|
|
|
func (c CompactUint32Codec) Encode(value protoreflect.Value, w io.Writer) error {
|
|
_, err := w.Write(EncodeCompactUint32(uint32(value.Uint())))
|
|
return err
|
|
}
|
|
|
|
func (c CompactUint32Codec) Compare(v1, v2 protoreflect.Value) int {
|
|
return compareUint(v1, v2)
|
|
}
|
|
|
|
func (c CompactUint32Codec) IsOrdered() bool {
|
|
return true
|
|
}
|
|
|
|
func (c CompactUint32Codec) FixedBufferSize() int {
|
|
return 5
|
|
}
|
|
|
|
func (c CompactUint32Codec) ComputeBufferSize(protoreflect.Value) (int, error) {
|
|
return c.FixedBufferSize(), nil
|
|
}
|
|
|
|
// EncodeCompactUint32 encodes uint32 values in 2,3,4 or 5 bytes.
|
|
// Unlike regular varints, this encoding is
|
|
// suitable for ordered prefix scans. The length of the output + 2 is encoded
|
|
// in the first 2 bits of the first byte and the remaining bits encoded with
|
|
// big-endian ordering.
|
|
// Values less than 2^14 fill fit in 2 bytes, values less than 2^22 will
|
|
// fit in 3, and values less than 2^30 will fit in 4.
|
|
func EncodeCompactUint32(x uint32) []byte {
|
|
switch {
|
|
case x < 16384: // 2^14
|
|
buf := make([]byte, 2)
|
|
buf[0] = byte(x >> 8)
|
|
buf[1] = byte(x)
|
|
return buf
|
|
case x < 4194304: // 2^22
|
|
buf := make([]byte, 3)
|
|
buf[0] = 0x40
|
|
buf[0] |= byte(x >> 16)
|
|
buf[1] = byte(x >> 8)
|
|
buf[2] = byte(x)
|
|
return buf
|
|
case x < 1073741824: // 2^30
|
|
buf := make([]byte, 4)
|
|
buf[0] = 0x80
|
|
buf[0] |= byte(x >> 24)
|
|
buf[1] = byte(x >> 16)
|
|
buf[2] = byte(x >> 8)
|
|
buf[3] = byte(x)
|
|
return buf
|
|
default:
|
|
buf := make([]byte, 5)
|
|
buf[0] = 0xC0
|
|
buf[0] |= byte(x >> 26)
|
|
buf[1] = byte(x >> 18)
|
|
buf[2] = byte(x >> 10)
|
|
buf[3] = byte(x >> 2)
|
|
buf[4] = byte(x) & 0x3
|
|
return buf
|
|
}
|
|
}
|
|
|
|
// DecodeCompactUint32 decodes a uint32 encoded with EncodeCompactU32.
|
|
func DecodeCompactUint32(reader io.Reader) (uint32, error) {
|
|
var buf [5]byte
|
|
|
|
n, err := reader.Read(buf[:1])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if n < 1 {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
|
|
switch buf[0] >> 6 {
|
|
case 0:
|
|
n, err := reader.Read(buf[1:2])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if n < 1 {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
|
|
x := uint32(buf[0]) << 8
|
|
x |= uint32(buf[1])
|
|
return x, nil
|
|
case 1:
|
|
n, err := reader.Read(buf[1:3])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if n < 2 {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
|
|
x := (uint32(buf[0]) & 0x3F) << 16
|
|
x |= uint32(buf[1]) << 8
|
|
x |= uint32(buf[2])
|
|
return x, nil
|
|
case 2:
|
|
n, err := reader.Read(buf[1:4])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if n < 3 {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
|
|
x := (uint32(buf[0]) & 0x3F) << 24
|
|
x |= uint32(buf[1]) << 16
|
|
x |= uint32(buf[2]) << 8
|
|
x |= uint32(buf[3])
|
|
return x, nil
|
|
case 3:
|
|
n, err := reader.Read(buf[1:5])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if n < 4 {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
|
|
x := (uint32(buf[0]) & 0x3F) << 26
|
|
x |= uint32(buf[1]) << 18
|
|
x |= uint32(buf[2]) << 10
|
|
x |= uint32(buf[3]) << 2
|
|
x |= uint32(buf[4])
|
|
return x, nil
|
|
default:
|
|
return 0, fmt.Errorf("unexpected case")
|
|
}
|
|
}
|