github.com/goki/ki@v1.1.11/runes/runes.go (about) 1 // Copyright (c) 2018, The GoKi Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 /* 6 Package runes provides a small subset of functions that are found in strings, bytes 7 standard packages, for rune slices. For rendering, and other logic, it is best to 8 keep raw data in runes, and not having to convert back and forth to byte or string 9 is more efficient. 10 11 These are largely copied from strings or bytes packages. 12 */ 13 package runes 14 15 import ( 16 "unicode" 17 "unicode/utf8" 18 ) 19 20 // EqualFold reports whether s and t are equal under Unicode case-folding. 21 // copied from strings.EqualFold 22 func EqualFold(s, t []rune) bool { 23 for len(s) > 0 && len(t) > 0 { 24 // Extract first rune from each string. 25 var sr, tr rune 26 sr, s = s[0], s[1:] 27 tr, t = t[0], t[1:] 28 // If they match, keep going; if not, return false. 29 30 // Easy case. 31 if tr == sr { 32 continue 33 } 34 35 // Make sr < tr to simplify what follows. 36 if tr < sr { 37 tr, sr = sr, tr 38 } 39 // Fast check for ASCII. 40 if tr < utf8.RuneSelf { 41 // ASCII only, sr/tr must be upper/lower case 42 if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' { 43 continue 44 } 45 return false 46 } 47 48 // General case. SimpleFold(x) returns the next equivalent rune > x 49 // or wraps around to smaller values. 50 r := unicode.SimpleFold(sr) 51 for r != sr && r < tr { 52 r = unicode.SimpleFold(r) 53 } 54 if r == tr { 55 continue 56 } 57 return false 58 } 59 60 // One string is empty. Are both? 61 return len(s) == len(t) 62 } 63 64 // Index returns the index of given rune string in the text, returning -1 if not found. 65 func Index(txt, find []rune) int { 66 fsz := len(find) 67 if fsz == 0 { 68 return -1 69 } 70 tsz := len(txt) 71 if tsz < fsz { 72 return -1 73 } 74 mn := tsz - fsz 75 for i := 0; i <= mn; i++ { 76 found := true 77 for j := range find { 78 if txt[i+j] != find[j] { 79 found = false 80 break 81 } 82 } 83 if found { 84 return i 85 } 86 } 87 return -1 88 } 89 90 // IndexFold returns the index of given rune string in the text, using case folding 91 // (i.e., case insensitive matching). Returns -1 if not found. 92 func IndexFold(txt, find []rune) int { 93 fsz := len(find) 94 if fsz == 0 { 95 return -1 96 } 97 tsz := len(txt) 98 if tsz < fsz { 99 return -1 100 } 101 mn := tsz - fsz 102 for i := 0; i <= mn; i++ { 103 if EqualFold(txt[i:i+fsz], find) { 104 return i 105 } 106 } 107 return -1 108 } 109 110 // Repeat returns a new rune slice consisting of count copies of b. 111 // 112 // It panics if count is negative or if 113 // the result of (len(b) * count) overflows. 114 func Repeat(r []rune, count int) []rune { 115 if count == 0 { 116 return []rune{} 117 } 118 // Since we cannot return an error on overflow, 119 // we should panic if the repeat will generate 120 // an overflow. 121 // See Issue golang.org/issue/16237. 122 if count < 0 { 123 panic("runes: negative Repeat count") 124 } else if len(r)*count/count != len(r) { 125 panic("runes: Repeat count causes overflow") 126 } 127 128 nb := make([]rune, len(r)*count) 129 bp := copy(nb, r) 130 for bp < len(nb) { 131 copy(nb[bp:], nb[:bp]) 132 bp *= 2 133 } 134 return nb 135 }