github.com/gramework/gramework@v1.8.1-0.20231027140105-82555c9057f5/tolower_go112.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the "third_party_licenses/Go (golang)" file. 4 5 //+build go1.12 6 7 package gramework 8 9 import ( 10 "strings" 11 "unicode" 12 "unicode/utf8" 13 ) 14 15 // toLower returns a copy of the string s with all Unicode letters mapped to their lower case. 16 func toLower(s string) string { 17 isASCII, hasUpper := true, false 18 for i := 0; i < len(s); i++ { 19 c := s[i] 20 if c >= utf8.RuneSelf { 21 isASCII = false 22 break 23 } 24 hasUpper = hasUpper || (c >= 'A' && c <= 'Z') 25 } 26 27 if isASCII { // optimize for ASCII-only strings. 28 if !hasUpper { 29 return s 30 } 31 var b strings.Builder 32 b.Grow(len(s)) 33 for i := 0; i < len(s); i++ { 34 c := s[i] 35 if c >= 'A' && c <= 'Z' { 36 c += 'a' - 'A' 37 } 38 b.WriteByte(c) 39 } 40 return b.String() 41 } 42 return stringsMap(unicode.ToLower, s) 43 } 44 45 // Map returns a copy of the string s with all its characters modified 46 // according to the mapping function. If mapping returns a negative value, the character is 47 // dropped from the string with no replacement. 48 func stringsMap(mapping func(rune) rune, s string) string { 49 // In the worst case, the string can grow when mapped, making 50 // things unpleasant. But it's so rare we barge in assuming it's 51 // fine. It could also shrink but that falls out naturally. 52 53 // The output buffer b is initialized on demand, the first 54 // time a character differs. 55 var b strings.Builder 56 57 for i, c := range s { 58 r := mapping(c) 59 if r == c { 60 continue 61 } 62 63 b.Grow(len(s) + utf8.UTFMax) 64 b.WriteString(s[:i]) 65 if r >= 0 { 66 b.WriteRune(r) 67 } 68 69 if c == utf8.RuneError { 70 // RuneError is the result of either decoding 71 // an invalid sequence or '\uFFFD'. Determine 72 // the correct number of bytes we need to advance. 73 _, w := utf8.DecodeRuneInString(s[i:]) 74 i += w 75 } else { 76 i += utf8.RuneLen(c) 77 } 78 79 s = s[i:] 80 break 81 } 82 83 // Fast path for unchanged input 84 if b.Cap() == 0 { // didn't call b.Grow above 85 return s 86 } 87 88 for _, c := range s { 89 r := mapping(c) 90 91 if r >= 0 { 92 // common case 93 // Due to inlining, it is more performant to determine if WriteByte should be 94 // invoked rather than always call WriteRune 95 if r < utf8.RuneSelf { 96 b.WriteByte(byte(r)) 97 } else { 98 // r is not a ASCII rune. 99 b.WriteRune(r) 100 } 101 } 102 } 103 104 return b.String() 105 }