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
|
||||
|
||||
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()
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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{},
|
||||
},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue