Made encode/decode api more symmetric. Added some unit test for the encoders/decoders.

This commit is contained in:
Sascha L. Teichmann 2014-08-18 18:01:34 +02:00
parent a210207f8e
commit ff14b83b1e
3 changed files with 83 additions and 33 deletions

View File

@ -9,40 +9,40 @@ import (
"strconv" "strconv"
) )
type (
KeyTransformer func(int64) int64
KeyEncoder func(int64) []byte
KeyDecoder func([]byte) int64
KeySplitter func(int64) (int16, int16, int16)
KeyJoiner func(int16, int16, int16) int64
)
// Constructs a database key out of byte slice.
func DecodePosFromBytes(key []byte) (pos int64, err error) {
return strconv.ParseInt(string(key), 10, 64)
}
// Encode a block pos to byte slice.
func EncodePosToBytes(key int64) []byte {
return []byte(strconv.FormatInt(key, 10))
}
func EncodeAsBigEndian(key int64) (enc []byte) {
enc = make([]byte, 8)
binary.BigEndian.PutUint64(enc, uint64(key))
return
}
func DecodeFromBigEndian(key []byte) int64 {
return int64(binary.BigEndian.Uint64(key))
}
const ( const (
numBitsPerComponent = 12 numBitsPerComponent = 12
maxPositive = 2048 maxPositive = 2048
modulo = 4096 modulo = 4096
) )
type (
KeyTransformer func(int64) int64
KeyEncoder func(int64) ([]byte, error)
KeyDecoder func([]byte) (int64, error)
KeySplitter func(int64) (int16, int16, int16)
KeyJoiner func(int16, int16, int16) int64
)
// Constructs a database key out of byte slice.
func DecodeStringFromBytes(key []byte) (pos int64, err error) {
return strconv.ParseInt(string(key), 10, 64)
}
// Encode a block pos to byte slice.
func EncodeStringToBytes(key int64) ([]byte, error) {
return []byte(strconv.FormatInt(key, 10)), nil
}
func EncodeToBigEndian(key int64) (enc []byte, err error) {
enc = make([]byte, 8)
binary.BigEndian.PutUint64(enc, uint64(key))
return
}
func DecodeFromBigEndian(key []byte) (int64, error) {
return int64(binary.BigEndian.Uint64(key)), nil
}
func XYZToInterleaved(x, y, z int16) (result int64) { func XYZToInterleaved(x, y, z int16) (result int64) {
const end = 1 << (numBitsPerComponent + 1) const end = 1 << (numBitsPerComponent + 1)
setmask := int64(1) setmask := int64(1)

View File

@ -2,11 +2,10 @@ package common
import "testing" import "testing"
//var data = []int16{-2}
var data = []int16{ var data = []int16{
-2045, -1850, -1811, -1629, -1104, -2045, -1850, -1811, -1629, -1104,
-967, -725, -646, -329, -212, -967, -725, -646, -329, -212,
-150, 88, 524, 527, 549, -150, -1, 0, 1, 88, 524, 527, 549,
1783, 1817, 1826, 2028, 2032} 1783, 1817, 1826, 2028, 2032}
func allData(f func(int16, int16, int16)) { func allData(f func(int16, int16, int16)) {
@ -19,6 +18,50 @@ func allData(f func(int16, int16, int16)) {
} }
} }
func checkEncodeDecode(
desc string,
join KeyJoiner,
encode KeyEncoder, decode KeyDecoder,
x, y, z int16, t *testing.T) {
k1 := join(x, y, z)
var err error
var b []byte
if b, err = encode(k1); err != nil {
t.Errorf("%s: Failed to encode (%d, %d, %d) %s\n",
desc, x, y, z, err)
return
}
var k2 int64
if k2, err = decode(b); err != nil {
t.Errorf("%s: Failed to decode (%d, %d, %d) %s\n",
desc, x, y, z, err)
return
}
if k1 != k2 {
t.Errorf("%s: Expected %d got %d for (%d, %d, %d) %b\n",
desc, k1, k2, x, y, z)
}
}
func TestEncodeDecode(t *testing.T) {
allData(func(x, y, z int16) {
checkEncodeDecode(
"Big endian",
XYZToInterleaved,
EncodeToBigEndian, DecodeFromBigEndian,
x, y, z, t)
})
allData(func(x, y, z int16) {
checkEncodeDecode(
"String",
XYZToInterleaved,
EncodeStringToBytes, DecodeStringFromBytes,
x, y, z, t)
})
}
func checkJoinSplit( func checkJoinSplit(
desc string, desc string,
join KeyJoiner, split KeySplitter, join KeyJoiner, split KeySplitter,

View File

@ -139,7 +139,7 @@ func (ss *SqliteSession) txStmt(stmt *sql.Stmt) *sql.Stmt {
func (ss *SqliteSession) Fetch(hash, key []byte) (data []byte, err error) { func (ss *SqliteSession) Fetch(hash, key []byte) (data []byte, err error) {
var pos int64 var pos int64
if pos, err = common.DecodePosFromBytes(key); err != nil { if pos, err = common.DecodeStringFromBytes(key); err != nil {
return return
} }
@ -161,7 +161,7 @@ func (ss *SqliteSession) InTransaction() bool {
func (ss *SqliteSession) Store(hash, key, value []byte) (exists bool, err error) { func (ss *SqliteSession) Store(hash, key, value []byte) (exists bool, err error) {
var pos int64 var pos int64
if pos, err = common.DecodePosFromBytes(key); err != nil { if pos, err = common.DecodeStringFromBytes(key); err != nil {
return return
} }
@ -241,13 +241,20 @@ func (ss *SqliteSession) AllKeys(hash []byte) (keys chan []byte, n int, err erro
defer globalLock.RUnlock() defer globalLock.RUnlock()
defer rows.Close() defer rows.Close()
defer close(keys) defer close(keys)
var err error
for rows.Next() { for rows.Next() {
var key int64 var key int64
if err := rows.Scan(&key); err != nil { if err := rows.Scan(&key); err != nil {
log.Printf("WARN: %s", err) log.Printf("WARN: %s", err)
break break
} }
keys <- common.EncodePosToBytes(key) var encoded []byte
if encoded, err = common.EncodeStringToBytes(key); err != nil {
log.Printf("Cannot encode key: %d %s\n", key, err)
break
}
keys <- encoded
} }
}() }()