diff options
| author | Agniva De Sarker <agnivade@yahoo.co.in> | 2017-11-08 09:15:53 +0530 |
|---|---|---|
| committer | Joe Tsai <joetsai@google.com> | 2017-11-08 21:47:19 +0000 |
| commit | 65fbf0e834e85997f137c46cc1677ed3e2c8ff4e (patch) | |
| tree | 60c4b6d3096094df3678719dc871f769065def2b /src | |
| parent | 506386fd370cd627c7f2475979860f8cb8cdbe65 (diff) | |
| download | go-65fbf0e834e85997f137c46cc1677ed3e2c8ff4e.tar.xz | |
strings: optimize ToLower
Handling the ASCII case inline and call unicode.ToLower only
for non-ASCII cases.
Gives good improvements for the ASCII case and minor perf
degrade for non-ASCII case
name old time/op new time/op delta
ToLower/#00 10.8ns ± 1% 9.0ns ± 1% -16.83% (p=0.008 n=5+5)
ToLower/abc 23.3ns ± 4% 12.6ns ± 1% -46.01% (p=0.008 n=5+5)
ToLower/AbC123 91.0ns ± 2% 70.4ns ± 0% -22.59% (p=0.008 n=5+5)
ToLower/azAZ09_ 104ns ± 3% 75ns ± 1% -28.35% (p=0.008 n=5+5)
ToLower/longStrinGwitHmixofsmaLLandcAps 254ns ± 4% 157ns ± 0% -38.19% (p=0.016 n=5+4)
ToLower/LONGⱯSTRINGⱯWITHⱯNONASCIIⱯCHARS 446ns ± 1% 451ns ± 1% ~ (p=0.056 n=5+5)
ToLower/ⱭⱭⱭⱭⱭ 345ns ± 1% 348ns ± 0% +0.93% (p=0.016 n=5+5)
name old alloc/op new alloc/op delta
ToLower/#00 0.00B 0.00B ~ (all equal)
ToLower/abc 0.00B 0.00B ~ (all equal)
ToLower/AbC123 16.0B ± 0% 16.0B ± 0% ~ (all equal)
ToLower/azAZ09_ 24.0B ± 0% 16.0B ± 0% -33.33% (p=0.008 n=5+5)
ToLower/longStrinGwitHmixofsmaLLandcAps 80.0B ± 0% 64.0B ± 0% -20.00% (p=0.008 n=5+5)
ToLower/LONGⱯSTRINGⱯWITHⱯNONASCIIⱯCHARS 96.0B ± 0% 96.0B ± 0% ~ (all equal)
ToLower/ⱭⱭⱭⱭⱭ 48.0B ± 0% 48.0B ± 0% ~ (all equal)
Ran on a machine with Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz
Fixes #17859
Change-Id: Iacc1e6b77e1aedba9447a6e94352606f131ea597
Reviewed-on: https://go-review.googlesource.com/76470
Reviewed-by: Marvin Stenger <marvin.stenger94@gmail.com>
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/strings/strings.go | 28 | ||||
| -rw-r--r-- | src/strings/strings_test.go | 15 |
2 files changed, 42 insertions, 1 deletions
diff --git a/src/strings/strings.go b/src/strings/strings.go index 73bba9278c..8520f8a732 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -571,7 +571,33 @@ func ToUpper(s string) string { } // ToLower returns a copy of the string s with all Unicode letters mapped to their lower case. -func ToLower(s string) string { return Map(unicode.ToLower, s) } +func ToLower(s string) string { + isASCII, hasUpper := true, false + for i := 0; i < len(s); i++ { + c := s[i] + if c >= utf8.RuneSelf { + isASCII = false + break + } + hasUpper = hasUpper || (c >= 'A' && c <= 'Z') + } + + if isASCII { // optimize for ASCII-only strings. + if !hasUpper { + return s + } + b := make([]byte, len(s)) + for i := 0; i < len(s); i++ { + c := s[i] + if c >= 'A' && c <= 'Z' { + c += 'a' - 'A' + } + b[i] = c + } + return string(b) + } + return Map(unicode.ToLower, s) +} // ToTitle returns a copy of the string s with all Unicode letters mapped to their title case. func ToTitle(s string) string { return Map(unicode.ToTitle, s) } diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go index b185e7eec8..289dd92d51 100644 --- a/src/strings/strings_test.go +++ b/src/strings/strings_test.go @@ -532,6 +532,8 @@ var lowerTests = []StringTest{ {"abc", "abc"}, {"AbC123", "abc123"}, {"azAZ09_", "azaz09_"}, + {"longStrinGwitHmixofsmaLLandcAps", "longstringwithmixofsmallandcaps"}, + {"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", "long\u0250string\u0250with\u0250nonascii\u0250chars"}, {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char } @@ -664,6 +666,19 @@ func BenchmarkToUpper(b *testing.B) { } } +func BenchmarkToLower(b *testing.B) { + for _, tc := range lowerTests { + b.Run(tc.in, func(b *testing.B) { + for i := 0; i < b.N; i++ { + actual := ToLower(tc.in) + if actual != tc.out { + b.Errorf("ToLower(%q) = %q; want %q", tc.in, actual, tc.out) + } + } + }) + } +} + func BenchmarkMapNoChanges(b *testing.B) { identity := func(r rune) rune { return r |
