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