// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import (
	
	
	
	
)

// The constant is known to the compiler.
// There is no fundamental theory behind this number.
const tmpStringBufSize = 32

type tmpBuf [tmpStringBufSize]byte

// concatstrings implements a Go string concatenation x+y+z+...
// The operands are passed in the slice a.
// If buf != nil, the compiler has determined that the result does not
// escape the calling function, so the string data can be stored in buf
// if small enough.
func concatstrings( *tmpBuf,  []string) string {
	 := 0
	 := 0
	 := 0
	for ,  := range  {
		 := len()
		if  == 0 {
			continue
		}
		if + <  {
			throw("string concatenation too long")
		}
		 += 
		++
		 = 
	}
	if  == 0 {
		return ""
	}

	// If there is just one string and either it is not on the stack
	// or our result does not escape the calling frame (buf != nil),
	// then we can return that string directly.
	if  == 1 && ( != nil || !stringDataOnStack([])) {
		return []
	}
	,  := rawstringtmp(, )
	for ,  := range  {
		copy(, )
		 = [len():]
	}
	return 
}

func concatstring2( *tmpBuf, ,  string) string {
	return concatstrings(, []string{, })
}

func concatstring3( *tmpBuf, , ,  string) string {
	return concatstrings(, []string{, , })
}

func concatstring4( *tmpBuf, , , ,  string) string {
	return concatstrings(, []string{, , , })
}

func concatstring5( *tmpBuf, , , , ,  string) string {
	return concatstrings(, []string{, , , , })
}

// slicebytetostring converts a byte slice to a string.
// It is inserted by the compiler into generated code.
// ptr is a pointer to the first element of the slice;
// n is the length of the slice.
// Buf is a fixed-size buffer for the result,
// it is not nil if the result does not escape.
//
// slicebytetostring should be an internal detail,
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
//   - github.com/cloudwego/frugal
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.
//
//go:linkname slicebytetostring
func slicebytetostring( *tmpBuf,  *byte,  int) string {
	if  == 0 {
		// Turns out to be a relatively common case.
		// Consider that you want to parse out data between parens in "foo()bar",
		// you find the indices and convert the subslice to string.
		return ""
	}
	if raceenabled {
		racereadrangepc(unsafe.Pointer(),
			uintptr(),
			getcallerpc(),
			abi.FuncPCABIInternal())
	}
	if msanenabled {
		msanread(unsafe.Pointer(), uintptr())
	}
	if asanenabled {
		asanread(unsafe.Pointer(), uintptr())
	}
	if  == 1 {
		 := unsafe.Pointer(&staticuint64s[*])
		if goarch.BigEndian {
			 = add(, 7)
		}
		return unsafe.String((*byte)(), 1)
	}

	var  unsafe.Pointer
	if  != nil &&  <= len() {
		 = unsafe.Pointer()
	} else {
		 = mallocgc(uintptr(), nil, false)
	}
	memmove(, unsafe.Pointer(), uintptr())
	return unsafe.String((*byte)(), )
}

// stringDataOnStack reports whether the string's data is
// stored on the current goroutine's stack.
func stringDataOnStack( string) bool {
	 := uintptr(unsafe.Pointer(unsafe.StringData()))
	 := getg().stack
	return .lo <=  &&  < .hi
}

func rawstringtmp( *tmpBuf,  int) ( string,  []byte) {
	if  != nil &&  <= len() {
		 = [:]
		 = slicebytetostringtmp(&[0], len())
	} else {
		,  = rawstring()
	}
	return
}

// slicebytetostringtmp returns a "string" referring to the actual []byte bytes.
//
// Callers need to ensure that the returned string will not be used after
// the calling goroutine modifies the original slice or synchronizes with
// another goroutine.
//
// The function is only called when instrumenting
// and otherwise intrinsified by the compiler.
//
// Some internal compiler optimizations use this function.
//   - Used for m[T1{... Tn{..., string(k), ...} ...}] and m[string(k)]
//     where k is []byte, T1 to Tn is a nesting of struct and array literals.
//   - Used for "<"+string(b)+">" concatenation where b is []byte.
//   - Used for string(b)=="foo" comparison where b is []byte.
func slicebytetostringtmp( *byte,  int) string {
	if raceenabled &&  > 0 {
		racereadrangepc(unsafe.Pointer(),
			uintptr(),
			getcallerpc(),
			abi.FuncPCABIInternal())
	}
	if msanenabled &&  > 0 {
		msanread(unsafe.Pointer(), uintptr())
	}
	if asanenabled &&  > 0 {
		asanread(unsafe.Pointer(), uintptr())
	}
	return unsafe.String(, )
}

func stringtoslicebyte( *tmpBuf,  string) []byte {
	var  []byte
	if  != nil && len() <= len() {
		* = tmpBuf{}
		 = [:len()]
	} else {
		 = rawbyteslice(len())
	}
	copy(, )
	return 
}

func stringtoslicerune( *[tmpStringBufSize]rune,  string) []rune {
	// two passes.
	// unlike slicerunetostring, no race because strings are immutable.
	 := 0
	for range  {
		++
	}

	var  []rune
	if  != nil &&  <= len() {
		* = [tmpStringBufSize]rune{}
		 = [:]
	} else {
		 = rawruneslice()
	}

	 = 0
	for ,  := range  {
		[] = 
		++
	}
	return 
}

func slicerunetostring( *tmpBuf,  []rune) string {
	if raceenabled && len() > 0 {
		racereadrangepc(unsafe.Pointer(&[0]),
			uintptr(len())*unsafe.Sizeof([0]),
			getcallerpc(),
			abi.FuncPCABIInternal())
	}
	if msanenabled && len() > 0 {
		msanread(unsafe.Pointer(&[0]), uintptr(len())*unsafe.Sizeof([0]))
	}
	if asanenabled && len() > 0 {
		asanread(unsafe.Pointer(&[0]), uintptr(len())*unsafe.Sizeof([0]))
	}
	var  [4]byte
	 := 0
	for ,  := range  {
		 += encoderune([:], )
	}
	,  := rawstringtmp(, +3)
	 := 0
	for ,  := range  {
		// check for race
		if  >=  {
			break
		}
		 += encoderune([:], )
	}
	return [:]
}

type stringStruct struct {
	str unsafe.Pointer
	len int
}

// Variant with *byte pointer type for DWARF debugging.
type stringStructDWARF struct {
	str *byte
	len int
}

func stringStructOf( *string) *stringStruct {
	return (*stringStruct)(unsafe.Pointer())
}

func intstring( *[4]byte,  int64) ( string) {
	var  []byte
	if  != nil {
		 = [:]
		 = slicebytetostringtmp(&[0], len())
	} else {
		,  = rawstring(4)
	}
	if int64(rune()) !=  {
		 = runeError
	}
	 := encoderune(, rune())
	return [:]
}

// rawstring allocates storage for a new string. The returned
// string and byte slice both refer to the same storage.
// The storage is not zeroed. Callers should use
// b to set the string contents and then drop b.
func rawstring( int) ( string,  []byte) {
	 := mallocgc(uintptr(), nil, false)
	return unsafe.String((*byte)(), ), unsafe.Slice((*byte)(), )
}

// rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
func rawbyteslice( int) ( []byte) {
	 := roundupsize(uintptr(), true)
	 := mallocgc(, nil, false)
	if  != uintptr() {
		memclrNoHeapPointers(add(, uintptr()), -uintptr())
	}

	*(*slice)(unsafe.Pointer(&)) = slice{, , int()}
	return
}

// rawruneslice allocates a new rune slice. The rune slice is not zeroed.
func rawruneslice( int) ( []rune) {
	if uintptr() > maxAlloc/4 {
		throw("out of memory")
	}
	 := roundupsize(uintptr()*4, true)
	 := mallocgc(, nil, false)
	if  != uintptr()*4 {
		memclrNoHeapPointers(add(, uintptr()*4), -uintptr()*4)
	}

	*(*slice)(unsafe.Pointer(&)) = slice{, , int( / 4)}
	return
}

// used by cmd/cgo
func gobytes( *byte,  int) ( []byte) {
	if  == 0 {
		return make([]byte, 0)
	}

	if  < 0 || uintptr() > maxAlloc {
		panic(errorString("gobytes: length out of range"))
	}

	 := mallocgc(uintptr(), nil, false)
	memmove(, unsafe.Pointer(), uintptr())

	*(*slice)(unsafe.Pointer(&)) = slice{, , }
	return
}

// This is exported via linkname to assembly in syscall (for Plan9) and cgo.
//
//go:linkname gostring
func gostring( *byte) string {
	 := findnull()
	if  == 0 {
		return ""
	}
	,  := rawstring()
	memmove(unsafe.Pointer(&[0]), unsafe.Pointer(), uintptr())
	return 
}

// internal_syscall_gostring is a version of gostring for internal/syscall/unix.
//
//go:linkname internal_syscall_gostring internal/syscall/unix.gostring
func internal_syscall_gostring( *byte) string {
	return gostring()
}

func gostringn( *byte,  int) string {
	if  == 0 {
		return ""
	}
	,  := rawstring()
	memmove(unsafe.Pointer(&[0]), unsafe.Pointer(), uintptr())
	return 
}

const (
	maxUint64 = ^uint64(0)
	maxInt64  = int64(maxUint64 >> 1)
)

// atoi64 parses an int64 from a string s.
// The bool result reports whether s is a number
// representable by a value of type int64.
func atoi64( string) (int64, bool) {
	if  == "" {
		return 0, false
	}

	 := false
	if [0] == '-' {
		 = true
		 = [1:]
	}

	 := uint64(0)
	for  := 0;  < len(); ++ {
		 := []
		if  < '0' ||  > '9' {
			return 0, false
		}
		if  > maxUint64/10 {
			// overflow
			return 0, false
		}
		 *= 10
		 :=  + uint64() - '0'
		if  <  {
			// overflow
			return 0, false
		}
		 = 
	}

	if ! &&  > uint64(maxInt64) {
		return 0, false
	}
	if  &&  > uint64(maxInt64)+1 {
		return 0, false
	}

	 := int64()
	if  {
		 = -
	}

	return , true
}

// atoi is like atoi64 but for integers
// that fit into an int.
func atoi( string) (int, bool) {
	if ,  := atoi64();  == int64(int()) {
		return int(), 
	}
	return 0, false
}

// atoi32 is like atoi but for integers
// that fit into an int32.
func atoi32( string) (int32, bool) {
	if ,  := atoi64();  == int64(int32()) {
		return int32(), 
	}
	return 0, false
}

// parseByteCount parses a string that represents a count of bytes.
//
// s must match the following regular expression:
//
//	^[0-9]+(([KMGT]i)?B)?$
//
// In other words, an integer byte count with an optional unit
// suffix. Acceptable suffixes include one of
// - KiB, MiB, GiB, TiB which represent binary IEC/ISO 80000 units, or
// - B, which just represents bytes.
//
// Returns an int64 because that's what its callers want and receive,
// but the result is always non-negative.
func parseByteCount( string) (int64, bool) {
	// The empty string is not valid.
	if  == "" {
		return 0, false
	}
	// Handle the easy non-suffix case.
	 := [len()-1]
	if  >= '0' &&  <= '9' {
		,  := atoi64()
		if ! ||  < 0 {
			return 0, false
		}
		return , 
	}
	// Failing a trailing digit, this must always end in 'B'.
	// Also at this point there must be at least one digit before
	// that B.
	if  != 'B' || len() < 2 {
		return 0, false
	}
	// The one before that must always be a digit or 'i'.
	if  := [len()-2];  >= '0' &&  <= '9' {
		// Trivial 'B' suffix.
		,  := atoi64([:len()-1])
		if ! ||  < 0 {
			return 0, false
		}
		return , 
	} else if  != 'i' {
		return 0, false
	}
	// Finally, we need at least 4 characters now, for the unit
	// prefix and at least one digit.
	if len() < 4 {
		return 0, false
	}
	 := 0
	switch [len()-3] {
	case 'K':
		 = 1
	case 'M':
		 = 2
	case 'G':
		 = 3
	case 'T':
		 = 4
	default:
		// Invalid suffix.
		return 0, false
	}
	 := uint64(1)
	for  := 0;  < ; ++ {
		 *= 1024
	}
	,  := atoi64([:len()-3])
	if ! ||  < 0 {
		return 0, false
	}
	 := uint64()
	if  > maxUint64/ {
		// Overflow.
		return 0, false
	}
	 *= 
	if  > uint64(maxInt64) {
		// Overflow.
		return 0, false
	}
	return int64(), true
}

//go:nosplit
func findnull( *byte) int {
	if  == nil {
		return 0
	}

	// Avoid IndexByteString on Plan 9 because it uses SSE instructions
	// on x86 machines, and those are classified as floating point instructions,
	// which are illegal in a note handler.
	if GOOS == "plan9" {
		 := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer())
		 := 0
		for [] != 0 {
			++
		}
		return 
	}

	// pageSize is the unit we scan at a time looking for NULL.
	// It must be the minimum page size for any architecture Go
	// runs on. It's okay (just a minor performance loss) if the
	// actual system page size is larger than this value.
	const  = 4096

	 := 0
	 := unsafe.Pointer()
	// IndexByteString uses wide reads, so we need to be careful
	// with page boundaries. Call IndexByteString on
	// [ptr, endOfPage) interval.
	 := int( - uintptr()%)

	for {
		 := *(*string)(unsafe.Pointer(&stringStruct{, }))
		// Check one page at a time.
		if  := bytealg.IndexByteString(, 0);  != -1 {
			return  + 
		}
		// Move to next page
		 = unsafe.Pointer(uintptr() + uintptr())
		 += 
		 = 
	}
}

func findnullw( *uint16) int {
	if  == nil {
		return 0
	}
	 := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer())
	 := 0
	for [] != 0 {
		++
	}
	return 
}

//go:nosplit
func gostringnocopy( *byte) string {
	 := stringStruct{str: unsafe.Pointer(), len: findnull()}
	 := *(*string)(unsafe.Pointer(&))
	return 
}

func gostringw( *uint16) string {
	var  [8]byte
	 := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer())
	 := 0
	for  := 0; [] != 0; ++ {
		 += encoderune([:], rune([]))
	}
	,  := rawstring( + 4)
	 := 0
	for  := 0; [] != 0; ++ {
		// check for race
		if  >=  {
			break
		}
		 += encoderune([:], rune([]))
	}
	[] = 0 // for luck
	return [:]
}