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

View file

@ -15,8 +15,7 @@
package keys package keys
import ( import (
"bytes" "sync"
"io"
"time" "time"
) )
@ -24,17 +23,35 @@ type encoder struct {
w *writer w *writer
} }
// encode encodes an interface using the unicode collation algorithm. var encoders = sync.Pool{
func encode(items ...interface{}) []byte { New: func() interface{} {
b := &bytes.Buffer{} return &encoder{
newEncoder(b).Encode(items...) w: newWriter(),
return b.Bytes() }
},
} }
func newEncoder(w io.Writer) *encoder { // Encode encodes an interface using the unicode collation algorithm.
return &encoder{ func Encode(items ...interface{}) []byte {
w: newWriter(w), 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{}) { func (e *encoder) Encode(items ...interface{}) {
@ -45,29 +62,29 @@ func (e *encoder) Encode(items ...interface{}) {
case nil: case nil:
e.w.write(bNIL) e.w.writeOne(bNIL)
e.w.write(bEND) e.w.writeOne(bEND)
case bool: case bool:
e.w.write(bVAL) e.w.writeOne(bVAL)
if value { if value {
e.w.write(bVAL) e.w.writeOne(bVAL)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case time.Time: case time.Time:
e.w.write(bTME) e.w.writeOne(bTME)
e.w.write(value) e.w.writeTime(value)
e.w.write(bEND) e.w.writeOne(bEND)
case []byte: case []byte:
e.w.write(bSTR) e.w.writeOne(bSTR)
e.w.write(value) e.w.writeMany(value)
e.w.write(bEND) e.w.writeOne(bEND)
e.w.write(bEND) e.w.writeOne(bEND)
case string: case string:
@ -76,156 +93,202 @@ func (e *encoder) Encode(items ...interface{}) {
} }
if value == Prefix { if value == Prefix {
e.w.write(bPRE) e.w.writeOne(bPRE)
e.w.write(bEND) e.w.writeOne(bEND)
break break
} }
if value == Suffix { if value == Suffix {
e.w.write(bSUF) e.w.writeOne(bSUF)
e.w.write(bEND) e.w.writeOne(bEND)
break break
} }
e.w.write(bSTR) e.w.writeOne(bSTR)
e.w.write(value) e.w.writeString(value)
e.w.write(bEND) e.w.writeOne(bEND)
e.w.write(bEND) e.w.writeOne(bEND)
case float32, float64: case int:
e.w.write(value) e.w.writeFloat(float64(value))
e.w.write(bEND) e.w.writeOne(bEND)
case int, int8, int16, int32, int64: case int8:
e.w.write(value) e.w.writeFloat(float64(value))
e.w.write(bEND) e.w.writeOne(bEND)
case uint, uint8, uint16, uint32, uint64: case int16:
e.w.write(value) e.w.writeFloat(float64(value))
e.w.write(bEND) 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: case []time.Time:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []bool: case []bool:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []string: case []string:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []int: case []int:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { 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: case []int8:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []int16: case []int16:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []int32: case []int32:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []int64: case []int64:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []uint: case []uint:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []uint16: case []uint16:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []uint32: case []uint32:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []uint64: case []uint64:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []float32: case []float32:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []float64: case []float64:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) e.Encode(val)
} }
e.w.write(bEND) e.w.writeOne(bEND)
case []interface{}: case []interface{}:
e.w.write(bARR) e.w.writeOne(bARR)
for _, val := range value { for _, val := range value {
e.Encode(val) 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 is the highest char found in a key
Suffix = suffix Suffix = suffix
// Ignore specifies an ignored field // Ignore specifies an ignored field
ignore = "\x01" ignore = "\x00"
// Prefix is the lowest char found in a key // Prefix is the lowest char found in a key
prefix = "\x00" prefix = "\x01"
// Suffix is the highest char found in a key // Suffix is the highest char found in a key
suffix = "\xff" suffix = "\xff"
) )
@ -39,33 +39,20 @@ var (
) )
var ( var (
skip interface{} skip string
) )
var ( var (
cEND = byte(0x00) bEND = byte(0x00)
cPRE = byte(0x01) bPRE = byte(0x01)
cNIL = byte(0x02) bNIL = byte(0x02)
cVAL = byte(0x03) bVAL = byte(0x03)
cTME = byte(0x04) bTME = byte(0x04)
cNEG = byte(0x05) bNEG = byte(0x05)
cPOS = byte(0x06) bPOS = byte(0x06)
cSTR = byte(0x07) bSTR = byte(0x07)
cARR = byte(0x08) bARR = byte(0x08)
cSUF = byte(0x09) bSUF = 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}
) )
const ( const (

View file

@ -161,7 +161,7 @@ func TestMain(t *testing.T) {
new: &Table{}, 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}, obj: &Thing{KV: "surreal", NS: "abcum", DB: "database", TB: "person", ID: Prefix},
new: &Thing{}, new: &Thing{},
}, },

View file

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

View file

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

View file

@ -16,86 +16,51 @@ package keys
import ( import (
"encoding/binary" "encoding/binary"
"io"
"math" "math"
"reflect" "reflect"
"time" "time"
"unsafe" "unsafe"
"github.com/abcum/bump"
) )
type writer struct { type writer struct {
io.Writer w *bump.Writer
} }
func newWriter(w io.Writer) *writer { func newWriter() *writer {
return &writer{ return &writer{
w, w: bump.NewWriter(nil),
} }
} }
func (w *writer) write(i interface{}) { func (w *writer) writeOne(v byte) {
w.w.WriteByte(v)
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) writeStr(v string) { func (w *writer) writeMany(v []byte) {
b := *(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&v)))) w.w.WriteBytes(v)
w.Write(b)
} }
func (w *writer) writeTme(v time.Time) { func (w *writer) writeTime(v time.Time) {
b := make([]byte, 8) b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(v.UTC().UnixNano())) 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) b := make([]byte, 8)
if v < 0 { if v < 0 {
w.Write(bNEG) w.w.WriteByte(bNEG)
binary.BigEndian.PutUint64(b, ^math.Float64bits(v)) binary.BigEndian.PutUint64(b, ^math.Float64bits(v))
} else { } else {
w.Write(bPOS) w.w.WriteByte(bPOS)
binary.BigEndian.PutUint64(b, math.Float64bits(v)) 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)
} }