diff --git a/map.go b/map.go index de01145..a9fe478 100644 --- a/map.go +++ b/map.go @@ -74,7 +74,7 @@ func (m *Map) Delete(key interface{}) bool { // UnorderedRange will range over the map in an unordered sequence. // This is same as ranging over a map using the "for range" syntax. // Parameter func f should not call any method of the Map, eg Get, Put, Delete, UnorderedRange, OrderedRange etc -// It will cause a deadlock +// It will cause a deadlock. func (m *Map) UnorderedRange(f func(key interface{}, value interface{})) { m.mu.RLock() defer m.mu.RUnlock() @@ -89,7 +89,7 @@ func (m *Map) UnorderedRange(f func(key interface{}, value interface{})) { // UnorderedRange completes in ~1.7 seconds, // OrderedRange completes in ~98 milli seconds. // Parameter func f should not call any method of the Map, eg Get, Put, Delete, UnorderedRange, OrderedRange etc -// It will cause a deadlock +// It will cause a deadlock. func (m *Map) OrderedRange(f func(key interface{}, value interface{})) { m.mu.RLock() defer m.mu.RUnlock() @@ -102,10 +102,43 @@ func (m *Map) OrderedRange(f func(key interface{}, value interface{})) { } } -// Length will return the length of Map +// Length will return the length of Map. func (m *Map) Length() int { m.mu.RLock() defer m.mu.RUnlock() return m.dll.Len() } + +// GetOrPut will return the existing value if the key exists in the Map. +// If the key did not exist previously it will be added to the Map. +// updated will be true if the key existed previously +// otherwise it will be false if the key did not exist and was added to the Map. +func (m *Map) GetOrPut(key interface{}, value interface{}) (finalValue interface{}, updated bool) { + m.mu.Lock() + defer m.mu.Unlock() + + if e, exists := m.mp[key]; exists { + e.Value = mapElement{key: key, value: value} + return value, true + } else { + m.mp[key] = m.dll.PushFront(mapElement{key: key, value: value}) + return value, false + } +} + +// GetAndDelete will get the value saved against the given key. +// deleted will be true if the key existed previously +// otherwise it will be false. +func (m *Map) GetAndDelete(key interface{}) (value interface{}, deleted bool) { + m.mu.Lock() + defer m.mu.Unlock() + + if e, exists := m.mp[key]; exists { + m.dll.Remove(e) + delete(m.mp, key) + return e.Value, true + } else { + return nil, false + } +} diff --git a/map_test.go b/map_test.go index 8673374..3c33706 100644 --- a/map_test.go +++ b/map_test.go @@ -163,3 +163,51 @@ func TestLength(t *testing.T) { t.FailNow() } } + +func TestGetOrPut(t *testing.T) { + m := initMap() + + m.Put("a", 1) + m.Put("b", 2) + m.Put("c", 3) + + if finalValue, updated := m.GetOrPut("a", 4); finalValue != 1 && !updated { + t.FailNow() + } + + if finalValue, updated := m.GetOrPut("d", 4); finalValue != 4 && updated { + t.FailNow() + } + + m.Delete("a") + if finalValue, updated := m.GetOrPut("a", 5); finalValue != 5 && updated { + t.FailNow() + } + + m.Put("e", 5) + if finalValue, updated := m.GetOrPut("e", 6); finalValue != 5 && !updated { + t.FailNow() + } +} + +func TestGetAndDelete(t *testing.T) { + m := initMap() + + m.Put("a", 1) + m.Put("b", 2) + m.Put("c", 3) + m.Put("d", 4) + + if value, deleted := m.GetAndDelete("a"); value != 1 && !deleted { + t.Fail() + } + + if value, deleted := m.GetAndDelete("a"); value != nil && deleted { + t.Fail() + } + + m.Put("a", 5) + if value, deleted := m.GetAndDelete("a"); value != 5 && !deleted { + t.Fail() + } +} diff --git a/readme.md b/readme.md index 5f9efef..b6f8363 100644 --- a/readme.md +++ b/readme.md @@ -41,5 +41,11 @@ func main() { // Length will return the length of the Map. m.Length() + + // GetOrPut will get the currect value if the key exists else it will save the new value + finalValue, updated := m.GetOrPut(key, value) + + // GetAndDelete will get the value for the give key and deleted the key from the Map + value, deleted := m.GetAndDelete(key) } ```