Improve efficiency of database key encoding and decoding

Make use of the github.com/abcum/bump package to efficiently encode and decode from and to byte slices, whilst at the same time using encoder and decoder pools, instead of creating a new buffer for each encoding / decoding process.
This commit is contained in:
Tobie Morgan Hitchcock 2017-11-16 20:18:42 +00:00
parent 61015c8f7a
commit e300e9c423
7 changed files with 370 additions and 379 deletions

View file

@ -15,8 +15,7 @@
package keys
import (
"bytes"
"io"
"sync"
"time"
)
@ -24,15 +23,30 @@ type decoder struct {
r *reader
}
// decode decodes an encoded string using the unicode collation algorithm.
func decode(data []byte, items ...interface{}) {
newDecoder(bytes.NewReader(data)).Decode(items...)
var decoders = sync.Pool{
New: func() interface{} {
return &decoder{
r: newReader(),
}
},
}
func newDecoder(r io.Reader) *decoder {
return &decoder{
r: newReader(r),
}
// decode decodes an encoded string using the unicode collation algorithm.
func decode(data []byte, items ...interface{}) {
dec := newDecoder(data)
dec.Decode(items...)
dec.Reset()
return
}
func newDecoder(b []byte) *decoder {
d := decoders.Get().(*decoder)
d.r.r.ResetBytes(b)
return d
}
func (d *decoder) Reset() {
decoders.Put(d)
}
func (d *decoder) Decode(items ...interface{}) {
@ -42,171 +56,171 @@ func (d *decoder) Decode(items ...interface{}) {
switch value := item.(type) {
case *time.Time:
*value = d.r.FindTime()
*value = d.r.readTime()
case *bool:
*value = d.r.FindBool()
*value = d.r.readBool()
case *[]byte:
*value = d.r.FindBytes()
*value = d.r.readBytes()
case *string:
*value = d.r.FindString()
*value = d.r.readString()
case *int:
*value = d.r.FindNumberInt()
*value = int(d.r.readFloat())
case *int8:
*value = d.r.FindNumberInt8()
*value = int8(d.r.readFloat())
case *int16:
*value = d.r.FindNumberInt16()
*value = int16(d.r.readFloat())
case *int32:
*value = d.r.FindNumberInt32()
*value = int32(d.r.readFloat())
case *int64:
*value = d.r.FindNumberInt64()
*value = int64(d.r.readFloat())
case *uint:
*value = d.r.FindNumberUint()
*value = uint(d.r.readFloat())
case *uint8:
*value = d.r.FindNumberUint8()
*value = uint8(d.r.readFloat())
case *uint16:
*value = d.r.FindNumberUint16()
*value = uint16(d.r.readFloat())
case *uint32:
*value = d.r.FindNumberUint32()
*value = uint32(d.r.readFloat())
case *uint64:
*value = d.r.FindNumberUint64()
*value = uint64(d.r.readFloat())
case *float32:
*value = d.r.FindNumberFloat32()
*value = float32(d.r.readFloat())
case *float64:
*value = d.r.FindNumberFloat64()
*value = float64(d.r.readFloat())
case *[]time.Time:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindTime())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, d.r.readTime())
}
}
case *[]bool:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindBool())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, d.r.readBool())
}
}
case *[]string:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindString())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, d.r.readString())
}
}
case *[]int:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberInt())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, int(d.r.readFloat()))
}
}
case *[]int8:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberInt8())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, int8(d.r.readFloat()))
}
}
case *[]int16:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberInt16())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, int16(d.r.readFloat()))
}
}
case *[]int32:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberInt32())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, int32(d.r.readFloat()))
}
}
case *[]int64:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberInt64())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, int64(d.r.readFloat()))
}
}
case *[]uint:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberUint())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, uint(d.r.readFloat()))
}
}
case *[]uint16:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberUint16())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, uint16(d.r.readFloat()))
}
}
case *[]uint32:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberUint32())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, uint32(d.r.readFloat()))
}
}
case *[]uint64:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberUint64())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, uint64(d.r.readFloat()))
}
}
case *[]float32:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberFloat32())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, float32(d.r.readFloat()))
}
}
case *[]float64:
if d.r.ReadNext(cARR) {
for !d.r.ReadNext(cEND) {
*value = append(*value, d.r.FindNumberFloat64())
if d.r.readNext(bARR) {
for !d.r.readNext(bEND) {
*value = append(*value, float64(d.r.readFloat()))
}
}
case *[]interface{}:
*value = d.r.FindArray()
*value = d.r.readArray()
case *interface{}:
switch fnd := d.r.FindNext(); fnd {
switch d.r.lookNext() {
default:
*value = d.r.FindAny()
case cNIL:
*value = d.r.FindNull()
case cVAL:
*value = d.r.FindBool()
case cTME:
*value = d.r.FindTime()
case cNEG, cPOS:
*value = d.r.FindNumber()
case cSTR, cPRE, cSUF:
*value = d.r.FindString()
case cARR:
*value = d.r.FindArray()
*value = d.r.readAny()
case bNIL:
*value = d.r.readNull()
case bVAL:
*value = d.r.readBool()
case bTME:
*value = d.r.readTime()
case bNEG, bPOS:
*value = d.r.readFloat()
case bSTR, bPRE, bSUF:
*value = d.r.readString()
case bARR:
*value = d.r.readArray()
}

View file

@ -15,8 +15,7 @@
package keys
import (
"bytes"
"io"
"sync"
"time"
)
@ -24,17 +23,35 @@ type encoder struct {
w *writer
}
// encode encodes an interface using the unicode collation algorithm.
func encode(items ...interface{}) []byte {
b := &bytes.Buffer{}
newEncoder(b).Encode(items...)
return b.Bytes()
var encoders = sync.Pool{
New: func() interface{} {
return &encoder{
w: newWriter(),
}
},
}
func newEncoder(w io.Writer) *encoder {
return &encoder{
w: newWriter(w),
}
// Encode encodes an interface using the unicode collation algorithm.
func Encode(items ...interface{}) []byte {
return encode(items...)
}
// encode encodes an interface using the unicode collation algorithm.
func encode(items ...interface{}) (dst []byte) {
enc := newEncoder(&dst)
enc.Encode(items...)
enc.Reset()
return
}
func newEncoder(b *[]byte) *encoder {
e := encoders.Get().(*encoder)
e.w.w.ResetBytes(b)
return e
}
func (e *encoder) Reset() {
encoders.Put(e)
}
func (e *encoder) Encode(items ...interface{}) {
@ -45,29 +62,29 @@ func (e *encoder) Encode(items ...interface{}) {
case nil:
e.w.write(bNIL)
e.w.write(bEND)
e.w.writeOne(bNIL)
e.w.writeOne(bEND)
case bool:
e.w.write(bVAL)
e.w.writeOne(bVAL)
if value {
e.w.write(bVAL)
e.w.writeOne(bVAL)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case time.Time:
e.w.write(bTME)
e.w.write(value)
e.w.write(bEND)
e.w.writeOne(bTME)
e.w.writeTime(value)
e.w.writeOne(bEND)
case []byte:
e.w.write(bSTR)
e.w.write(value)
e.w.write(bEND)
e.w.write(bEND)
e.w.writeOne(bSTR)
e.w.writeMany(value)
e.w.writeOne(bEND)
e.w.writeOne(bEND)
case string:
@ -76,156 +93,202 @@ func (e *encoder) Encode(items ...interface{}) {
}
if value == Prefix {
e.w.write(bPRE)
e.w.write(bEND)
e.w.writeOne(bPRE)
e.w.writeOne(bEND)
break
}
if value == Suffix {
e.w.write(bSUF)
e.w.write(bEND)
e.w.writeOne(bSUF)
e.w.writeOne(bEND)
break
}
e.w.write(bSTR)
e.w.write(value)
e.w.write(bEND)
e.w.write(bEND)
e.w.writeOne(bSTR)
e.w.writeString(value)
e.w.writeOne(bEND)
e.w.writeOne(bEND)
case float32, float64:
case int:
e.w.write(value)
e.w.write(bEND)
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case int, int8, int16, int32, int64:
case int8:
e.w.write(value)
e.w.write(bEND)
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case uint, uint8, uint16, uint32, uint64:
case int16:
e.w.write(value)
e.w.write(bEND)
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case int32:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case int64:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case uint:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case uint8:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case uint16:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case uint32:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case uint64:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case float32:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case float64:
e.w.writeFloat(float64(value))
e.w.writeOne(bEND)
case []time.Time:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []bool:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []string:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []int:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
e.w.writeFloat(float64(val))
e.w.writeOne(bEND)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []int8:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []int16:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []int32:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []int64:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []uint:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []uint16:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []uint32:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []uint64:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []float32:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []float64:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
case []interface{}:
e.w.write(bARR)
e.w.writeOne(bARR)
for _, val := range value {
e.Encode(val)
}
e.w.write(bEND)
e.w.writeOne(bEND)
}

View file

@ -24,9 +24,9 @@ const (
// Suffix is the highest char found in a key
Suffix = suffix
// Ignore specifies an ignored field
ignore = "\x01"
ignore = "\x00"
// Prefix is the lowest char found in a key
prefix = "\x00"
prefix = "\x01"
// Suffix is the highest char found in a key
suffix = "\xff"
)
@ -39,33 +39,20 @@ var (
)
var (
skip interface{}
skip string
)
var (
cEND = byte(0x00)
cPRE = byte(0x01)
cNIL = byte(0x02)
cVAL = byte(0x03)
cTME = byte(0x04)
cNEG = byte(0x05)
cPOS = byte(0x06)
cSTR = byte(0x07)
cARR = byte(0x08)
cSUF = byte(0x09)
)
var (
bEND = []byte{cEND}
bPRE = []byte{cPRE}
bNIL = []byte{cNIL}
bVAL = []byte{cVAL}
bTME = []byte{cTME}
bNEG = []byte{cNEG}
bPOS = []byte{cPOS}
bSTR = []byte{cSTR}
bARR = []byte{cARR}
bSUF = []byte{cSUF}
bEND = byte(0x00)
bPRE = byte(0x01)
bNIL = byte(0x02)
bVAL = byte(0x03)
bTME = byte(0x04)
bNEG = byte(0x05)
bPOS = byte(0x06)
bSTR = byte(0x07)
bARR = byte(0x08)
bSUF = byte(0x09)
)
const (

View file

@ -161,7 +161,7 @@ func TestMain(t *testing.T) {
new: &Table{},
},
{
str: "/surreal/abcum/*/database/*/person/*/\x00",
str: "/surreal/abcum/*/database/*/person/*/\x01",
obj: &Thing{KV: "surreal", NS: "abcum", DB: "database", TB: "person", ID: Prefix},
new: &Thing{},
},

View file

@ -19,12 +19,7 @@ import "fmt"
// output decodes an encoded string using the unicode collation algorithm.
func output(items ...interface{}) (out string) {
for _, v := range items {
switch v.(type) {
default:
out = out + fmt.Sprintf("/%s", v)
case []interface{}:
out = out + fmt.Sprintf("/%v", v)
}
out = out + fmt.Sprintf("/%v", v)
}
return
}

View file

@ -15,47 +15,66 @@
package keys
import (
"bufio"
"encoding/binary"
"io"
"math"
"time"
"github.com/abcum/bump"
)
type reader struct {
*bufio.Reader
r *bump.Reader
}
func newReader(r io.Reader) *reader {
func newReader() *reader {
return &reader{
bufio.NewReader(r),
r: bump.NewReader(nil),
}
}
func (r *reader) ReadNext(exp byte) (fnd bool) {
byt, _ := r.ReadByte()
if exp == byt {
func (r *reader) unread() {
}
func (r *reader) lookNext() (byt byte) {
byt, _ = r.r.PeekByte()
return
}
func (r *reader) readNext(exp byte) (fnd bool) {
if byt, _ := r.r.PeekByte(); byt == exp {
r.r.ReadByte()
return true
}
r.UnreadByte()
return false
}
func (r *reader) ReadUpto(exp ...byte) (byt []byte) {
func (r *reader) readSize(sze int) (byt []byte) {
byt, _ = r.r.ReadBytes(sze)
return byt
}
for i := 0; i < len(exp); i++ {
if i == 0 {
rng, _ := r.ReadBytes(exp[i])
byt = append(byt, rng...)
func (r *reader) readUpto(exp ...byte) (byt []byte) {
LOOP:
for {
bit, _ := r.r.ReadByte()
byt = append(byt, bit)
if bit != exp[0] {
continue
}
if i >= 1 {
if r.ReadNext(exp[i]) {
byt = append(byt, exp[i])
for j := 1; j < len(exp); j++ {
if r.readNext(exp[j]) {
byt = append(byt, bit)
continue
} else {
i = 0
}
break LOOP
}
break
}
return byt[:len(byt)-len(exp)]
@ -68,72 +87,82 @@ func (r *reader) ReadUpto(exp ...byte) (byt []byte) {
// --------------------------------------------------
// --------------------------------------------------
func (r *reader) FindNext() (byt byte) {
byt, _ = r.ReadByte()
r.UnreadByte()
return
func (r *reader) readAny() (val interface{}) {
return r.readUpto(bEND)
}
func (r *reader) FindAny() (val interface{}) {
return r.ReadUpto(cEND)
}
func (r *reader) FindNull() (val interface{}) {
if r.ReadNext(cNIL) {
r.ReadNext(cEND)
func (r *reader) readNull() (val interface{}) {
if r.readNext(bNIL) {
r.readNext(bEND)
}
return
}
func (r *reader) FindTime() (val time.Time) {
if r.ReadNext(cTME) {
var out int64
binary.Read(r.Reader, binary.BigEndian, &out)
val = time.Unix(0, out).UTC()
r.ReadNext(cEND)
func (r *reader) readTime() (val time.Time) {
if r.readNext(bTME) {
bin := r.readSize(8)
dec := binary.BigEndian.Uint64(bin)
val = time.Unix(0, int64(dec)).UTC()
r.readNext(bEND)
}
return
}
func (r *reader) FindBool() (val bool) {
if r.ReadNext(cVAL) {
val = r.ReadNext(cVAL)
r.ReadNext(cEND)
func (r *reader) readBool() (val bool) {
if r.readNext(bVAL) {
val = r.readNext(bVAL)
r.readNext(bEND)
}
return
}
func (r *reader) FindBytes() (val []byte) {
if r.ReadNext(cSTR) {
val = r.ReadUpto(cEND, cEND)
func (r *reader) readBytes() (val []byte) {
if r.readNext(bSTR) {
val = r.readUpto(bEND, bEND)
}
return
}
func (r *reader) FindString() (val string) {
if r.ReadNext(cSTR) {
val = string(r.ReadUpto(cEND, cEND))
} else if r.ReadNext(cPRE) {
func (r *reader) readFloat() (val float64) {
if r.readNext(bNEG) {
bin := r.readSize(8)
dec := binary.BigEndian.Uint64(bin)
val = math.Float64frombits(^dec)
r.readNext(bEND)
} else if r.readNext(bPOS) {
bin := r.readSize(8)
dec := binary.BigEndian.Uint64(bin)
val = math.Float64frombits(dec)
r.readNext(bEND)
}
return
}
func (r *reader) readString() (val string) {
if r.readNext(bSTR) {
val = string(r.readUpto(bEND, bEND))
} else if r.readNext(bPRE) {
val = Prefix
r.ReadNext(cEND)
} else if r.ReadNext(cSUF) {
r.readNext(bEND)
} else if r.readNext(bSUF) {
val = Suffix
r.ReadNext(cEND)
r.readNext(bEND)
}
return
}
func (r *reader) FindNumber() (val interface{}) {
var dec uint64
func (r *reader) readNumber() (val interface{}) {
var num float64
if r.ReadNext(cNEG) {
binary.Read(r.Reader, binary.BigEndian, &dec)
if r.readNext(bNEG) {
bin := r.readSize(8)
dec := binary.BigEndian.Uint64(bin)
num = math.Float64frombits(^dec)
r.ReadNext(cEND)
} else if r.ReadNext(cPOS) {
binary.Read(r.Reader, binary.BigEndian, &dec)
r.readNext(bEND)
} else if r.readNext(bPOS) {
bin := r.readSize(8)
dec := binary.BigEndian.Uint64(bin)
num = math.Float64frombits(dec)
r.ReadNext(cEND)
r.readNext(bEND)
}
if math.Trunc(num) == num {
return int64(math.Trunc(num))
@ -141,89 +170,27 @@ func (r *reader) FindNumber() (val interface{}) {
return num
}
func (r *reader) FindDouble() (val float64) {
var dec uint64
if r.ReadNext(cNEG) {
binary.Read(r.Reader, binary.BigEndian, &dec)
val = math.Float64frombits(^dec)
r.ReadNext(cEND)
} else if r.ReadNext(cPOS) {
binary.Read(r.Reader, binary.BigEndian, &dec)
val = math.Float64frombits(dec)
r.ReadNext(cEND)
}
return
}
func (r *reader) FindNumberInt() (val int) {
return int(r.FindDouble())
}
func (r *reader) FindNumberInt8() (val int8) {
return int8(r.FindDouble())
}
func (r *reader) FindNumberInt16() (val int16) {
return int16(r.FindDouble())
}
func (r *reader) FindNumberInt32() (val int32) {
return int32(r.FindDouble())
}
func (r *reader) FindNumberInt64() (val int64) {
return int64(r.FindDouble())
}
func (r *reader) FindNumberUint() (val uint) {
return uint(r.FindDouble())
}
func (r *reader) FindNumberUint8() (val uint8) {
return uint8(r.FindDouble())
}
func (r *reader) FindNumberUint16() (val uint16) {
return uint16(r.FindDouble())
}
func (r *reader) FindNumberUint32() (val uint32) {
return uint32(r.FindDouble())
}
func (r *reader) FindNumberUint64() (val uint64) {
return uint64(r.FindDouble())
}
func (r *reader) FindNumberFloat32() (val float32) {
return float32(r.FindDouble())
}
func (r *reader) FindNumberFloat64() (val float64) {
return float64(r.FindDouble())
}
func (r *reader) FindArray() (val []interface{}) {
if r.ReadNext(cARR) {
for !r.ReadNext(cEND) {
switch fnd := r.FindNext(); fnd {
func (r *reader) readArray() (val []interface{}) {
if r.readNext(bARR) {
for !r.readNext(bEND) {
switch r.lookNext() {
default:
val = append(val, []interface{}{r.FindAny()}...)
case cNIL:
val = append(val, []interface{}{r.FindNull()}...)
case cVAL:
val = append(val, []interface{}{r.FindBool()}...)
case cTME:
val = append(val, []interface{}{r.FindTime()}...)
case cNEG, cPOS:
val = append(val, []interface{}{r.FindNumber()}...)
case cSTR, cPRE, cSUF:
val = append(val, []interface{}{r.FindString()}...)
case cARR:
val = append(val, []interface{}{r.FindArray()}...)
val = append(val, []interface{}{r.readAny()}...)
case bNIL:
val = append(val, []interface{}{r.readNull()}...)
case bVAL:
val = append(val, []interface{}{r.readBool()}...)
case bTME:
val = append(val, []interface{}{r.readTime()}...)
case bNEG, bPOS:
val = append(val, []interface{}{r.readNumber()}...)
case bSTR, bPRE, bSUF:
val = append(val, []interface{}{r.readString()}...)
case bARR:
val = append(val, []interface{}{r.readArray()}...)
}
}
r.ReadNext(cEND)
r.readNext(bEND)
}
return
}

View file

@ -16,86 +16,51 @@ package keys
import (
"encoding/binary"
"io"
"math"
"reflect"
"time"
"unsafe"
"github.com/abcum/bump"
)
type writer struct {
io.Writer
w *bump.Writer
}
func newWriter(w io.Writer) *writer {
func newWriter() *writer {
return &writer{
w,
w: bump.NewWriter(nil),
}
}
func (w *writer) write(i interface{}) {
switch v := i.(type) {
case []byte:
w.Write(v)
case string:
w.writeStr(v)
case time.Time:
w.writeTme(v)
case uint:
w.writeNum(float64(v))
case uint8:
w.writeNum(float64(v))
case uint16:
w.writeNum(float64(v))
case uint32:
w.writeNum(float64(v))
case uint64:
w.writeNum(float64(v))
case int:
w.writeNum(float64(v))
case int8:
w.writeNum(float64(v))
case int16:
w.writeNum(float64(v))
case int32:
w.writeNum(float64(v))
case int64:
w.writeNum(float64(v))
case float32:
w.writeNum(float64(v))
case float64:
w.writeNum(float64(v))
}
func (w *writer) writeOne(v byte) {
w.w.WriteByte(v)
}
func (w *writer) writeStr(v string) {
b := *(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&v))))
w.Write(b)
func (w *writer) writeMany(v []byte) {
w.w.WriteBytes(v)
}
func (w *writer) writeTme(v time.Time) {
func (w *writer) writeTime(v time.Time) {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(v.UTC().UnixNano()))
w.Write(b)
w.w.WriteBytes(b)
}
func (w *writer) writeNum(v float64) {
func (w *writer) writeFloat(v float64) {
b := make([]byte, 8)
if v < 0 {
w.Write(bNEG)
w.w.WriteByte(bNEG)
binary.BigEndian.PutUint64(b, ^math.Float64bits(v))
} else {
w.Write(bPOS)
w.w.WriteByte(bPOS)
binary.BigEndian.PutUint64(b, math.Float64bits(v))
}
w.Write(b)
w.w.WriteBytes(b)
}
func (w *writer) writeString(v string) {
b := *(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&v))))
w.w.WriteBytes(b)
}