diff options
Diffstat (limited to 'libgo/go/runtime/string_test.go')
-rw-r--r-- | libgo/go/runtime/string_test.go | 219 |
1 files changed, 179 insertions, 40 deletions
diff --git a/libgo/go/runtime/string_test.go b/libgo/go/runtime/string_test.go index 64abd57d28..ee306999e2 100644 --- a/libgo/go/runtime/string_test.go +++ b/libgo/go/runtime/string_test.go @@ -5,10 +5,15 @@ package runtime_test import ( + "runtime" "strings" "testing" ) +// Strings and slices that don't escape and fit into tmpBuf are stack allocated, +// which defeats using AllocsPerRun to test other optimizations. +const sizeNoStack = 100 + func BenchmarkCompareStringEqual(b *testing.B) { bytes := []byte("Hello Gophers!") s1, s2 := string(bytes), string(bytes) @@ -77,26 +82,59 @@ func BenchmarkCompareStringBig(b *testing.B) { b.SetBytes(int64(len(s1))) } -func BenchmarkRuneIterate(b *testing.B) { - bytes := make([]byte, 100) - for i := range bytes { - bytes[i] = byte('A') - } - s := string(bytes) +func BenchmarkConcatStringAndBytes(b *testing.B) { + s1 := []byte("Gophers!") for i := 0; i < b.N; i++ { - for range s { - } + _ = "Hello " + string(s1) } } -func BenchmarkRuneIterate2(b *testing.B) { - bytes := make([]byte, 100) - for i := range bytes { - bytes[i] = byte('A') - } - s := string(bytes) +var stringdata = []struct{ name, data string }{ + {"ASCII", "01234567890"}, + {"Japanese", "日本語日本語日本語"}, + {"MixedLength", "$Ѐࠀက퀀𐀀\U00040000\U0010FFFF"}, +} + +func BenchmarkRuneIterate(b *testing.B) { + b.Run("range", func(b *testing.B) { + for _, sd := range stringdata { + b.Run(sd.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + for range sd.data { + } + } + }) + } + }) + b.Run("range1", func(b *testing.B) { + for _, sd := range stringdata { + b.Run(sd.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _ = range sd.data { + } + } + }) + } + }) + b.Run("range2", func(b *testing.B) { + for _, sd := range stringdata { + b.Run(sd.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, _ = range sd.data { + } + } + }) + } + }) +} + +func BenchmarkArrayEqual(b *testing.B) { + a1 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + a2 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + b.ResetTimer() for i := 0; i < b.N; i++ { - for range s { + if a1 != a2 { + b.Fatal("not equal") } } } @@ -134,23 +172,8 @@ func TestLargeStringConcat(t *testing.T) { } } -/* -func TestGostringnocopy(t *testing.T) { - max := *runtime.Maxstring - b := make([]byte, max+10) - for i := uintptr(0); i < max+9; i++ { - b[i] = 'a' - } - _ = runtime.Gostringnocopy(&b[0]) - newmax := *runtime.Maxstring - if newmax != max+9 { - t.Errorf("want %d, got %d", max+9, newmax) - } -} -*/ - func TestCompareTempString(t *testing.T) { - s := "foo" + s := strings.Repeat("x", sizeNoStack) b := []byte(s) n := testing.AllocsPerRun(1000, func() { if string(b) != s { @@ -161,7 +184,8 @@ func TestCompareTempString(t *testing.T) { t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) } }) - if n != 0 { + // was n != 0, changed for gccgo. + if n > 2 { t.Fatalf("want 0 allocs, got %v", n) } } @@ -207,13 +231,15 @@ func TestIntStringAllocs(t *testing.T) { t.Fatalf("bad") } }) - if n != 0 { + // was n != 0, changed for gccgo, which currently does one + // allocation for each call to string(unknown). + if n > 2 { t.Fatalf("want 0 allocs, got %v", n) } } func TestRangeStringCast(t *testing.T) { - s := "abc" + s := strings.Repeat("x", sizeNoStack) n := testing.AllocsPerRun(1000, func() { for i, c := range []byte(s) { if c != s[i] { @@ -221,22 +247,135 @@ func TestRangeStringCast(t *testing.T) { } } }) - if n != 0 { + // was n != 0, changed for gccgo. + if n > 1 { t.Fatalf("want 0 allocs, got %v", n) } } +func isZeroed(b []byte) bool { + for _, x := range b { + if x != 0 { + return false + } + } + return true +} + +func isZeroedR(r []rune) bool { + for _, x := range r { + if x != 0 { + return false + } + } + return true +} + func TestString2Slice(t *testing.T) { // Make sure we don't return slices that expose // an unzeroed section of stack-allocated temp buf - // between len and cap. See issue 14232. + // between len and cap. See issue 14232. s := "foož" b := ([]byte)(s) - if cap(b) != 5 { - t.Errorf("want cap of 5, got %d", cap(b)) + if !isZeroed(b[len(b):cap(b)]) { + t.Errorf("extra bytes not zeroed") } r := ([]rune)(s) - if cap(r) != 4 { - t.Errorf("want cap of 4, got %d", cap(r)) + if !isZeroedR(r[len(r):cap(r)]) { + t.Errorf("extra runes not zeroed") + } +} + +const intSize = 32 << (^uint(0) >> 63) + +type atoi64Test struct { + in string + out int64 + ok bool +} + +var atoi64tests = []atoi64Test{ + {"", 0, false}, + {"0", 0, true}, + {"-0", 0, true}, + {"1", 1, true}, + {"-1", -1, true}, + {"12345", 12345, true}, + {"-12345", -12345, true}, + {"012345", 12345, true}, + {"-012345", -12345, true}, + {"12345x", 0, false}, + {"-12345x", 0, false}, + {"98765432100", 98765432100, true}, + {"-98765432100", -98765432100, true}, + {"20496382327982653440", 0, false}, + {"-20496382327982653440", 0, false}, + {"9223372036854775807", 1<<63 - 1, true}, + {"-9223372036854775807", -(1<<63 - 1), true}, + {"9223372036854775808", 0, false}, + {"-9223372036854775808", -1 << 63, true}, + {"9223372036854775809", 0, false}, + {"-9223372036854775809", 0, false}, +} + +func TestAtoi(t *testing.T) { + switch intSize { + case 32: + for i := range atoi32tests { + test := &atoi32tests[i] + out, ok := runtime.Atoi(test.in) + if test.out != int32(out) || test.ok != ok { + t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)", + test.in, out, ok, test.out, test.ok) + } + } + case 64: + for i := range atoi64tests { + test := &atoi64tests[i] + out, ok := runtime.Atoi(test.in) + if test.out != int64(out) || test.ok != ok { + t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)", + test.in, out, ok, test.out, test.ok) + } + } + } +} + +type atoi32Test struct { + in string + out int32 + ok bool +} + +var atoi32tests = []atoi32Test{ + {"", 0, false}, + {"0", 0, true}, + {"-0", 0, true}, + {"1", 1, true}, + {"-1", -1, true}, + {"12345", 12345, true}, + {"-12345", -12345, true}, + {"012345", 12345, true}, + {"-012345", -12345, true}, + {"12345x", 0, false}, + {"-12345x", 0, false}, + {"987654321", 987654321, true}, + {"-987654321", -987654321, true}, + {"2147483647", 1<<31 - 1, true}, + {"-2147483647", -(1<<31 - 1), true}, + {"2147483648", 0, false}, + {"-2147483648", -1 << 31, true}, + {"2147483649", 0, false}, + {"-2147483649", 0, false}, +} + +func TestAtoi32(t *testing.T) { + for i := range atoi32tests { + test := &atoi32tests[i] + out, ok := runtime.Atoi32(test.in) + if test.out != out || test.ok != ok { + t.Errorf("atoi32(%q) = (%v, %v) want (%v, %v)", + test.in, out, ok, test.out, test.ok) + } } } |