Skip to content

Commit

Permalink
Add GetOrPut and GetAndDelete functions
Browse files Browse the repository at this point in the history
Signed-off-by: m-murad <murad.kuka@gmail.com>
  • Loading branch information
m-murad committed Aug 24, 2021
1 parent bbe8ac6 commit dbe832a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 3 deletions.
39 changes: 36 additions & 3 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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
}
}
48 changes: 48 additions & 0 deletions map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
6 changes: 6 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
```

0 comments on commit dbe832a

Please sign in to comment.