internal/bytealg: reimplement bytealg in pure Go
Previously, we implemented individual bytealg functions via linknaming, and had to update them every once in a while when we hit linker errors. Instead, this change reimplements the bytealg package in pure Go. If something is missing, it will cause a compiler error rather than a linker error. This is easier to test and maintain.
Этот коммит содержится в:
родитель
38fc340802
коммит
473644d918
6 изменённых файлов: 130 добавлений и 48 удалений
|
@ -180,7 +180,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
|
|||
path = path[len(tinygoPath+"/src/"):]
|
||||
}
|
||||
switch path {
|
||||
case "machine", "os", "reflect", "runtime", "runtime/interrupt", "runtime/volatile", "sync", "testing", "internal/reflectlite", "internal/task":
|
||||
case "machine", "os", "reflect", "runtime", "runtime/interrupt", "runtime/volatile", "sync", "testing", "internal/reflectlite", "internal/bytealg", "internal/task":
|
||||
return path
|
||||
default:
|
||||
if strings.HasPrefix(path, "device/") || strings.HasPrefix(path, "examples/") {
|
||||
|
|
126
src/internal/bytealg/bytealg.go
Обычный файл
126
src/internal/bytealg/bytealg.go
Обычный файл
|
@ -0,0 +1,126 @@
|
|||
package bytealg
|
||||
|
||||
const (
|
||||
// Index can search any valid length of string.
|
||||
|
||||
MaxLen = int(-1) >> 31
|
||||
MaxBruteForce = MaxLen
|
||||
)
|
||||
|
||||
// Compare two byte slices.
|
||||
// Returns -1 if the first differing byte is lower in a, or 1 if the first differing byte is greater in b.
|
||||
// If the byte slices are equal, returns 0.
|
||||
// If the lengths are different and there are no differing bytes, compares based on length.
|
||||
func Compare(a, b []byte) int {
|
||||
// Compare for differing bytes.
|
||||
for i := 0; i < len(a) && i < len(b); i++ {
|
||||
switch {
|
||||
case a[0] < b[0]:
|
||||
return -1
|
||||
case a[0] > b[0]:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Compare lengths.
|
||||
switch {
|
||||
case len(a) > len(b):
|
||||
return 1
|
||||
case len(a) < len(b):
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Count the number of instances of a byte in a slice.
|
||||
func Count(b []byte, c byte) int {
|
||||
// Use a simple implementation, as there is no intrinsic that does this like we want.
|
||||
n := 0
|
||||
for _, v := range b {
|
||||
if v == c {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Count the number of instances of a byte in a string.
|
||||
func CountString(s string, c byte) int {
|
||||
// Use a simple implementation, as there is no intrinsic that does this like we want.
|
||||
// Currently, the compiler does not generate zero-copy byte-string conversions, so this needs to be seperate from Count.
|
||||
n := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == c {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Cutover is not reachable in TinyGo, but must exist as it is referenced.
|
||||
func Cutover(n int) int {
|
||||
// Setting MaxLen and MaxBruteForce should force a different path to be taken.
|
||||
// This should never be called.
|
||||
panic("cutover is unreachable")
|
||||
}
|
||||
|
||||
// Equal checks if two byte slices are equal.
|
||||
// It is equivalent to bytes.Equal.
|
||||
func Equal(a, b []byte) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Index finds the base index of the first instance of the byte sequence b in a.
|
||||
// If a does not contain b, this returns -1.
|
||||
func Index(a, b []byte) int {
|
||||
for i := 0; i <= len(a)-len(b); i++ {
|
||||
if Equal(a[i:i+len(b)], b) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Index finds the index of the first instance of the specified byte in the slice.
|
||||
// If the byte is not found, this returns -1.
|
||||
func IndexByte(b []byte, c byte) int {
|
||||
for i, v := range b {
|
||||
if v == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Index finds the index of the first instance of the specified byte in the string.
|
||||
// If the byte is not found, this returns -1.
|
||||
func IndexByteString(s string, c byte) int {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Index finds the base index of the first instance of a substring in a string.
|
||||
// If the substring is not found, this returns -1.
|
||||
func IndexString(str, sub string) int {
|
||||
for i := 0; i <= len(str)-len(sub); i++ {
|
||||
if str[i:i+len(sub)] == sub {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package runtime
|
||||
|
||||
//go:linkname indexBytePortable internal/bytealg.IndexByte
|
||||
func indexBytePortable(s []byte, c byte) int {
|
||||
for i, b := range s {
|
||||
if b == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
|
@ -204,15 +204,3 @@ func decodeUTF8(s string, index uintptr) (rune, uintptr) {
|
|||
return 0xfffd, 1
|
||||
}
|
||||
}
|
||||
|
||||
// indexByteString returns the index of the first instance of c in s, or -1 if c
|
||||
// is not present in s.
|
||||
//go:linkname indexByteString internal/bytealg.IndexByteString
|
||||
func indexByteString(s string, c byte) int {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
// +build amd64 arm,go1.13 arm64 ppc64le ppc64 s390x
|
||||
|
||||
package runtime
|
||||
|
||||
// This file implements the string counting functions used by the strings
|
||||
// package, for example. It must be reimplemented here as a replacement for the
|
||||
// Go stdlib asm implementations, but only when the asm implementations are used
|
||||
// (this varies by Go version).
|
||||
// Track this file for updates:
|
||||
// https://github.com/golang/go/blob/master/src/internal/bytealg/count_native.go
|
||||
|
||||
// countString copies the implementation from
|
||||
// https://github.com/golang/go/blob/67f181bfd84dfd5942fe9a29d8a20c9ce5eb2fea/src/internal/bytealg/count_generic.go#L1
|
||||
//go:linkname countString internal/bytealg.CountString
|
||||
func countString(s string, c byte) int {
|
||||
n := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == c {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
package runtime
|
||||
|
||||
import "internal/bytealg"
|
||||
|
||||
// indexByte provides compatibility with Go 1.11.
|
||||
// See the following:
|
||||
// https://github.com/tinygo-org/tinygo/issues/351
|
||||
// https://github.com/golang/go/commit/ad4a58e31501bce5de2aad90a620eaecdc1eecb8
|
||||
//go:linkname indexByte strings.IndexByte
|
||||
func indexByte(s string, c byte) int {
|
||||
return indexByteString(s, c)
|
||||
return bytealg.IndexByteString(s, c)
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче