diff --git a/tests/hashmap.go b/tests/hashmap.go new file mode 100755 index 00000000000..f4b15183c7f --- /dev/null +++ b/tests/hashmap.go @@ -0,0 +1,186 @@ +// $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. + +// To compile: go hashmap.go && gcc -o g.out main.go.c gort0.c && g.out + +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() { + 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); + + // this doesn't work I think... + //hmap.Lookup(x1, true); + //hmap.Lookup(x2, true); + //hmap.Lookup(x3, true); + + print "done\n"; +}