github.com/aykevl/tinygo@v0.5.0/src/runtime/string.go (about) 1 package runtime 2 3 // This file implements functions related to Go strings. 4 5 import ( 6 "unsafe" 7 ) 8 9 // The underlying struct for the Go string type. 10 type _string struct { 11 ptr *byte 12 length uintptr 13 } 14 15 // The iterator state for a range over a string. 16 type stringIterator struct { 17 byteindex uintptr 18 } 19 20 // Return true iff the strings match. 21 //go:nobounds 22 func stringEqual(x, y string) bool { 23 if len(x) != len(y) { 24 return false 25 } 26 for i := 0; i < len(x); i++ { 27 if x[i] != y[i] { 28 return false 29 } 30 } 31 return true 32 } 33 34 // Return true iff x < y. 35 //go:nobounds 36 func stringLess(x, y string) bool { 37 l := len(x) 38 if m := len(y); m < l { 39 l = m 40 } 41 for i := 0; i < l; i++ { 42 if x[i] < y[i] { 43 return true 44 } 45 if x[i] > y[i] { 46 return false 47 } 48 } 49 return len(x) < len(y) 50 } 51 52 // Add two strings together. 53 func stringConcat(x, y _string) _string { 54 if x.length == 0 { 55 return y 56 } else if y.length == 0 { 57 return x 58 } else { 59 length := x.length + y.length 60 buf := alloc(length) 61 memcpy(buf, unsafe.Pointer(x.ptr), x.length) 62 memcpy(unsafe.Pointer(uintptr(buf)+x.length), unsafe.Pointer(y.ptr), y.length) 63 return _string{ptr: (*byte)(buf), length: length} 64 } 65 } 66 67 // Create a string from a []byte slice. 68 func stringFromBytes(x struct { 69 ptr *byte 70 len uintptr 71 cap uintptr 72 }) _string { 73 buf := alloc(x.len) 74 memcpy(buf, unsafe.Pointer(x.ptr), x.len) 75 return _string{ptr: (*byte)(buf), length: x.len} 76 } 77 78 // Convert a string to a []byte slice. 79 func stringToBytes(x _string) (slice struct { 80 ptr *byte 81 len uintptr 82 cap uintptr 83 }) { 84 buf := alloc(x.length) 85 memcpy(buf, unsafe.Pointer(x.ptr), x.length) 86 slice.ptr = (*byte)(buf) 87 slice.len = x.length 88 slice.cap = x.length 89 return 90 } 91 92 // Create a string from a Unicode code point. 93 func stringFromUnicode(x rune) _string { 94 array, length := encodeUTF8(x) 95 // Array will be heap allocated. 96 // The heap most likely doesn't work with blocks below 4 bytes, so there's 97 // no point in allocating a smaller buffer for the string here. 98 return _string{ptr: (*byte)(unsafe.Pointer(&array)), length: length} 99 } 100 101 // Iterate over a string. 102 // Returns (ok, key, value). 103 func stringNext(s string, it *stringIterator) (bool, int, rune) { 104 if len(s) <= int(it.byteindex) { 105 return false, 0, 0 106 } 107 i := int(it.byteindex) 108 r, length := decodeUTF8(s, it.byteindex) 109 it.byteindex += length 110 return true, i, r 111 } 112 113 // Convert a Unicode code point into an array of bytes and its length. 114 func encodeUTF8(x rune) ([4]byte, uintptr) { 115 // https://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 116 // Note: this code can probably be optimized (in size and speed). 117 switch { 118 case x <= 0x7f: 119 return [4]byte{byte(x), 0, 0, 0}, 1 120 case x <= 0x7ff: 121 b1 := 0xc0 | byte(x>>6) 122 b2 := 0x80 | byte(x&0x3f) 123 return [4]byte{b1, b2, 0, 0}, 2 124 case x <= 0xffff: 125 b1 := 0xe0 | byte(x>>12) 126 b2 := 0x80 | byte((x>>6)&0x3f) 127 b3 := 0x80 | byte((x>>0)&0x3f) 128 return [4]byte{b1, b2, b3, 0}, 3 129 case x <= 0x10ffff: 130 b1 := 0xf0 | byte(x>>18) 131 b2 := 0x80 | byte((x>>12)&0x3f) 132 b3 := 0x80 | byte((x>>6)&0x3f) 133 b4 := 0x80 | byte((x>>0)&0x3f) 134 return [4]byte{b1, b2, b3, b4}, 4 135 default: 136 // Invalid Unicode code point. 137 return [4]byte{0xef, 0xbf, 0xbd, 0}, 3 138 } 139 } 140 141 // Decode a single UTF-8 character from a string. 142 //go:nobounds 143 func decodeUTF8(s string, index uintptr) (rune, uintptr) { 144 remaining := uintptr(len(s)) - index // must be >= 1 before calling this function 145 x := s[index] 146 switch { 147 case x&0x80 == 0x00: // 0xxxxxxx 148 return rune(x), 1 149 case x&0xe0 == 0xc0: // 110xxxxx 150 if remaining < 2 { 151 return 0xfffd, 1 152 } 153 return (rune(x&0x1f) << 6) | (rune(s[index+1]) & 0x3f), 2 154 case x&0xf0 == 0xe0: // 1110xxxx 155 if remaining < 3 { 156 return 0xfffd, 1 157 } 158 return (rune(x&0x0f) << 12) | ((rune(s[index+1]) & 0x3f) << 6) | (rune(s[index+2]) & 0x3f), 3 159 case x&0xf8 == 0xf0: // 11110xxx 160 if remaining < 4 { 161 return 0xfffd, 1 162 } 163 return (rune(x&0x07) << 18) | ((rune(s[index+1]) & 0x3f) << 12) | ((rune(s[index+2]) & 0x3f) << 6) | (rune(s[index+3]) & 0x3f), 4 164 default: 165 return 0xfffd, 1 166 } 167 } 168 169 // indexByte returns the index of the first instance of c in s, or -1 if c is not present in s. 170 //go:linkname indexByte strings.IndexByte 171 func indexByte(s string, c byte) int { 172 for i := 0; i < len(s); i++ { 173 if s[i] == c { 174 return i 175 } 176 } 177 return -1 178 }