| // $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; | |
| } | |
| // Using the Array type below doesn't seem to work | |
| //type Array array [1024] Entry; | |
| type HashMap struct { | |
| map_ *[1024] Entry; | |
| 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([1024] Entry); | |
| 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) Resize(); | |
| 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 *[1024] Entry = 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() { | |
| //f unc (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); | |
| // this doesn't work I think... | |
| //hmap.Lookup(x1, true); | |
| //hmap.Lookup(x2, true); | |
| //hmap.Lookup(x3, true); | |
| //print "done\n"; | |
| } |