From acbfc278f552668fc616cd20cad3f15548190647 Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Tue, 29 Oct 2024 08:22:32 +0100 Subject: [PATCH] modify Delete method to return deleted value Signed-off-by: Matthias Bertschy --- map.go | 16 +++++++++------- mapi.go | 2 +- mapi_test.go | 12 ++++++++---- safe_map.go | 7 ++++--- safe_map_test.go | 3 ++- safe_slice_map.go | 9 +++++---- safe_slice_map_test.go | 3 ++- seti_test.go | 3 ++- slice_map.go | 9 +++++---- slice_map_test.go | 3 ++- std_map.go | 19 ++++++++++++------- std_map_test.go | 3 ++- 12 files changed, 54 insertions(+), 35 deletions(-) diff --git a/map.go b/map.go index 5cf2e4a..b4e764b 100644 --- a/map.go +++ b/map.go @@ -4,9 +4,10 @@ package maps // // The recommended way to create a Map is to first declare a concrete type alias, and then call // new on it, like this: -// type MyMap = Map[string,int] // -// m := new(MyMap) +// type MyMap = Map[string,int] +// +// m := new(MyMap) // // This will allow you to swap in a different kind of Map just by changing the type. type Map[K comparable, V any] struct { @@ -48,8 +49,8 @@ func (m Map[K, V]) Has(k K) bool { } // Delete removes the key from the map. If the key does not exist, nothing happens. -func (m Map[K, V]) Delete(k K) { - m.items.Delete(k) +func (m Map[K, V]) Delete(k K) V { + return m.items.Delete(k) } // Keys returns a new slice containing the keys of the map. @@ -95,9 +96,10 @@ func (m Map[K, V]) MarshalBinary() ([]byte, error) { // UnmarshalBinary implements the BinaryUnmarshaler interface to convert a byte stream to a Map. // // Note that you may need to register the map at init time with gob like this: -// func init() { -// gob.Register(new(Map[keytype,valuetype])) -// } +// +// func init() { +// gob.Register(new(Map[keytype,valuetype])) +// } func (m *Map[K, V]) UnmarshalBinary(data []byte) (err error) { return m.items.UnmarshalBinary(data) } diff --git a/mapi.go b/mapi.go index 0c564d4..0dd035a 100644 --- a/mapi.go +++ b/mapi.go @@ -13,7 +13,7 @@ type MapI[K comparable, V any] interface { Values() []V Merge(MapI[K, V]) Equal(MapI[K, V]) bool - Delete(k K) + Delete(k K) (v V) } // Setter sets a value in a map. diff --git a/mapi_test.go b/mapi_test.go index 75b81c9..b93bef1 100644 --- a/mapi_test.go +++ b/mapi_test.go @@ -4,8 +4,9 @@ import ( "bytes" "encoding/gob" "encoding/json" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) type makeF func(sources ...mapT) MapI[string, int] @@ -243,14 +244,17 @@ func testUnmarshalJSON[M any](t *testing.T, f makeF) { func testDelete(t *testing.T, f makeF) { t.Run("Delete", func(t *testing.T) { m := f(mapT{"a": 1, "b": 2}) - m.Delete("a") + v := m.Delete("a") + assert.Equal(t, 1, v) assert.False(t, m.Has("a")) assert.True(t, m.Has("b")) - m.Delete("b") + v = m.Delete("b") + assert.Equal(t, 2, v) assert.False(t, m.Has("b")) - m.Delete("b") // make sure deleting from an empty map is a no-op + v = m.Delete("b") // make sure deleting from an empty map is a no-op + assert.Equal(t, 0, v) }) } diff --git a/safe_map.go b/safe_map.go index a330970..90d6b20 100644 --- a/safe_map.go +++ b/safe_map.go @@ -67,11 +67,12 @@ func (m *SafeMap[K, V]) Load(k K) (v V, ok bool) { return } -// Delete removes the key from the map. If the key does not exist, nothing happens. -func (m *SafeMap[K, V]) Delete(k K) { +// Delete removes the key from the map and returns the value. If the key does not exist, the zero value will be returned. +func (m *SafeMap[K, V]) Delete(k K) (v V) { m.Lock() - m.items.Delete(k) + v = m.items.Delete(k) m.Unlock() + return } // Values returns a slice of the values. It will return a nil slice if the map is empty. diff --git a/safe_map_test.go b/safe_map_test.go index 7140fae..1ba4a48 100644 --- a/safe_map_test.go +++ b/safe_map_test.go @@ -3,8 +3,9 @@ package maps import ( "encoding/gob" "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestSafeMap_Mapi(t *testing.T) { diff --git a/safe_slice_map.go b/safe_slice_map.go index a7359ae..3fee5fa 100644 --- a/safe_slice_map.go +++ b/safe_slice_map.go @@ -125,14 +125,14 @@ func (m *SafeSliceMap[K, V]) SetAt(index int, key K, val V) { m.Unlock() } -// Delete removes the item with the given key. -func (m *SafeSliceMap[K, V]) Delete(key K) { +// Delete removes the item with the given key and returns the value. +func (m *SafeSliceMap[K, V]) Delete(key K) (val V) { m.Lock() if _, ok := m.items[key]; ok { + val = m.items[key] if m.lessF != nil { - oldVal := m.items[key] loc := sort.Search(len(m.items), func(n int) bool { - return !m.lessF(m.order[n], key, m.items[m.order[n]], oldVal) + return !m.lessF(m.order[n], key, m.items[m.order[n]], val) }) m.order = append(m.order[:loc], m.order[loc+1:]...) } else { @@ -146,6 +146,7 @@ func (m *SafeSliceMap[K, V]) Delete(key K) { delete(m.items, key) } m.Unlock() + return } // Get returns the value based on its key. If the key does not exist, an empty value is returned. diff --git a/safe_slice_map_test.go b/safe_slice_map_test.go index a1d811c..edf738d 100644 --- a/safe_slice_map_test.go +++ b/safe_slice_map_test.go @@ -3,8 +3,9 @@ package maps import ( "encoding/gob" "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestSafeSliceMap_Mapi(t *testing.T) { diff --git a/seti_test.go b/seti_test.go index a209daf..e0477e8 100644 --- a/seti_test.go +++ b/seti_test.go @@ -4,8 +4,9 @@ import ( "bytes" "encoding/gob" "encoding/json" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) type makeSetF func(sources ...string) SetI[string] diff --git a/slice_map.go b/slice_map.go index b9e1b7b..165360b 100644 --- a/slice_map.go +++ b/slice_map.go @@ -128,17 +128,17 @@ func (m *SliceMap[K, V]) SetAt(index int, key K, val V) { m.items[key] = val } -// Delete removes the item with the given key. -func (m *SliceMap[K, V]) Delete(key K) { +// Delete removes the key from the map and returns the value. If the key does not exist, the zero value will be returned. +func (m *SliceMap[K, V]) Delete(key K) (val V) { if m == nil { return } if _, ok := m.items[key]; ok { + val = m.items[key] if m.lessF != nil { - oldVal := m.items[key] loc := sort.Search(len(m.items), func(n int) bool { - return !m.lessF(m.order[n], key, m.items[m.order[n]], oldVal) + return !m.lessF(m.order[n], key, m.items[m.order[n]], val) }) m.order = append(m.order[:loc], m.order[loc+1:]...) } else { @@ -151,6 +151,7 @@ func (m *SliceMap[K, V]) Delete(key K) { } delete(m.items, key) } + return } // Get returns the value based on its key. If the key does not exist, an empty value is returned. diff --git a/slice_map_test.go b/slice_map_test.go index 624b571..8d2c673 100644 --- a/slice_map_test.go +++ b/slice_map_test.go @@ -3,8 +3,9 @@ package maps import ( "encoding/gob" "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestSliceMap_Mapi(t *testing.T) { diff --git a/std_map.go b/std_map.go index 5e88a2a..48acedc 100644 --- a/std_map.go +++ b/std_map.go @@ -12,7 +12,8 @@ import ( // // The zero value is NOT settable. Use NewStdMap to create a new StdMap object, or use standard // map instantiation syntax like this: -// m := StdMap[string, int]{"a":1} +// +// m := StdMap[string, int]{"a":1} // // StdMap is mostly a convenience type for making a standard Go map into a MapI interface. // Generally, you should use Map instead, as it presents a consistent interface that allows you @@ -22,7 +23,8 @@ type StdMap[K comparable, V any] map[K]V // NewStdMap creates a new map that maps values of type K to values of type V. // Pass in zero or more standard maps and the contents of those maps will be copied to the new StdMap. // You can also create a new StdMap like this: -// m := StdMap[string, int]{"a":1} +// +// m := StdMap[string, int]{"a":1} func NewStdMap[K comparable, V any](sources ...map[K]V) StdMap[K, V] { m := StdMap[K, V]{} for _, i := range sources { @@ -103,9 +105,11 @@ func (m StdMap[K, V]) Set(k K, v V) { m[k] = v } -// Delete removes the key from the map. If the key does not exist, nothing happens. -func (m StdMap[K, V]) Delete(k K) { +// Delete removes the key from the map and returns the value. If the key does not exist, the zero value will be returned. +func (m StdMap[K, V]) Delete(k K) (v V) { + v, _ = m.Load(k) delete(m, k) + return } // Keys returns a new slice containing the keys of the map. @@ -176,9 +180,10 @@ func (m StdMap[K, V]) MarshalBinary() ([]byte, error) { // UnmarshalBinary implements the BinaryUnmarshaler interface to convert a byte stream to a Map. // // Note that you will likely need to register the unmarshaller at init time with gob like this: -// func init() { -// gob.Register(new(Map[K,V])) -// } +// +// func init() { +// gob.Register(new(Map[K,V])) +// } func (m *StdMap[K, V]) UnmarshalBinary(data []byte) (err error) { b := bytes.NewBuffer(data) dec := gob.NewDecoder(b) diff --git a/std_map_test.go b/std_map_test.go index ae7a654..7f04a62 100644 --- a/std_map_test.go +++ b/std_map_test.go @@ -3,8 +3,9 @@ package maps import ( "encoding/gob" "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) type mapT = StdMap[string, int]