...
Run Format

Source file src/runtime/string.go

     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) 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 && l > 0 {
    81			racereadrangepc(unsafe.Pointer(&b[0]),
    82				uintptr(l),
    83				getcallerpc(unsafe.Pointer(&buf)),
    84				funcPC(slicebytetostring))
    85		}
    86		if msanenabled && l > 0 {
    87			msanread(unsafe.Pointer(&b[0]), uintptr(l))
    88		}
    89		s, c := rawstringtmp(buf, l)
    90		copy(c, b)
    91		return s
    92	}
    93	
    94	// stringDataOnStack reports whether the string's data is
    95	// stored on the current goroutine's stack.
    96	func stringDataOnStack(s string) bool {
    97		ptr := uintptr(stringStructOf(&s).str)
    98		stk := getg().stack
    99		return stk.lo <= ptr && ptr < stk.hi
   100	}
   101	
   102	func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
   103		if buf != nil && l <= len(buf) {
   104			b = buf[:l]
   105			s = slicebytetostringtmp(b)
   106		} else {
   107			s, b = rawstring(l)
   108		}
   109		return
   110	}
   111	
   112	// slicebytetostringtmp returns a "string" referring to the actual []byte bytes.
   113	//
   114	// Callers need to ensure that the returned string will not be used after
   115	// the calling goroutine modifies the original slice or synchronizes with
   116	// another goroutine.
   117	//
   118	// The function is only called when instrumenting
   119	// and otherwise intrinsified by the compiler.
   120	//
   121	// Some internal compiler optimizations use this function.
   122	// - Used for m[string(k)] lookup where m is a string-keyed map and k is a []byte.
   123	// - Used for "<"+string(b)+">" concatenation where b is []byte.
   124	// - Used for string(b)=="foo" comparison where b is []byte.
   125	func slicebytetostringtmp(b []byte) string {
   126		if raceenabled && len(b) > 0 {
   127			racereadrangepc(unsafe.Pointer(&b[0]),
   128				uintptr(len(b)),
   129				getcallerpc(unsafe.Pointer(&b)),
   130				funcPC(slicebytetostringtmp))
   131		}
   132		if msanenabled && len(b) > 0 {
   133			msanread(unsafe.Pointer(&b[0]), uintptr(len(b)))
   134		}
   135		return *(*string)(unsafe.Pointer(&b))
   136	}
   137	
   138	func stringtoslicebyte(buf *tmpBuf, s string) []byte {
   139		var b []byte
   140		if buf != nil && len(s) <= len(buf) {
   141			*buf = tmpBuf{}
   142			b = buf[:len(s)]
   143		} else {
   144			b = rawbyteslice(len(s))
   145		}
   146		copy(b, s)
   147		return b
   148	}
   149	
   150	func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
   151		// two passes.
   152		// unlike slicerunetostring, no race because strings are immutable.
   153		n := 0
   154		for range s {
   155			n++
   156		}
   157	
   158		var a []rune
   159		if buf != nil && n <= len(buf) {
   160			*buf = [tmpStringBufSize]rune{}
   161			a = buf[:n]
   162		} else {
   163			a = rawruneslice(n)
   164		}
   165	
   166		n = 0
   167		for _, r := range s {
   168			a[n] = r
   169			n++
   170		}
   171		return a
   172	}
   173	
   174	func slicerunetostring(buf *tmpBuf, a []rune) string {
   175		if raceenabled && len(a) > 0 {
   176			racereadrangepc(unsafe.Pointer(&a[0]),
   177				uintptr(len(a))*unsafe.Sizeof(a[0]),
   178				getcallerpc(unsafe.Pointer(&buf)),
   179				funcPC(slicerunetostring))
   180		}
   181		if msanenabled && len(a) > 0 {
   182			msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
   183		}
   184		var dum [4]byte
   185		size1 := 0
   186		for _, r := range a {
   187			size1 += encoderune(dum[:], r)
   188		}
   189		s, b := rawstringtmp(buf, size1+3)
   190		size2 := 0
   191		for _, r := range a {
   192			// check for race
   193			if size2 >= size1 {
   194				break
   195			}
   196			size2 += encoderune(b[size2:], r)
   197		}
   198		return s[:size2]
   199	}
   200	
   201	type stringStruct struct {
   202		str unsafe.Pointer
   203		len int
   204	}
   205	
   206	// Variant with *byte pointer type for DWARF debugging.
   207	type stringStructDWARF struct {
   208		str *byte
   209		len int
   210	}
   211	
   212	func stringStructOf(sp *string) *stringStruct {
   213		return (*stringStruct)(unsafe.Pointer(sp))
   214	}
   215	
   216	func intstring(buf *[4]byte, v int64) string {
   217		var s string
   218		var b []byte
   219		if buf != nil {
   220			b = buf[:]
   221			s = slicebytetostringtmp(b)
   222		} else {
   223			s, b = rawstring(4)
   224		}
   225		if int64(rune(v)) != v {
   226			v = runeError
   227		}
   228		n := encoderune(b, rune(v))
   229		return s[:n]
   230	}
   231	
   232	// rawstring allocates storage for a new string. The returned
   233	// string and byte slice both refer to the same storage.
   234	// The storage is not zeroed. Callers should use
   235	// b to set the string contents and then drop b.
   236	func rawstring(size int) (s string, b []byte) {
   237		p := mallocgc(uintptr(size), nil, false)
   238	
   239		stringStructOf(&s).str = p
   240		stringStructOf(&s).len = size
   241	
   242		*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
   243	
   244		return
   245	}
   246	
   247	// rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
   248	func rawbyteslice(size int) (b []byte) {
   249		cap := roundupsize(uintptr(size))
   250		p := mallocgc(cap, nil, false)
   251		if cap != uintptr(size) {
   252			memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))
   253		}
   254	
   255		*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
   256		return
   257	}
   258	
   259	// rawruneslice allocates a new rune slice. The rune slice is not zeroed.
   260	func rawruneslice(size int) (b []rune) {
   261		if uintptr(size) > _MaxMem/4 {
   262			throw("out of memory")
   263		}
   264		mem := roundupsize(uintptr(size) * 4)
   265		p := mallocgc(mem, nil, false)
   266		if mem != uintptr(size)*4 {
   267			memclrNoHeapPointers(add(p, uintptr(size)*4), mem-uintptr(size)*4)
   268		}
   269	
   270		*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
   271		return
   272	}
   273	
   274	// used by cmd/cgo
   275	func gobytes(p *byte, n int) []byte {
   276		if n == 0 {
   277			return make([]byte, 0)
   278		}
   279		x := make([]byte, n)
   280		memmove(unsafe.Pointer(&x[0]), unsafe.Pointer(p), uintptr(n))
   281		return x
   282	}
   283	
   284	func gostring(p *byte) string {
   285		l := findnull(p)
   286		if l == 0 {
   287			return ""
   288		}
   289		s, b := rawstring(l)
   290		memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
   291		return s
   292	}
   293	
   294	func gostringn(p *byte, l int) string {
   295		if l == 0 {
   296			return ""
   297		}
   298		s, b := rawstring(l)
   299		memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
   300		return s
   301	}
   302	
   303	func index(s, t string) int {
   304		if len(t) == 0 {
   305			return 0
   306		}
   307		for i := 0; i < len(s); i++ {
   308			if s[i] == t[0] && hasprefix(s[i:], t) {
   309				return i
   310			}
   311		}
   312		return -1
   313	}
   314	
   315	func contains(s, t string) bool {
   316		return index(s, t) >= 0
   317	}
   318	
   319	func hasprefix(s, t string) bool {
   320		return len(s) >= len(t) && s[:len(t)] == t
   321	}
   322	
   323	const (
   324		maxUint = ^uint(0)
   325		maxInt  = int(maxUint >> 1)
   326	)
   327	
   328	// atoi parses an int from a string s.
   329	// The bool result reports whether s is a number
   330	// representable by a value of type int.
   331	func atoi(s string) (int, bool) {
   332		if s == "" {
   333			return 0, false
   334		}
   335	
   336		neg := false
   337		if s[0] == '-' {
   338			neg = true
   339			s = s[1:]
   340		}
   341	
   342		un := uint(0)
   343		for i := 0; i < len(s); i++ {
   344			c := s[i]
   345			if c < '0' || c > '9' {
   346				return 0, false
   347			}
   348			if un > maxUint/10 {
   349				// overflow
   350				return 0, false
   351			}
   352			un *= 10
   353			un1 := un + uint(c) - '0'
   354			if un1 < un {
   355				// overflow
   356				return 0, false
   357			}
   358			un = un1
   359		}
   360	
   361		if !neg && un > uint(maxInt) {
   362			return 0, false
   363		}
   364		if neg && un > uint(maxInt)+1 {
   365			return 0, false
   366		}
   367	
   368		n := int(un)
   369		if neg {
   370			n = -n
   371		}
   372	
   373		return n, true
   374	}
   375	
   376	// atoi32 is like atoi but for integers
   377	// that fit into an int32.
   378	func atoi32(s string) (int32, bool) {
   379		if n, ok := atoi(s); n == int(int32(n)) {
   380			return int32(n), ok
   381		}
   382		return 0, false
   383	}
   384	
   385	//go:nosplit
   386	func findnull(s *byte) int {
   387		if s == nil {
   388			return 0
   389		}
   390		p := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s))
   391		l := 0
   392		for p[l] != 0 {
   393			l++
   394		}
   395		return l
   396	}
   397	
   398	func findnullw(s *uint16) int {
   399		if s == nil {
   400			return 0
   401		}
   402		p := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(s))
   403		l := 0
   404		for p[l] != 0 {
   405			l++
   406		}
   407		return l
   408	}
   409	
   410	//go:nosplit
   411	func gostringnocopy(str *byte) string {
   412		ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
   413		s := *(*string)(unsafe.Pointer(&ss))
   414		return s
   415	}
   416	
   417	func gostringw(strw *uint16) string {
   418		var buf [8]byte
   419		str := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(strw))
   420		n1 := 0
   421		for i := 0; str[i] != 0; i++ {
   422			n1 += encoderune(buf[:], rune(str[i]))
   423		}
   424		s, b := rawstring(n1 + 4)
   425		n2 := 0
   426		for i := 0; str[i] != 0; i++ {
   427			// check for race
   428			if n2 >= n1 {
   429				break
   430			}
   431			n2 += encoderune(b[n2:], rune(str[i]))
   432		}
   433		b[n2] = 0 // for luck
   434		return s[:n2]
   435	}
   436	

View as plain text