Skip to content

Commit

Permalink
mapx: 支持 builtinMap,用于接入其它装饰器实现
Browse files Browse the repository at this point in the history
  • Loading branch information
flycash committed Aug 4, 2023
1 parent caa168d commit 62faa8f
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 1 deletion.
1 change: 1 addition & 0 deletions .CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# 开发中
- [mapx: TreeMap 添加 Keys 和 Values 方法](https://github.com/ecodeclub/ekit/pull/181)
- [mapx: 修正 HashMap 中使用泛型不当的地方](https://github.com/ecodeclub/ekit/pull/186)
- [mapx: 支持 builtinMap,用于接入其它装饰器实现](https://github.com/ecodeclub/ekit/pull/202)
- [pool: 重构TaskPool测试用例](https://github.com/ecodeclub/ekit/pull/178)
- [sqlx:ScanRows 和 ScanAll方法](https://github.com/ecodeclub/ekit/pull/180)
- [mapx: 修复红黑树删除节点问题](https://github.com/ecodeclub/ekit/pull/183)
Expand Down
52 changes: 52 additions & 0 deletions mapx/builtin_map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2021 ecodeclub
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mapx

// builtinMap 是对 map 的二次封装
// 主要用于各种装饰器模式中被装饰的那个
type builtinMap[K comparable, V any] struct {
data map[K]V
}

func (b *builtinMap[K, V]) Put(key K, val V) error {
b.data[key] = val
return nil
}

func (b *builtinMap[K, V]) Get(key K) (V, bool) {
val, ok := b.data[key]
return val, ok
}

func (b *builtinMap[K, V]) Delete(k K) (V, bool) {
v, ok := b.data[k]
delete(b.data, k)
return v, ok
}

// Keys 返回的 key 是随机的。即便对于同一个实例,调用两次,得到的结果都可能不同。
func (b *builtinMap[K, V]) Keys() []K {
return Keys[K, V](b.data)
}

func (b *builtinMap[K, V]) Values() []V {
return Values[K, V](b.data)
}

func newBuiltinMap[K comparable, V any](capacity int) *builtinMap[K, V] {
return &builtinMap[K, V]{
data: make(map[K]V, capacity),
}
}
215 changes: 215 additions & 0 deletions mapx/builtin_map_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// Copyright 2021 ecodeclub
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mapx

import (
"testing"

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

func TestBuiltinMap_Delete(t *testing.T) {
testCases := []struct {
name string
data map[string]string

key string

wantVal string
wantDeleted bool
}{
{
name: "deleted",
data: map[string]string{
"key1": "val1",
},
key: "key1",

wantVal: "val1",
wantDeleted: true,
},
{
name: "key not exist",
data: map[string]string{
"key1": "val1",
},
key: "key2",
},
{
name: "nil map",
key: "key2",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
m := builtinMapOf[string, string](tc.data)
val, ok := m.Delete(tc.key)
assert.Equal(t, tc.wantDeleted, ok)
assert.Equal(t, tc.wantVal, val)
_, ok = m.data[tc.key]
assert.False(t, ok)
})
}
}

func TestBuiltinMap_Get(t *testing.T) {
testCases := []struct {
name string
data map[string]string

key string

wantVal string
found bool
}{
{
name: "found",
data: map[string]string{
"key1": "val1",
},
key: "key1",

wantVal: "val1",
found: true,
},
{
name: "key not exist",
data: map[string]string{
"key1": "val1",
},
key: "key2",
},
{
name: "nil map",
key: "key2",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
m := builtinMapOf[string, string](tc.data)
val, ok := m.Get(tc.key)
assert.Equal(t, tc.found, ok)
assert.Equal(t, tc.wantVal, val)
})
}
}

func TestBuiltinMap_Put(t *testing.T) {
testCases := []struct {
name string

key string
val string
cap int

wantErr error
}{
{
name: "puted",
key: "key1",
val: "val1",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
m := newBuiltinMap[string, string](tc.cap)
err := m.Put(tc.key, tc.val)
assert.Equal(t, tc.wantErr, err)
v, ok := m.data[tc.key]
assert.True(t, ok)
assert.Equal(t, tc.val, v)
})
}
}

func TestBuiltinMap_Keys(t *testing.T) {
testCases := []struct {
name string
data map[string]string

wantKeys []string
}{
{
name: "got keys",
data: map[string]string{
"key1": "val1",
"key2": "val1",
"key3": "val1",
"key4": "val1",
},
wantKeys: []string{"key1", "key2", "key3", "key4"},
},
{
name: "empty map",
data: map[string]string{},
wantKeys: []string{},
},
{
name: "nil map",
wantKeys: []string{},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
m := builtinMapOf[string, string](tc.data)
keys := m.Keys()
assert.ElementsMatch(t, tc.wantKeys, keys)
})
}
}

func TestBuiltinMap_Values(t *testing.T) {
testCases := []struct {
name string
data map[string]string

wantValues []string
}{
{
name: "got values",
data: map[string]string{
"key1": "val1",
"key2": "val2",
"key3": "val3",
"key4": "val4",
},
wantValues: []string{"val1", "val2", "val3", "val4"},
},
{
name: "empty map",
data: map[string]string{},
wantValues: []string{},
},
{
name: "nil map",
wantValues: []string{},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
m := builtinMapOf[string, string](tc.data)
vals := m.Values()
assert.ElementsMatch(t, tc.wantValues, vals)
})
}
}

func builtinMapOf[K comparable, V any](data map[K]V) *builtinMap[K, V] {
return &builtinMap[K, V]{data: data}
}
7 changes: 7 additions & 0 deletions mapx/multiMap.go → mapx/multi_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ func NewMultiHashMap[K Hashable, V any](size int) *MultiMap[K, V] {
}
}

func NewMultiBuiltinMap[K comparable, V any](size int) *MultiMap[K, V] {
var m mapi[K, []V] = newBuiltinMap[K, []V](size)
return &MultiMap[K, V]{
m: m,
}
}

// Put 在 MultiMap 中添加键值对或向已有键 k 的值追加数据
func (m *MultiMap[K, V]) Put(k K, v V) error {
return m.PutMany(k, v)
Expand Down
27 changes: 27 additions & 0 deletions mapx/multiMap_test.go → mapx/multi_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,33 @@ func TestMultiMap_NewMultiTreeMap(t *testing.T) {
}
}

func TestNewMultiBuiltinMap(t *testing.T) {
testCases := []struct {
name string
size int
}{
{
name: "negative size",
size: -1,
},
{
name: "zero size",
size: 0,
},
{
name: "Positive size",
size: 1,
},
}

for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
multiMap := NewMultiBuiltinMap[testData, int](tt.size)
assert.NotNil(t, multiMap)
})
}
}

func TestMultiMap_Keys(t *testing.T) {
testCases := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion set/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ package set

type Set[T comparable] interface {
Add(key T)
// 返回是否存在这个元素
Delete(key T)
// Exist 返回是否存在这个元素
Exist(key T) bool
Keys() []T
}
Expand Down

0 comments on commit 62faa8f

Please sign in to comment.