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:
parent
61015c8f7a
commit
e300e9c423
7 changed files with 370 additions and 379 deletions
|
@ -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()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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{},
|
||||||
},
|
},
|
||||||
|
|
|
@ -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) {
|
|
||||||
default:
|
|
||||||
out = out + fmt.Sprintf("/%s", v)
|
|
||||||
case []interface{}:
|
|
||||||
out = out + fmt.Sprintf("/%v", v)
|
out = out + fmt.Sprintf("/%v", v)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
}
|
|
||||||
if i >= 1 {
|
bit, _ := r.r.ReadByte()
|
||||||
if r.ReadNext(exp[i]) {
|
byt = append(byt, bit)
|
||||||
byt = append(byt, exp[i])
|
if bit != exp[0] {
|
||||||
continue
|
continue
|
||||||
} else {
|
|
||||||
i = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for j := 1; j < len(exp); j++ {
|
||||||
|
if r.readNext(exp[j]) {
|
||||||
|
byt = append(byt, bit)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue