mirror of
https://github.com/golang/go
synced 2024-09-05 07:54:46 +00:00
![Martin Möhrmann](/assets/img/avatar_default.png)
Generate a for loop for ranging over strings that only needs to call the runtime function charntorune for non ASCII characters. This provides faster iteration over ASCII characters and slightly faster iteration for other characters. The runtime function charntorune is changed to take an index from where to start decoding and returns the index after the last byte belonging to the decoded rune. All call sites of charntorune in the runtime are replaced by a for loop that will be transformed by the compiler instead of calling the charntorune function directly. go binary size decreases by 80 bytes. godoc binary size increases by around 4 kilobytes. runtime: name old time/op new time/op delta RuneIterate/range/ASCII-4 43.7ns ± 3% 10.3ns ± 4% -76.33% (p=0.000 n=44+45) RuneIterate/range/Japanese-4 72.5ns ± 2% 62.8ns ± 2% -13.41% (p=0.000 n=49+50) RuneIterate/range1/ASCII-4 43.5ns ± 2% 10.4ns ± 3% -76.18% (p=0.000 n=50+50) RuneIterate/range1/Japanese-4 72.5ns ± 2% 62.9ns ± 2% -13.26% (p=0.000 n=50+49) RuneIterate/range2/ASCII-4 43.5ns ± 3% 10.3ns ± 2% -76.22% (p=0.000 n=48+47) RuneIterate/range2/Japanese-4 72.4ns ± 2% 62.7ns ± 2% -13.47% (p=0.000 n=50+50) strings: name old time/op new time/op delta IndexRune-4 64.7ns ± 5% 22.4ns ± 3% -65.43% (p=0.000 n=25+21) MapNoChanges-4 269ns ± 2% 157ns ± 2% -41.46% (p=0.000 n=23+24) Fields-4 23.0ms ± 2% 19.7ms ± 2% -14.35% (p=0.000 n=25+25) FieldsFunc-4 23.1ms ± 2% 19.6ms ± 2% -14.94% (p=0.000 n=25+24) name old speed new speed delta Fields-4 45.6MB/s ± 2% 53.2MB/s ± 2% +16.87% (p=0.000 n=24+25) FieldsFunc-4 45.5MB/s ± 2% 53.5MB/s ± 2% +17.57% (p=0.000 n=25+24) Updates #13162 Change-Id: I79ffaf828d82bf9887592f08e5cad883e9f39701 Reviewed-on: https://go-review.googlesource.com/27853 TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com> Run-TryBot: Martin Möhrmann <martisch@uos.de>
83 lines
1.6 KiB
Go
83 lines
1.6 KiB
Go
// run
|
|
|
|
// Copyright 2016 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 a string have the requisite side-effects.
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
func check(n int) {
|
|
var i int
|
|
var r rune
|
|
|
|
b := make([]byte, n)
|
|
for i = range b {
|
|
b[i] = byte(i + 1)
|
|
}
|
|
s := string(b)
|
|
|
|
// When n == 0, i is untouched by the range loop.
|
|
// Picking an initial value of -1 for i makes the
|
|
// "want" calculation below correct in all cases.
|
|
i = -1
|
|
for i = range s {
|
|
b[i] = s[i]
|
|
}
|
|
if want := n - 1; i != want {
|
|
fmt.Printf("index after range with side-effect = %d want %d\n", i, want)
|
|
os.Exit(1)
|
|
}
|
|
|
|
i = -1
|
|
r = '\x00'
|
|
for i, r = range s {
|
|
b[i] = byte(r)
|
|
}
|
|
if want := n - 1; i != want {
|
|
fmt.Printf("index after range with side-effect = %d want %d\n", i, want)
|
|
os.Exit(1)
|
|
}
|
|
if want := rune(n); r != want {
|
|
fmt.Printf("rune after range with side-effect = %q want %q\n", r, want)
|
|
os.Exit(1)
|
|
}
|
|
|
|
i = -1
|
|
// i is shadowed here, so its value should be unchanged.
|
|
for i := range s {
|
|
b[i] = s[i]
|
|
}
|
|
if want := -1; i != want {
|
|
fmt.Printf("index after range without side-effect = %d want %d\n", i, want)
|
|
os.Exit(1)
|
|
}
|
|
|
|
i = -1
|
|
r = -1
|
|
// i and r are shadowed here, so their values should be unchanged.
|
|
for i, r := range s {
|
|
b[i] = byte(r)
|
|
}
|
|
if want := -1; i != want {
|
|
fmt.Printf("index after range without side-effect = %d want %d\n", i, want)
|
|
os.Exit(1)
|
|
}
|
|
if want := rune(-1); r != want {
|
|
fmt.Printf("rune after range without side-effect = %q want %q\n", r, want)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
check(0)
|
|
check(1)
|
|
check(15)
|
|
}
|