From cee590521350a06ddb7b1f62bbbe667d29f761d0 Mon Sep 17 00:00:00 2001 From: fy Date: Thu, 7 Apr 2022 17:47:18 +0800 Subject: [PATCH 1/2] add hmap.Iterate() --- README.md | 22 ++++++++++++++++------ hashmap/hmap.go | 11 +++++++++++ hashmap/hmap_test.go | 24 ++++++++++++++++++++++++ map.go | 3 +++ 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3e95fb2..929aa38 100644 --- a/README.md +++ b/README.md @@ -79,13 +79,13 @@ The default bucket size is 24 if a BucketSizeOption is not set. ### for k, v := range Since this is a concurrent hashmap, you'll need to call `Lock()` before doing a range operation. And remember to call `Unlock()` afterwards. -``` +```go func rangeMap(m HashMap) error { - f := func(interface{}, interface{}) error { - // define what to do for each entry in the map - return - } - + f := func(interface{}, interface{}) error { + // define what to do for each entry in the map + return + } + m.Lock() for k, v, ok := m.Next(); ok; k, v, ok = m.Next() { if err := f(k, v); err != nil { @@ -98,6 +98,16 @@ func rangeMap(m HashMap) error { return nil } ``` +A shortcut: +```go +m.Iterate(func(_k interface{}, _v interface{}) error { + k := _k.(string) + v := _v.(int64) + // do something + return nil +}) +``` + ## Queue - FIFO list that can be concurrently accessed - can put different data types into the queue diff --git a/hashmap/hmap.go b/hashmap/hmap.go index 302db18..c554f03 100644 --- a/hashmap/hmap.go +++ b/hashmap/hmap.go @@ -147,6 +147,17 @@ func (h *hmap) Next() (interface{}, interface{}, bool) { } +func (h *hmap) Iterate(f func(_k interface{}, _v interface{}) error) error { + h.Lock() + defer h.Unlock() // unlock even panic + for k, v, ok := h.Next(); ok; k, v, ok = h.Next() { + if err := f(k, v); err != nil { + return err + } + } + return nil +} + func (h *hmap) getBucket(hash uint64) *bucket { h.mutex.RLock() b := h.buckets[hash>>(64-h.B)] diff --git a/hashmap/hmap_test.go b/hashmap/hmap_test.go index e1e5f29..27ad706 100644 --- a/hashmap/hmap_test.go +++ b/hashmap/hmap_test.go @@ -97,4 +97,28 @@ func TestHmap(t *testing.T) { req.Equal(len(tests)-1, match) req.Equal(10000+len(tests)-1, total) m.info() + + // test Iterate() + total = 0 + match = 0 + err := m.Iterate(func(k interface{}, v interface{}) error { + for i := range tests { + if k == tests[i].k { + req.Equal(tests[i].v, v) + match++ + } + } + total++ + return nil + }) + req.Nil(err) + + k, v, ok = m.Next() + req.False(ok) + req.Nil(k) + req.Nil(v) + m.Unlock() + req.Equal(len(tests)-1, match) + req.Equal(10000+len(tests)-1, total) + m.info() } diff --git a/map.go b/map.go index 99017c7..53bc97a 100644 --- a/map.go +++ b/map.go @@ -41,6 +41,9 @@ type ( // returns next in the map Next() (interface{}, interface{}, bool) + + // iterate over all element + Iterate(func(_k interface{}, _v interface{}) error) error } ) From 0985fc56003b88b02e719ff6339a1fff66a9b824 Mon Sep 17 00:00:00 2001 From: fy Date: Thu, 7 Apr 2022 17:59:11 +0800 Subject: [PATCH 2/2] fix readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 929aa38..79b4144 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ m.Iterate(func(_k interface{}, _v interface{}) error { k := _k.(string) v := _v.(int64) // do something - return nil + return nil }) ```