// $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"; }