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) (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 func gostring(p *byte) string {
330 l := findnull(p)
331 if l == 0 {
332 return ""
333 }
334 s, b := rawstring(l)
335 memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
336 return s
337 }
338
339 func gostringn(p *byte, l int) string {
340 if l == 0 {
341 return ""
342 }
343 s, b := rawstring(l)
344 memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
345 return s
346 }
347
348 func hasPrefix(s, prefix string) bool {
349 return len(s) >= len(prefix) && s[:len(prefix)] == prefix
350 }
351
352 const (
353 maxUint = ^uint(0)
354 maxInt = int(maxUint >> 1)
355 )
356
357
358
359
360 func atoi(s string) (int, 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 := uint(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 > maxUint/10 {
378
379 return 0, false
380 }
381 un *= 10
382 un1 := un + uint(c) - '0'
383 if un1 < un {
384
385 return 0, false
386 }
387 un = un1
388 }
389
390 if !neg && un > uint(maxInt) {
391 return 0, false
392 }
393 if neg && un > uint(maxInt)+1 {
394 return 0, false
395 }
396
397 n := int(un)
398 if neg {
399 n = -n
400 }
401
402 return n, true
403 }
404
405
406
407 func atoi32(s string) (int32, bool) {
408 if n, ok := atoi(s); n == int(int32(n)) {
409 return int32(n), ok
410 }
411 return 0, false
412 }
413
414
415 func findnull(s *byte) int {
416 if s == nil {
417 return 0
418 }
419
420
421
422
423 if GOOS == "plan9" {
424 p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
425 l := 0
426 for p[l] != 0 {
427 l++
428 }
429 return l
430 }
431
432
433
434
435
436 const pageSize = 4096
437
438 offset := 0
439 ptr := unsafe.Pointer(s)
440
441
442
443 safeLen := int(pageSize - uintptr(ptr)%pageSize)
444
445 for {
446 t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
447
448 if i := bytealg.IndexByteString(t, 0); i != -1 {
449 return offset + i
450 }
451
452 ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
453 offset += safeLen
454 safeLen = pageSize
455 }
456 }
457
458 func findnullw(s *uint16) int {
459 if s == nil {
460 return 0
461 }
462 p := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(s))
463 l := 0
464 for p[l] != 0 {
465 l++
466 }
467 return l
468 }
469
470
471 func gostringnocopy(str *byte) string {
472 ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
473 s := *(*string)(unsafe.Pointer(&ss))
474 return s
475 }
476
477 func gostringw(strw *uint16) string {
478 var buf [8]byte
479 str := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(strw))
480 n1 := 0
481 for i := 0; str[i] != 0; i++ {
482 n1 += encoderune(buf[:], rune(str[i]))
483 }
484 s, b := rawstring(n1 + 4)
485 n2 := 0
486 for i := 0; str[i] != 0; i++ {
487
488 if n2 >= n1 {
489 break
490 }
491 n2 += encoderune(b[n2:], rune(str[i]))
492 }
493 b[n2] = 0
494 return s[:n2]
495 }
496
View as plain text