| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | // $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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | func ASSERT(p bool) { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	if !p { | 
					
						
							|  |  |  | 		// panic 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ---------------------------------------------------------------------------- | 
					
						
							|  |  |  | // Implementation of the HashMap | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | type KeyType interface { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	Hash() uint32; | 
					
						
							|  |  |  | 	Match(other *KeyType) bool | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | type ValueType interface { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	// empty interface | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | type Entry struct { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	key *KeyType; | 
					
						
							|  |  |  | 	value *ValueType; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Using the Array type below doesn't seem to work | 
					
						
							|  |  |  | //type Array array [1024] Entry; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | type HashMap struct { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	map_ *[1024] Entry; | 
					
						
							|  |  |  | 	log2_capacity_ uint32; | 
					
						
							|  |  |  | 	occupancy_ uint32; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *HashMap) capacity() uint32 { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:33:34 -07:00
										 |  |  | 	return 1 << m.log2_capacity_; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *HashMap) Clear() { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	// 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 | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *HashMap) Initialize (initial_log2_capacity uint32) { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	m.log2_capacity_ = initial_log2_capacity; | 
					
						
							| 
									
										
										
										
											2009-01-06 15:19:02 -08:00
										 |  |  | 	m.map_ = new([1024] Entry); | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	m.Clear(); | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *HashMap) Probe (key *KeyType) *Entry { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	ASSERT(key != nil); | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	var i uint32 = key.Hash() % m.capacity(); | 
					
						
							|  |  |  | 	ASSERT(0 <= i && i < m.capacity()); | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	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; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	return &m.map_[i]; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *HashMap) Resize(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *HashMap) Lookup (key *KeyType, insert bool) *Entry { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	// 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_++; | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 		// Grow the map if we reached >= 80% occupancy. | 
					
						
							|  |  |  | 		if m.occupancy_ + m.occupancy_/4 >= m.capacity() { | 
					
						
							|  |  |  | 			m.Resize(); | 
					
						
							|  |  |  | 			p = m.Probe(key); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 		return p; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// No entry found and none inserted. | 
					
						
							|  |  |  | 	return nil; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *HashMap) Resize() { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	var hmap *[1024] Entry = m.map_; | 
					
						
							|  |  |  | 	var n uint32 = m.occupancy_; | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	// Allocate a new map of twice the current size. | 
					
						
							|  |  |  | 	m.Initialize(m.log2_capacity_ << 1); | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	// 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++; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ---------------------------------------------------------------------------- | 
					
						
							|  |  |  | // Test code | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | type Number struct { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	x uint32; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (n *Number) Hash() uint32 { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	return n.x * 23; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (n *Number) Match(other *KeyType) bool { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	// var y *Number = other; | 
					
						
							|  |  |  | 	// return n.x == y.x; | 
					
						
							|  |  |  | 	return false; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | func MakeNumber (x uint32) *Number { | 
					
						
							| 
									
										
										
										
											2009-01-06 15:19:02 -08:00
										 |  |  | 	var n *Number = new(Number); | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	n.x = x; | 
					
						
							|  |  |  | 	return n; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func main() { | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	//f unc (n int) int { return n + 1; }(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//print "HashMap - gri 2/8/2008\n"; | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 15:19:02 -08:00
										 |  |  | 	var hmap *HashMap = new(HashMap); | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	hmap.Initialize(0); | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	var x1 *Number = MakeNumber(1001); | 
					
						
							|  |  |  | 	var x2 *Number = MakeNumber(2002); | 
					
						
							|  |  |  | 	var x3 *Number = MakeNumber(3003); | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	// this doesn't work I think... | 
					
						
							|  |  |  | 	//hmap.Lookup(x1, true); | 
					
						
							|  |  |  | 	//hmap.Lookup(x2, true); | 
					
						
							|  |  |  | 	//hmap.Lookup(x3, true); | 
					
						
							| 
									
										
										
										
											2008-12-19 03:05:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-29 13:21:00 -07:00
										 |  |  | 	//print "done\n"; | 
					
						
							| 
									
										
										
										
											2008-03-12 15:10:10 -07:00
										 |  |  | } |