提交 1329c4a0 编写于 作者: 3 3dgen

Merge branch 'master' of https://gitee.com/wa-lang/wa

......@@ -3,6 +3,7 @@
default:
GOOS=js GOARCH=wasm go build -o wa.wasm
mv wa.wasm ../../../docs
cd ../../../docs && zip wa.wasm.zip wa.wasm
dev-chai:
-rm wa.wasm
......
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
import "math/bits"
func AAA {
println(bits.UintSize)
}
const (
_S = _W / 8 // 字宽(以字节为单位)
_W = bits.UintSize // 字宽(以位为单位)
_B = 1 << _W // 基数
_M = _B - 1 // 基数掩码
)
// z1<<_W + z0 = x*y
func mulWW(x, y: uint) => (z1, z0: uint) {
return bits.Mul(x, y)
}
// z1<<_W + z0 = x*y + c
func mulAddWWW(x, y, c: uint) => (z1, z0: uint) {
hi, lo := bits.Mul(x, y)
cc: uint
lo, cc = bits.Add(lo, c, 0)
return hi + cc, lo
}
// nlz returns the number of leading zeros in x.
// Wraps bits.LeadingZeros call for convenience.
func nlz(x: uint) => uint {
return uint(bits.LeadingZeros(x))
}
// The resulting carry c is either 0 or 1.
func addVV(z, x, y: []uint) => (c: uint) {
for i := 0; i < len(z) && i < len(x) && i < len(y); i++ {
zi, cc := bits.Add(x[i], y[i], c)
z[i] = zi
c = cc
}
return
}
// The resulting carry c is either 0 or 1.
func subVV(z, x, y: []uint) => (c: uint) {
for i := 0; i < len(z) && i < len(x) && i < len(y); i++ {
zi, cc := bits.Sub(x[i], y[i], c)
z[i] = zi
c = cc
}
return
}
// The resulting carry c is either 0 or 1.
func addVW(z, x: []uint, y: uint) => (c: uint) {
c = y
for i := 0; i < len(z) && i < len(x); i++ {
zi, cc := bits.Add(x[i], c, 0)
z[i] = zi
c = cc
}
return
}
func subVW(z, x: []uint, y: uint) => (c: uint) {
c = y
for i := 0; i < len(z) && i < len(x); i++ {
zi, cc := bits.Sub(x[i], c, 0)
z[i] = zi
c = cc
}
return
}
func shlVU(z, x: []uint, s: uint) => (c: uint) {
if s == 0 {
copy(z, x)
return
}
if len(z) == 0 {
return
}
s &= _W - 1 // hint to the compiler that shifts by s don't need guard code
ŝ := _W - s
ŝ &= _W - 1 // ditto
c = x[len(z)-1] >> ŝ
for i := len(z) - 1; i > 0; i-- {
z[i] = x[i]<<s | x[i-1]>>ŝ
}
z[0] = x[0] << s
return
}
func shrVU(z, x: []uint, s: uint) => (c: uint) {
if s == 0 {
copy(z, x)
return
}
if len(z) == 0 {
return
}
if len(x) != len(z) {
// This is an invariant guaranteed by the caller.
panic("len(x) != len(z)")
}
s &= _W - 1 // hint to the compiler that shifts by s don't need guard code
ŝ := _W - s
ŝ &= _W - 1 // ditto
c = x[0] << ŝ
for i := 1; i < len(z); i++ {
z[i-1] = x[i-1]>>s | x[i]<<ŝ
}
z[len(z)-1] = x[len(z)-1] >> s
return
}
func mulAddVWW(z, x: []uint, y, r: uint) => (c: uint) {
c = r
for i := 0; i < len(z) && i < len(x); i++ {
c, z[i] = mulAddWWW(x[i], y, c)
}
return
}
func addMulVVW(z, x: []uint, y: uint) => (c: uint) {
for i := 0; i < len(z) && i < len(x); i++ {
z1, z0 := mulAddWWW(x[i], y, z[i])
lo, cc := bits.Add(z0, c, 0)
c, z[i] = cc, lo
c += z1
}
return
}
// q = ( x1 << _W + x0 - r)/y. m = floor(( _B^2 - 1 ) / d - _B). Requiring x1<y.
// An approximate reciprocal with a reference to "Improved Division by Invariant Integers
// (IEEE Transactions on Computers, 11 Jun. 2010)"
func divWW(x1, x0, y, m: uint) => (q, r: uint) {
s := nlz(y)
if s != 0 {
x1 = x1<<s | x0>>(_W-s)
x0 <<= s
y <<= s
}
d := y
// We know that
// m = ⎣(B^2-1)/d⎦-B
// ⎣(B^2-1)/d⎦ = m+B
// (B^2-1)/d = m+B+delta1 0 <= delta1 <= (d-1)/d
// B^2/d = m+B+delta2 0 <= delta2 <= 1
// The quotient we're trying to compute is
// quotient = ⎣(x1*B+x0)/d⎦
// = ⎣(x1*B*(B^2/d)+x0*(B^2/d))/B^2⎦
// = ⎣(x1*B*(m+B+delta2)+x0*(m+B+delta2))/B^2⎦
// = ⎣(x1*m+x1*B+x0)/B + x0*m/B^2 + delta2*(x1*B+x0)/B^2⎦
// The latter two terms of this three-term sum are between 0 and 1.
// So we can compute just the first term, and we will be low by at most 2.
t1, t0 := bits.Mul(m, x1)
_, c := bits.Add(t0, x0, 0)
t1, _ = bits.Add(t1, x1, c)
// The quotient is either t1, t1+1, or t1+2.
// We'll try t1 and adjust if needed.
qq := t1
// compute remainder r=x-d*q.
dq1, dq0 := bits.Mul(d, qq)
r0, b := bits.Sub(x0, dq0, 0)
r1, _ := bits.Sub(x1, dq1, b)
// The remainder we just computed is bounded above by B+d:
// r = x1*B + x0 - d*q.
// = x1*B + x0 - d*⎣(x1*m+x1*B+x0)/B⎦
// = x1*B + x0 - d*((x1*m+x1*B+x0)/B-alpha) 0 <= alpha < 1
// = x1*B + x0 - x1*d/B*m - x1*d - x0*d/B + d*alpha
// = x1*B + x0 - x1*d/B*⎣(B^2-1)/d-B⎦ - x1*d - x0*d/B + d*alpha
// = x1*B + x0 - x1*d/B*⎣(B^2-1)/d-B⎦ - x1*d - x0*d/B + d*alpha
// = x1*B + x0 - x1*d/B*((B^2-1)/d-B-beta) - x1*d - x0*d/B + d*alpha 0 <= beta < 1
// = x1*B + x0 - x1*B + x1/B + x1*d + x1*d/B*beta - x1*d - x0*d/B + d*alpha
// = x0 + x1/B + x1*d/B*beta - x0*d/B + d*alpha
// = x0*(1-d/B) + x1*(1+d*beta)/B + d*alpha
// < B*(1-d/B) + d*B/B + d because x0<B (and 1-d/B>0), x1<d, 1+d*beta<=B, alpha<1
// = B - d + d + d
// = B+d
// So r1 can only be 0 or 1. If r1 is 1, then we know q was too small.
// Add 1 to q and subtract d from r. That guarantees that r is <B, so
// we no longer need to keep track of r1.
if r1 != 0 {
qq++
r0 -= d
}
// If the remainder is still too large, increment q one more time.
if r0 >= d {
qq++
r0 -= d
}
return qq, r0 >> s
}
// reciprocalWord return the reciprocal of the divisor. rec = floor(( _B^2 - 1 ) / u - _B). u = d1 << nlz(d1).
func reciprocalWord(d1: uint) => uint {
u := uint(d1 << nlz(d1))
x1 := ^u
x0 := uint(_M)
rec, _ := bits.Div(x1, x0, u) // (_B^2-1)/U-_B = (_B*(_M-C)+_M)/U
return uint(rec)
}
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
// 暂时把go的大端转换代码copy过来
func Buf2Uint64(b: []byte) => uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
func Buf2Uint32(b: []byte) => uint32 {
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
}
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
type Int struct {
neg: bool // sign
abs: nat // absolute value of the integer
}
var intOne = &Int{false, natOne}
// 测试用
func NewInt(x: string) => *Int {
t := new(Int)
neg := false
if x[0] == '-' {
neg = true
x = x[1:]
}
t.abs = natFromString(x)
t.neg = neg
return t
}
func NewIntWithuint(x: uint) => *Int {
t := new(Int)
t.abs = nat{[]uint{x}}
t.neg = false
return t
}
// Sign returns:
//
// -1 if x < 0
// 0 if x == 0
// +1 if x > 0
//
func Int.Sign() => int {
if len(this.abs.Data) == 0 {
return 0
}
if this.neg {
return -1
}
return 1
}
// Set sets z to x and returns z.
func Int.Set(x: *Int) => *Int {
if this != x {
this.abs = this.abs.set(x.abs)
this.neg = x.neg
}
return this
}
// Bits provides raw (unchecked but fast) access to x by returning its
// absolute value as a little-endian Word slice. The result and x share
// the same underlying array.
// Bits is intended to support implementation of missing low-level Int
// functionality outside this package; it should be avoided otherwise.
func Int.Bits() => []uint {
return this.abs.Data
}
// SetBits provides raw (unchecked but fast) access to z by setting its
// value to abs, interpreted as a little-endian Word slice, and returning
// z. The result and abs share the same underlying array.
// SetBits is intended to support implementation of missing low-level Int
// functionality outside this package; it should be avoided otherwise.
func Int.SetBits(abs: []uint) => *Int {
temp := &nat{abs}
this.abs = temp.norm()
this.neg = false
return this
}
// Abs sets z to |x| (the absolute value of x) and returns z.
func Int.Abs(x: *Int) => *Int {
this.Set(x)
this.neg = false
return this
}
// Neg sets z to -x and returns z.
func Int.Neg(x: *Int) => *Int {
this.Set(x)
this.neg = len(this.abs.Data) > 0 && !this.neg // 0 has no sign
return this
}
// Add sets z to the sum x+y and returns z.
func Int.Add(x, y: *Int) => *Int {
neg := x.neg
if x.neg == y.neg {
// x + y == x + y
// (-x) + (-y) == -(x + y)
this.abs = this.abs.add(x.abs, y.abs)
} else {
// x + (-y) == x - y == -(y - x)
// (-x) + y == y - x == -(x - y)
if x.abs.cmp(y.abs) >= 0 {
this.abs = this.abs.sub(x.abs, y.abs)
} else {
neg = !neg
this.abs = this.abs.sub(y.abs, x.abs)
}
}
this.neg = len(this.abs.Data) > 0 && neg // 0 has no sign
return this
}
// Sub sets z to the difference x-y and returns z.
func Int.Sub(x, y: *Int) => *Int {
neg := x.neg
if x.neg != y.neg {
// x - (-y) == x + y
// (-x) - y == -(x + y)
this.abs = this.abs.add(x.abs, y.abs)
} else {
// x - y == x - y == -(y - x)
// (-x) - (-y) == y - x == -(x - y)
if x.abs.cmp(y.abs) >= 0 {
this.abs = this.abs.sub(x.abs, y.abs)
} else {
neg = !neg
this.abs = this.abs.sub(y.abs, x.abs)
}
}
this.neg = len(this.abs.Data) > 0 && neg // 0 has no sign
return this
}
// Mul sets z to the product x*y and returns z.
func Int.Mul(x, y: *Int) => *Int {
// x * y == x * y
// x * (-y) == -(x * y)
// (-x) * y == -(x * y)
// (-x) * (-y) == x * y
this.abs = this.abs.mul(x.abs, y.abs)
this.neg = len(this.abs.Data) > 0 && this.neg != this.neg // 0 has no sign
return this
}
// QuoRem sets z to the quotient x/y and r to the remainder x%y
// and returns the pair (z, r) for y != 0.
// If y == 0, a division-by-zero run-time panic occurs.
//
// QuoRem implements T-division and modulus (like Go):
//
// q = x/y with the result truncated to zero
// r = x - y*q
//
// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
// See DivMod for Euclidean division and modulus (unlike Go).
//
func Int.QuoRem(x, y, r: *Int) => (*Int, *Int) {
this.abs, r.abs = this.abs.div(r.abs, x.abs, y.abs)
this.neg, r.neg = len(this.abs.Data) > 0 && x.neg != y.neg, len(r.abs.Data) > 0 && x.neg // 0 has no sign
return this, r
}
// DivMod sets z to the quotient x div y and m to the modulus x mod y
// and returns the pair (z, m) for y != 0.
// If y == 0, a division-by-zero run-time panic occurs.
//
// DivMod implements Euclidean division and modulus (unlike Go):
//
// q = x div y such that
// m = x - y*q with 0 <= m < |y|
//
// (See Raymond T. Boute, ``The Euclidean definition of the functions
// div and mod''. ACM Transactions on Programming Languages and
// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
// ACM press.)
// See QuoRem for T-division and modulus (like Go).
//
func Int.DivMod(x, y, m: *Int) => (*Int, *Int) {
y0 := y // save y
if this == y || alias(this.abs, y.abs) {
y0 = new(Int).Set(y)
}
this.QuoRem(x, y, m)
if m.neg {
if y0.neg {
this.Add(this, intOne)
m.Sub(m, y0)
} else {
this.Sub(this, intOne)
m.Add(m, y0)
}
}
return this, m
}
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
//
func Int.Cmp(y: *Int) => (r: int) {
// x cmp y == x cmp y
// x cmp (-y) == x
// (-x) cmp y == y
// (-x) cmp (-y) == -(x cmp y)
switch {
case this == y:
// nothing to do
case this.neg == y.neg:
r = this.abs.cmp(y.abs)
if this.neg {
r = -r
}
case this.neg:
r = -1
default:
r = 1
}
return
}
// CmpAbs compares the absolute values of x and y and returns:
//
// -1 if |x| < |y|
// 0 if |x| == |y|
// +1 if |x| > |y|
//
func Int.CmpAbs(y: *Int) => int {
return this.abs.cmp(y.abs)
}
// SetBytes interprets buf as the bytes of a big-endian unsigned
// integer, sets z to that value, and returns z.
func Int.SetBytes(buf: []byte) => *Int {
this.abs = this.abs.setBytes(buf)
this.neg = false
return this
}
// Bytes returns the absolute value of x as a big-endian byte slice.
//
// To use a fixed length slice, or a preallocated one, use FillBytes.
func Int.Bytes() => []byte {
buf := make([]byte, len(this.abs.Data)*_S)
return buf[this.abs.bytes(buf):]
}
// BitLen returns the length of the absolute value of x in bits.
// The bit length of 0 is 0.
func Int.BitLen() => int {
return this.abs.bitLen()
}
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
type funZZ func(z, x, y: *Int) => *Int
type argZZ struct {
z, x, y: *Int
}
var sumZZ = []argZZ{
{NewInt("0"), NewInt("0"), NewInt("0")},
{NewInt("1"), NewInt("1"), NewInt("0")},
{NewInt("1111111110"), NewInt("123456789"), NewInt("987654321")},
{NewInt("-1"), NewInt("-1"), NewInt("0")},
{NewInt("864197532"), NewInt("-123456789"), NewInt("987654321")},
{NewInt("-1111111110"), NewInt("-123456789"), NewInt("-987654321")},
}
func Test_Int_Set() {
println("start test set")
for _, a := range sumZZ {
z: Int
z.Set(a.z)
if (&z).Cmp(a.z) != 0 {
println("error for Int Set")
}
}
}
func testFunZZ(msg: string, f: funZZ, a: argZZ) {
z: Int
f(&z, a.x, a.y)
t := (&z).Cmp(a.z)
if t != 0 {
println(msg, " compute error ", t, ".")
}
}
func Test_Int_Sum() {
println("start test int add and sub")
AddZZ := func(z, x, y: *Int) => *Int { return z.Add(x, y) }
SubZZ := func(z, x, y: *Int) => *Int { return z.Sub(x, y) }
for _, a := range sumZZ {
arg := a
testFunZZ("AddZZ", AddZZ, arg)
arg = argZZ{a.z, a.y, a.x}
testFunZZ("AddZZ symmetric", AddZZ, arg)
arg = argZZ{a.x, a.z, a.y}
testFunZZ("SubZZ", SubZZ, arg)
arg = argZZ{a.y, a.z, a.x}
testFunZZ("SubZZ symmetric", SubZZ, arg)
}
}
var quoTests = []struct {
x, y: string
q, r: string
}{
{
"476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
"9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
"50911",
"1",
},
{
"11510768301994997771168",
"1328165573307167369775",
"8",
"885443715537658812968",
},
}
func Test_Quo() {
println("start test int quo")
for _, test := range quoTests {
x := NewInt(test.x)
y := NewInt(test.y)
expectedQ := NewInt(test.q)
expectedR := NewInt(test.r)
r := NewInt("0")
q, r := NewInt("0").QuoRem(x, y, r)
if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
println("error for Int quo")
}
}
}
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
import (
"math/bits"
)
type nat struct {
Data: []uint
}
func natFromString(s: string) => nat {
temp := &nat{nil}
return temp.setString(s)
}
// 这个方法是临时使用的, 用于部分内容的测试
func nat.setString(s: string) => nat {
// 长度应该是超过的
z := this.make((len(s) + _S - 1) / _S)
val: uint = 0
for i := 0; i < len(s); i++ {
if s[i] < '0' || s[i] > '9' {
println("bad big integer:", s[i])
}
val = uint(s[i] - '0')
z = z.mulAddWW(z, 10, val)
val = 0
}
return z.norm()
}
func nat.clear() {
for i := range this.Data {
this.Data[i] = 0
}
}
var (
natOne = nat{Data: []uint{1}}
)
// 临时使用
func nat.raw_print() {
print("raw_nat: {")
for i := range this.Data {
print(this.Data[i])
if i != len(this.Data)-1 {
print(",")
}
}
println("}")
}
func nat.norm() => nat {
i := len(this.Data)
for i > 0 && this.Data[i-1] == 0 {
i--
}
return nat{Data: this.Data[0:i]}
}
func nat.make(n: int) => nat {
if n <= cap(this.Data) {
return nat{Data: this.Data[:n]} // reuse this.Data
}
if n == 1 {
// Most nats start small and stay that way; don't over-allocate.
return nat{Data: make([]uint, 1)}
}
// Choosing a good value for e has significant performance impact
// because it increases the chance that a value can be reused.
const e = 4 // extra capacity
return nat{Data: make([]uint, n, n+e)}
}
func nat.setWord(x: uint) => nat {
if x == 0 {
return nat{Data: this.Data[:0]}
}
z := this.make(1)
z.Data[0] = x
return z
}
func nat.set(x: nat) => nat {
z := this.make(len(x.Data))
copy(z.Data, x.Data)
return z
}
func nat.add(x, y: nat) => nat {
m := len(x.Data)
n := len(y.Data)
switch {
case m < n:
return this.add(y, x)
case m == 0:
// n == 0 because m >= n; result is 0
return nat{Data: this.Data[:0]}
case n == 0:
// result is x
return this.set(x)
}
// m > 0
z := this.make(m + 1)
c := addVV(z.Data[0:n], x.Data, y.Data)
if m > n {
c = addVW(z.Data[n:m], x.Data[n:], c)
}
z.Data[m] = c
return z.norm()
}
func nat.sub(x, y: nat) => nat {
m := len(x.Data)
n := len(y.Data)
switch {
case m < n:
panic("underflow")
case m == 0:
// n == 0 because m >= n; result is 0
return nat{Data: this.Data[:0]}
case n == 0:
// result is x
return this.set(x)
}
// m > 0
z := this.make(m)
c := subVV(z.Data[0:n], x.Data, y.Data)
if m > n {
c = subVW(z.Data[n:], x.Data[n:], c)
}
if c != 0 {
panic("underflow")
}
return z.norm()
}
func nat.cmp(y: nat) => int {
r := 0
m := len(this.Data)
n := len(y.Data)
if m != n || m == 0 {
switch {
case m < n:
r = -1
case m > n:
r = 1
}
return r
}
i := m - 1
for i > 0 && this.Data[i] == y.Data[i] {
i--
}
switch {
case this.Data[i] < y.Data[i]:
r = -1
case this.Data[i] > y.Data[i]:
r = 1
}
return r
}
func nat.mulAddWW(x: nat, y, r: uint) => nat {
m := len(x.Data)
if m == 0 || y == 0 {
return this.setWord(r) // result is r
}
// m > 0
z := this.make(m + 1)
z.Data[m] = mulAddVWW(z.Data[:m], x.Data, y, r)
return z.norm()
}
// basicMul multiplies x and y and leaves the result in z.
// The (non-normalized) result is placed in z[0 : len(x) + len(y)].
func basicMul(z, x, y: nat) {
// z.Data[:len(x.Data)+len(y.Data)].clear()
// initialize z
t := nat{Data: z.Data[:len(x.Data)+len(y.Data)]}
t.clear()
for i, d := range y.Data {
if d != 0 {
z.Data[len(x.Data)+i] = addMulVVW(z.Data[i:i+len(x.Data)], x.Data, d)
}
}
}
// alias reports whether x and y share the same base array.
// Note: alias assumes that the capacity of underlying arrays
// is never changed for nat values; i.e. that there are
// no 3-operand slice expressions in this code (or worse,
// reflect-based operations to the same effect).
func alias(x, y: nat) => bool {
x_cap := cap(x.Data)
y_cap := cap(y.Data)
return x_cap > 0 && y_cap > 0 && &x.Data[:x_cap][x_cap-1] == &y.Data[:y_cap][y_cap-1]
}
// addAt implements z += x<<(_W*i); z must be long enough.
// (we don't use nat.add because we need z to stay the same
// slice, and we don't need to normalize z after each addition)
func addAt(z, x: nat, i: int) {
if n := len(x.Data); n > 0 {
if c := addVV(z.Data[i:i+n], z.Data[i:], x.Data); c != 0 {
j := i + n
if j < len(z.Data) {
addVW(z.Data[j:], z.Data[j:], c)
}
}
}
}
func nat.mul(x, y: nat) => nat {
m := len(x.Data)
n := len(y.Data)
switch {
case m < n:
return this.mul(y, x)
case m == 0 || n == 0:
return nat{Data: this.Data[:0]}
case n == 1:
return this.mulAddWW(x, y.Data[0], 0)
}
// m >= n > 1
// determine if z can be reused
if alias(*this, x) || alias(*this, y) {
// 空指针操作
this = nil // z is an alias for x or y - cannot reuse
}
z := this.make(m + n)
basicMul(z, x, y)
return z.norm()
}
func getNat(n: int) => *nat {
r := (&nat{}).make(n)
return &r
}
func putNat(x: *nat) {
// panic("todo")
}
func nat.bitLen() => int {
if i := len(this.Data) - 1; i >= 0 {
return i*_W + bits.Len(uint(this.Data[i]))
}
return 0
}
// bytes writes the value of z into buf using big-endian encoding.
// The value of z is encoded in the slice buf[i:]. If the value of z
// cannot be represented in buf, bytes panics. The number i of unused
// bytes at the beginning of buf is returned as result.
func nat.bytes(buf: []byte) => int {
i := len(buf)
for _, d := range this.Data {
for j := 0; j < _S; j++ {
i--
if i >= 0 {
buf[i] = byte(d)
} else if byte(d) != 0 {
panic("math/big: buffer too small to fit value")
}
d >>= 8
}
}
if i < 0 {
i = 0
}
for i < len(buf) && buf[i] == 0 {
i++
}
return i
}
// bigEndianWord returns the contents of buf interpreted as a big-endian encoded Word value.
func bigEndianWord(buf: []byte) => uint {
if _W == 64 {
return uint(Buf2Uint64(buf))
}
return uint(Buf2Uint32(buf))
}
// setBytes interprets buf as the bytes of a big-endian unsigned
// integer, sets z to that value, and returns z.
func nat.setBytes(buf: []byte) => nat {
z := this.make((len(buf) + _S - 1) / _S)
i := len(buf)
for k := 0; i >= _S; k++ {
z.Data[k] = bigEndianWord(buf[i-_S : i])
i -= _S
}
if i > 0 {
d: uint = 0
for s := uint(0); i > 0; s += 8 {
d |= uint(buf[i-1]) << s
i--
}
z.Data[len(z.Data)-1] = d
}
return z.norm()
}
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
// test好像并不执行该文件夹, 改为导出方法放在外层执行
func Test_Norm {
t := nat{Data: []uint{1, 0, 0, 0}}
t = t.norm()
if len(t.Data) == 1 && t.Data[0] == 1 {
println("NORM TEST PASS!")
} else {
println("NORM TEST FAILED!")
}
}
func Test_setWord {
t := nat{Data: []uint{1, 2, 3, 4}}
z := t.setWord(0)
println("set zero:", len(z.Data))
z = t.setWord(10)
println("set to 10:", z.Data[0], " ", t.Data[0])
}
func Test_set {
t := nat{Data: []uint{1, 2, 3, 4}}
z := t.set(t)
println(len(z.Data) == len(t.Data))
for i := 0; i < len(z.Data); i++ {
println("item:", z.Data[i], "===", t.Data[i])
}
}
// 参考go单元测试的内容
type funNN func(z: nat, x: nat, y: nat) => nat
type argNN struct {
z: nat
x: nat
y: nat
}
var sumNN = []argNN{
{},
{z: nat{[]uint{1}}, x: nat{nil}, y: nat{[]uint{1}}},
{z: nat{[]uint{1111111110}}, x: nat{[]uint{123456789}}, y: nat{[]uint{987654321}}},
{z: nat{[]uint{0, 0, 0, 1}}, x: nat{nil}, y: nat{[]uint{0, 0, 0, 1}}},
{z: nat{[]uint{0, 0, 0, 1111111110}}, x: nat{[]uint{0, 0, 0, 123456789}}, y: nat{Data: []uint{0, 0, 0, 987654321}}},
{z: nat{[]uint{0, 0, 0, 1}}, x: nat{[]uint{0, 0, _M}}, y: nat{[]uint{0, 0, 1}}},
}
var prodNN = []argNN{
{},
{z: nat{nil}, x: nat{nil}, y: nat{nil}},
{z: nat{nil}, x: nat{[]uint{991}}, y: nat{nil}},
{z: nat{[]uint{991}}, x: nat{[]uint{991}}, y: nat{[]uint{1}}},
{z: nat{[]uint{991 * 991}}, x: nat{[]uint{991}}, y: nat{[]uint{991}}},
{z: nat{[]uint{0, 0, 991 * 991}}, x: nat{[]uint{0, 991}}, y: nat{[]uint{0, 991}}},
{z: nat{[]uint{1 * 991, 2 * 991, 3 * 991, 4 * 991}}, x: nat{[]uint{1, 2, 3, 4}}, y: nat{[]uint{991}}},
{z: nat{[]uint{4, 11, 20, 30, 20, 11, 4}}, x: nat{[]uint{1, 2, 3, 4}}, y: nat{[]uint{4, 3, 2, 1}}},
{
z: natFromString("11790184577738583171520872861412518665678211592275841109096961"),
x: natFromString("515377520732011331036461129765621272702107522001"),
y: natFromString("22876792454961"),
},
}
func testAdd(a: argNN) {
temp := &nat{Data: nil}
z := temp.add(a.x, a.y)
if z.cmp(a.z) != 0 {
println("Error for add result")
}
}
func testSub(a: argNN) {
temp := &nat{Data: nil}
z := temp.sub(a.x, a.y)
if z.cmp(a.z) != 0 {
println("Error for sub result")
}
}
func testMul(a: argNN) {
temp := &nat{Data: nil}
z := temp.mul(a.x, a.y)
if z.cmp(a.z) != 0 {
println("Error for mul result")
}
}
func Test_add {
println("start test add")
for _, a := range sumNN {
testAdd(a)
}
}
func Test_sub {
println("start test sub")
for _, a := range sumNN {
arg := argNN{a.x, a.z, a.y}
testSub(arg)
}
}
func Test_mul {
println("start test mul")
for _, a := range prodNN {
arg := a
testMul(arg)
arg = argNN{a.z, a.y, a.x}
testMul(arg)
}
}
func Test_div {
u := natFromString("11790184577738583171520872861412518665678211592275841109096961")
v := natFromString("515377520732011331036461129765621272702107522001")
w := natFromString("22876792454961") // 商
r := natFromString("0") // 余数
q := &nat{nil}
q2, r2 := q.div(nat{nil}, u, v)
if q2.cmp(w) != 0 {
println("wrong div result")
} else {
println("ok div result")
}
if r2.cmp(r) != 0 {
println("wrong div remainder result")
} else {
println("ok div remainder result")
}
}
func Test_setString {
n := natFromString("22876792454961")
for _, i := range n.Data {
println(i)
}
}
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
import "math/bits"
// div returns q, r such that q = ⌊u/v⌋ and r = u%v = u - q·v.
// It uses z and z2 as the storage for q and r.
func nat.div(z2, u, v: nat) => (q: nat, r: nat) {
if len(v.Data) == 0 {
panic("division by zero")
}
if u.cmp(v) < 0 {
q.Data = this.Data[:0]
r = z2.set(u)
return
}
if len(v.Data) == 1 {
// Short division: long optimized for a single-word divisor.
// In that case, the 2-by-1 guess is all we need at each step.
r2: uint
q, r2 = this.divW(u, v.Data[0])
r = z2.setWord(r2)
return
}
q, r = this.divLarge(z2, u, v)
return
}
func nat.divW(x: nat, y: uint) => (q: nat, r: uint) {
m := len(x.Data)
switch {
case y == 0:
panic("division by zero")
case y == 1:
q = this.set(x) // result is x
return
case m == 0:
q.Data = this.Data[:0] // result is 0
return
}
// m > 0
z := this.make(m)
r = divWVW(z.Data, 0, x.Data, y)
q = z.norm()
return
}
// divWVW overwrites z with ⌊x/y⌋, returning the remainder r.
// The caller must ensure that len(z) = len(x).
func divWVW(z: []uint, xn: uint, x: []uint, y: uint) => (r: uint) {
r = xn
if len(x) == 1 {
qq, rr := bits.Div(uint(r), uint(x[0]), uint(y))
z[0] = uint(qq)
return uint(rr)
}
rec := reciprocalWord(y)
for i := len(z) - 1; i >= 0; i-- {
z[i], r = divWW(r, x[i], y, rec)
}
return r
}
// div returns q, r such that q = ⌊uIn/vIn⌋ and r = uIn%vIn = uIn - q·vIn.
// It uses z and u as the storage for q and r.
// The caller must ensure that len(vIn) ≥ 2 (use divW otherwise)
// and that len(uIn) ≥ len(vIn) (the answer is 0, uIn otherwise).
func nat.divLarge(u, uIn, vIn: nat) => (q: nat, r: nat) {
z := *this
n := len(vIn.Data)
m := len(uIn.Data) - n
// Scale the inputs so vIn's top bit is 1 (see “Scaling Inputs” above).
// vIn is treated as a read-only input (it may be in use by another
// goroutine), so we must make a copy.
shift := nlz(vIn.Data[n-1])
vp := getNat(n)
v := *vp
shlVU(v.Data, vIn.Data, shift)
u = u.make(len(uIn.Data) + 1)
u.Data[len(uIn.Data)] = shlVU(u.Data[0:len(uIn.Data)], uIn.Data, shift)
// The caller should not pass aliased z and u, since those are
// the two different outputs, but correct just in case.
if alias(z, u) {
z.Data = nil
}
q = z.make(m + 1)
// Use basic or recursive long division depending on size.
if n < divRecursiveThreshold {
q.divBasic(u, v)
} else {
q.divRecursive(u, v)
}
putNat(vp)
q = q.norm()
// Undo scaling of remainder.
shrVU(u.Data, u.Data, shift)
r = u.norm()
return q, r
}
// divBasic implements long division as described above.
// It overwrites q with ⌊u/v⌋ and overwrites u with the remainder r.
// q must be large enough to hold ⌊u/v⌋.
func nat.divBasic(u, v: nat) {
n := len(v.Data)
m := len(u.Data) - n
qhatvp := getNat(n + 1)
qhatv := *qhatvp
// Set up for divWW below, precomputing reciprocal argument.
vn1 := v.Data[n-1]
rec := reciprocalWord(vn1)
// Compute each digit of quotient.
for j := m; j >= 0; j-- {
// Compute the 2-by-1 guess q̂.
// The first iteration must invent a leading 0 for u.
qhat := uint(_M)
ujn: uint
if j+n < len(u.Data) {
ujn = u.Data[j+n]
}
// ujn ≤ vn1, or else q̂ would be more than one digit.
// For ujn == vn1, we set q̂ to the max digit M above.
// Otherwise, we compute the 2-by-1 guess.
if ujn != vn1 {
rhat: uint
qhat, rhat = divWW(ujn, u.Data[j+n-1], vn1, rec)
// Refine q̂ to a 3-by-2 guess. See “Refining Guesses” above.
vn2 := v.Data[n-2]
x1, x2 := mulWW(qhat, vn2)
ujn2 := u.Data[j+n-2]
for greaterThan(x1, x2, rhat, ujn2) {
qhat--
prevRhat := rhat
rhat += vn1
// If r̂ overflows, then
// r̂ u[j+n-2]v[n-1] is now definitely > x1 x2.
if rhat < prevRhat {
break
}
// TODO(rsc): No need for a full mulWW.
// x2 += vn2; if x2 overflows, x1++
x1, x2 = mulWW(qhat, vn2)
}
}
// Compute q̂·v.
qhatv.Data[n] = mulAddVWW(qhatv.Data[0:n], v.Data, qhat, 0)
qhl := len(qhatv.Data)
if j+qhl > len(u.Data) && qhatv.Data[n] == 0 {
qhl--
}
// Subtract q̂·v from the current section of u.
// If it underflows, q̂·v > u, which we fix up
// by decrementing q̂ and adding v back.
c := subVV(u.Data[j:j+qhl], u.Data[j:], qhatv.Data)
if c != 0 {
c := addVV(u.Data[j:j+n], u.Data[j:], v.Data)
// If n == qhl, the carry from subVV and the carry from addVV
// cancel out and don't affect u[j+n].
if n < qhl {
u.Data[j+n] += c
}
qhat--
}
// Save quotient digit.
// Caller may know the top digit is zero and not leave room for it.
if j == m && m == len(this.Data) && qhat == 0 {
continue
}
this.Data[j] = qhat
}
putNat(qhatvp)
}
// greaterThan reports whether the two digit numbers x1 x2 > y1 y2.
// TODO(rsc): In contradiction to most of this file, x1 is the high
// digit and x2 is the low digit. This should be fixed.
func greaterThan(x1, x2, y1, y2: uint) => bool {
return x1 > y1 || x1 == y1 && x2 > y2
}
// divRecursiveThreshold is the number of divisor digits
// at which point divRecursive is faster than divBasic.
const divRecursiveThreshold = 100
// divRecursive implements recursive division as described above.
// It overwrites z with ⌊u/v⌋ and overwrites u with the remainder r.
// z must be large enough to hold ⌊u/v⌋.
// This function is just for allocating and freeing temporaries
// around divRecursiveStep, the real implementation.
func nat.divRecursive(u, v: nat) {
// Recursion depth is (much) less than 2 log₂(len(v)).
// Allocate a slice of temporaries to be reused across recursion,
// plus one extra temporary not live across the recursion.
recDepth := 2 * bits.Len(uint(len(v.Data)))
tmp := getNat(3 * len(v.Data))
temps := make([]*nat, recDepth)
this.clear()
this.divRecursiveStep(u, v, 0, tmp, temps)
// Free temporaries.
for _, n := range temps {
if n != nil {
putNat(n)
}
}
putNat(tmp)
}
// divRecursiveStep is the actual implementation of recursive division.
// It adds ⌊u/v⌋ to z and overwrites u with the remainder r.
// z must be large enough to hold ⌊u/v⌋.
// It uses temps[depth] (allocating if needed) as a temporary live across
// the recursive call. It also uses tmp, but not live across the recursion.
func nat.divRecursiveStep(u, v: nat, depth: int, tmp: *nat, temps: []*nat) {
// u is a subsection of the original and may have leading zeros.
// TODO(rsc): The v = v.norm() is useless and should be removed.
// We know (and require) that v's top digit is ≥ B/2.
u = u.norm()
v = v.norm()
if len(u.Data) == 0 {
this.clear()
return
}
// Fall back to basic division if the problem is now small enough.
n := len(v.Data)
if n < divRecursiveThreshold {
this.divBasic(u, v)
return
}
// Nothing to do if u is shorter than v (implies u < v).
m := len(u.Data) - n
if m < 0 {
return
}
// We consider B digits in a row as a single wide digit.
// (See “Recursive Division” above.)
//
// TODO(rsc): rename B to Wide, to avoid confusion with _B,
// which is something entirely different.
// TODO(rsc): Look into whether using ⌈n/2⌉ is better than ⌊n/2⌋.
B := n / 2
// Allocate a nat for qhat below.
if temps[depth] == nil {
temps[depth] = getNat(n) // TODO(rsc): Can be just B+1.
} else {
*temps[depth] = temps[depth].make(B + 1)
}
// Compute each wide digit of the quotient.
//
// TODO(rsc): Change the loop to be
// for j := (m+B-1)/B*B; j > 0; j -= B {
// which will make the final step a regular step, letting us
// delete what amounts to an extra copy of the loop body below.
j := m
for j > B {
// Divide u[j-B:j+n] (3 wide digits) by v (2 wide digits).
// First make the 2-by-1-wide-digit guess using a recursive call.
// Then extend the guess to the full 3-by-2 (see “Refining Guesses”).
//
// For the 2-by-1-wide-digit guess, instead of doing 2B-by-B-digit,
// we use a (2B+1)-by-(B+1) digit, which handles the possibility that
// the result has an extra leading 1 digit as well as guaranteeing
// that the computed q̂ will be off by at most 1 instead of 2.
// s is the number of digits to drop from the 3B- and 2B-digit chunks.
// We drop B-1 to be left with 2B+1 and B+1.
s := (B - 1)
// uu is the up-to-3B-digit section of u we are working on.
uu := nat{u.Data[j-B:]}
// Compute the 2-by-1 guess q̂, leaving r̂ in uu[s:B+n].
qhat := *temps[depth]
qhat.clear()
qhat.divRecursiveStep(nat{uu.Data[s : B+n]}, nat{v.Data[s:]}, depth+1, tmp, temps)
qhat = qhat.norm()
// Extend to a 3-by-2 quotient and remainder.
// Because divRecursiveStep overwrote the top part of uu with
// the remainder r̂, the full uu already contains the equivalent
// of r̂·B + uₙ₋₂ from the “Refining Guesses” discussion.
// Subtracting q̂·vₙ₋₂ from it will compute the full-length remainder.
// If that subtraction underflows, q̂·v > u, which we fix up
// by decrementing q̂ and adding v back, same as in long division.
// TODO(rsc): Instead of subtract and fix-up, this code is computing
// q̂·vₙ₋₂ and decrementing q̂ until that product is ≤ u.
// But we can do the subtraction directly, as in the comment above
// and in long division, because we know that q̂ is wrong by at most one.
qhatv := tmp.make(3 * n)
qhatv.clear()
qhatv = qhatv.mul(qhat, nat{v.Data[:s]})
for i := 0; i < 2; i++ {
e := qhatv.cmp(uu.norm())
if e <= 0 {
break
}
subVW(qhat.Data, qhat.Data, 1)
c := subVV(qhatv.Data[:s], qhatv.Data[:s], v.Data[:s])
if len(qhatv.Data) > s {
subVW(qhatv.Data[s:], qhatv.Data[s:], c)
}
addAt(nat{uu.Data[s:]}, nat{v.Data[s:]}, 0)
}
if qhatv.cmp(uu.norm()) > 0 {
panic("impossible")
}
c := subVV(uu.Data[:len(qhatv.Data)], uu.Data[:len(qhatv.Data)], qhatv.Data)
if c > 0 {
subVW(uu.Data[len(qhatv.Data):], uu.Data[len(qhatv.Data):], c)
}
addAt(*this, qhat, j-B)
j -= B
}
// TODO(rsc): Rewrite loop as described above and delete all this code.
// Now u < (v<<B), compute lower bits in the same way.
// Choose shift = B-1 again.
s := B - 1
qhat := *temps[depth]
qhat.clear()
temp_u := &nat{u.Data[s:]}
qhat.divRecursiveStep(temp_u.norm(), nat{v.Data[s:]}, depth+1, tmp, temps)
qhat = qhat.norm()
qhatv := tmp.make(3 * n)
qhatv.clear()
qhatv = qhatv.mul(qhat, nat{v.Data[:s]})
// Set the correct remainder as before.
for i := 0; i < 2; i++ {
if e := qhatv.cmp(u.norm()); e > 0 {
subVW(qhat.Data, qhat.Data, 1)
c := subVV(qhatv.Data[:s], qhatv.Data[:s], v.Data[:s])
if len(qhatv.Data) > s {
subVW(qhatv.Data[s:], qhatv.Data[s:], c)
}
addAt(nat{u.Data[s:]}, nat{v.Data[s:]}, 0)
}
}
if qhatv.cmp(u.norm()) > 0 {
panic("impossible")
}
c := subVV(u.Data[0:len(qhatv.Data)], u.Data[0:len(qhatv.Data)], qhatv.Data)
if c > 0 {
c = subVW(u.Data[len(qhatv.Data):], u.Data[len(qhatv.Data):], c)
}
if c > 0 {
panic("impossible")
}
// Done!
addAt(*this, qhat.norm(), 0)
}
......@@ -384,7 +384,7 @@ func testReverse(x64, want64: u64) {
func TestReverseBytes {
for _, test := range []struct {
x, r uint64
x, r: uint64
}{
{0, 0},
{0x01, 0x01 << 56},
......
......@@ -129,7 +129,7 @@ func TestEncodeRune {
}
}
func _TestDecodeRune {
func TestDecodeRune {
for _, m := range utf8map {
b := []byte(m.str)
r, size := DecodeRune(b)
......@@ -195,6 +195,336 @@ func _TestDecodeRune {
}
}
func TestDecodeSurrogateRune {
for _, m := range surrogateMap {
b := []byte(m.str)
r, size := DecodeRune(b)
if r != RuneError || size != 1 {
assert(false)
//t.Errorf("DecodeRune(%q) = %x, %d want %x, %d", b, r, size, RuneError, 1)
}
s := m.str
r, size = DecodeRuneInString(s)
if r != RuneError || size != 1 {
assert(false)
//t.Errorf("DecodeRuneInString(%q) = %x, %d want %x, %d", b, r, size, RuneError, 1)
}
}
}
// Check that a range loop, len([]rune(string)) optimization and
// []rune conversions visit the same runes.
// Not really a test of this package, but the assumption is used here and
// it's good to verify.
func TestRuntimeConversion {
/*
for _, ts := range testStrings {
count := RuneCountInString(ts)
if n := runtimeRuneCount(ts); n != count {
assert(false)
//t.Errorf("%q: len([]rune()) counted %d runes; got %d from RuneCountInString", ts, n, count)
//break
}
runes := []rune(ts)
if n := len(runes); n != count {
assert(false)
//t.Errorf("%q: []rune() has length %d; got %d from RuneCountInString", ts, n, count)
//break
}
i := 0
for _, r := range ts {
if r != runes[i] {
assert(false)
//t.Errorf("%q[%d]: expected %c (%U); got %c (%U)", ts, i, runes[i], runes[i], r, r)
}
i++
}
}
*/
}
global invalidSequenceTests = []string{
"\xed\xa0\x80\x80", // surrogate min
"\xed\xbf\xbf\x80", // surrogate max
// xx
"\x91\x80\x80\x80",
// s1
"\xC2\x7F\x80\x80",
"\xC2\xC0\x80\x80",
"\xDF\x7F\x80\x80",
"\xDF\xC0\x80\x80",
// s2
"\xE0\x9F\xBF\x80",
"\xE0\xA0\x7F\x80",
"\xE0\xBF\xC0\x80",
"\xE0\xC0\x80\x80",
// s3
"\xE1\x7F\xBF\x80",
"\xE1\x80\x7F\x80",
"\xE1\xBF\xC0\x80",
"\xE1\xC0\x80\x80",
//s4
"\xED\x7F\xBF\x80",
"\xED\x80\x7F\x80",
"\xED\x9F\xC0\x80",
"\xED\xA0\x80\x80",
// s5
"\xF0\x8F\xBF\xBF",
"\xF0\x90\x7F\xBF",
"\xF0\x90\x80\x7F",
"\xF0\xBF\xBF\xC0",
"\xF0\xBF\xC0\x80",
"\xF0\xC0\x80\x80",
// s6
"\xF1\x7F\xBF\xBF",
"\xF1\x80\x7F\xBF",
"\xF1\x80\x80\x7F",
"\xF1\xBF\xBF\xC0",
"\xF1\xBF\xC0\x80",
"\xF1\xC0\x80\x80",
// s7
"\xF4\x7F\xBF\xBF",
"\xF4\x80\x7F\xBF",
"\xF4\x80\x80\x7F",
"\xF4\x8F\xBF\xC0",
"\xF4\x8F\xC0\x80",
"\xF4\x90\x80\x80",
}
func TestDecodeInvalidSequence {
for _, s := range invalidSequenceTests {
r1, _ := DecodeRune([]byte(s))
if want := RuneError; r1 != want {
assert(false)
//t.Errorf("DecodeRune(%#x) = %#04x, want %#04x", s, r1, want)
//return
}
r2, _ := DecodeRuneInString(s)
if want := RuneError; r2 != want {
assert(false)
//t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s, r2, want)
//return
}
if r1 != r2 {
assert(false)
//t.Errorf("DecodeRune(%#x) = %#04x mismatch with DecodeRuneInString(%q) = %#04x", s, r1, s, r2)
//return
}
//r3 := runtimeDecodeRune(s)
//if r2 != r3 {
// t.Errorf("DecodeRuneInString(%q) = %#04x mismatch with runtime.decoderune(%q) = %#04x", s, r2, s, r3)
// return
//}
}
}
func testSequence(s: string) {
/*
type info struct {
index: int
r: rune
}
index := make([]info, len(s))
b := []byte(s)
si := 0
j := 0
for i, r := range s {
if si != i {
t.Errorf("Sequence(%q) mismatched index %d, want %d", s, si, i)
return
}
index[j] = info{i, r}
j++
r1, size1 := DecodeRune(b[i:])
if r != r1 {
t.Errorf("DecodeRune(%q) = %#04x, want %#04x", s[i:], r1, r)
return
}
r2, size2 := DecodeRuneInString(s[i:])
if r != r2 {
t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s[i:], r2, r)
return
}
if size1 != size2 {
t.Errorf("DecodeRune/DecodeRuneInString(%q) size mismatch %d/%d", s[i:], size1, size2)
return
}
si += size1
}
j--
for si = len(s); si > 0; {
r1, size1 := DecodeLastRune(b[0:si])
r2, size2 := DecodeLastRuneInString(s[0:si])
if size1 != size2 {
t.Errorf("DecodeLastRune/DecodeLastRuneInString(%q, %d) size mismatch %d/%d", s, si, size1, size2)
return
}
if r1 != index[j].r {
t.Errorf("DecodeLastRune(%q, %d) = %#04x, want %#04x", s, si, r1, index[j].r)
return
}
if r2 != index[j].r {
t.Errorf("DecodeLastRuneInString(%q, %d) = %#04x, want %#04x", s, si, r2, index[j].r)
return
}
si -= size1
if si != index[j].index {
t.Errorf("DecodeLastRune(%q) index mismatch at %d, want %d", s, si, index[j].index)
return
}
j--
}
if si != 0 {
t.Errorf("DecodeLastRune(%q) finished at %d, not 0", s, si)
}
*/
}
// Check that negative runes encode as U+FFFD.
func TestNegativeRune {
errorbuf := make([]byte, UTFMax)
errorbuf = errorbuf[0:EncodeRune(errorbuf, RuneError)]
buf := make([]byte, UTFMax)
buf = buf[0:EncodeRune(buf, -1)]
if !bytes_Equal(buf, errorbuf) {
assert(false)
//t.Errorf("incorrect encoding [% x] for -1; expected [% x]", buf, errorbuf)
}
}
type RuneCountTest struct {
in: string
out: int
}
global runecounttests = []RuneCountTest{
{"abcd", 4},
{"☺☻☹", 3},
{"1,2,3,4", 7},
{"\xe2\x00", 2},
{"\xe2\x80", 2},
{"a\xe2\x80", 3},
}
func TestRuneCount {
for _, tt := range runecounttests {
if out := RuneCountInString(tt.in); out != tt.out {
assert(false)
//t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
}
if out := RuneCount([]byte(tt.in)); out != tt.out {
assert(false)
//t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out)
}
}
}
type RuneLenTest struct {
r: rune
size: int
}
global runelentests = []RuneLenTest{
{0, 1},
{'e', 1},
{'é', 2},
{'☺', 3},
{RuneError, 3},
{MaxRune, 4},
{0xD800, -1},
{0xDFFF, -1},
{MaxRune + 1, -1},
{-1, -1},
}
func TestRuneLen {
for _, tt := range runelentests {
if size := RuneLen(tt.r); size != tt.size {
assert(false)
//t.Errorf("RuneLen(%#U) = %d, want %d", tt.r, size, tt.size)
}
}
}
type ValidTest struct {
in: string
out: bool
}
global validTests = []ValidTest{
{"", true},
{"a", true},
{"abc", true},
{"Ж", true},
{"ЖЖ", true},
{"брэд-ЛГТМ", true},
{"☺☻☹", true},
{"aa\xe2", false},
{string([]byte{66, 250}), false},
{string([]byte{66, 250, 67}), false},
{"a\uFFFDb", true},
{string("\xF4\x8F\xBF\xBF"), true}, // U+10FFFF
{string("\xF4\x90\x80\x80"), false}, // U+10FFFF+1; out of range
{string("\xF7\xBF\xBF\xBF"), false}, // 0x1FFFFF; out of range
{string("\xFB\xBF\xBF\xBF\xBF"), false}, // 0x3FFFFFF; out of range
{string("\xc0\x80"), false}, // U+0000 encoded in two bytes: incorrect
{string("\xed\xa0\x80"), false}, // U+D800 high surrogate (sic)
{string("\xed\xbf\xbf"), false}, // U+DFFF low surrogate (sic)
}
func TestValid {
for _, tt := range validTests {
if Valid([]byte(tt.in)) != tt.out {
assert(false)
//t.Errorf("Valid(%q) = %v; want %v", tt.in, !tt.out, tt.out)
}
if ValidString(tt.in) != tt.out {
assert(false)
//t.Errorf("ValidString(%q) = %v; want %v", tt.in, !tt.out, tt.out)
}
}
}
type ValidRuneTest struct {
r: rune
ok: bool
}
global validrunetests = []ValidRuneTest{
{0, true},
{'e', true},
{'é', true},
{'☺', true},
{RuneError, true},
{MaxRune, true},
{0xD7FF, true},
{0xD800, false},
{0xDFFF, false},
{0xE000, true},
{MaxRune + 1, false},
{-1, false},
}
func TestValidRune {
for _, tt := range validrunetests {
if ok := ValidRune(tt.r); ok != tt.ok {
assert(false)
//t.Errorf("ValidRune(%#U) = %t, want %t", tt.r, ok, tt.ok)
}
}
}
func bytes_Equal(a, b: []byte) => bool {
// Neither cmd/compile nor gccgo allocates for these string conversions.
return string(a) == string(b)
......
......@@ -118,6 +118,7 @@ var stdPkgs = []string{
"image/color/palette",
"io",
"math",
"math/big",
"math/bits",
"os",
"reflect",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册