From 7bf9214ebb72ff91687bc35040d9e6f45daf044f Mon Sep 17 00:00:00 2001 From: Deng Ming Date: Thu, 3 Aug 2023 23:45:20 +0800 Subject: [PATCH] =?UTF-8?q?mapx:=20=E6=94=AF=E6=8C=81=20builtinMap?= =?UTF-8?q?=EF=BC=8C=E7=94=A8=E4=BA=8E=E6=8E=A5=E5=85=A5=E5=85=B6=E5=AE=83?= =?UTF-8?q?=E8=A3=85=E9=A5=B0=E5=99=A8=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .CHANGELOG.md | 1 + mapx/builtin_map.go | 52 +++++ mapx/builtin_map_test.go | 215 +++++++++++++++++++ mapx/{multiMap.go => multi_map.go} | 7 + mapx/{multiMap_test.go => multi_map_test.go} | 0 set/set.go | 2 +- 6 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 mapx/builtin_map.go create mode 100644 mapx/builtin_map_test.go rename mapx/{multiMap.go => multi_map.go} (93%) rename mapx/{multiMap_test.go => multi_map_test.go} (100%) diff --git a/.CHANGELOG.md b/.CHANGELOG.md index 14a849a6..e49469a0 100644 --- a/.CHANGELOG.md +++ b/.CHANGELOG.md @@ -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) diff --git a/mapx/builtin_map.go b/mapx/builtin_map.go new file mode 100644 index 00000000..a5621d1e --- /dev/null +++ b/mapx/builtin_map.go @@ -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), + } +} diff --git a/mapx/builtin_map_test.go b/mapx/builtin_map_test.go new file mode 100644 index 00000000..63572e66 --- /dev/null +++ b/mapx/builtin_map_test.go @@ -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} +} diff --git a/mapx/multiMap.go b/mapx/multi_map.go similarity index 93% rename from mapx/multiMap.go rename to mapx/multi_map.go index 2a3fcbec..f6497164 100644 --- a/mapx/multiMap.go +++ b/mapx/multi_map.go @@ -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) diff --git a/mapx/multiMap_test.go b/mapx/multi_map_test.go similarity index 100% rename from mapx/multiMap_test.go rename to mapx/multi_map_test.go diff --git a/set/set.go b/set/set.go index dee45070..b1d194b3 100644 --- a/set/set.go +++ b/set/set.go @@ -16,8 +16,8 @@ package set type Set[T comparable] interface { Add(key T) - // 返回是否存在这个元素 Delete(key T) + // Exist 返回是否存在这个元素 Exist(key T) bool Keys() []T }