2022-01-22 09:49:46 +00:00
|
|
|
package pmap
|
|
|
|
|
|
|
|
const deg = 8 // branch factor of nodes
|
|
|
|
const log2deg = 3
|
|
|
|
const mask = 0b111
|
|
|
|
|
|
|
|
type Key = interface{}
|
|
|
|
type Value = interface{}
|
|
|
|
|
|
|
|
type Map interface {
|
|
|
|
Get(Key) (Value, bool)
|
|
|
|
Set(Key, Value) Map
|
|
|
|
Del(Key) Map
|
|
|
|
Len() int
|
|
|
|
}
|
|
|
|
|
|
|
|
type pmap struct {
|
|
|
|
root interface{}
|
|
|
|
len int
|
|
|
|
hash func(Key) uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// A Map implemented as a hashed trie
|
|
|
|
type node struct {
|
|
|
|
child [deg]interface{}
|
|
|
|
bitmap uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type collision struct {
|
|
|
|
hash uint32
|
|
|
|
leaf []leaf
|
|
|
|
}
|
|
|
|
|
|
|
|
type leaf struct {
|
|
|
|
k Key
|
|
|
|
v Value
|
|
|
|
}
|
|
|
|
|
|
|
|
func New() Map {
|
|
|
|
return pmap{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p pmap) Len() int {
|
|
|
|
return p.len
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p pmap) Get(k Key) (Value, bool) {
|
|
|
|
h := hash(k) // TODO: p.hash
|
|
|
|
return lookup(p.root, 0, h, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p pmap) Set(k Key, v Value) Map {
|
2022-01-22 21:04:29 +00:00
|
|
|
h := hash(k) // TODO: p.hash
|
|
|
|
root, added := insert(p.root, 0, h, k, v, hash)
|
|
|
|
p.root = root
|
|
|
|
if added {
|
|
|
|
p.len++
|
|
|
|
}
|
|
|
|
//pretty.Println(p)
|
|
|
|
return p
|
|
|
|
|
2022-01-22 09:49:46 +00:00
|
|
|
//p.root = leaf{k, v}
|
|
|
|
//p.len = 1
|
|
|
|
//return p
|
|
|
|
|
2022-01-22 21:04:29 +00:00
|
|
|
h = hash(k) // TODO: p.hash
|
2022-01-22 09:49:46 +00:00
|
|
|
n, _ := p.root.(*node)
|
|
|
|
if n == nil {
|
|
|
|
n = &node{}
|
|
|
|
}
|
|
|
|
n.child[h&mask] = leaf{k, v}
|
|
|
|
n.bitmap = 1 << (h & mask)
|
|
|
|
p.root = n
|
|
|
|
p.len++
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p pmap) Del(k Key) Map {
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func hash(k Key) uint32 {
|
|
|
|
u := k.(int)
|
|
|
|
return uint32(uint(u) + uint(u)>>32)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *node) getNode(shift, hash uint32, key Key) interface{} {
|
|
|
|
i := hash >> shift & mask
|
|
|
|
return m.child[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *collision) getNode(hash uint32, key Key) interface{} {
|
|
|
|
if hash != m.hash {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
for i := range m.leaf {
|
|
|
|
if key == m.leaf[i].k {
|
|
|
|
return m.leaf[i].v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func lookup(root interface{}, shift, hash uint32, key Key) (Value, bool) {
|
|
|
|
cur := root
|
|
|
|
for {
|
|
|
|
switch n := cur.(type) {
|
|
|
|
case nil:
|
|
|
|
return nil, false
|
|
|
|
case leaf:
|
|
|
|
if n.k == key {
|
|
|
|
return n.v, true
|
|
|
|
} else {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
case *node:
|
|
|
|
cur = n.getNode(shift, hash, key)
|
|
|
|
shift += log2deg
|
|
|
|
case *collision:
|
|
|
|
cur = n.getNode(hash, key)
|
|
|
|
default:
|
|
|
|
panic("pmap: unhandled case in lookup")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func singleton(key Key, val Value, hash, shift uint32) *node {
|
2022-01-22 21:04:29 +00:00
|
|
|
return newnode(leaf{key, val}, hash, shift)
|
|
|
|
}
|
|
|
|
|
|
|
|
func newnode(child interface{}, hash, shift uint32) *node {
|
2022-01-22 09:49:46 +00:00
|
|
|
n := &node{}
|
|
|
|
idx := hash >> shift & mask
|
2022-01-22 21:04:29 +00:00
|
|
|
n.child[idx] = child
|
2022-01-22 09:49:46 +00:00
|
|
|
n.bitmap = 1 << idx
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
type hashFunc = func(Key) uint32
|
|
|
|
|
|
|
|
func insert(n interface{}, shift, hash uint32, key Key, val Value, hashFn hashFunc) (newNode interface{}, added bool) {
|
|
|
|
if n == nil {
|
|
|
|
return leaf{key, val}, true
|
|
|
|
}
|
2022-01-22 21:04:29 +00:00
|
|
|
var _insert func(n interface{}, shift uint32) interface{}
|
|
|
|
_insert = func(n interface{}, shift uint32) interface{} {
|
|
|
|
//fmt.Printf("insert %v %x %#v\n", shift, hash, n)
|
2022-01-22 09:49:46 +00:00
|
|
|
switch n := n.(type) {
|
|
|
|
//case nil:
|
|
|
|
// added = true
|
|
|
|
// return leaf{key, val}
|
|
|
|
case leaf:
|
|
|
|
if n.k == key {
|
|
|
|
// replace existing entry
|
|
|
|
added = false
|
|
|
|
return leaf{key, val}
|
|
|
|
} else if h := hashFn(n.k); h == hash {
|
|
|
|
// collision
|
|
|
|
added = true
|
|
|
|
return collision{hash, []leaf{{key, val}, n}}
|
|
|
|
} else {
|
2022-01-22 21:04:29 +00:00
|
|
|
if h>>shift == hash>>shift {
|
|
|
|
panic("pmap: infinite loop in insert")
|
|
|
|
}
|
|
|
|
// not a collision, so we must still have some hash bits left
|
2022-01-22 09:49:46 +00:00
|
|
|
// split the trie
|
2022-01-22 21:04:29 +00:00
|
|
|
m := newnode(n, h, shift)
|
|
|
|
return _insert(m, shift)
|
2022-01-22 09:49:46 +00:00
|
|
|
}
|
|
|
|
case *node:
|
|
|
|
c := n.getNode(shift, hash, key)
|
|
|
|
if c == nil {
|
|
|
|
// new node
|
2022-01-22 21:04:29 +00:00
|
|
|
c = leaf{key, val}
|
2022-01-22 09:49:46 +00:00
|
|
|
added = true
|
|
|
|
} else {
|
2022-01-22 21:04:29 +00:00
|
|
|
c = _insert(c, shift+log2deg)
|
2022-01-22 09:49:46 +00:00
|
|
|
}
|
2022-01-22 21:04:29 +00:00
|
|
|
idx := hash >> shift & mask
|
|
|
|
x := &node{child: n.child, bitmap: n.bitmap}
|
|
|
|
x.child[idx] = c
|
|
|
|
x.bitmap |= 1 << idx
|
|
|
|
return x
|
2022-01-22 09:49:46 +00:00
|
|
|
case *collision:
|
|
|
|
if n.hash != hash {
|
2022-01-22 21:04:29 +00:00
|
|
|
// not a collision, so we must still have some hash bits left
|
|
|
|
// split the trie
|
|
|
|
m := newnode(n, n.hash, shift)
|
|
|
|
return _insert(m, shift)
|
2022-01-22 09:49:46 +00:00
|
|
|
}
|
|
|
|
for i := range n.leaf {
|
|
|
|
if key == n.leaf[i].k {
|
|
|
|
// replace existing entry
|
|
|
|
l := make([]leaf, 1, len(n.leaf))
|
|
|
|
l[0] = leaf{key, val}
|
|
|
|
l = append(l, n.leaf[:i]...)
|
|
|
|
l = append(l, n.leaf[i+1:]...)
|
|
|
|
added = false
|
|
|
|
return collision{hash, l}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// new collision
|
|
|
|
added = true
|
|
|
|
return collision{hash, append([]leaf{{key, val}}, n.leaf...)}
|
|
|
|
default:
|
|
|
|
panic("pmap: unhandled case in insert")
|
|
|
|
}
|
|
|
|
}
|
2022-01-22 21:04:29 +00:00
|
|
|
newNode = _insert(n, shift)
|
2022-01-22 09:49:46 +00:00
|
|
|
return
|
|
|
|
}
|