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