From e300e9c423488287d8163c98707a12742f94179d Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Thu, 16 Nov 2017 20:18:42 +0000 Subject: [PATCH] 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. --- util/keys/decode.go | 178 ++++++++++++++++-------------- util/keys/encode.go | 205 ++++++++++++++++++++++------------ util/keys/keys.go | 39 +++---- util/keys/keys_test.go | 2 +- util/keys/output.go | 7 +- util/keys/reader.go | 243 ++++++++++++++++++----------------------- util/keys/writer.go | 75 ++++--------- 7 files changed, 370 insertions(+), 379 deletions(-) diff --git a/util/keys/decode.go b/util/keys/decode.go index 8828c4d4..3f3471f2 100644 --- a/util/keys/decode.go +++ b/util/keys/decode.go @@ -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() } diff --git a/util/keys/encode.go b/util/keys/encode.go index 99d47165..e5e5d823 100644 --- a/util/keys/encode.go +++ b/util/keys/encode.go @@ -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) } diff --git a/util/keys/keys.go b/util/keys/keys.go index 2c6225ce..cc7a6102 100644 --- a/util/keys/keys.go +++ b/util/keys/keys.go @@ -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 ( diff --git a/util/keys/keys_test.go b/util/keys/keys_test.go index 0859431a..771dba6e 100644 --- a/util/keys/keys_test.go +++ b/util/keys/keys_test.go @@ -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{}, }, diff --git a/util/keys/output.go b/util/keys/output.go index 6808da95..c82f0771 100644 --- a/util/keys/output.go +++ b/util/keys/output.go @@ -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 } diff --git a/util/keys/reader.go b/util/keys/reader.go index 856b2174..4f8e0916 100644 --- a/util/keys/reader.go +++ b/util/keys/reader.go @@ -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 } diff --git a/util/keys/writer.go b/util/keys/writer.go index fad7456b..a0b2deb6 100644 --- a/util/keys/writer.go +++ b/util/keys/writer.go @@ -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) }