Skip to content

Commit

Permalink
Use 0 as empty metadata to allocate faster
Browse files Browse the repository at this point in the history
Current value has to be written for all metadata values when we're
instantiating a new map or growing.

This changes empty to be the zero byte, and tombstone to be byte 1, by
adding 2 to all hashes.
Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
  • Loading branch information
colega committed Jul 3, 2024
1 parent 9ec4a36 commit b3003fc
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 18 deletions.
2 changes: 1 addition & 1 deletion bits.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func metaMatchH2(m *metadata, h h2) bitset {
}

func metaMatchEmpty(m *metadata) bitset {
return hasZeroByte(castUint64(m) ^ hiBits)
return hasZeroByte(castUint64(m))
}

func nextMatch(b *bitset) uint32 {
Expand Down
20 changes: 10 additions & 10 deletions bits_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,25 @@ import (
func TestMatchMetadata(t *testing.T) {
var meta metadata
for i := range meta {
meta[i] = h2(i)
meta[i] = h2(i) + 2
}
t.Run("metaMatchH2", func(t *testing.T) {
for _, x := range meta {
mask := metaMatchH2(&meta, h2(x))
for i, m := range meta {
mask := metaMatchH2(&meta, m)
assert.NotZero(t, mask)
assert.Equal(t, uint32(x), nextMatch(&mask))
assert.Equal(t, uint32(i), nextMatch(&mask))
}
})
t.Run("metaMatchEmpty", func(t *testing.T) {
mask := metaMatchEmpty(&meta)
assert.Equal(t, mask, bitset(0))

for i := range meta {
meta[i] = empty
mask = metaMatchEmpty(&meta)
assert.NotZero(t, mask)
assert.Equal(t, uint32(i), nextMatch(&mask))
meta[i] = h2(i)
meta[i] = h2(i) + 2
}
})
t.Run("nextMatch", func(t *testing.T) {
Expand Down Expand Up @@ -90,11 +91,10 @@ func nextPow2(x uint32) uint32 {
}

func TestConstants(t *testing.T) {
c1, c2 := empty, tombstone
assert.Equal(t, byte(0b1000_0000), byte(c1))
assert.Equal(t, byte(0b1000_0000), reinterpretCast(c1))
assert.Equal(t, byte(0b1111_1110), byte(c2))
assert.Equal(t, byte(0b1111_1110), reinterpretCast(c2))
assert.Equal(t, byte(0b0000_0000), byte(empty))
assert.Equal(t, byte(0b0000_0000), reinterpretCast(empty))
assert.Equal(t, byte(0b0000_0001), byte(tombstone))
assert.Equal(t, byte(0b0000_0001), reinterpretCast(tombstone))
}

func reinterpretCast(i h2) byte {
Expand Down
12 changes: 5 additions & 7 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ type group[K comparable, V any] struct {
const (
h1Mask uint64 = 0xffff_ffff_ffff_ff80
h2Mask uint64 = 0x0000_0000_0000_007f
empty h2 = 0b1000_0000
tombstone h2 = 0b1111_1110
empty h2 = 0b0000_0000
tombstone h2 = 0b0000_0001
)

// h1 is a 57 bit hash prefix
Expand Down Expand Up @@ -236,10 +236,8 @@ func (m *Map[K, V]) Iter(cb func(k K, v V) (stop bool)) {

// Clear removes all elements from the Map.
func (m *Map[K, V]) Clear() {
for i, c := range m.ctrl {
for j := range c {
m.ctrl[i][j] = empty
}
for i := range m.ctrl {
m.ctrl[i] = metadata{}
}
var k K
var v V
Expand Down Expand Up @@ -341,7 +339,7 @@ func newEmptyMetadata() (meta metadata) {
}

func splitHash(h uint64) (h1, h2) {
return h1((h & h1Mask) >> 7), h2(h & h2Mask)
return h1((h & h1Mask) >> 7), h2(h&h2Mask) + 2
}

func probeStart(hi h1, groups int) uint32 {
Expand Down

0 comments on commit b3003fc

Please sign in to comment.