Source file
src/runtime/string.go
Documentation: runtime
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/bytealg"
10 "internal/goarch"
11 "unsafe"
12 )
13
14
15
16 const tmpStringBufSize = 32
17
18 type tmpBuf [tmpStringBufSize]byte
19
20
21
22
23
24
25 func concatstrings(buf *tmpBuf, a []string) string {
26 idx := 0
27 l := 0
28 count := 0
29 for i, x := range a {
30 n := len(x)
31 if n == 0 {
32 continue
33 }
34 if l+n < l {
35 throw("string concatenation too long")
36 }
37 l += n
38 count++
39 idx = i
40 }
41 if count == 0 {
42 return ""
43 }
44
45
46
47
48 if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
49 return a[idx]
50 }
51 s, b := rawstringtmp(buf, l)
52 for _, x := range a {
53 copy(b, x)
54 b = b[len(x):]
55 }
56 return s
57 }
58
59 func concatstring2(buf *tmpBuf, a0, a1 string) string {
60 return concatstrings(buf, []string{a0, a1})
61 }
62
63 func concatstring3(buf *tmpBuf, a0, a1, a2 string) string {
64 return concatstrings(buf, []string{a0, a1, a2})
65 }
66
67 func concatstring4(buf *tmpBuf, a0, a1, a2, a3 string) string {
68 return concatstrings(buf, []string{a0, a1, a2, a3})
69 }
70
71 func concatstring5(buf *tmpBuf, a0, a1, a2, a3, a4 string) string {
72 return concatstrings(buf, []string{a0, a1, a2, a3, a4})
73 }
74
75
76
77
78
79
80
81 func slicebytetostring(buf *tmpBuf, ptr *byte, n int) string {
82 if n == 0 {
83
84
85
86 return ""
87 }
88 if raceenabled {
89 racereadrangepc(unsafe.Pointer(ptr),
90 uintptr(n),
91 getcallerpc(),
92 abi.FuncPCABIInternal(slicebytetostring))
93 }
94 if msanenabled {
95 msanread(unsafe.Pointer(ptr), uintptr(n))
96 }
97 if asanenabled {
98 asanread(unsafe.Pointer(ptr), uintptr(n))
99 }
100 if n == 1 {
101 p := unsafe.Pointer(&staticuint64s[*ptr])
102 if goarch.BigEndian {
103 p = add(p, 7)
104 }
105 return unsafe.String((*byte)(p), 1)
106 }
107
108 var p unsafe.Pointer
109 if buf != nil && n <= len(buf) {
110 p = unsafe.Pointer(buf)
111 } else {
112 p = mallocgc(uintptr(n), nil, false)
113 }
114 memmove(p, unsafe.Pointer(ptr), uintptr(n))
115 return unsafe.String((*byte)(p), n)
116 }
117
118
119
120 func stringDataOnStack(s string) bool {
121 ptr := uintptr(unsafe.Pointer(unsafe.StringData(s)))
122 stk := getg().stack
123 return stk.lo <= ptr && ptr < stk.hi
124 }
125
126 func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
127 if buf != nil && l <= len(buf) {
128 b = buf[:l]
129 s = slicebytetostringtmp(&b[0], len(b))
130 } else {
131 s, b = rawstring(l)
132 }
133 return
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 func slicebytetostringtmp(ptr *byte, n int) string {
151 if raceenabled && n > 0 {
152 racereadrangepc(unsafe.Pointer(ptr),
153 uintptr(n),
154 getcallerpc(),
155 abi.FuncPCABIInternal(slicebytetostringtmp))
156 }
157 if msanenabled && n > 0 {
158 msanread(unsafe.Pointer(ptr), uintptr(n))
159 }
160 if asanenabled && n > 0 {
161 asanread(unsafe.Pointer(ptr), uintptr(n))
162 }
163 return unsafe.String(ptr, n)
164 }
165
166 func stringtoslicebyte(buf *tmpBuf, s string) []byte {
167 var b []byte
168 if buf != nil && len(s) <= len(buf) {
169 *buf = tmpBuf{}
170 b = buf[:len(s)]
171 } else {
172 b = rawbyteslice(len(s))
173 }
174 copy(b, s)
175 return b
176 }
177
178 func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
179
180
181 n := 0
182 for range s {
183 n++
184 }
185
186 var a []rune
187 if buf != nil && n <= len(buf) {
188 *buf = [tmpStringBufSize]rune{}
189 a = buf[:n]
190 } else {
191 a = rawruneslice(n)
192 }
193
194 n = 0
195 for _, r := range s {
196 a[n] = r
197 n++
198 }
199 return a
200 }
201
202 func slicerunetostring(buf *tmpBuf, a []rune) string {
203 if raceenabled && len(a) > 0 {
204 racereadrangepc(unsafe.Pointer(&a[0]),
205 uintptr(len(a))*unsafe.Sizeof(a[0]),
206 getcallerpc(),
207 abi.FuncPCABIInternal(slicerunetostring))
208 }
209 if msanenabled && len(a) > 0 {
210 msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
211 }
212 if asanenabled && len(a) > 0 {
213 asanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
214 }
215 var dum [4]byte
216 size1 := 0
217 for _, r := range a {
218 size1 += encoderune(dum[:], r)
219 }
220 s, b := rawstringtmp(buf, size1+3)
221 size2 := 0
222 for _, r := range a {
223
224 if size2 >= size1 {
225 break
226 }
227 size2 += encoderune(b[size2:], r)
228 }
229 return s[:size2]
230 }
231
232 type stringStruct struct {
233 str unsafe.Pointer
234 len int
235 }
236
237
238 type stringStructDWARF struct {
239 str *byte
240 len int
241 }
242
243 func stringStructOf(sp *string) *stringStruct {
244 return (*stringStruct)(unsafe.Pointer(sp))
245 }
246
247 func intstring(buf *[4]byte, v int64) (s string) {
248 var b []byte
249 if buf != nil {
250 b = buf[:]
251 s = slicebytetostringtmp(&b[0], len(b))
252 } else {
253 s, b = rawstring(4)
254 }
255 if int64(rune(v)) != v {
256 v = runeError
257 }
258 n := encoderune(b, rune(v))
259 return s[:n]
260 }
261
262
263
264
265
266 func rawstring(size int) (s string, b []byte) {
267 p := mallocgc(uintptr(size), nil, false)
268 return unsafe.String((*byte)(p), size), unsafe.Slice((*byte)(p), size)
269 }
270
271
272 func rawbyteslice(size int) (b []byte) {
273 cap := roundupsize(uintptr(size), true)
274 p := mallocgc(cap, nil, false)
275 if cap != uintptr(size) {
276 memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))
277 }
278
279 *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
280 return
281 }
282
283
284 func rawruneslice(size int) (b []rune) {
285 if uintptr(size) > maxAlloc/4 {
286 throw("out of memory")
287 }
288 mem := roundupsize(uintptr(size)*4, true)
289 p := mallocgc(mem, nil, false)
290 if mem != uintptr(size)*4 {
291 memclrNoHeapPointers(add(p, uintptr(size)*4), mem-uintptr(size)*4)
292 }
293
294 *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
295 return
296 }
297
298
299 func gobytes(p *byte, n int) (b []byte) {
300 if n == 0 {
301 return make([]byte, 0)
302 }
303
304 if n < 0 || uintptr(n) > maxAlloc {
305 panic(errorString("gobytes: length out of range"))
306 }
307
308 bp := mallocgc(uintptr(n), nil, false)
309 memmove(bp, unsafe.Pointer(p), uintptr(n))
310
311 *(*slice)(unsafe.Pointer(&b)) = slice{bp, n, n}
312 return
313 }
314
315
316
317
318 func gostring(p *byte) string {
319 l := findnull(p)
320 if l == 0 {
321 return ""
322 }
323 s, b := rawstring(l)
324 memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
325 return s
326 }
327
328
329
330
331 func internal_syscall_gostring(p *byte) string {
332 return gostring(p)
333 }
334
335 func gostringn(p *byte, l int) string {
336 if l == 0 {
337 return ""
338 }
339 s, b := rawstring(l)
340 memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
341 return s
342 }
343
344 func hasPrefix(s, prefix string) bool {
345 return len(s) >= len(prefix) && s[:len(prefix)] == prefix
346 }
347
348 func hasSuffix(s, suffix string) bool {
349 return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
350 }
351
352 const (
353 maxUint64 = ^uint64(0)
354 maxInt64 = int64(maxUint64 >> 1)
355 )
356
357
358
359
360 func atoi64(s string) (int64, bool) {
361 if s == "" {
362 return 0, false
363 }
364
365 neg := false
366 if s[0] == '-' {
367 neg = true
368 s = s[1:]
369 }
370
371 un := uint64(0)
372 for i := 0; i < len(s); i++ {
373 c := s[i]
374 if c < '0' || c > '9' {
375 return 0, false
376 }
377 if un > maxUint64/10 {
378
379 return 0, false
380 }
381 un *= 10
382 un1 := un + uint64(c) - '0'
383 if un1 < un {
384
385 return 0, false
386 }
387 un = un1
388 }
389
390 if !neg && un > uint64(maxInt64) {
391 return 0, false
392 }
393 if neg && un > uint64(maxInt64)+1 {
394 return 0, false
395 }
396
397 n := int64(un)
398 if neg {
399 n = -n
400 }
401
402 return n, true
403 }
404
405
406
407 func atoi(s string) (int, bool) {
408 if n, ok := atoi64(s); n == int64(int(n)) {
409 return int(n), ok
410 }
411 return 0, false
412 }
413
414
415
416 func atoi32(s string) (int32, bool) {
417 if n, ok := atoi64(s); n == int64(int32(n)) {
418 return int32(n), ok
419 }
420 return 0, false
421 }
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436 func parseByteCount(s string) (int64, bool) {
437
438 if s == "" {
439 return 0, false
440 }
441
442 last := s[len(s)-1]
443 if last >= '0' && last <= '9' {
444 n, ok := atoi64(s)
445 if !ok || n < 0 {
446 return 0, false
447 }
448 return n, ok
449 }
450
451
452
453 if last != 'B' || len(s) < 2 {
454 return 0, false
455 }
456
457 if c := s[len(s)-2]; c >= '0' && c <= '9' {
458
459 n, ok := atoi64(s[:len(s)-1])
460 if !ok || n < 0 {
461 return 0, false
462 }
463 return n, ok
464 } else if c != 'i' {
465 return 0, false
466 }
467
468
469 if len(s) < 4 {
470 return 0, false
471 }
472 power := 0
473 switch s[len(s)-3] {
474 case 'K':
475 power = 1
476 case 'M':
477 power = 2
478 case 'G':
479 power = 3
480 case 'T':
481 power = 4
482 default:
483
484 return 0, false
485 }
486 m := uint64(1)
487 for i := 0; i < power; i++ {
488 m *= 1024
489 }
490 n, ok := atoi64(s[:len(s)-3])
491 if !ok || n < 0 {
492 return 0, false
493 }
494 un := uint64(n)
495 if un > maxUint64/m {
496
497 return 0, false
498 }
499 un *= m
500 if un > uint64(maxInt64) {
501
502 return 0, false
503 }
504 return int64(un), true
505 }
506
507
508 func findnull(s *byte) int {
509 if s == nil {
510 return 0
511 }
512
513
514
515
516 if GOOS == "plan9" {
517 p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
518 l := 0
519 for p[l] != 0 {
520 l++
521 }
522 return l
523 }
524
525
526
527
528
529 const pageSize = 4096
530
531 offset := 0
532 ptr := unsafe.Pointer(s)
533
534
535
536 safeLen := int(pageSize - uintptr(ptr)%pageSize)
537
538 for {
539 t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
540
541 if i := bytealg.IndexByteString(t, 0); i != -1 {
542 return offset + i
543 }
544
545 ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
546 offset += safeLen
547 safeLen = pageSize
548 }
549 }
550
551 func findnullw(s *uint16) int {
552 if s == nil {
553 return 0
554 }
555 p := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(s))
556 l := 0
557 for p[l] != 0 {
558 l++
559 }
560 return l
561 }
562
563
564 func gostringnocopy(str *byte) string {
565 ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
566 s := *(*string)(unsafe.Pointer(&ss))
567 return s
568 }
569
570 func gostringw(strw *uint16) string {
571 var buf [8]byte
572 str := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(strw))
573 n1 := 0
574 for i := 0; str[i] != 0; i++ {
575 n1 += encoderune(buf[:], rune(str[i]))
576 }
577 s, b := rawstring(n1 + 4)
578 n2 := 0
579 for i := 0; str[i] != 0; i++ {
580
581 if n2 >= n1 {
582 break
583 }
584 n2 += encoderune(b[n2:], rune(str[i]))
585 }
586 b[n2] = 0
587 return s[:n2]
588 }
589
View as plain text