Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hashmap delete功能实现 #138

Merged
merged 14 commits into from
Jan 8, 2023
1 change: 1 addition & 0 deletions .CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- [queue: 基于semaphore的并发阻塞队列实现](https://github.com/gotomicro/ekit/pull/129)
- [mapx: hashmap实现](https://github.com/gotomicro/ekit/pull/132)
- [mapx: 添加 Keys 方法](https://github.com/gotomicro/ekit/pull/134)
- [mapx: hashmap添加刪除功能](https://github.com/gotomicro/ekit/pull/138)

# v0.0.5
- [atomicx: 泛型封装 atomic.Value](https://github.com/gotomicro/ekit/pull/101)
Expand Down
39 changes: 39 additions & 0 deletions mapx/hashmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,42 @@ type mapi[T any, ValType any] interface {
}

var _ mapi[Hashable, any] = (*HashMap[Hashable, any])(nil)

// Delete 第一个返回值为删除key的值,第二个是hashmap是否真的有这个key
func (m *HashMap[T, ValType]) Delete(key T) (ValType, bool) {
root, ok := m.hashmap[key.Code()]
if !ok {
var t ValType
return t, false
}
pre := root
num := 0
for root != nil {
if root.key.Equals(key) {
if num == 0 && root.next == nil {
delete(m.hashmap, key.Code())
} else if num == 0 && root.next != nil {
m.hashmap[key.Code()] = root.next
} else {
pre.next = root.next
}
val := root.value
root.formatting()
m.nodePool.Put(root)
return val, true
}
num++
pre = root
root = root.next
}
var t ValType
return t, false
}

func (n *node[T, ValType]) formatting() {
var val ValType
var t T
n.key = t
n.value = val
n.next = nil
}
214 changes: 213 additions & 1 deletion mapx/hashmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package mapx
import (
"testing"

"github.com/stretchr/testify/require"

"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -60,7 +62,7 @@ func TestHashMap(t *testing.T) {
for _, kv := range testKV {
err := myhashmap.Put(kv.key, kv.val)
if err != nil {
panic(err)
require.NoError(t, err)
}
}

Expand Down Expand Up @@ -128,6 +130,216 @@ func TestHashMap(t *testing.T) {
}

}
func TestHashMap_Delete(t *testing.T) {
testcases := []struct {
name string
key testData
setHashMap func() map[uint64]*node[testData, int]
wantHashMap func() map[uint64]*node[testData, int]
wantVal int
isFound bool
}{
{
name: "hash not found",
setHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{}
},
isFound: false,
key: testData{
id: 1,
},
},
{
name: "key not found",
setHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{
1: &node[testData, int]{
key: testData{
id: 1,
},
value: 1,
},
}
},
isFound: false,
key: testData{
id: 11,
},
},
{
name: "many link elements delete first",
setHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{
1: &node[testData, int]{
key: testData{
id: 1,
},
value: 1,
next: &node[testData, int]{
key: testData{
id: 11,
},
value: 11,
next: &node[testData, int]{
key: testData{
id: 21,
},
value: 21,
},
},
},
}
},
isFound: true,
key: testData{
id: 1,
},
wantVal: 1,
wantHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{
1: &node[testData, int]{
key: testData{
id: 11,
},
value: 11,
next: &node[testData, int]{
key: testData{
id: 21,
},
value: 21,
},
},
}
},
},
{
name: "delete only one link element",
key: testData{
id: 1,
},
setHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{
1: &node[testData, int]{
key: testData{
id: 1,
},
value: 1,
},
}
},
wantHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{}
},
wantVal: 1,
isFound: true,
},
{
name: "many link elements delete middle",
key: testData{
id: 11,
},
setHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{
1: &node[testData, int]{
key: testData{
id: 1,
},
value: 1,
next: &node[testData, int]{
key: testData{
id: 11,
},
value: 11,
next: &node[testData, int]{
key: testData{
id: 21,
},
value: 21,
},
},
},
}
},
wantHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{
1: &node[testData, int]{
key: testData{
id: 1,
},
value: 1,
next: &node[testData, int]{
key: testData{
id: 21,
},
value: 21,
},
},
}
},
isFound: true,
wantVal: 11,
},
{
name: "many link elements delete end",
key: testData{
id: 21,
},
setHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{
1: &node[testData, int]{
key: testData{
id: 1,
},
value: 1,
next: &node[testData, int]{
key: testData{
id: 11,
},
value: 11,
next: &node[testData, int]{
key: testData{
id: 21,
},
value: 21,
},
},
},
}
},
wantHashMap: func() map[uint64]*node[testData, int] {
return map[uint64]*node[testData, int]{
1: &node[testData, int]{
key: testData{
id: 1,
},
value: 1,
next: &node[testData, int]{
key: testData{
id: 11,
},
value: 11,
},
},
}
},
isFound: true,
wantVal: 21,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
h := NewHashMap[testData, int](10)
h.hashmap = tc.setHashMap()
val, ok := h.Delete(tc.key)
assert.Equal(t, tc.isFound, ok)
if !ok {
return
}
assert.Equal(t, tc.wantVal, val)
assert.Equal(t, tc.wantHashMap(), h.hashmap)
})
}
}

type testData struct {
id int
Expand Down