Source file
src/runtime/string.go
Documentation: runtime
1
2
3
4
5 package runtime
6
7 import "unsafe"
8
9
10
11 const tmpStringBufSize = 32
12
13 type tmpBuf [tmpStringBufSize]byte
14
15
16
17
18
19
20 func concatstrings(buf *tmpBuf, a []string) string {
21 idx := 0
22 l := 0
23 count := 0
24 for i, x := range a {
25 n := len(x)
26 if n == 0 {
27 continue
28 }
29 if l+n < l {
30 throw("string concatenation too long")
31 }
32 l += n
33 count++
34 idx = i
35 }
36 if count == 0 {
37 return ""
38 }
39
40
41
42
43 if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
44 return a[idx]
45 }
46 s, b := rawstringtmp(buf, l)
47 for _, x := range a {
48 copy(b, x)
49 b = b[len(x):]
50 }
51 return s
52 }
53
54 func concatstring2(buf *tmpBuf, a [2]string) string {
55 return concatstrings(buf, a[:])
56 }
57
58 func concatstring3(buf *tmpBuf, a [3]string) string {
59 return concatstrings(buf, a[:])
60 }
61
62 func concatstring4(buf *tmpBuf, a [4]string) string {
63 return concatstrings(buf, a[:])
64 }
65
66 func concatstring5(buf *tmpBuf, a [5]string) string {
67 return concatstrings(buf, a[:])
68 }
69
70
71
72 func slicebytetostring(buf *tmpBuf, b []byte) (str string) {
73 l := len(b)
74 if l == 0 {
75
76
77
78 return ""
79 }
80 if raceenabled {
81 racereadrangepc(unsafe.Pointer(&b[0]),
82 uintptr(l),
83 getcallerpc(),
84 funcPC(slicebytetostring))
85 }
86 if msanenabled {
87 msanread(unsafe.Pointer(&b[0]), uintptr(l))
88 }
89
90 var p unsafe.Pointer
91 if buf != nil && len(b) <= len(buf) {
92 p = unsafe.Pointer(buf)
93 } else {
94 p = mallocgc(uintptr(len(b)), nil, false)
95 }
96 stringStructOf(&str).str = p
97 stringStructOf(&str).len = len(b)
98 memmove(p, (*(*slice)(unsafe.Pointer(&b))).array, uintptr(len(b)))
99 return
100 }
101
102
103
104 func stringDataOnStack(s string) bool {
105 ptr := uintptr(stringStructOf(&s).str)
106 stk := getg().stack
107 return stk.lo <= ptr && ptr < stk.hi
108 }
109
110 func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
111 if buf != nil && l <= len(buf) {
112 b = buf[:l]
113 s = slicebytetostringtmp(b)
114 } else {
115 s, b = rawstring(l)
116 }
117 return
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 func slicebytetostringtmp(b []byte) string {
134 if raceenabled && len(b) > 0 {
135 racereadrangepc(unsafe.Pointer(&b[0]),
136 uintptr(len(b)),
137 getcallerpc(),
138 funcPC(slicebytetostringtmp))
139 }
140 if msanenabled && len(b) > 0 {
141 msanread(unsafe.Pointer(&b[0]), uintptr(len(b)))
142 }
143 return *(*string)(unsafe.Pointer(&b))
144 }
145
146 func stringtoslicebyte(buf *tmpBuf, s string) []byte {
147 var b []byte
148 if buf != nil && len(s) <= len(buf) {
149 *buf = tmpBuf{}
150 b = buf[:len(s)]
151 } else {
152 b = rawbyteslice(len(s))
153 }
154 copy(b, s)
155 return b
156 }
157
158 func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
159
160
161 n := 0
162 for range s {
163 n++
164 }
165
166 var a []rune
167 if buf != nil && n <= len(buf) {
168 *buf = [tmpStringBufSize]rune{}
169 a = buf[:n]
170 } else {
171 a = rawruneslice(n)
172 }
173
174 n = 0
175 for _, r := range s {
176 a[n] = r
177 n++
178 }
179 return a
180 }
181
182 func slicerunetostring(buf *tmpBuf, a []rune) string {
183 if raceenabled && len(a) > 0 {
184 racereadrangepc(unsafe.Pointer(&a[0]),
185 uintptr(len(a))*unsafe.Sizeof(a[0]),
186 getcallerpc(),
187 funcPC(slicerunetostring))
188 }
189 if msanenabled && len(a) > 0 {
190 msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
191 }
192 var dum [4]byte
193 size1 := 0
194 for _, r := range a {
195 size1 += encoderune(dum[:], r)
196 }
197 s, b := rawstringtmp(buf, size1+3)
198 size2 := 0
199 for _, r := range a {
200
201 if size2 >= size1 {
202 break
203 }
204 size2 += encoderune(b[size2:], r)
205 }
206 return s[:size2]
207 }
208
209 type stringStruct struct {
210 str unsafe.Pointer
211 len int
212 }
213
214
215 type stringStructDWARF struct {
216 str *byte
217 len int
218 }
219
220 func stringStructOf(sp *string) *stringStruct {
221 return (*stringStruct)(unsafe.Pointer(sp))
222 }
223
224 func intstring(buf *[4]byte, v int64) string {
225 var s string
226 var b []byte
227 if buf != nil {
228 b = buf[:]
229 s = slicebytetostringtmp(b)
230 } else {
231 s, b = rawstring(4)
232 }
233 if int64(rune(v)) != v {
234 v = runeError
235 }
236 n := encoderune(b, rune(v))
237 return s[:n]
238 }
239
240
241
242
243
244 func rawstring(size int) (s string, b []byte) {
245 p := mallocgc(uintptr(size), nil, false)
246
247 stringStructOf(&s).str = p
248 stringStructOf(&s).len = size
249
250 *(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
251
252 return
253 }
254
255
256 func rawbyteslice(size int) (b []byte) {
257 cap := roundupsize(uintptr(size))
258 p := mallocgc(cap, nil, false)
259 if cap != uintptr(size) {
260 memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))
261 }
262
263 *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
264 return
265 }
266
267
268 func rawruneslice(size int) (b []rune) {
269 if uintptr(size) > _MaxMem/4 {
270 throw("out of memory")
271 }
272 mem := roundupsize(uintptr(size) * 4)
273 p := mallocgc(mem, nil, false)
274 if mem != uintptr(size)*4 {
275 memclrNoHeapPointers(add(p, uintptr(size)*4), mem-uintptr(size)*4)
276 }
277
278 *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
279 return
280 }
281
282
283 func gobytes(p *byte, n int) []byte {
284 if n == 0 {
285 return make([]byte, 0)
286 }
287 x := make([]byte, n)
288 memmove(unsafe.Pointer(&x[0]), unsafe.Pointer(p), uintptr(n))
289 return x
290 }
291
292 func gostring(p *byte) string {
293 l := findnull(p)
294 if l == 0 {
295 return ""
296 }
297 s, b := rawstring(l)
298 memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
299 return s
300 }
301
302 func gostringn(p *byte, l int) string {
303 if l == 0 {
304 return ""
305 }
306 s, b := rawstring(l)
307 memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
308 return s
309 }
310
311 func index(s, t string) int {
312 if len(t) == 0 {
313 return 0
314 }
315 for i := 0; i < len(s); i++ {
316 if s[i] == t[0] && hasprefix(s[i:], t) {
317 return i
318 }
319 }
320 return -1
321 }
322
323 func contains(s, t string) bool {
324 return index(s, t) >= 0
325 }
326
327 func hasprefix(s, t string) bool {
328 return len(s) >= len(t) && s[:len(t)] == t
329 }
330
331 const (
332 maxUint = ^uint(0)
333 maxInt = int(maxUint >> 1)
334 )
335
336
337
338
339 func atoi(s string) (int, bool) {
340 if s == "" {
341 return 0, false
342 }
343
344 neg := false
345 if s[0] == '-' {
346 neg = true
347 s = s[1:]
348 }
349
350 un := uint(0)
351 for i := 0; i < len(s); i++ {
352 c := s[i]
353 if c < '0' || c > '9' {
354 return 0, false
355 }
356 if un > maxUint/10 {
357
358 return 0, false
359 }
360 un *= 10
361 un1 := un + uint(c) - '0'
362 if un1 < un {
363
364 return 0, false
365 }
366 un = un1
367 }
368
369 if !neg && un > uint(maxInt) {
370 return 0, false
371 }
372 if neg && un > uint(maxInt)+1 {
373 return 0, false
374 }
375
376 n := int(un)
377 if neg {
378 n = -n
379 }
380
381 return n, true
382 }
383
384
385
386 func atoi32(s string) (int32, bool) {
387 if n, ok := atoi(s); n == int(int32(n)) {
388 return int32(n), ok
389 }
390 return 0, false
391 }
392
393
394 func findnull(s *byte) int {
395 if s == nil {
396 return 0
397 }
398 p := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s))
399 l := 0
400 for p[l] != 0 {
401 l++
402 }
403 return l
404 }
405
406 func findnullw(s *uint16) int {
407 if s == nil {
408 return 0
409 }
410 p := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(s))
411 l := 0
412 for p[l] != 0 {
413 l++
414 }
415 return l
416 }
417
418
419 func gostringnocopy(str *byte) string {
420 ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
421 s := *(*string)(unsafe.Pointer(&ss))
422 return s
423 }
424
425 func gostringw(strw *uint16) string {
426 var buf [8]byte
427 str := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(strw))
428 n1 := 0
429 for i := 0; str[i] != 0; i++ {
430 n1 += encoderune(buf[:], rune(str[i]))
431 }
432 s, b := rawstring(n1 + 4)
433 n2 := 0
434 for i := 0; str[i] != 0; i++ {
435
436 if n2 >= n1 {
437 break
438 }
439 n2 += encoderune(b[n2:], rune(str[i]))
440 }
441 b[n2] = 0
442 return s[:n2]
443 }
444
View as plain text