1
0
mirror of https://github.com/fumiama/go-base16384.git synced 2026-06-23 20:50:41 +08:00

fix: encoder/decoder

This commit is contained in:
源文雨
2025-10-27 22:26:01 +08:00
parent d548cdd86f
commit 2840c604c1
7 changed files with 240 additions and 87 deletions

View File

@@ -3,6 +3,7 @@ package base14
import (
"bytes"
"encoding/hex"
"errors"
"io"
"math/rand"
"testing"
@@ -31,85 +32,69 @@ func TestBase14(t *testing.T) {
}
func TestEncoder(t *testing.T) {
buf := make([]byte, 1024*1024+1)
buf := make([]byte, 4096+1)
_, err := rand.Read(buf)
if err != nil {
t.Fatal(err)
}
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+1))
for i := 0; i <= 1024*1024; i += rand.Intn(128) * 7 {
e := NewEncoder(bytes.NewReader(buf[:i]))
_, err = io.Copy(w, e)
w := bytes.NewBuffer(make([]byte, 0, 4096+1))
for i := 0; i <= 4096; i++ {
e := NewEncoder(w)
_, err = io.Copy(e, bytes.NewReader(buf[:i]))
if err != nil {
t.Fatal(err)
}
_ = e.Close()
if !bytes.Equal(Encode(buf[:i]), w.Bytes()) {
t.Fail()
}
w.Reset()
}
}
func TestBufferedEncoder(t *testing.T) {
buf := make([]byte, 1024*1024+1)
_, err := rand.Read(buf)
if err != nil {
t.Fatal(err)
}
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+1))
for i := 0; i <= 1024*1024; i += rand.Intn(128) * 7 {
e := NewBufferedEncoder(buf[:i])
_, err = io.Copy(w, e)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(Encode(buf[:i]), w.Bytes()) {
t.Fail()
t.Log("expect", hex.EncodeToString(Encode(buf[:i])))
t.Log("butgot", hex.EncodeToString(w.Bytes()))
t.Fatal("unexpected at index", i)
}
w.Reset()
}
}
func TestDecoder(t *testing.T) {
buf := make([]byte, 1024*1024+1)
buf := make([]byte, 4096+1)
_, err := rand.Read(buf)
if err != nil {
t.Fatal(err)
}
encd := Encode(buf)
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+1))
for i := 0; i <= 1024*1024; i += rand.Intn(128) * 8 {
d := NewDecoder(bytes.NewReader(encd[:i]))
w := bytes.NewBuffer(make([]byte, 0, 4096+1))
for i := 0; i <= 4096; i++ {
d := NewDecoder(bytes.NewReader(Encode(buf[:i])))
_, err = io.Copy(w, d)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf[:i/8*7], w.Bytes()) {
if !bytes.Equal(buf[:i], w.Bytes()) {
t.Fail()
}
w.Reset()
}
}
func TestBufferedDecoder(t *testing.T) {
buf := make([]byte, 1024*1024+1)
_, err := rand.Read(buf)
if err != nil {
t.Fatal(err)
//go:nosplit
func encodeToGeneric(b, encd []byte) (int, error) {
outlen := len(b) / 7 * 8
offset := len(b) % 7
switch offset { //算上偏移标志字符占用的2字节
case 0:
break
case 1:
outlen += 4
case 2, 3:
outlen += 6
case 4, 5:
outlen += 8
case 6:
outlen += 10
}
encd := Encode(buf)
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+1))
for i := 0; i <= 1024*1024; i += rand.Intn(128) * 8 {
d := NewBufferedDecoder(encd[:i])
_, err = io.Copy(w, d)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf[:i/8*7], w.Bytes()) {
t.Fail()
}
w.Reset()
if len(encd) < outlen {
return 0, errors.New("encd too small")
}
encodeGeneric(offset, outlen, b, encd)
return outlen, nil
}
func benchEncode(b *testing.B, data []byte) {
@@ -125,6 +110,46 @@ func benchEncode(b *testing.B, data []byte) {
}
}
func benchEncodeGeneric(b *testing.B, data []byte) {
_, err := rand.Read(data)
if err != nil {
panic(err)
}
buf := make([]byte, EncodeLen(len(data)))
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = encodeToGeneric(data, buf)
}
}
//go:nosplit
func decodeToGeneric(b []byte, decd []byte) (int, error) {
outlen := len(b)
offset := 0
if b[len(b)-2] == '=' {
offset = int(b[len(b)-1])
switch offset { //算上偏移标志字符占用的2字节
case 0:
break
case 1:
outlen -= 4
case 2, 3:
outlen -= 6
case 4, 5:
outlen -= 8
case 6:
outlen -= 10
}
}
outlen = outlen/8*7 + offset
if len(decd) < outlen {
return 0, errors.New("decd too small")
}
decodeGeneric(offset, outlen, b, decd)
return outlen, nil
}
func benchDecode(b *testing.B, data []byte) {
_, err := rand.Read(data)
if err != nil {
@@ -142,6 +167,23 @@ func benchDecode(b *testing.B, data []byte) {
}
}
func benchDecodeGeneric(b *testing.B, data []byte) {
_, err := rand.Read(data)
if err != nil {
panic(err)
}
buf := make([]byte, EncodeLen(len(data)))
_, err = encodeToGeneric(data, buf)
if err != nil {
panic(err)
}
b.SetBytes(int64(len(buf)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = decodeToGeneric(buf, data)
}
}
func BenchmarkEncodeTo(b *testing.B) {
b.Run("16", func(b *testing.B) {
data := make([]byte, 16)
@@ -161,6 +203,25 @@ func BenchmarkEncodeTo(b *testing.B) {
})
}
func BenchmarkEncodeToGeneric(b *testing.B) {
b.Run("16", func(b *testing.B) {
data := make([]byte, 16)
benchEncodeGeneric(b, data)
})
b.Run("256", func(b *testing.B) {
data := make([]byte, 256)
benchEncodeGeneric(b, data)
})
b.Run("4K", func(b *testing.B) {
data := make([]byte, 1024*4)
benchEncodeGeneric(b, data)
})
b.Run("32K", func(b *testing.B) {
data := make([]byte, 1024*32)
benchEncodeGeneric(b, data)
})
}
func BenchmarkDecodeTo(b *testing.B) {
b.Run("16", func(b *testing.B) {
data := make([]byte, 16)
@@ -180,21 +241,42 @@ func BenchmarkDecodeTo(b *testing.B) {
})
}
func BenchmarkDecodeToGeneric(b *testing.B) {
b.Run("16", func(b *testing.B) {
data := make([]byte, 16)
benchDecodeGeneric(b, data)
})
b.Run("256", func(b *testing.B) {
data := make([]byte, 256)
benchDecodeGeneric(b, data)
})
b.Run("4K", func(b *testing.B) {
data := make([]byte, 4096)
benchDecodeGeneric(b, data)
})
b.Run("32K", func(b *testing.B) {
data := make([]byte, 1024*32)
benchDecodeGeneric(b, data)
})
}
func benchEncoder(b *testing.B, cnt int64) {
enc := NewEncoder(rand.New(rand.NewSource(0)))
s := rand.New(rand.NewSource(0))
buf := bytes.NewBuffer(make([]byte, 0, cnt))
enc := NewEncoder(buf)
b.SetBytes(cnt)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = io.CopyN(buf, enc, cnt)
_, _ = io.CopyN(enc, s, cnt)
buf.Reset()
}
}
func benchDecoder(b *testing.B, cnt int64) {
enc := NewEncoder(rand.New(rand.NewSource(0)))
s := rand.New(rand.NewSource(0))
buf := bytes.NewBuffer(make([]byte, 0, cnt))
_, err := io.CopyN(buf, enc, cnt)
enc := NewEncoder(buf)
_, err := io.CopyN(enc, s, cnt)
if err != nil {
panic(err)
}