package runtime
import (
"internal/abi"
"internal/bytealg"
"internal/goarch"
"unsafe"
)
const tmpStringBufSize = 32
type tmpBuf [tmpStringBufSize ]byte
func concatstrings (buf *tmpBuf , a []string ) string {
idx := 0
l := 0
count := 0
for i , x := range a {
n := len (x )
if n == 0 {
continue
}
if l +n < l {
throw ("string concatenation too long" )
}
l += n
count ++
idx = i
}
if count == 0 {
return ""
}
if count == 1 && (buf != nil || !stringDataOnStack (a [idx ])) {
return a [idx ]
}
s , b := rawstringtmp (buf , l )
for _ , x := range a {
copy (b , x )
b = b [len (x ):]
}
return s
}
func concatstring2 (buf *tmpBuf , a0 , a1 string ) string {
return concatstrings (buf , []string {a0 , a1 })
}
func concatstring3 (buf *tmpBuf , a0 , a1 , a2 string ) string {
return concatstrings (buf , []string {a0 , a1 , a2 })
}
func concatstring4 (buf *tmpBuf , a0 , a1 , a2 , a3 string ) string {
return concatstrings (buf , []string {a0 , a1 , a2 , a3 })
}
func concatstring5 (buf *tmpBuf , a0 , a1 , a2 , a3 , a4 string ) string {
return concatstrings (buf , []string {a0 , a1 , a2 , a3 , a4 })
}
func slicebytetostring (buf *tmpBuf , ptr *byte , n int ) string {
if n == 0 {
return ""
}
if raceenabled {
racereadrangepc (unsafe .Pointer (ptr ),
uintptr (n ),
getcallerpc (),
abi .FuncPCABIInternal (slicebytetostring ))
}
if msanenabled {
msanread (unsafe .Pointer (ptr ), uintptr (n ))
}
if asanenabled {
asanread (unsafe .Pointer (ptr ), uintptr (n ))
}
if n == 1 {
p := unsafe .Pointer (&staticuint64s [*ptr ])
if goarch .BigEndian {
p = add (p , 7 )
}
return unsafe .String ((*byte )(p ), 1 )
}
var p unsafe .Pointer
if buf != nil && n <= len (buf ) {
p = unsafe .Pointer (buf )
} else {
p = mallocgc (uintptr (n ), nil , false )
}
memmove (p , unsafe .Pointer (ptr ), uintptr (n ))
return unsafe .String ((*byte )(p ), n )
}
func stringDataOnStack (s string ) bool {
ptr := uintptr (unsafe .Pointer (unsafe .StringData (s )))
stk := getg ().stack
return stk .lo <= ptr && ptr < stk .hi
}
func rawstringtmp (buf *tmpBuf , l int ) (s string , b []byte ) {
if buf != nil && l <= len (buf ) {
b = buf [:l ]
s = slicebytetostringtmp (&b [0 ], len (b ))
} else {
s , b = rawstring (l )
}
return
}
func slicebytetostringtmp (ptr *byte , n int ) string {
if raceenabled && n > 0 {
racereadrangepc (unsafe .Pointer (ptr ),
uintptr (n ),
getcallerpc (),
abi .FuncPCABIInternal (slicebytetostringtmp ))
}
if msanenabled && n > 0 {
msanread (unsafe .Pointer (ptr ), uintptr (n ))
}
if asanenabled && n > 0 {
asanread (unsafe .Pointer (ptr ), uintptr (n ))
}
return unsafe .String (ptr , n )
}
func stringtoslicebyte (buf *tmpBuf , s string ) []byte {
var b []byte
if buf != nil && len (s ) <= len (buf ) {
*buf = tmpBuf {}
b = buf [:len (s )]
} else {
b = rawbyteslice (len (s ))
}
copy (b , s )
return b
}
func stringtoslicerune (buf *[tmpStringBufSize ]rune , s string ) []rune {
n := 0
for range s {
n ++
}
var a []rune
if buf != nil && n <= len (buf ) {
*buf = [tmpStringBufSize ]rune {}
a = buf [:n ]
} else {
a = rawruneslice (n )
}
n = 0
for _ , r := range s {
a [n ] = r
n ++
}
return a
}
func slicerunetostring (buf *tmpBuf , a []rune ) string {
if raceenabled && len (a ) > 0 {
racereadrangepc (unsafe .Pointer (&a [0 ]),
uintptr (len (a ))*unsafe .Sizeof (a [0 ]),
getcallerpc (),
abi .FuncPCABIInternal (slicerunetostring ))
}
if msanenabled && len (a ) > 0 {
msanread (unsafe .Pointer (&a [0 ]), uintptr (len (a ))*unsafe .Sizeof (a [0 ]))
}
if asanenabled && len (a ) > 0 {
asanread (unsafe .Pointer (&a [0 ]), uintptr (len (a ))*unsafe .Sizeof (a [0 ]))
}
var dum [4 ]byte
size1 := 0
for _ , r := range a {
size1 += encoderune (dum [:], r )
}
s , b := rawstringtmp (buf , size1 +3 )
size2 := 0
for _ , r := range a {
if size2 >= size1 {
break
}
size2 += encoderune (b [size2 :], r )
}
return s [:size2 ]
}
type stringStruct struct {
str unsafe .Pointer
len int
}
type stringStructDWARF struct {
str *byte
len int
}
func stringStructOf (sp *string ) *stringStruct {
return (*stringStruct )(unsafe .Pointer (sp ))
}
func intstring (buf *[4 ]byte , v int64 ) (s string ) {
var b []byte
if buf != nil {
b = buf [:]
s = slicebytetostringtmp (&b [0 ], len (b ))
} else {
s , b = rawstring (4 )
}
if int64 (rune (v )) != v {
v = runeError
}
n := encoderune (b , rune (v ))
return s [:n ]
}
func rawstring (size int ) (s string , b []byte ) {
p := mallocgc (uintptr (size ), nil , false )
return unsafe .String ((*byte )(p ), size ), unsafe .Slice ((*byte )(p ), size )
}
func rawbyteslice (size int ) (b []byte ) {
cap := roundupsize (uintptr (size ))
p := mallocgc (cap , nil , false )
if cap != uintptr (size ) {
memclrNoHeapPointers (add (p , uintptr (size )), cap -uintptr (size ))
}
*(*slice )(unsafe .Pointer (&b )) = slice {p , size , int (cap )}
return
}
func rawruneslice (size int ) (b []rune ) {
if uintptr (size ) > maxAlloc /4 {
throw ("out of memory" )
}
mem := roundupsize (uintptr (size ) * 4 )
p := mallocgc (mem , nil , false )
if mem != uintptr (size )*4 {
memclrNoHeapPointers (add (p , uintptr (size )*4 ), mem -uintptr (size )*4 )
}
*(*slice )(unsafe .Pointer (&b )) = slice {p , size , int (mem / 4 )}
return
}
func gobytes (p *byte , n int ) (b []byte ) {
if n == 0 {
return make ([]byte , 0 )
}
if n < 0 || uintptr (n ) > maxAlloc {
panic (errorString ("gobytes: length out of range" ))
}
bp := mallocgc (uintptr (n ), nil , false )
memmove (bp , unsafe .Pointer (p ), uintptr (n ))
*(*slice )(unsafe .Pointer (&b )) = slice {bp , n , n }
return
}
func gostring (p *byte ) string {
l := findnull (p )
if l == 0 {
return ""
}
s , b := rawstring (l )
memmove (unsafe .Pointer (&b [0 ]), unsafe .Pointer (p ), uintptr (l ))
return s
}
func internal_syscall_gostring (p *byte ) string {
return gostring (p )
}
func gostringn (p *byte , l int ) string {
if l == 0 {
return ""
}
s , b := rawstring (l )
memmove (unsafe .Pointer (&b [0 ]), unsafe .Pointer (p ), uintptr (l ))
return s
}
func hasPrefix (s , prefix string ) bool {
return len (s ) >= len (prefix ) && s [:len (prefix )] == prefix
}
func hasSuffix (s , suffix string ) bool {
return len (s ) >= len (suffix ) && s [len (s )-len (suffix ):] == suffix
}
const (
maxUint64 = ^uint64 (0 )
maxInt64 = int64 (maxUint64 >> 1 )
)
func atoi64 (s string ) (int64 , bool ) {
if s == "" {
return 0 , false
}
neg := false
if s [0 ] == '-' {
neg = true
s = s [1 :]
}
un := uint64 (0 )
for i := 0 ; i < len (s ); i ++ {
c := s [i ]
if c < '0' || c > '9' {
return 0 , false
}
if un > maxUint64 /10 {
return 0 , false
}
un *= 10
un1 := un + uint64 (c ) - '0'
if un1 < un {
return 0 , false
}
un = un1
}
if !neg && un > uint64 (maxInt64 ) {
return 0 , false
}
if neg && un > uint64 (maxInt64 )+1 {
return 0 , false
}
n := int64 (un )
if neg {
n = -n
}
return n , true
}
func atoi (s string ) (int , bool ) {
if n , ok := atoi64 (s ); n == int64 (int (n )) {
return int (n ), ok
}
return 0 , false
}
func atoi32 (s string ) (int32 , bool ) {
if n , ok := atoi64 (s ); n == int64 (int32 (n )) {
return int32 (n ), ok
}
return 0 , false
}
func parseByteCount (s string ) (int64 , bool ) {
if s == "" {
return 0 , false
}
last := s [len (s )-1 ]
if last >= '0' && last <= '9' {
n , ok := atoi64 (s )
if !ok || n < 0 {
return 0 , false
}
return n , ok
}
if last != 'B' || len (s ) < 2 {
return 0 , false
}
if c := s [len (s )-2 ]; c >= '0' && c <= '9' {
n , ok := atoi64 (s [:len (s )-1 ])
if !ok || n < 0 {
return 0 , false
}
return n , ok
} else if c != 'i' {
return 0 , false
}
if len (s ) < 4 {
return 0 , false
}
power := 0
switch s [len (s )-3 ] {
case 'K' :
power = 1
case 'M' :
power = 2
case 'G' :
power = 3
case 'T' :
power = 4
default :
return 0 , false
}
m := uint64 (1 )
for i := 0 ; i < power ; i ++ {
m *= 1024
}
n , ok := atoi64 (s [:len (s )-3 ])
if !ok || n < 0 {
return 0 , false
}
un := uint64 (n )
if un > maxUint64 /m {
return 0 , false
}
un *= m
if un > uint64 (maxInt64 ) {
return 0 , false
}
return int64 (un ), true
}
func findnull (s *byte ) int {
if s == nil {
return 0
}
if GOOS == "plan9" {
p := (*[maxAlloc /2 - 1 ]byte )(unsafe .Pointer (s ))
l := 0
for p [l ] != 0 {
l ++
}
return l
}
const pageSize = 4096
offset := 0
ptr := unsafe .Pointer (s )
safeLen := int (pageSize - uintptr (ptr )%pageSize )
for {
t := *(*string )(unsafe .Pointer (&stringStruct {ptr , safeLen }))
if i := bytealg .IndexByteString (t , 0 ); i != -1 {
return offset + i
}
ptr = unsafe .Pointer (uintptr (ptr ) + uintptr (safeLen ))
offset += safeLen
safeLen = pageSize
}
}
func findnullw (s *uint16 ) int {
if s == nil {
return 0
}
p := (*[maxAlloc /2 /2 - 1 ]uint16 )(unsafe .Pointer (s ))
l := 0
for p [l ] != 0 {
l ++
}
return l
}
func gostringnocopy (str *byte ) string {
ss := stringStruct {str : unsafe .Pointer (str ), len : findnull (str )}
s := *(*string )(unsafe .Pointer (&ss ))
return s
}
func gostringw (strw *uint16 ) string {
var buf [8 ]byte
str := (*[maxAlloc /2 /2 - 1 ]uint16 )(unsafe .Pointer (strw ))
n1 := 0
for i := 0 ; str [i ] != 0 ; i ++ {
n1 += encoderune (buf [:], rune (str [i ]))
}
s , b := rawstring (n1 + 4 )
n2 := 0
for i := 0 ; str [i ] != 0 ; i ++ {
if n2 >= n1 {
break
}
n2 += encoderune (b [n2 :], rune (str [i ]))
}
b [n2 ] = 0
return s [:n2 ]
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .