Skip to content

Commit

Permalink
feat: add binary encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
xgzlucario committed Dec 14, 2024
1 parent 7e656f3 commit 05ca100
Show file tree
Hide file tree
Showing 25 changed files with 263 additions and 4 deletions.
17 changes: 17 additions & 0 deletions internal/hash/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package hash
import (
"fmt"
"github.com/stretchr/testify/assert"
"github.com/xgzlucario/rotom/internal/iface"
"golang.org/x/exp/maps"
"testing"
)
Expand Down Expand Up @@ -50,6 +51,10 @@ func FuzzTestMap(f *testing.F) {
ast.ElementsMatch(kv1, kv2)

case 9: // Encode
w := iface.NewWriter(nil)
zipmap.WriteTo(w)
zipmap = New()
zipmap.ReadFrom(iface.NewReaderFrom(w))
}
})
}
Expand Down Expand Up @@ -99,6 +104,18 @@ func FuzzTestSet(f *testing.F) {
ast.ElementsMatch(keys1, keys3)

case 9: // Encode
{
w := iface.NewWriter(nil)
hashset.WriteTo(w)
hashset = NewSet()
hashset.ReadFrom(iface.NewReaderFrom(w))
}
{
w := iface.NewWriter(nil)
zipset.WriteTo(w)
zipset = NewZipSet()
zipset.ReadFrom(iface.NewReaderFrom(w))
}
}
})
}
13 changes: 13 additions & 0 deletions internal/hash/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,16 @@ func (s Set) Scan(fn func(string)) {
func (s Set) Exist(key string) bool { return s.Set.ContainsOne(key) }

func (s Set) Len() int { return s.Cardinality() }

func (s Set) ReadFrom(rd *iface.Reader) {
for !rd.IsEnd() {
s.Add(rd.ReadString())
}
}

// WriteTo encode set to [klen, key, ...].
func (s Set) WriteTo(w *iface.Writer) {
s.Scan(func(key string) {
w.WriteString(key)
})
}
19 changes: 19 additions & 0 deletions internal/hash/zipmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,22 @@ func (zm *ZipMap) Migrate() {
}

func (zm *ZipMap) Len() int { return zm.index.Len() }

func (zm *ZipMap) ReadFrom(rd *iface.Reader) {
zm.unused = int(rd.ReadUint64())
zm.data = rd.ReadBytes()
for !rd.IsEnd() {
zm.index.Put(rd.ReadString(), rd.ReadUint32())
}
}

// WriteTo encode zipmap to [unused, data, key1, pos1, ...].
func (zm *ZipMap) WriteTo(w *iface.Writer) {
w.WriteUint64(uint64(zm.unused))
w.WriteBytes(zm.data)
zm.index.All(func(key string, pos uint32) bool {
w.WriteString(key)
w.WriteUint32(pos)
return true
})
}
8 changes: 8 additions & 0 deletions internal/hash/zipset.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ func (zs *ZipSet) ToSet() *Set {
return s
}

func (zs *ZipSet) ReadFrom(rd *iface.Reader) {
zs.data.ReadFrom(rd)
}

func (zs *ZipSet) WriteTo(w *iface.Writer) {
zs.data.WriteTo(w)
}

func b2s(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
76 changes: 76 additions & 0 deletions internal/iface/encoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package iface

import (
"encoding/binary"
)

var order = binary.LittleEndian

type Writer struct {
b []byte
}

func NewWriter(b []byte) *Writer {
return &Writer{b: b}
}

func (w *Writer) WriteString(key string) {
w.b = binary.AppendUvarint(w.b, uint64(len(key)))
w.b = append(w.b, key...)
}

func (w *Writer) WriteBytes(key []byte) {
w.b = binary.AppendUvarint(w.b, uint64(len(key)))
w.b = append(w.b, key...)
}

func (w *Writer) WriteUint32(n uint32) {
w.b = order.AppendUint32(w.b, n)
}

func (w *Writer) WriteUint64(n uint64) {
w.b = order.AppendUint64(w.b, n)
}

func (w *Writer) Bytes() []byte { return w.b }

func (w *Writer) Reset() { w.b = w.b[:0] }

type Reader struct {
b []byte
}

func NewReader(b []byte) *Reader {
return &Reader{b: b}
}

func NewReaderFrom(w *Writer) *Reader {
return &Reader{b: w.b}
}

func (r *Reader) ReadString() string {
return string(r.ReadBytes())
}

func (r *Reader) ReadBytes() []byte {
klen, n := binary.Uvarint(r.b)
key := r.b[n : int(klen)+n]
r.b = r.b[int(klen)+n:]
return key
}

func (r *Reader) ReadUint32() uint32 {
n := order.Uint32(r.b)
r.b = r.b[4:]
return n
}

func (r *Reader) ReadUint64() uint64 {
n := order.Uint64(r.b)
r.b = r.b[8:]
return n
}

func (r *Reader) IsEnd() bool {
return len(r.b) == 0
}
2 changes: 2 additions & 0 deletions internal/iface/iface.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package iface

type Encoder interface {
WriteTo(writer *Writer)
ReadFrom(reader *Reader)
}

type MapI interface {
Expand Down
16 changes: 15 additions & 1 deletion internal/list/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package list

import (
"github.com/xgzlucario/rotom/internal/iface"
"math/rand/v2"
"testing"

Expand Down Expand Up @@ -97,7 +98,20 @@ func FuzzTestList(f *testing.F) {
ast.ElementsMatch(keys1, keys2)
ast.ElementsMatch(keys1, keys3)

case 7: // Marshal
case 7: // Encode
{
w := iface.NewWriter(nil)
lp.WriteTo(w)
lp = NewListPack()
lp.ReadFrom(iface.NewReaderFrom(w))
}
{
w := iface.NewWriter(nil)
ls.WriteTo(w)
ls = New()
ls.ReadFrom(iface.NewReaderFrom(w))
}
ast.Equal(lp.Len(), ls.Len())
}
})
}
20 changes: 20 additions & 0 deletions internal/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package list
import (
"github.com/xgzlucario/rotom/internal/iface"
"github.com/zyedidia/generic/list"
"unsafe"
)

var (
Expand Down Expand Up @@ -129,3 +130,22 @@ func (ls *QuickList) Range(start int, fn func(key []byte) (stop bool)) {
}
}
}

func (ls *QuickList) ReadFrom(rd *iface.Reader) {
for !rd.IsEnd() {
key := rd.ReadBytes()
ls.RPush(b2s(key))
}
}

// WriteTo encode zipmap to [size, listpack1, listpack2, ...].
func (ls *QuickList) WriteTo(w *iface.Writer) {
ls.Range(0, func(key []byte) (stop bool) {
w.WriteBytes(key)
return false
})
}

func b2s(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
12 changes: 12 additions & 0 deletions internal/list/listpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package list

import (
"encoding/binary"
"github.com/xgzlucario/rotom/internal/iface"
"github.com/xgzlucario/rotom/internal/pool"
"slices"
)
Expand Down Expand Up @@ -163,3 +164,14 @@ func appendEntry(dst []byte, data string) []byte {
dst = append(dst, data...)
return appendUvarint(dst, len(data), true)
}

func (lp *ListPack) ReadFrom(rd *iface.Reader) {
lp.size = rd.ReadUint32()
lp.data = rd.ReadBytes()
}

// WriteTo encode zipmap to [size, data].
func (lp *ListPack) WriteTo(w *iface.Writer) {
w.WriteUint32(lp.size)
w.WriteBytes(lp.data)
}
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/0f07e22c441de464
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(17)
string("")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/13168e93828f3a43
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(27)
string("0")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/15a6db7167d4df30
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(136)
string("0")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/167e1152dc754454
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(186)
string("0")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/17720d681679fc2e
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(356)
string("0")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/1b16223bbfd08585
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(697)
string("0")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/34bed71fad115fa0
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(466)
string("0")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/35c5224f6183dd5c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(88)
string("y")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/64520a7aa2404f5a
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(476)
string("0")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/66ffc8651ce58d98
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(76)
string("%")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/a2867db89164c7e2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(116)
string("0")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/a9c9884151704695
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(156)
string("1")
3 changes: 3 additions & 0 deletions internal/list/testdata/fuzz/FuzzTestList/c17158d6e51c9989
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
go test fuzz v1
int(226)
string("0")
14 changes: 14 additions & 0 deletions internal/zset/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package zset
import (
"fmt"
"github.com/stretchr/testify/assert"
"github.com/xgzlucario/rotom/internal/iface"
"testing"
"time"
)
Expand Down Expand Up @@ -48,6 +49,19 @@ func FuzzTestZSet(f *testing.F) {
ast.Equal(kv1, kv2)

case 9: // Encode
{
w := iface.NewWriter(nil)
zs.WriteTo(w)
zs = New()
zs.ReadFrom(iface.NewReaderFrom(w))
}
{
w := iface.NewWriter(nil)
zzs.WriteTo(w)
zzs = NewZipZSet()
zzs.ReadFrom(iface.NewReaderFrom(w))
}
ast.Equal(zs.Len(), zzs.Len())
}
})
}
14 changes: 11 additions & 3 deletions internal/zset/zipzset.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,19 @@ func (zs *ZipZSet) Len() int {
}

func (zs *ZipZSet) ToZSet() *ZSet {
zs2 := New()
zsNew := New()
zs.Scan(func(key string, score float64) {
zs2.Set(key, score)
zsNew.Set(key, score)
})
return zs2
return zsNew
}

func (zs *ZipZSet) ReadFrom(rd *iface.Reader) {
zs.data.ReadFrom(rd)
}

func (zs *ZipZSet) WriteTo(w *iface.Writer) {
zs.data.WriteTo(w)
}

func b2s(b []byte) string {
Expand Down
17 changes: 17 additions & 0 deletions internal/zset/zset.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/chen3feng/stl4go"
"github.com/cockroachdb/swiss"
"github.com/xgzlucario/rotom/internal/iface"
"math"
)

var (
Expand Down Expand Up @@ -97,3 +98,19 @@ func (z *ZSet) Scan(fn func(key string, score float64)) {
func (z *ZSet) Len() int {
return z.m.Len()
}

func (z *ZSet) ReadFrom(rd *iface.Reader) {
for !rd.IsEnd() {
key := rd.ReadString()
n := rd.ReadUint64()
score := math.Float64frombits(n)
z.Set(key, score)
}
}

func (z *ZSet) WriteTo(w *iface.Writer) {
z.Scan(func(key string, score float64) {
w.WriteString(key)
w.WriteUint64(math.Float64bits(score))
})
}

0 comments on commit 05ca100

Please sign in to comment.