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