From 4ccb4f4016a30fec899540c78e7c8ef8cf4a87f3 Mon Sep 17 00:00:00 2001
From: eson <474420502@qq.com>
Date: Mon, 22 Apr 2019 04:46:07 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90hashmap?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 hashmap/avlkeydup.go    |  46 +++++++++
 hashmap/hashmap.go      | 199 ++++++++++++++++++++-------------------
 hashmap/hashmap_test.go |  50 ++++++++--
 hashmap/table.go        | 202 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 396 insertions(+), 101 deletions(-)
 create mode 100644 hashmap/table.go

diff --git a/hashmap/avlkeydup.go b/hashmap/avlkeydup.go
index 835416a..2489fb5 100644
--- a/hashmap/avlkeydup.go
+++ b/hashmap/avlkeydup.go
@@ -116,6 +116,52 @@ func (tree *avlTree) GetNode(key interface{}) (*avlNode, bool) {
 	return nil, false
 }
 
+func (tree *avlTree) PutNode(pnode *avlNode) bool {
+
+	pnode.height = 0
+	pnode.children[0] = nil
+	pnode.children[1] = nil
+	// pnode.parent = nil
+
+	if tree.size == 0 {
+		tree.size++
+		tree.root = pnode
+		pnode.parent = nil
+		return true
+	}
+
+	for cur, c := tree.root, 0; ; {
+		c = tree.Compare(pnode.key, cur.key)
+		if c == -1 {
+			if cur.children[0] == nil {
+				tree.size++
+				cur.children[0] = pnode
+				cur.children[0].parent = cur
+				if cur.height == 0 {
+					tree.fixPutHeight(cur)
+				}
+				return true
+			}
+			cur = cur.children[0]
+		} else if c == 1 {
+			if cur.children[1] == nil {
+				tree.size++
+				cur.children[1] = pnode
+				cur.children[1].parent = cur
+				if cur.height == 0 {
+					tree.fixPutHeight(cur)
+				}
+				return true
+			}
+			cur = cur.children[1]
+		} else {
+			cur.key = pnode.key
+			cur.value = pnode.value
+			return false
+		}
+	}
+}
+
 func (tree *avlTree) Put(key, value interface{}) bool {
 
 	if tree.size == 0 {
diff --git a/hashmap/hashmap.go b/hashmap/hashmap.go
index 51f0efa..2124206 100644
--- a/hashmap/hashmap.go
+++ b/hashmap/hashmap.go
@@ -10,7 +10,7 @@ type HashMap struct {
 	growfactor     uint
 	slimmingfactor uint
 
-	table []interface{}
+	table []*avlTree
 
 	GetHash HashCode
 	Compare compare.Compare
@@ -42,49 +42,74 @@ func New(hcode HashCode, comp compare.Compare) *HashMap {
 	hm.GetHash = hcode
 	hm.Compare = comp
 	initcap := uint(8)
-	hm.table = make([]interface{}, initcap, initcap)
-	hm.growsize = initcap - initcap>>2
+	hm.table = make([]*avlTree, initcap, initcap)
+	hm.countNextGrow()
 	return hm
 }
 
+// func (hm *HashMap) grow() {
+// 	if hm.size >= hm.growsize {
+// 		newsize := hm.size << 1
+// 		newtable := make([]*Bucket, newsize, newsize)
+// 		hm.growsize = newsize - newsize>>2
+
+// 		for _, bucket := range hm.table {
+// 			if bucket != nil {
+// 				cur := bucket.head
+// 				hash := hm.GetHash(cur.Key)
+// 				index := hash % newsize
+// 				// var bkt *Bucket
+// 				bkt := newtable[index]
+
+// 				if bkt == nil {
+// 					bkt = &Bucket{size: 1}
+// 					newtable[index] = bkt
+// 					bkt.head = &bNode{Value: cur.Value, Key: cur.Key}
+
+// 					cur = cur.Next
+// 				}
+
+// 				for ; cur != nil; cur = cur.Next {
+// 					bn := &bNode{Value: cur.Value, Key: cur.Key}
+// 					bkt.size++
+// 					bn.Next = bkt.head
+// 					bkt.head = bn
+// 				}
+
+// 			}
+
+// 			hm.table = newtable
+// 		}
+// 	}
+// }
+
+func (hm *HashMap) countNextGrow() {
+	hm.growsize = uint(len(hm.table)) << 2
+}
+
 func (hm *HashMap) grow() {
 	if hm.size >= hm.growsize {
 		newsize := hm.size << 1
-		newtable := make([]interface{}, newsize, newsize)
-		hm.growsize = newsize - newsize>>2
-		hm.size = 0
-
-		for _, v := range hm.table {
-			if v != nil {
-				bucket := v.(*Bucket)
-				cur := bucket.head
-				hash := hm.GetHash(cur.Key)
-				index := hash % newsize
-				var bkt *Bucket
-				n := newtable[index]
-
-				if n == nil {
-					bkt = &Bucket{size: 1}
-					newtable[index] = bkt
-					bkt.head = &bNode{Value: cur.Value, Key: cur.Key}
-					hm.size++
-					cur = cur.Next
-				} else {
-					bkt = n.(*Bucket)
-				}
-
-				for ; cur != nil; cur = cur.Next {
-					bn := &bNode{Value: cur.Value, Key: cur.Key}
-					hm.size++
-					bkt.size++
-					bn.Next = bkt.head
-					bkt.head = bn
-				}
+		newtable := make([]*avlTree, newsize, newsize)
 
+		for _, cur := range hm.table {
+			if cur != nil {
+				cur.Traversal(func(k, v interface{}) bool {
+					hash := hm.GetHash(k)
+					index := hash % newsize
+					bkt := newtable[index]
+					if bkt == nil {
+						bkt = avlNew(hm.Compare)
+						newtable[index] = bkt
+					}
+					bkt.Put(k, v)
+					return true
+				})
 			}
-
-			hm.table = newtable
 		}
+
+		hm.table = newtable
+		hm.countNextGrow()
 	}
 }
 
@@ -93,74 +118,58 @@ func (hm *HashMap) Put(key, value interface{}) {
 
 	tlen := uint(len(hm.table))
 	index := hash % tlen
-	n := hm.table[index]
+	bkt := hm.table[index]
 
-	// if n == nil {
-	// 	n = avlNew(hm.Compare)
-	// 	hm.table[index] = n
-	// }
+	if bkt == nil {
+		bkt = avlNew(hm.Compare)
+		hm.table[index] = bkt
+	}
 
-	// bucket := n.(*avlTree)
-	// if bucket.Put(key, value) {
+	if bkt.Put(key, value) {
+		hm.size++
+		hm.grow()
+	}
+
+	// if bkt == nil {
+	// 	nbucket := &Bucket{size: 1}
+	// 	hm.table[index] = nbucket
+	// 	nbucket.head = &bNode{Value: value, Key: key}
 	// 	hm.size++
 
-	// 	if hm.size >= hm.growsize {
-	// 		newsize := hm.size << 1
-	// 		newtable := make([]interface{}, newsize, newsize)
-	// 		hm.growsize = newsize - newsize>>2
-
-	// 		for _, v := range hm.table {
-	// 			if v != nil {
-	// 				cur := v.(*avlTree)
-	// 				cur.Traversal(func(k, v interface{}) bool {
-	// 					hash := hm.GetHash(k)
-	// 					index := hash % newsize
-	// 					n := newtable[index]
-	// 					if n == nil {
-	// 						n = avlNew(hm.Compare)
-	// 						newtable[index] = n
-	// 					}
-	// 					bucket := n.(*avlTree)
-	// 					bucket.Put(k, v)
-	// 					return true
-	// 				})
-
-	// 			}
-	// 		}
-
-	// 		hm.table = newtable
-
-	// 	}
+	// 	hm.grow()
+	// 	return
 	// }
 
-	if n == nil {
-		nbucket := &Bucket{size: 1}
-		hm.table[index] = nbucket
-		nbucket.head = &bNode{Value: value, Key: key}
-		hm.size++
+	// cur := bkt.head
 
-		hm.grow()
-		return
-	}
+	// for cur.Next != nil {
+	// 	if hm.Compare(key, cur.Key) == 0 {
+	// 		cur.Key = key
+	// 		cur.Value = value
+	// 		return
+	// 	}
+	// 	cur = cur.Next
+	// }
 
-	bkt := n.(*Bucket)
-	cur := bkt.head
+	// bn := &bNode{Value: value, Key: key}
+	// hm.size++
+	// bkt.size++
 
-	for cur.Next != nil {
-		if hm.Compare(key, cur.Key) == 0 {
-			cur.Key = key
-			cur.Value = value
-			return
-		}
-		cur = cur.Next
-	}
+	// bn.Next = bkt.head
+	// bkt.head = bn
 
-	bn := &bNode{Value: value, Key: key}
-	hm.size++
-	bkt.size++
-
-	bn.Next = bkt.head
-	bkt.head = bn
-
-	hm.grow()
+	// hm.grow()
+}
+
+func (hm *HashMap) Get(key interface{}) (interface{}, bool) {
+	hash := hm.GetHash(key)
+
+	tlen := uint(len(hm.table))
+	index := hash % tlen
+	bkt := hm.table[index]
+	if bkt != nil {
+		return bkt.Get(key)
+	}
+
+	return nil, false
 }
diff --git a/hashmap/hashmap_test.go b/hashmap/hashmap_test.go
index b91cebb..b1e770e 100644
--- a/hashmap/hashmap_test.go
+++ b/hashmap/hashmap_test.go
@@ -30,23 +30,61 @@ func bToMb(b uint64) uint64 {
 	return b / 1024 / 1024
 }
 
-func BenchmarkCount(b *testing.B) {
+func BenchmarkPut(b *testing.B) {
 	hm := New(HashInt, compare.Int)
 	b.N = 100000
 	for i := 0; i < b.N; i++ {
 		hm.Put(i, i)
 	}
 
-	b.Log(len(hm.table), hm.size)
-	PrintMemUsage()
+	//b.Log(len(hm.table), hm.size)
+	//PrintMemUsage()
 }
 
-func BenchmarkGoCount(b *testing.B) {
+func BenchmarkGet(b *testing.B) {
+	b.StopTimer()
+	hm := New(HashInt, compare.Int)
+	b.N = 100000
+	for i := 0; i < b.N; i++ {
+		hm.Put(i, i)
+	}
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		hm.Get(i)
+	}
+
+	//b.Log(len(hm.table), hm.size)
+	//PrintMemUsage()
+}
+
+func BenchmarkGoPut(b *testing.B) {
 	m := make(map[int]int)
 	b.N = 100000
 	for i := 0; i < b.N; i++ {
 		m[i] = i
 	}
-	b.Log(len(m))
-	PrintMemUsage()
+	//b.Log(len(m))
+	//PrintMemUsage()
+}
+
+func BenchmarkGoGet(b *testing.B) {
+	b.StopTimer()
+	m := make(map[int]int)
+	b.N = 100000
+	for i := 0; i < b.N; i++ {
+		m[i] = i
+	}
+	for i := 0; i < b.N; i++ {
+		if _, ok := m[i]; !ok {
+
+		}
+	}
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if _, ok := m[i]; !ok {
+
+		}
+	}
+	//b.Log(len(m))
+	//PrintMemUsage()
 }
diff --git a/hashmap/table.go b/hashmap/table.go
new file mode 100644
index 0000000..76d6040
--- /dev/null
+++ b/hashmap/table.go
@@ -0,0 +1,202 @@
+package hashmap
+
+type Table struct {
+	// ysizes    []int
+	// xsizes    [][]int
+	// xyproduct int
+
+	size     uint
+	growsize uint
+
+	data [][4][4]*avlTree
+	cap  uint
+}
+
+func newTable() *Table {
+	table := &Table{}
+	table.data = make([][4][4]*avlTree, 4, 4)
+	table.countCap()
+	return table
+}
+
+func (t *Table) countCap() {
+	t.cap = uint(len(t.data)) << 4 // * (4 * 4)
+}
+
+// func (t *Table) countNextGrow() {
+// 	t.growsize = uint(len(t.data)) << 6 // +4 * (4 * 4)
+// }
+
+// func (arr *Table) debugValues() []interface{} {
+// 	var result []interface{}
+// 	for _, z := range arr.data {
+// 		if z != nil {
+// 			for _, y := range z {
+// 				if y == nil {
+// 					for i := 0; i < arr.xsize; i++ {
+// 						result = append(result, nil)
+// 					}
+// 				} else {
+// 					for _, x := range y {
+// 						if x == nil {
+// 							result = append(result, struct{}{})
+// 						} else {
+// 							result = append(result, x)
+// 						}
+// 					}
+// 				}
+// 			}
+// 		} else {
+// 			for i := 0; i < arr.ysize*arr.xsize; i++ {
+// 				result = append(result, nil)
+// 			}
+// 		}
+// 	}
+// 	return result
+// }
+
+// func (arr *Table) Values() []interface{} {
+// 	var result []interface{}
+// 	for _, z := range arr.data {
+// 		if z != nil {
+
+// 			for _, y := range z {
+// 				if y == nil {
+// 					for i := 0; i < arr.xsize; i++ {
+// 						result = append(result, nil)
+// 					}
+// 				} else {
+// 					for _, x := range y {
+// 						if x == nil {
+// 							result = append(result, nil)
+// 						} else {
+// 							result = append(result, x)
+// 						}
+// 					}
+// 				}
+// 			}
+// 		} else {
+// 			for i := 0; i < arr.ysize*arr.xsize; i++ {
+// 				result = append(result, nil)
+// 			}
+// 		}
+// 	}
+
+// 	return result
+// }
+
+func (t *Table) Cap() uint {
+	return t.cap
+}
+
+func (t *Table) Grow(size int) {
+	zsize := len(t.data) + size
+	temp := make([][4][4]*avlTree, zsize, zsize)
+	copy(temp, t.data)
+	t.data = temp
+	t.countCap()
+}
+
+func (t *Table) GetWithNilSet(idx int, DoSetValue func([4]*avlTree, int)) *avlTree {
+	zindex := idx / 16
+	nidx := (idx % 16)
+	yindex := nidx / 4
+	xindex := nidx % 4
+
+	ydata := t.data[zindex]
+	xdata := ydata[yindex]
+
+	v := xdata[xindex]
+	if v == nil {
+		DoSetValue(xdata, xindex)
+	}
+	return v
+}
+
+// func (arr *Table) Get(idx int) (interface{}, bool) {
+// 	zindex := idx / arr.xyproduct
+// 	nextsize := (idx % arr.xyproduct)
+// 	yindex := nextsize / arr.xsize
+// 	xindex := nextsize % arr.xsize
+
+// 	ydata := arr.data[zindex]
+// 	if ydata == nil {
+// 		return nil, false
+// 	}
+
+// 	xdata := ydata[yindex]
+// 	if xdata == nil {
+// 		return nil, false
+// 	}
+
+// 	v := xdata[xindex]
+// 	return v, v != nil
+// }
+
+// func (arr *Table) GetOrSet(idx int, DoSetValue func([]interface{}, int)) (result interface{}, isSet bool) {
+// 	zindex := idx / arr.xyproduct
+// 	nidx := (idx % arr.xyproduct)
+// 	yindex := nidx / arr.xsize
+// 	xindex := nidx % arr.xsize
+
+// 	ydata := arr.data[zindex]
+// 	if ydata == nil {
+// 		ydata = make([][]interface{}, arr.ysize, arr.ysize)
+// 		arr.data[zindex] = ydata
+// 	}
+
+// 	xdata := ydata[yindex]
+// 	if xdata == nil {
+// 		xdata = make([]interface{}, arr.xsize, arr.xsize)
+// 		ydata[yindex] = xdata
+// 		arr.ysizes[zindex]++
+// 	}
+
+// 	result = xdata[xindex]
+// 	if result == nil {
+// 		DoSetValue(xdata, xindex)
+// 		result = xdata[xindex]
+// 		if result == nil {
+// 			panic("DoSetValue Not Set <nil> Value")
+// 		}
+// 		arr.xsizes[zindex][yindex]++
+// 		return result, false
+// 	}
+// 	return result, true
+// }
+
+// func (arr *Table) Del(idx int) (interface{}, bool) {
+// 	zindex := idx / arr.xyproduct
+// 	nextsize := (idx % arr.xyproduct)
+// 	yindex := nextsize / arr.xsize
+// 	xindex := nextsize % arr.xsize
+
+// 	ydata := arr.data[zindex]
+// 	if ydata == nil {
+// 		return nil, false
+// 	}
+
+// 	xdata := ydata[yindex]
+// 	if xdata == nil {
+// 		return nil, false
+// 	}
+
+// 	v := xdata[xindex]
+// 	xdata[xindex] = nil
+
+// 	isnotnil := v != nil
+
+// 	if isnotnil {
+// 		arr.xsizes[zindex][yindex]--
+// 		if arr.xsizes[zindex][yindex] == 0 {
+// 			arr.data[zindex][yindex] = nil
+
+// 			arr.ysizes[zindex]--
+// 			if arr.ysizes[zindex] == 0 {
+// 				arr.data[zindex] = nil
+// 			}
+// 		}
+// 	}
+
+// 	return v, isnotnil
+// }