| // $G $F.go && $L $F.$A && ./$A.out |
| |
| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main |
| |
| // ---------------------------------------------------------------------------- |
| // Helper functions |
| |
| func ASSERT(p bool) { |
| if !p { |
| // panic 0 |
| } |
| } |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Implementation of the HashMap |
| |
| type KeyType interface { |
| Hash() uint32 |
| Match(other KeyType) bool |
| } |
| |
| |
| type ValueType interface { |
| // empty interface |
| } |
| |
| |
| type Entry struct { |
| key KeyType |
| value ValueType |
| } |
| |
| |
| type Array [1024]Entry |
| |
| type HashMap struct { |
| map_ *Array |
| log2_capacity_ uint32 |
| occupancy_ uint32 |
| } |
| |
| |
| func (m *HashMap) capacity() uint32 { |
| return 1 << m.log2_capacity_ |
| } |
| |
| |
| func (m *HashMap) Clear() { |
| // Mark all entries as empty. |
| var i uint32 = m.capacity() - 1 |
| for i > 0 { |
| m.map_[i].key = nil |
| i = i - 1 |
| } |
| m.occupancy_ = 0 |
| } |
| |
| |
| func (m *HashMap) Initialize (initial_log2_capacity uint32) { |
| m.log2_capacity_ = initial_log2_capacity |
| m.map_ = new(Array) |
| m.Clear() |
| } |
| |
| |
| func (m *HashMap) Probe (key KeyType) *Entry { |
| ASSERT(key != nil) |
| |
| var i uint32 = key.Hash() % m.capacity() |
| ASSERT(0 <= i && i < m.capacity()) |
| |
| ASSERT(m.occupancy_ < m.capacity()) // guarantees loop termination |
| for m.map_[i].key != nil && !m.map_[i].key.Match(key) { |
| i++ |
| if i >= m.capacity() { |
| i = 0 |
| } |
| } |
| |
| return &m.map_[i] |
| } |
| |
| |
| func (m *HashMap) Lookup (key KeyType, insert bool) *Entry { |
| // Find a matching entry. |
| var p *Entry = m.Probe(key) |
| if p.key != nil { |
| return p |
| } |
| |
| // No entry found; insert one if necessary. |
| if insert { |
| p.key = key |
| p.value = nil |
| m.occupancy_++ |
| |
| // Grow the map if we reached >= 80% occupancy. |
| if m.occupancy_ + m.occupancy_/4 >= m.capacity() { |
| m.Resize() |
| p = m.Probe(key) |
| } |
| |
| return p |
| } |
| |
| // No entry found and none inserted. |
| return nil |
| } |
| |
| |
| func (m *HashMap) Resize() { |
| var hmap *Array = m.map_ |
| var n uint32 = m.occupancy_ |
| |
| // Allocate a new map of twice the current size. |
| m.Initialize(m.log2_capacity_ << 1) |
| |
| // Rehash all current entries. |
| var i uint32 = 0 |
| for n > 0 { |
| if hmap[i].key != nil { |
| m.Lookup(hmap[i].key, true).value = hmap[i].value |
| n = n - 1 |
| } |
| i++ |
| } |
| } |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Test code |
| |
| type Number struct { |
| x uint32 |
| } |
| |
| |
| func (n *Number) Hash() uint32 { |
| return n.x * 23 |
| } |
| |
| |
| func (n *Number) Match(other KeyType) bool { |
| // var y *Number = other |
| // return n.x == y.x |
| return false |
| } |
| |
| |
| func MakeNumber (x uint32) *Number { |
| var n *Number = new(Number) |
| n.x = x |
| return n |
| } |
| |
| |
| func main() { |
| // func (n int) int { return n + 1; }(1) |
| |
| //print "HashMap - gri 2/8/2008\n" |
| |
| var hmap *HashMap = new(HashMap) |
| hmap.Initialize(0) |
| |
| var x1 *Number = MakeNumber(1001) |
| var x2 *Number = MakeNumber(2002) |
| var x3 *Number = MakeNumber(3003) |
| _, _, _ = x1, x2, x3 |
| |
| // this doesn't work I think... |
| //hmap.Lookup(x1, true) |
| //hmap.Lookup(x2, true) |
| //hmap.Lookup(x3, true) |
| |
| //print "done\n" |
| } |