]> Cypherpunks repositories - gostls13.git/commitdiff
- added another test case
authorRobert Griesemer <gri@golang.org>
Wed, 12 Mar 2008 22:10:10 +0000 (15:10 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 12 Mar 2008 22:10:10 +0000 (15:10 -0700)
SVN=112273

tests/hashmap.go [new file with mode: 0755]

diff --git a/tests/hashmap.go b/tests/hashmap.go
new file mode 100755 (executable)
index 0000000..f4b1518
--- /dev/null
@@ -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";
+}