mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 16:50:58 +00:00 
			
		
		
		
	
		
			
	
	
		
			187 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			187 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|   | // $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"; | ||
|  | } |