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 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 const (
345 maxUint64 = ^uint64(0)
346 maxInt64 = int64(maxUint64 >> 1)
347 )
348
349
350
351
352 func atoi64(s string) (int64, bool) {
353 if s == "" {
354 return 0, false
355 }
356
357 neg := false
358 if s[0] == '-' {
359 neg = true
360 s = s[1:]
361 }
362
363 un := uint64(0)
364 for i := 0; i < len(s); i++ {
365 c := s[i]
366 if c < '0' || c > '9' {
367 return 0, false
368 }
369 if un > maxUint64/10 {
370
371 return 0, false
372 }
373 un *= 10
374 un1 := un + uint64(c) - '0'
375 if un1 < un {
376
377 return 0, false
378 }
379 un = un1
380 }
381
382 if !neg && un > uint64(maxInt64) {
383 return 0, false
384 }
385 if neg && un > uint64(maxInt64)+1 {
386 return 0, false
387 }
388
389 n := int64(un)
390 if neg {
391 n = -n
392 }
393
394 return n, true
395 }
396
397
398
399 func atoi(s string) (int, bool) {
400 if n, ok := atoi64(s); n == int64(int(n)) {
401 return int(n), ok
402 }
403 return 0, false
404 }
405
406
407
408 func atoi32(s string) (int32, bool) {
409 if n, ok := atoi64(s); n == int64(int32(n)) {
410 return int32(n), ok
411 }
412 return 0, false
413 }
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428 func parseByteCount(s string) (int64, bool) {
429
430 if s == "" {
431 return 0, false
432 }
433
434 last := s[len(s)-1]
435 if last >= '0' && last <= '9' {
436 n, ok := atoi64(s)
437 if !ok || n < 0 {
438 return 0, false
439 }
440 return n, ok
441 }
442
443
444
445 if last != 'B' || len(s) < 2 {
446 return 0, false
447 }
448
449 if c := s[len(s)-2]; c >= '0' && c <= '9' {
450
451 n, ok := atoi64(s[:len(s)-1])
452 if !ok || n < 0 {
453 return 0, false
454 }
455 return n, ok
456 } else if c != 'i' {
457 return 0, false
458 }
459
460
461 if len(s) < 4 {
462 return 0, false
463 }
464 power := 0
465 switch s[len(s)-3] {
466 case 'K':
467 power = 1
468 case 'M':
469 power = 2
470 case 'G':
471 power = 3
472 case 'T':
473 power = 4
474 default:
475
476 return 0, false
477 }
478 m := uint64(1)
479 for i := 0; i < power; i++ {
480 m *= 1024
481 }
482 n, ok := atoi64(s[:len(s)-3])
483 if !ok || n < 0 {
484 return 0, false
485 }
486 un := uint64(n)
487 if un > maxUint64/m {
488
489 return 0, false
490 }
491 un *= m
492 if un > uint64(maxInt64) {
493
494 return 0, false
495 }
496 return int64(un), true
497 }
498
499
500 func findnull(s *byte) int {
501 if s == nil {
502 return 0
503 }
504
505
506
507
508 if GOOS == "plan9" {
509 p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
510 l := 0
511 for p[l] != 0 {
512 l++
513 }
514 return l
515 }
516
517
518
519
520
521 const pageSize = 4096
522
523 offset := 0
524 ptr := unsafe.Pointer(s)
525
526
527
528 safeLen := int(pageSize - uintptr(ptr)%pageSize)
529
530 for {
531 t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
532
533 if i := bytealg.IndexByteString(t, 0); i != -1 {
534 return offset + i
535 }
536
537 ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
538 offset += safeLen
539 safeLen = pageSize
540 }
541 }
542
543 func findnullw(s *uint16) int {
544 if s == nil {
545 return 0
546 }
547 p := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(s))
548 l := 0
549 for p[l] != 0 {
550 l++
551 }
552 return l
553 }
554
555
556 func gostringnocopy(str *byte) string {
557 ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
558 s := *(*string)(unsafe.Pointer(&ss))
559 return s
560 }
561
562 func gostringw(strw *uint16) string {
563 var buf [8]byte
564 str := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(strw))
565 n1 := 0
566 for i := 0; str[i] != 0; i++ {
567 n1 += encoderune(buf[:], rune(str[i]))
568 }
569 s, b := rawstring(n1 + 4)
570 n2 := 0
571 for i := 0; str[i] != 0; i++ {
572
573 if n2 >= n1 {
574 break
575 }
576 n2 += encoderune(b[n2:], rune(str[i]))
577 }
578 b[n2] = 0
579 return s[:n2]
580 }
581
View as plain text