github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/runtime/string.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime
     6  
     7  import (
     8  	"runtime/internal/atomic"
     9  	"unsafe"
    10  )
    11  
    12  // The constant is known to the compiler.
    13  // There is no fundamental theory behind this number.
    14  const tmpStringBufSize = 32
    15  
    16  type tmpBuf [tmpStringBufSize]byte
    17  
    18  // concatstrings implements a Go string concatenation x+y+z+...
    19  // The operands are passed in the slice a.
    20  // If buf != nil, the compiler has determined that the result does not
    21  // escape the calling function, so the string data can be stored in buf
    22  // if small enough.
    23  func concatstrings(buf *tmpBuf, a []string) string {
    24  	idx := 0
    25  	l := 0
    26  	count := 0
    27  	for i, x := range a {
    28  		n := len(x)
    29  		if n == 0 {
    30  			continue
    31  		}
    32  		if l+n < l {
    33  			throw("string concatenation too long")
    34  		}
    35  		l += n
    36  		count++
    37  		idx = i
    38  	}
    39  	if count == 0 {
    40  		return ""
    41  	}
    42  
    43  	// If there is just one string and either it is not on the stack
    44  	// or our result does not escape the calling frame (buf != nil),
    45  	// then we can return that string directly.
    46  	if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
    47  		return a[idx]
    48  	}
    49  	s, b := rawstringtmp(buf, l)
    50  	l = 0
    51  	for _, x := range a {
    52  		copy(b[l:], x)
    53  		l += len(x)
    54  	}
    55  	return s
    56  }
    57  
    58  func concatstring2(buf *tmpBuf, a [2]string) string {
    59  	return concatstrings(buf, a[:])
    60  }
    61  
    62  func concatstring3(buf *tmpBuf, a [3]string) string {
    63  	return concatstrings(buf, a[:])
    64  }
    65  
    66  func concatstring4(buf *tmpBuf, a [4]string) string {
    67  	return concatstrings(buf, a[:])
    68  }
    69  
    70  func concatstring5(buf *tmpBuf, a [5]string) string {
    71  	return concatstrings(buf, a[:])
    72  }
    73  
    74  // Buf is a fixed-size buffer for the result,
    75  // it is not nil if the result does not escape.
    76  func slicebytetostring(buf *tmpBuf, b []byte) string {
    77  	l := len(b)
    78  	if l == 0 {
    79  		// Turns out to be a relatively common case.
    80  		// Consider that you want to parse out data between parens in "foo()bar",
    81  		// you find the indices and convert the subslice to string.
    82  		return ""
    83  	}
    84  	if raceenabled && l > 0 {
    85  		racereadrangepc(unsafe.Pointer(&b[0]),
    86  			uintptr(l),
    87  			getcallerpc(unsafe.Pointer(&buf)),
    88  			funcPC(slicebytetostring))
    89  	}
    90  	if msanenabled && l > 0 {
    91  		msanread(unsafe.Pointer(&b[0]), uintptr(l))
    92  	}
    93  	s, c := rawstringtmp(buf, l)
    94  	copy(c, b)
    95  	return s
    96  }
    97  
    98  // stringDataOnStack reports whether the string's data is
    99  // stored on the current goroutine's stack.
   100  func stringDataOnStack(s string) bool {
   101  	ptr := uintptr(stringStructOf(&s).str)
   102  	stk := getg().stack
   103  	return stk.lo <= ptr && ptr < stk.hi
   104  }
   105  
   106  func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
   107  	if buf != nil && l <= len(buf) {
   108  		b = buf[:l]
   109  		s = slicebytetostringtmp(b)
   110  	} else {
   111  		s, b = rawstring(l)
   112  	}
   113  	return
   114  }
   115  
   116  func slicebytetostringtmp(b []byte) string {
   117  	// Return a "string" referring to the actual []byte bytes.
   118  	// This is only for use by internal compiler optimizations
   119  	// that know that the string form will be discarded before
   120  	// the calling goroutine could possibly modify the original
   121  	// slice or synchronize with another goroutine.
   122  	// First such case is a m[string(k)] lookup where
   123  	// m is a string-keyed map and k is a []byte.
   124  	// Second such case is "<"+string(b)+">" concatenation where b is []byte.
   125  	// Third such case is string(b)=="foo" comparison where b is []byte.
   126  
   127  	if raceenabled && len(b) > 0 {
   128  		racereadrangepc(unsafe.Pointer(&b[0]),
   129  			uintptr(len(b)),
   130  			getcallerpc(unsafe.Pointer(&b)),
   131  			funcPC(slicebytetostringtmp))
   132  	}
   133  	if msanenabled && len(b) > 0 {
   134  		msanread(unsafe.Pointer(&b[0]), uintptr(len(b)))
   135  	}
   136  	return *(*string)(unsafe.Pointer(&b))
   137  }
   138  
   139  func stringtoslicebyte(buf *tmpBuf, s string) []byte {
   140  	var b []byte
   141  	if buf != nil && len(s) <= len(buf) {
   142  		*buf = tmpBuf{}
   143  		b = buf[:len(s)]
   144  	} else {
   145  		b = rawbyteslice(len(s))
   146  	}
   147  	copy(b, s)
   148  	return b
   149  }
   150  
   151  func stringtoslicebytetmp(s string) []byte {
   152  	// Return a slice referring to the actual string bytes.
   153  	// This is only for use by internal compiler optimizations
   154  	// that know that the slice won't be mutated.
   155  	// The only such case today is:
   156  	// for i, c := range []byte(str)
   157  
   158  	str := stringStructOf(&s)
   159  	ret := slice{array: str.str, len: str.len, cap: str.len}
   160  	return *(*[]byte)(unsafe.Pointer(&ret))
   161  }
   162  
   163  func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
   164  	// two passes.
   165  	// unlike slicerunetostring, no race because strings are immutable.
   166  	n := 0
   167  	t := s
   168  	for len(s) > 0 {
   169  		_, k := charntorune(s)
   170  		s = s[k:]
   171  		n++
   172  	}
   173  	var a []rune
   174  	if buf != nil && n <= len(buf) {
   175  		*buf = [tmpStringBufSize]rune{}
   176  		a = buf[:n]
   177  	} else {
   178  		a = rawruneslice(n)
   179  	}
   180  	n = 0
   181  	for len(t) > 0 {
   182  		r, k := charntorune(t)
   183  		t = t[k:]
   184  		a[n] = r
   185  		n++
   186  	}
   187  	return a
   188  }
   189  
   190  func slicerunetostring(buf *tmpBuf, a []rune) string {
   191  	if raceenabled && len(a) > 0 {
   192  		racereadrangepc(unsafe.Pointer(&a[0]),
   193  			uintptr(len(a))*unsafe.Sizeof(a[0]),
   194  			getcallerpc(unsafe.Pointer(&buf)),
   195  			funcPC(slicerunetostring))
   196  	}
   197  	if msanenabled && len(a) > 0 {
   198  		msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
   199  	}
   200  	var dum [4]byte
   201  	size1 := 0
   202  	for _, r := range a {
   203  		size1 += runetochar(dum[:], r)
   204  	}
   205  	s, b := rawstringtmp(buf, size1+3)
   206  	size2 := 0
   207  	for _, r := range a {
   208  		// check for race
   209  		if size2 >= size1 {
   210  			break
   211  		}
   212  		size2 += runetochar(b[size2:], r)
   213  	}
   214  	return s[:size2]
   215  }
   216  
   217  type stringStruct struct {
   218  	str unsafe.Pointer
   219  	len int
   220  }
   221  
   222  // Variant with *byte pointer type for DWARF debugging.
   223  type stringStructDWARF struct {
   224  	str *byte
   225  	len int
   226  }
   227  
   228  func stringStructOf(sp *string) *stringStruct {
   229  	return (*stringStruct)(unsafe.Pointer(sp))
   230  }
   231  
   232  func intstring(buf *[4]byte, v int64) string {
   233  	var s string
   234  	var b []byte
   235  	if buf != nil {
   236  		b = buf[:]
   237  		s = slicebytetostringtmp(b)
   238  	} else {
   239  		s, b = rawstring(4)
   240  	}
   241  	if int64(rune(v)) != v {
   242  		v = runeerror
   243  	}
   244  	n := runetochar(b, rune(v))
   245  	return s[:n]
   246  }
   247  
   248  // stringiter returns the index of the next
   249  // rune after the rune that starts at s[k].
   250  func stringiter(s string, k int) int {
   251  	if k >= len(s) {
   252  		// 0 is end of iteration
   253  		return 0
   254  	}
   255  
   256  	c := s[k]
   257  	if c < runeself {
   258  		return k + 1
   259  	}
   260  
   261  	// multi-char rune
   262  	_, n := charntorune(s[k:])
   263  	return k + n
   264  }
   265  
   266  // stringiter2 returns the rune that starts at s[k]
   267  // and the index where the next rune starts.
   268  func stringiter2(s string, k int) (int, rune) {
   269  	if k >= len(s) {
   270  		// 0 is end of iteration
   271  		return 0, 0
   272  	}
   273  
   274  	c := s[k]
   275  	if c < runeself {
   276  		return k + 1, rune(c)
   277  	}
   278  
   279  	// multi-char rune
   280  	r, n := charntorune(s[k:])
   281  	return k + n, r
   282  }
   283  
   284  // rawstring allocates storage for a new string. The returned
   285  // string and byte slice both refer to the same storage.
   286  // The storage is not zeroed. Callers should use
   287  // b to set the string contents and then drop b.
   288  func rawstring(size int) (s string, b []byte) {
   289  	p := mallocgc(uintptr(size), nil, false)
   290  
   291  	stringStructOf(&s).str = p
   292  	stringStructOf(&s).len = size
   293  
   294  	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
   295  
   296  	for {
   297  		ms := maxstring
   298  		if uintptr(size) <= ms || atomic.Casuintptr((*uintptr)(unsafe.Pointer(&maxstring)), ms, uintptr(size)) {
   299  			return
   300  		}
   301  	}
   302  }
   303  
   304  // rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
   305  func rawbyteslice(size int) (b []byte) {
   306  	cap := roundupsize(uintptr(size))
   307  	p := mallocgc(cap, nil, false)
   308  	if cap != uintptr(size) {
   309  		memclr(add(p, uintptr(size)), cap-uintptr(size))
   310  	}
   311  
   312  	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
   313  	return
   314  }
   315  
   316  // rawruneslice allocates a new rune slice. The rune slice is not zeroed.
   317  func rawruneslice(size int) (b []rune) {
   318  	if uintptr(size) > _MaxMem/4 {
   319  		throw("out of memory")
   320  	}
   321  	mem := roundupsize(uintptr(size) * 4)
   322  	p := mallocgc(mem, nil, false)
   323  	if mem != uintptr(size)*4 {
   324  		memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
   325  	}
   326  
   327  	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
   328  	return
   329  }
   330  
   331  // used by cmd/cgo
   332  func gobytes(p *byte, n int) []byte {
   333  	if n == 0 {
   334  		return make([]byte, 0)
   335  	}
   336  	x := make([]byte, n)
   337  	memmove(unsafe.Pointer(&x[0]), unsafe.Pointer(p), uintptr(n))
   338  	return x
   339  }
   340  
   341  func gostring(p *byte) string {
   342  	l := findnull(p)
   343  	if l == 0 {
   344  		return ""
   345  	}
   346  	s, b := rawstring(l)
   347  	memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
   348  	return s
   349  }
   350  
   351  func gostringn(p *byte, l int) string {
   352  	if l == 0 {
   353  		return ""
   354  	}
   355  	s, b := rawstring(l)
   356  	memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
   357  	return s
   358  }
   359  
   360  func index(s, t string) int {
   361  	if len(t) == 0 {
   362  		return 0
   363  	}
   364  	for i := 0; i < len(s); i++ {
   365  		if s[i] == t[0] && hasprefix(s[i:], t) {
   366  			return i
   367  		}
   368  	}
   369  	return -1
   370  }
   371  
   372  func contains(s, t string) bool {
   373  	return index(s, t) >= 0
   374  }
   375  
   376  func hasprefix(s, t string) bool {
   377  	return len(s) >= len(t) && s[:len(t)] == t
   378  }
   379  
   380  func atoi(s string) int {
   381  	n := 0
   382  	for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
   383  		n = n*10 + int(s[0]) - '0'
   384  		s = s[1:]
   385  	}
   386  	return n
   387  }
   388  
   389  //go:nosplit
   390  func findnull(s *byte) int {
   391  	if s == nil {
   392  		return 0
   393  	}
   394  	p := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s))
   395  	l := 0
   396  	for p[l] != 0 {
   397  		l++
   398  	}
   399  	return l
   400  }
   401  
   402  func findnullw(s *uint16) int {
   403  	if s == nil {
   404  		return 0
   405  	}
   406  	p := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(s))
   407  	l := 0
   408  	for p[l] != 0 {
   409  		l++
   410  	}
   411  	return l
   412  }
   413  
   414  var maxstring uintptr = 256 // a hint for print
   415  
   416  //go:nosplit
   417  func gostringnocopy(str *byte) string {
   418  	ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
   419  	s := *(*string)(unsafe.Pointer(&ss))
   420  	for {
   421  		ms := maxstring
   422  		if uintptr(len(s)) <= ms || atomic.Casuintptr(&maxstring, ms, uintptr(len(s))) {
   423  			break
   424  		}
   425  	}
   426  	return s
   427  }
   428  
   429  func gostringw(strw *uint16) string {
   430  	var buf [8]byte
   431  	str := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(strw))
   432  	n1 := 0
   433  	for i := 0; str[i] != 0; i++ {
   434  		n1 += runetochar(buf[:], rune(str[i]))
   435  	}
   436  	s, b := rawstring(n1 + 4)
   437  	n2 := 0
   438  	for i := 0; str[i] != 0; i++ {
   439  		// check for race
   440  		if n2 >= n1 {
   441  			break
   442  		}
   443  		n2 += runetochar(b[n2:], rune(str[i]))
   444  	}
   445  	b[n2] = 0 // for luck
   446  	return s[:n2]
   447  }