mirror of
https://github.com/golang/go
synced 2024-11-19 00:14:39 -07:00
01f8cd246d
They will be deleted from their current homes once this has landed. Changes made to import paths to make the code compile, and to find errchk in the right place in cmd/vet's Makefile. TODO in a later CL: tidy up vet. R=golang-dev, gri CC=golang-dev https://golang.org/cl/9495043
102 lines
2.2 KiB
Go
102 lines
2.2 KiB
Go
package interp
|
|
|
|
// Custom hashtable atop map.
|
|
// For use when the key's equivalence relation is not consistent with ==.
|
|
|
|
// The Go specification doesn't address the atomicity of map operations.
|
|
// The FAQ states that an implementation is permitted to crash on
|
|
// concurrent map access.
|
|
|
|
import (
|
|
"code.google.com/p/go.tools/go/types"
|
|
)
|
|
|
|
type hashable interface {
|
|
hash() int
|
|
eq(x interface{}) bool
|
|
}
|
|
|
|
type entry struct {
|
|
key hashable
|
|
value value
|
|
next *entry
|
|
}
|
|
|
|
// A hashtable atop the built-in map. Since each bucket contains
|
|
// exactly one hash value, there's no need to perform hash-equality
|
|
// tests when walking the linked list. Rehashing is done by the
|
|
// underlying map.
|
|
type hashmap struct {
|
|
table map[int]*entry
|
|
length int // number of entries in map
|
|
}
|
|
|
|
// makeMap returns an empty initialized map of key type kt,
|
|
// preallocating space for reserve elements.
|
|
func makeMap(kt types.Type, reserve int) value {
|
|
if usesBuiltinMap(kt) {
|
|
return make(map[value]value, reserve)
|
|
}
|
|
return &hashmap{table: make(map[int]*entry, reserve)}
|
|
}
|
|
|
|
// delete removes the association for key k, if any.
|
|
func (m *hashmap) delete(k hashable) {
|
|
hash := k.hash()
|
|
head := m.table[hash]
|
|
if head != nil {
|
|
if k.eq(head.key) {
|
|
m.table[hash] = head.next
|
|
m.length--
|
|
return
|
|
}
|
|
prev := head
|
|
for e := head.next; e != nil; e = e.next {
|
|
if k.eq(e.key) {
|
|
prev.next = e.next
|
|
m.length--
|
|
return
|
|
}
|
|
prev = e
|
|
}
|
|
}
|
|
}
|
|
|
|
// lookup returns the value associated with key k, if present, or
|
|
// value(nil) otherwise.
|
|
func (m *hashmap) lookup(k hashable) value {
|
|
hash := k.hash()
|
|
for e := m.table[hash]; e != nil; e = e.next {
|
|
if k.eq(e.key) {
|
|
return e.value
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// insert updates the map to associate key k with value v. If there
|
|
// was already an association for an eq() (though not necessarily ==)
|
|
// k, the previous key remains in the map and its associated value is
|
|
// updated.
|
|
func (m *hashmap) insert(k hashable, v value) {
|
|
hash := k.hash()
|
|
head := m.table[hash]
|
|
for e := head; e != nil; e = e.next {
|
|
if k.eq(e.key) {
|
|
e.value = v
|
|
return
|
|
}
|
|
}
|
|
m.table[hash] = &entry{
|
|
key: k,
|
|
value: v,
|
|
next: head,
|
|
}
|
|
m.length++
|
|
}
|
|
|
|
// len returns the number of key/value associations in the map.
|
|
func (m *hashmap) len() int {
|
|
return m.length
|
|
}
|