Skip to content

Commit

Permalink
adding Key type
Browse files Browse the repository at this point in the history
  • Loading branch information
jmank88 committed Sep 3, 2017
1 parent 8bbbedb commit f6dc7c3
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
22 changes: 22 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package nuts

import (
"fmt"
)

func ExampleKey_UUID() {
type uuid struct{ a, b uint64 }

u := uuid{
a: 0xaaaaaaaaaaaaaaaa,
b: 0xbbbbbbbbbbbbbbbb,
}

key := make(Key, 16)
key[:8].Put(u.a)
key[8:].Put(u.b)
fmt.Printf("%#x", key)

// Output:
// 0xaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb
}
39 changes: 39 additions & 0 deletions key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package nuts

// KeyLen returns the minimum number of bytes required to represent x; the result is 1 for x == 0.
// Returns 1-8.
func KeyLen(x uint64) int {
n := 1
if x >= 1<<32 {
x >>= 32
n += 4
}
if x >= 1<<16 {
x >>= 16
n += 2
}
if x >= 1<<8 {
x >>= 8
n += 1
}
return n
}

// Key is a byte slice with methods for serializing uint64 (big endian).
// Length can minimized (<8) with KeyLen.
// make(Key, KeyLen(uint64(max)))
// Large Keys can constructed by slicing.
// uuid := make(Key, 16)
// uuid[:8].Put(a)
// uuid[8:].Put(b)
type Key []byte

// Put serializes x into the buffer (big endian). Behavior is undefined when x
// does not fit, so the caller must ensure c is large enough.
func (c Key) Put(x uint64) {
s := uint(8 * (len(c) - 1))
for i := range c {
c[i] = byte(x >> s)
s -= 8
}
}
114 changes: 114 additions & 0 deletions key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package nuts

import (
"bytes"
"strconv"
"testing"
)

func TestKeyLen(t *testing.T) {
for _, test := range []struct {
x uint64
exp int
}{
{0, 1},
{1, 1},
{1 << 8, 2},
{1 << 16, 3},
{1 << 24, 4},
{1 << 32, 5},
{1 << 40, 6},
{1 << 48, 7},
{1 << 56, 8},
} {
got := KeyLen(test.x)
if got != test.exp {
t.Errorf("%d: expected length %d but got %d", test.x, test.exp, got)
}
}
}

func TestNewCacheIntKeyBuf(t *testing.T) {
for _, test := range []struct {
max int
xs []uint64
bs [][]byte
}{
{
max: 1 << 7,
xs: []uint64{0, 1, (1 << 8) - 1},
bs: [][]byte{
{0x00}, {0x01}, {0xFF},
},
},
{
max: 1 << 15,
xs: []uint64{0, 1, (1 << 16) - 1},
bs: [][]byte{
{0x00, 0x00}, {0x00, 0x01}, {0xFF, 0xFF},
},
},
{
max: 1 << 23,
xs: []uint64{0, 1, (1 << 24) - 1},
bs: [][]byte{
{0x00, 0x00, 0x00}, {0x00, 0x00, 0x01}, {0xFF, 0xFF, 0xFF},
},
},
{
max: 1 << 31,
xs: []uint64{0, 1, (1 << 32) - 1},
bs: [][]byte{
{0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x01},
{0xFF, 0xFF, 0xFF, 0xFF},
},
},
{
max: 1 << 39,
xs: []uint64{0, 1, (1 << 40) - 1},
bs: [][]byte{
{0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x01},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
},
},
{
max: 1 << 47,
xs: []uint64{0, 1, (1 << 48) - 1},
bs: [][]byte{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
},
},
{
max: 1 << 55,
xs: []uint64{0, 1, (1 << 56) - 1},
bs: [][]byte{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
},
},
{
max: 1 << 60,
xs: []uint64{0, 1, (1 << 60) - 1},
bs: [][]byte{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
{0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
},
},
} {
t.Run(strconv.Itoa(test.max), func(t *testing.T) {
k := make(Key, KeyLen(uint64(test.max)))
for i, x := range test.xs {
k.Put(x)
if !bytes.Equal(k, test.bs[i]) {
t.Errorf("unexpected serialized integer %d:\n\t(GOT): %#x\n\t(WNT): %#x", x, k, test.bs[i])
}
}
})
}
}

0 comments on commit f6dc7c3

Please sign in to comment.