aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/map.go
diff options
context:
space:
mode:
authorcuiweixie <cuiweixie@gmail.com>2023-04-02 15:49:58 +0800
committerKeith Randall <khr@golang.org>2023-05-19 15:54:43 +0000
commitf283cba396d40b8ae8e724d7368480a85a255c7f (patch)
tree555cc9897e506f518745870d05a4fe26d969bd62 /src/runtime/map.go
parent251daf46fb6531220145603ff3d977f9146a43f6 (diff)
downloadgo-f283cba396d40b8ae8e724d7368480a85a255c7f.tar.xz
maps,runtime: improve maps.Keys
name old time/op new time/op delta Keys-10 8.65ms ± 0% 7.06ms ± 0% -18.41% (p=0.000 n=9+9) name old alloc/op new alloc/op delta Keys-10 58.2kB ± 1% 47.4kB ± 2% -18.54% (p=0.000 n=10+10) name old allocs/op new allocs/op delta Keys-10 0.00 0.00 ~ (all equal) Change-Id: Ia7061c37be89e906e79bc3ef3bb1ef0d7913f9f6 Reviewed-on: https://go-review.googlesource.com/c/go/+/481435 Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Heschi Kreinick <heschi@google.com> Run-TryBot: xie cui <523516579@qq.com>
Diffstat (limited to 'src/runtime/map.go')
-rw-r--r--src/runtime/map.go64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/runtime/map.go b/src/runtime/map.go
index a1fe08f758..33685269cd 100644
--- a/src/runtime/map.go
+++ b/src/runtime/map.go
@@ -1593,3 +1593,67 @@ func mapclone2(t *maptype, src *hmap) *hmap {
}
return dst
}
+
+// keys for implementing maps.keys
+//
+//go:linkname keys maps.keys
+func keys(m any, p unsafe.Pointer) {
+ e := efaceOf(&m)
+ t := (*maptype)(unsafe.Pointer(e._type))
+ h := (*hmap)(e.data)
+
+ if h == nil || h.count == 0 {
+ return
+ }
+ s := (*slice)(p)
+ r := int(fastrand())
+ offset := uint8(r >> h.B & (bucketCnt - 1))
+ if h.B == 0 {
+ copyKeys(t, h, (*bmap)(h.buckets), s, offset)
+ return
+ }
+ arraySize := int(bucketShift(h.B))
+ buckets := h.buckets
+ for i := 0; i < arraySize; i++ {
+ bucket := (i + r) & (arraySize - 1)
+ b := (*bmap)(add(buckets, uintptr(bucket)*uintptr(t.BucketSize)))
+ copyKeys(t, h, b, s, offset)
+ }
+
+ if h.growing() {
+ oldArraySize := int(h.noldbuckets())
+ for i := 0; i < oldArraySize; i++ {
+ bucket := (i + r) & (oldArraySize - 1)
+ b := (*bmap)(add(h.oldbuckets, uintptr(bucket)*uintptr(t.BucketSize)))
+ if evacuated(b) {
+ continue
+ }
+ copyKeys(t, h, b, s, offset)
+ }
+ }
+ return
+}
+
+func copyKeys(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) {
+ for b != nil {
+ for i := uintptr(0); i < bucketCnt; i++ {
+ offi := (i + uintptr(offset)) & (bucketCnt - 1)
+ if isEmpty(b.tophash[offi]) {
+ continue
+ }
+ if h.flags&hashWriting != 0 {
+ fatal("concurrent map read and map write")
+ }
+ k := add(unsafe.Pointer(b), dataOffset+offi*uintptr(t.KeySize))
+ if t.IndirectKey() {
+ k = *((*unsafe.Pointer)(k))
+ }
+ if s.len >= s.cap {
+ fatal("concurrent map read and map write")
+ }
+ typedmemmove(t.Key, add(s.array, uintptr(s.len)*uintptr(t.KeySize)), k)
+ s.len++
+ }
+ b = b.overflow(t)
+ }
+}