Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion mapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 8 additions & 4 deletions mapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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)
})
}
7 changes: 4 additions & 3 deletions safe_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion safe_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
9 changes: 5 additions & 4 deletions safe_slice_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion safe_slice_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion seti_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
9 changes: 5 additions & 4 deletions slice_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion slice_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
19 changes: 12 additions & 7 deletions std_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion std_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down