mirror of
https://github.com/golang/go
synced 2024-09-06 00:19:45 +00:00
![Martin Möhrmann](/assets/img/avatar_default.png)
replace map clears of the form: for k := range m { delete(m, k) } (where m is map with key type that is reflexive for ==) with a new runtime function that clears the maps backing array with a memclr and reinitializes the hmap struct. Map key types that for example contain floats are not replaced by this optimization since NaN keys cannot be deleted from maps using delete. name old time/op new time/op delta GoMapClear/Reflexive/1 92.2ns ± 1% 47.1ns ± 2% -48.89% (p=0.000 n=9+9) GoMapClear/Reflexive/10 108ns ± 1% 48ns ± 2% -55.68% (p=0.000 n=10+10) GoMapClear/Reflexive/100 303ns ± 2% 110ns ± 3% -63.56% (p=0.000 n=10+10) GoMapClear/Reflexive/1000 3.58µs ± 3% 1.23µs ± 2% -65.49% (p=0.000 n=9+10) GoMapClear/Reflexive/10000 28.2µs ± 3% 10.3µs ± 2% -63.55% (p=0.000 n=9+10) GoMapClear/NonReflexive/1 121ns ± 2% 124ns ± 7% ~ (p=0.097 n=10+10) GoMapClear/NonReflexive/10 137ns ± 2% 139ns ± 3% +1.53% (p=0.033 n=10+10) GoMapClear/NonReflexive/100 331ns ± 3% 334ns ± 2% ~ (p=0.342 n=10+10) GoMapClear/NonReflexive/1000 3.64µs ± 3% 3.64µs ± 2% ~ (p=0.887 n=9+10) GoMapClear/NonReflexive/10000 28.1µs ± 2% 28.4µs ± 3% ~ (p=0.247 n=10+10) Fixes #20138 Change-Id: I181332a8ef434a4f0d89659f492d8711db3f3213 Reviewed-on: https://go-review.googlesource.com/110055 Reviewed-by: Keith Randall <khr@golang.org>
90 lines
1.5 KiB
Go
90 lines
1.5 KiB
Go
// run
|
|
|
|
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Ensure that range loops over maps with delete statements
|
|
// have the requisite side-effects.
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
func checkcleared() {
|
|
m := make(map[byte]int)
|
|
m[1] = 1
|
|
m[2] = 2
|
|
for k := range m {
|
|
delete(m, k)
|
|
}
|
|
l := len(m)
|
|
if want := 0; l != want {
|
|
fmt.Printf("len after map clear = %d want %d\n", l, want)
|
|
os.Exit(1)
|
|
}
|
|
|
|
m[0] = 0 // To have non empty map and avoid internal map code fast paths.
|
|
n := 0
|
|
for range m {
|
|
n++
|
|
}
|
|
if want := 1; n != want {
|
|
fmt.Printf("number of keys found = %d want %d\n", n, want)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func checkloopvars() {
|
|
k := 0
|
|
m := make(map[int]int)
|
|
m[42] = 0
|
|
for k = range m {
|
|
delete(m, k)
|
|
}
|
|
if want := 42; k != want {
|
|
fmt.Printf("var after range with side-effect = %d want %d\n", k, want)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func checksideeffects() {
|
|
var x int
|
|
f := func() int {
|
|
x++
|
|
return 0
|
|
}
|
|
m := make(map[int]int)
|
|
m[0] = 0
|
|
m[1] = 1
|
|
for k := range m {
|
|
delete(m, k+f())
|
|
}
|
|
if want := 2; x != want {
|
|
fmt.Printf("var after range with side-effect = %d want %d\n", x, want)
|
|
os.Exit(1)
|
|
}
|
|
|
|
var n int
|
|
m = make(map[int]int)
|
|
m[0] = 0
|
|
m[1] = 1
|
|
for k := range m {
|
|
delete(m, k)
|
|
n++
|
|
}
|
|
if want := 2; n != want {
|
|
fmt.Printf("counter for range with side-effect = %d want %d\n", n, want)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
checkcleared()
|
|
checkloopvars()
|
|
checksideeffects()
|
|
}
|