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