Skip to content

Commit 651a021

Browse files
committed
update dtrie to use new bitmap
1 parent 036d4fd commit 651a021

File tree

3 files changed

+45
-45
lines changed

3 files changed

+45
-45
lines changed

trie/dtrie/dtrie.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3232
// Jurgen J. Vinju
3333
package dtrie
3434

35+
import "fmt"
36+
3537
// Dtrie is a persistent hash trie that dynamically expands or shrinks
3638
// to provide efficient memory allocation.
3739
type Dtrie struct {
3840
root *node
3941
hasher func(v interface{}) uint32
4042
}
4143

44+
type entry struct {
45+
hash uint32
46+
key interface{}
47+
value interface{}
48+
}
49+
50+
func (e *entry) KeyHash() uint32 {
51+
return e.hash
52+
}
53+
54+
func (e *entry) Key() interface{} {
55+
return e.key
56+
}
57+
58+
func (e *entry) Value() interface{} {
59+
return e.value
60+
}
61+
62+
func (e *entry) String() string {
63+
return fmt.Sprintf("%v:%v", e.key, e.value)
64+
}
65+
4266
// New creates an empty DTrie with the given hashing function.
4367
// If nil is passed in, the default hashing function will be used.
4468
func New(hasher func(v interface{}) uint32) *Dtrie {
@@ -67,8 +91,8 @@ func (d *Dtrie) Get(key interface{}) Entry {
6791

6892
// Insert adds an entry to the Dtrie, replacing the existing value if
6993
// the key already exists and returns the resulting Dtrie.
70-
func (d *Dtrie) Insert(entry Entry) *Dtrie {
71-
root := insert(d.root, entry)
94+
func (d *Dtrie) Insert(key, value interface{}) *Dtrie {
95+
root := insert(d.root, &entry{d.hasher(key), key, value})
7296
return &Dtrie{root, d.hasher}
7397
}
7498

trie/dtrie/dtrie_test.go

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2727
package dtrie
2828

2929
import (
30-
"fmt"
3130
"testing"
3231

3332
"github.com/stretchr/testify/assert"
@@ -40,28 +39,6 @@ func TestDefaultHasher(t *testing.T) {
4039
assert.NotEqual(t, defaultHasher("foo"), defaultHasher("bar"))
4140
}
4241

43-
type testEntry struct {
44-
hash uint32
45-
key int
46-
value int
47-
}
48-
49-
func (e *testEntry) KeyHash() uint32 {
50-
return e.hash
51-
}
52-
53-
func (e *testEntry) Key() interface{} {
54-
return e.key
55-
}
56-
57-
func (e *testEntry) Value() interface{} {
58-
return e.value
59-
}
60-
61-
func (e *testEntry) String() string {
62-
return fmt.Sprint(e.value)
63-
}
64-
6542
func collisionHash(key interface{}) uint32 {
6643
return uint32(0xffffffff) // for testing collisions
6744
}
@@ -74,7 +51,7 @@ func TestInsert(t *testing.T) {
7451
func insertTest(t *testing.T, hashfunc func(interface{}) uint32, count int) *node {
7552
n := emptyNode(0, 32)
7653
for i := 0; i < count; i++ {
77-
n = insert(n, &testEntry{hashfunc(i), i, i})
54+
n = insert(n, &entry{hashfunc(i), i, i})
7855
}
7956
return n
8057
}
@@ -117,7 +94,7 @@ func TestUpdate(t *testing.T) {
11794
func updateTest(t *testing.T, hashfunc func(interface{}) uint32, count int) {
11895
n := insertTest(t, hashfunc, count)
11996
for i := 0; i < count; i++ {
120-
n = insert(n, &testEntry{hashfunc(i), i, -i})
97+
n = insert(n, &entry{hashfunc(i), i, -i})
12198
}
12299
}
123100

@@ -161,7 +138,7 @@ func BenchmarkInsert(b *testing.B) {
161138
n := emptyNode(0, 32)
162139
b.ResetTimer()
163140
for i := b.N; i > 0; i-- {
164-
n = insert(n, &testEntry{defaultHasher(i), i, i})
141+
n = insert(n, &entry{defaultHasher(i), i, i})
165142
}
166143
}
167144

@@ -188,6 +165,6 @@ func BenchmarkUpdate(b *testing.B) {
188165
n := insertTest(nil, defaultHasher, b.N)
189166
b.ResetTimer()
190167
for i := b.N; i > 0; i-- {
191-
n = insert(n, &testEntry{defaultHasher(i), i, -i})
168+
n = insert(n, &entry{defaultHasher(i), i, -i})
192169
}
193170
}

trie/dtrie/node.go

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ import (
3030
"fmt"
3131
"sync"
3232

33-
"github.com/Workiva/go-datastructures/bitmap"
33+
//TODO switch back to "github.com/Workiva/go-datastructures/bitarray"
34+
"github.com/theodus/go-datastructures/bitarray"
3435
)
3536

3637
type node struct {
3738
entries []Entry
38-
nodeMap bitmap.Bitmap32
39-
dataMap bitmap.Bitmap32
39+
nodeMap bitarray.Bitmap32
40+
dataMap bitarray.Bitmap32
4041
level uint32 // level starts at 0
4142
}
4243

@@ -74,12 +75,14 @@ func emptyNode(level uint32, capacity int) *node {
7475
func insert(n *node, entry Entry) *node {
7576
index := mask(entry.KeyHash(), n.level)
7677
newNode := n
77-
if newNode.level == 6 { // handle hash collisions on 6th level
78-
if newNode.entries[index] == nil {
79-
newNode.entries[index] = entry
80-
newNode.dataMap = newNode.dataMap.SetBit(uint(index))
81-
return newNode
82-
}
78+
// insert directly
79+
if newNode.entries[index] == nil {
80+
newNode.entries[index] = entry
81+
newNode.dataMap = newNode.dataMap.SetBit(uint(index))
82+
return newNode
83+
}
84+
// handle hash collisions on 6th level
85+
if newNode.level == 6 {
8386
if newNode.dataMap.HasBit(uint(index)) {
8487
if newNode.entries[index].Key() == entry.Key() {
8588
newNode.entries[index] = entry
@@ -96,16 +99,12 @@ func insert(n *node, entry Entry) *node {
9699
cNode.entries = append(cNode.entries, entry)
97100
return newNode
98101
}
99-
// insert directly
100-
if !newNode.dataMap.HasBit(uint(index)) && !newNode.nodeMap.HasBit(uint(index)) {
101-
newNode.entries[index] = entry
102-
newNode.dataMap = newNode.dataMap.SetBit(uint(index))
103-
return newNode
104-
}
105-
if newNode.nodeMap.HasBit(uint(index)) { // insert into sub-node
102+
// insert into sub-node
103+
if newNode.nodeMap.HasBit(uint(index)) {
106104
newNode.entries[index] = insert(newNode.entries[index].(*node), entry)
107105
return newNode
108106
}
107+
// replace existing entry
109108
if newNode.entries[index].Key() == entry.Key() {
110109
newNode.entries[index] = entry
111110
return newNode

0 commit comments

Comments
 (0)