From ff14b83b1ecdbf180aec84b34f72a562771d8b0b Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Mon, 18 Aug 2014 18:01:34 +0200 Subject: [PATCH] Made encode/decode api more symmetric. Added some unit test for the encoders/decoders. --- common/coords.go | 56 +++++++++++++++++++++---------------------- common/coords_test.go | 47 ++++++++++++++++++++++++++++++++++-- sqlite.go | 13 +++++++--- 3 files changed, 83 insertions(+), 33 deletions(-) diff --git a/common/coords.go b/common/coords.go index 6bbc0af..da10333 100644 --- a/common/coords.go +++ b/common/coords.go @@ -9,40 +9,40 @@ import ( "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 ( numBitsPerComponent = 12 maxPositive = 2048 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) { const end = 1 << (numBitsPerComponent + 1) setmask := int64(1) diff --git a/common/coords_test.go b/common/coords_test.go index 169206f..84e32c9 100644 --- a/common/coords_test.go +++ b/common/coords_test.go @@ -2,11 +2,10 @@ package common import "testing" -//var data = []int16{-2} var data = []int16{ -2045, -1850, -1811, -1629, -1104, -967, -725, -646, -329, -212, - -150, 88, 524, 527, 549, + -150, -1, 0, 1, 88, 524, 527, 549, 1783, 1817, 1826, 2028, 2032} 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( desc string, join KeyJoiner, split KeySplitter, diff --git a/sqlite.go b/sqlite.go index 4f4cc6d..4d9a0ea 100644 --- a/sqlite.go +++ b/sqlite.go @@ -139,7 +139,7 @@ func (ss *SqliteSession) txStmt(stmt *sql.Stmt) *sql.Stmt { func (ss *SqliteSession) Fetch(hash, key []byte) (data []byte, err error) { var pos int64 - if pos, err = common.DecodePosFromBytes(key); err != nil { + if pos, err = common.DecodeStringFromBytes(key); err != nil { return } @@ -161,7 +161,7 @@ func (ss *SqliteSession) InTransaction() bool { func (ss *SqliteSession) Store(hash, key, value []byte) (exists bool, err error) { var pos int64 - if pos, err = common.DecodePosFromBytes(key); err != nil { + if pos, err = common.DecodeStringFromBytes(key); err != nil { return } @@ -241,13 +241,20 @@ func (ss *SqliteSession) AllKeys(hash []byte) (keys chan []byte, n int, err erro defer globalLock.RUnlock() defer rows.Close() defer close(keys) + var err error for rows.Next() { var key int64 if err := rows.Scan(&key); err != nil { log.Printf("WARN: %s", err) 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 } }()