Skip to content

Commit 93a32f6

Browse files
Merge pull request #133 from Theodus/master
Bitmap
2 parents 6980a5f + e9712ca commit 93a32f6

File tree

8 files changed

+260
-104
lines changed

8 files changed

+260
-104
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
*.out
2-
*.test
2+
*.test
3+
.idea

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ Bitarray used to detect existence without having to resort to hashing with
2121
hashmaps. Requires entities have a uint64 unique identifier. Two
2222
implementations exist, regular and sparse. Sparse saves a great deal of space
2323
but insertions are O(log n). There are some useful functions on the BitArray
24-
interface to detect intersection between two bitarrays.
24+
interface to detect intersection between two bitarrays. This package also
25+
includes bitmaps of length 32 and 64 that provide increased speed and O(1) for
26+
all operations by storing the bitmaps in unsigned integers rather than arrays.
2527

2628
#### Futures
2729

bitarray/bitmap.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
Copyright (c) 2016, Theodore Butler
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
* Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
11+
* Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
15+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
// Package bitmap contains bitmaps of length 32 and 64 for tracking bool
28+
// values without the need for arrays or hashing.
29+
package bitarray
30+
31+
// Bitmap32 tracks 32 bool values within a uint32
32+
type Bitmap32 uint32
33+
34+
// SetBit returns a Bitmap32 with the bit at the given position set to 1
35+
func (b Bitmap32) SetBit(pos uint) Bitmap32 {
36+
return b | (1 << pos)
37+
}
38+
39+
// ClearBit returns a Bitmap32 with the bit at the given position set to 0
40+
func (b Bitmap32) ClearBit(pos uint) Bitmap32 {
41+
return b & ^(1 << pos)
42+
}
43+
44+
// GetBit returns true if the bit at the given position in the Bitmap32 is 1
45+
func (b Bitmap32) GetBit(pos uint) bool {
46+
return (b & (1 << pos)) != 0
47+
}
48+
49+
// PopCount returns the amount of bits set to 1 in the Bitmap32
50+
func (b Bitmap32) PopCount() int {
51+
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
52+
b -= (b >> 1) & 0x55555555
53+
b = (b>>2)&0x33333333 + b&0x33333333
54+
b += b >> 4
55+
b &= 0x0f0f0f0f
56+
b *= 0x01010101
57+
return int(byte(b >> 24))
58+
}
59+
60+
// Bitmap64 tracks 64 bool values within a uint64
61+
type Bitmap64 uint64
62+
63+
// SetBit returns a Bitmap64 with the bit at the given position set to 1
64+
func (b Bitmap64) SetBit(pos uint) Bitmap64 {
65+
return b | (1 << pos)
66+
}
67+
68+
// ClearBit returns a Bitmap64 with the bit at the given position set to 0
69+
func (b Bitmap64) ClearBit(pos uint) Bitmap64 {
70+
return b & ^(1 << pos)
71+
}
72+
73+
// GetBit returns true if the bit at the given position in the Bitmap64 is 1
74+
func (b Bitmap64) GetBit(pos uint) bool {
75+
return (b & (1 << pos)) != 0
76+
}
77+
78+
// PopCount returns the amount of bits set to 1 in the Bitmap64
79+
func (b Bitmap64) PopCount() int {
80+
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
81+
b -= (b >> 1) & 0x5555555555555555
82+
b = (b>>2)&0x3333333333333333 + b&0x3333333333333333
83+
b += b >> 4
84+
b &= 0x0f0f0f0f0f0f0f0f
85+
b *= 0x0101010101010101
86+
return int(byte(b >> 56))
87+
}

bitarray/bitmap_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
Copyright (c) 2016, Theodore Butler
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
* Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
11+
* Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
15+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
package bitarray
28+
29+
import (
30+
"testing"
31+
32+
"github.com/stretchr/testify/assert"
33+
)
34+
35+
func TestBitmap32_PopCount(t *testing.T) {
36+
b := []uint32{
37+
uint32(0x55555555), // 0x55555555 = 01010101 01010101 01010101 01010101
38+
uint32(0x33333333), // 0x33333333 = 00110011 00110011 00110011 00110011
39+
uint32(0x0F0F0F0F), // 0x0F0F0F0F = 00001111 00001111 00001111 00001111
40+
uint32(0x00FF00FF), // 0x00FF00FF = 00000000 11111111 00000000 11111111
41+
uint32(0x0000FFFF), // 0x0000FFFF = 00000000 00000000 11111111 11111111
42+
}
43+
for _, x := range b {
44+
assert.Equal(t, 16, Bitmap32(x).PopCount())
45+
}
46+
}
47+
48+
func TestBitmap64_PopCount(t *testing.T) {
49+
b := []uint64{
50+
uint64(0x5555555555555555),
51+
uint64(0x3333333333333333),
52+
uint64(0x0F0F0F0F0F0F0F0F),
53+
uint64(0x00FF00FF00FF00FF),
54+
uint64(0x0000FFFF0000FFFF),
55+
}
56+
for _, x := range b {
57+
assert.Equal(t, 32, Bitmap64(x).PopCount())
58+
}
59+
}
60+
61+
func TestBitmap32_SetBit(t *testing.T) {
62+
m := Bitmap32(0)
63+
assert.Equal(t, Bitmap32(0x4), m.SetBit(2))
64+
}
65+
66+
func TestBitmap32_ClearBit(t *testing.T) {
67+
m := Bitmap32(0x4)
68+
assert.Equal(t, Bitmap32(0), m.ClearBit(2))
69+
}
70+
71+
func TestBitmap32_zGetBit(t *testing.T) {
72+
m := Bitmap32(0x55555555)
73+
assert.Equal(t, true, m.GetBit(2))
74+
}
75+
76+
func TestBitmap64_SetBit(t *testing.T) {
77+
m := Bitmap64(0)
78+
assert.Equal(t, Bitmap64(0x4), m.SetBit(2))
79+
}
80+
81+
func TestBitmap64_ClearBit(t *testing.T) {
82+
m := Bitmap64(0x4)
83+
assert.Equal(t, Bitmap64(0), m.ClearBit(2))
84+
}
85+
86+
func TestBitmap64_GetBit(t *testing.T) {
87+
m := Bitmap64(0x55555555)
88+
assert.Equal(t, true, m.GetBit(2))
89+
}
90+
91+
func BenchmarkBitmap32_PopCount(b *testing.B) {
92+
m := Bitmap32(0x33333333)
93+
b.ResetTimer()
94+
for i := b.N; i > 0; i-- {
95+
m.PopCount()
96+
}
97+
}
98+
99+
func BenchmarkBitmap64_PopCount(b *testing.B) {
100+
m := Bitmap64(0x3333333333333333)
101+
b.ResetTimer()
102+
for i := b.N; i > 0; i-- {
103+
m.PopCount()
104+
}
105+
}

trie/dtrie/dtrie.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ type Dtrie struct {
3939
hasher func(v interface{}) uint32
4040
}
4141

42+
type entry struct {
43+
hash uint32
44+
key interface{}
45+
value interface{}
46+
}
47+
48+
func (e *entry) KeyHash() uint32 {
49+
return e.hash
50+
}
51+
52+
func (e *entry) Key() interface{} {
53+
return e.key
54+
}
55+
56+
func (e *entry) Value() interface{} {
57+
return e.value
58+
}
59+
4260
// New creates an empty DTrie with the given hashing function.
4361
// If nil is passed in, the default hashing function will be used.
4462
func New(hasher func(v interface{}) uint32) *Dtrie {
@@ -59,16 +77,16 @@ func (d *Dtrie) Size() (size int) {
5977
return size
6078
}
6179

62-
// Get returns the Entry for the associated key or returns nil if the
80+
// Get returns the value for the associated key or returns nil if the
6381
// key does not exist.
64-
func (d *Dtrie) Get(key interface{}) Entry {
65-
return get(d.root, d.hasher(key), key)
82+
func (d *Dtrie) Get(key interface{}) interface{} {
83+
return get(d.root, d.hasher(key), key).Value()
6684
}
6785

68-
// Insert adds an entry to the Dtrie, replacing the existing value if
86+
// Insert adds a key value pair to the Dtrie, replacing the existing value if
6987
// the key already exists and returns the resulting Dtrie.
70-
func (d *Dtrie) Insert(entry Entry) *Dtrie {
71-
root := insert(d.root, entry)
88+
func (d *Dtrie) Insert(key, value interface{}) *Dtrie {
89+
root := insert(d.root, &entry{d.hasher(key), key, value})
7290
return &Dtrie{root, d.hasher}
7391
}
7492

trie/dtrie/dtrie_test.go

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,54 +27,18 @@ 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"
3433
)
3534

36-
func TestPopCount(t *testing.T) {
37-
b := []uint32{
38-
uint32(0x55555555), // 0x55555555 = 01010101 01010101 01010101 01010101
39-
uint32(0x33333333), // 0x33333333 = 00110011 00110011 00110011 00110011
40-
uint32(0x0F0F0F0F), // 0x0F0F0F0F = 00001111 00001111 00001111 00001111
41-
uint32(0x00FF00FF), // 0x00FF00FF = 00000000 11111111 00000000 11111111
42-
uint32(0x0000FFFF), // 0x0000FFFF = 00000000 00000000 11111111 11111111
43-
}
44-
for _, x := range b {
45-
assert.Equal(t, 16, popCount(x))
46-
}
47-
}
48-
4935
func TestDefaultHasher(t *testing.T) {
5036
assert.Equal(t,
5137
defaultHasher(map[int]string{11234: "foo"}),
5238
defaultHasher(map[int]string{11234: "foo"}))
5339
assert.NotEqual(t, defaultHasher("foo"), defaultHasher("bar"))
5440
}
5541

56-
type testEntry struct {
57-
hash uint32
58-
key int
59-
value int
60-
}
61-
62-
func (e *testEntry) KeyHash() uint32 {
63-
return e.hash
64-
}
65-
66-
func (e *testEntry) Key() interface{} {
67-
return e.key
68-
}
69-
70-
func (e *testEntry) Value() interface{} {
71-
return e.value
72-
}
73-
74-
func (e *testEntry) String() string {
75-
return fmt.Sprint(e.value)
76-
}
77-
7842
func collisionHash(key interface{}) uint32 {
7943
return uint32(0xffffffff) // for testing collisions
8044
}
@@ -87,7 +51,7 @@ func TestInsert(t *testing.T) {
8751
func insertTest(t *testing.T, hashfunc func(interface{}) uint32, count int) *node {
8852
n := emptyNode(0, 32)
8953
for i := 0; i < count; i++ {
90-
n = insert(n, &testEntry{hashfunc(i), i, i})
54+
n = insert(n, &entry{hashfunc(i), i, i})
9155
}
9256
return n
9357
}
@@ -130,7 +94,7 @@ func TestUpdate(t *testing.T) {
13094
func updateTest(t *testing.T, hashfunc func(interface{}) uint32, count int) {
13195
n := insertTest(t, hashfunc, count)
13296
for i := 0; i < count; i++ {
133-
n = insert(n, &testEntry{hashfunc(i), i, -i})
97+
n = insert(n, &entry{hashfunc(i), i, -i})
13498
}
13599
}
136100

@@ -152,7 +116,7 @@ func TestIterate(t *testing.T) {
152116
close(stop)
153117
}
154118
}
155-
assert.Equal(t, c, 100)
119+
assert.True(t, c == 100)
156120
// test with collisions
157121
n = insertTest(t, collisionHash, 1000)
158122
c = 0
@@ -174,7 +138,7 @@ func BenchmarkInsert(b *testing.B) {
174138
n := emptyNode(0, 32)
175139
b.ResetTimer()
176140
for i := b.N; i > 0; i-- {
177-
n = insert(n, &testEntry{defaultHasher(i), i, i})
141+
n = insert(n, &entry{defaultHasher(i), i, i})
178142
}
179143
}
180144

@@ -201,6 +165,6 @@ func BenchmarkUpdate(b *testing.B) {
201165
n := insertTest(nil, defaultHasher, b.N)
202166
b.ResetTimer()
203167
for i := b.N; i > 0; i-- {
204-
n = insert(n, &testEntry{defaultHasher(i), i, -i})
168+
n = insert(n, &entry{defaultHasher(i), i, -i})
205169
}
206170
}

0 commit comments

Comments
 (0)