1
0
mirror of https://github.com/golang/go synced 2024-11-19 05:54:44 -07:00
go/ssa/interp/map.go
Rob Pike 01f8cd246d go.tools: add go/types, ssa, and cmd/vet
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
2013-05-17 13:20:39 -07:00

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
}