1
0
mirror of https://github.com/fumiama/unibase2n.git synced 2026-06-05 00:32:47 +08:00

complete all encode & unit test

This commit is contained in:
源文雨
2022-10-01 14:53:17 +08:00
parent a68a04bbe9
commit 08228b7a61
10 changed files with 449 additions and 66 deletions

View File

@@ -1,9 +1,5 @@
package unibase2n
func (bs Base) Encode(data []byte) []byte {
return nil
}
func (bs Base) Decode(data []byte) []byte {
return nil
}

View File

@@ -15,11 +15,11 @@ var (
// Base64 箭頭 Arrows
Base64, _ = NewBase(0x2190, 0x21d0, 6)
// Base64Gua 六十四卦 YiJing Hexagram Symbols
Base64Gua, _ = NewBase(0x3400, 0x262f, 6)
Base64Gua, _ = NewBase(0x4dc0, 0x262f, 6)
// Base32 方塊元素 Block Elements
Base32, _ = NewBase(0x2580, 0x259f, 5)
// Base16 漢文訓讀點 Kanbun Kundoku Den
Base16, _ = NewBase(0x3190, 0, 4)
// Base8 八卦 YiJing Hexagram Symbols
Base8, _ = NewBase(0x2630, 0x2689, 3)
// Base8Gua 八卦 YiJing Hexagram Symbols
Base8Gua, _ = NewBase(0x2630, 0x2689, 3)
)

212
encode.go Normal file
View File

@@ -0,0 +1,212 @@
package unibase2n
import (
"encoding/binary"
)
// Encode data to base2n
func (bs Base) Encode(data []byte) (out []byte) {
outlen, offset := bs.EncodeLen(len(data))
if outlen <= 0 || offset < 0 {
return nil
}
out = make([]byte, outlen)
switch bs.bit {
case 3, 5, 7, 9, 11, 13, 15:
mask64 := uint64(bs.off) | uint64(bs.off)<<16 | uint64(bs.off)<<32 | uint64(bs.off)<<48
mask := uint128be{a: mask64, b: mask64}
enc128blk(mask, bs.bit, data, out)
case 6, 10, 12, 14:
mask := uint64(bs.off) | uint64(bs.off)<<16 | uint64(bs.off)<<32 | uint64(bs.off)<<48
enc64blk(mask, bs.bit, data, out)
case 8:
enc16blk8(bs.off, data, out)
case 4:
mask := uint32(bs.off) | uint32(bs.off)<<16
enc32blk4(mask, data, out)
case 2:
mask := uint64(bs.off) | uint64(bs.off)<<16 | uint64(bs.off)<<32 | uint64(bs.off)<<48
enc64blk2(mask, data, out)
case 1:
enc16blk1(bs.off, data, out)
}
if offset > 0 {
binary.BigEndian.PutUint16(out[outlen-2:outlen], bs.til+uint16(offset))
}
return
}
// enc16blk1 for bit 1 (actual enc128blk1)
// len(in)!=0, len(out)==len(in)*16
func enc16blk1(mask uint16, in, out []byte) {
for i, n := range in {
c := i * 16
binary.BigEndian.PutUint16(out[c:c+2], uint16(n>>7)+mask)
binary.BigEndian.PutUint16(out[c+2:c+4], uint16(n>>6&1)+mask)
binary.BigEndian.PutUint16(out[c+4:c+6], uint16(n>>5&1)+mask)
binary.BigEndian.PutUint16(out[c+6:c+8], uint16(n>>4&1)+mask)
binary.BigEndian.PutUint16(out[c+8:c+10], uint16(n>>3&1)+mask)
binary.BigEndian.PutUint16(out[c+10:c+12], uint16(n>>2&1)+mask)
binary.BigEndian.PutUint16(out[c+12:c+14], uint16(n>>1&1)+mask)
binary.BigEndian.PutUint16(out[c+14:c+16], uint16(n&1)+mask)
}
}
// enc64blk2 for bit 2
// len(in)!=0, len(out)==len(in)*8
func enc64blk2(mask uint64, in, out []byte) {
for i, n := range in {
c := i * 8
x := (uint64(n)<<42 | uint64(n)<<28 | uint64(n)<<14 | uint64(n)) & 0x30003_00030003
binary.BigEndian.PutUint64(out[c:c+8], x+mask)
}
}
// enc32blk4 for bit 4
// len(in)!=0, len(out)==len(in)*4
func enc32blk4(mask uint32, in, out []byte) {
for i, n := range in {
c := i * 4
x := (uint32(n)<<12 | uint32(n)) & 0xf000f
binary.BigEndian.PutUint32(out[c:c+4], x+mask)
}
}
// enc16blk8 for bit 8
// len(in)!=0, len(out)==len(in)*2
func enc16blk8(mask uint16, in, out []byte) {
for i, n := range in {
c := i * 2
binary.BigEndian.PutUint16(out[c:c+2], uint16(n)+mask)
}
}
// enc128blk for bit 3 5 6 7 9 11 13 15
// len(in)>0, len(out)==len(in)/bit*16
func enc128blk(mask uint128be, bit uint8, in, out []byte) {
// 由于最后一次处理有读取越界, 因此作扩展
var buf [16]byte
last := 0
if len(in)%int(bit) == 0 {
last = len(in) - int(bit)
} else {
last = len(in) / int(bit) * int(bit)
}
copy(buf[:], in[last:])
n := 0
c := 16 - bit
for i := 0; i < last; i += int(bit) {
m := uint128be{a: (uint64(1)<<bit - 1) << 48}
shift := readuint128be(in[i:])
shift.shreq(c)
sum := shift.and(m)
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
sum.addeq(mask)
sum.write(out[n : n+16])
n += 16
}
// 最后一次
m := uint128be{a: (uint64(1)<<bit - 1) << 48}
shift := readuint128be(buf[:])
shift.shreq(c)
sum := shift.and(m)
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
shift.shreq(c)
m.shreq(16)
sum.oreq(shift.and(m))
sum.addeq(mask)
sum.write(buf[:])
copy(out[n:], buf[:])
}
// enc64blk for bit 6 10 12 14
// len(in)>0, len(out)==len(in)/bit*16
func enc64blk(mask uint64, bit uint8, in, out []byte) {
// 由于最后一次处理有读取越界, 因此作扩展
var buf [8]byte
s := int(bit) >> 1
last := 0
if len(in)%s == 0 {
last = len(in) - s
} else {
last = len(in) / s * s
}
copy(buf[:], in[last:])
n := 0
c := 16 - bit
for i := 0; i < last; i += s {
m := (uint64(1)<<bit - 1) << 48
b := in[i:]
if len(b) < 8 {
b = append(b, make([]byte, 8-len(b))...)
}
shift := binary.BigEndian.Uint64(b) >> c
sum := shift
sum &= m
m >>= 16
shift >>= c
sum |= shift & m
m >>= 16
shift >>= c
sum |= shift & m
m >>= 16
shift >>= c
sum |= shift & m
sum += mask
binary.BigEndian.PutUint64(out[n:], sum)
n += 8
}
m := (uint64(1)<<bit - 1) << 48
shift := binary.BigEndian.Uint64(buf[:]) >> c
sum := shift
sum &= m
m >>= 16
shift >>= c
sum |= shift & m
m >>= 16
shift >>= c
sum |= shift & m
m >>= 16
shift >>= c
sum |= shift & m
sum += mask
binary.BigEndian.PutUint64(buf[:], sum)
copy(out[n:], buf[:])
}

147
encode_test.go Normal file
View File

@@ -0,0 +1,147 @@
package unibase2n
import (
"math/rand"
"testing"
base14 "github.com/fumiama/go-base16384"
"github.com/stretchr/testify/assert"
)
func TestEncodeBase16384(t *testing.T) {
var buf [4096]byte
_, err := rand.Read(buf[:])
if err != nil {
t.Fatal(err)
}
for i := 1; i <= 4096; i++ {
if !assert.Equal(t, base14.Encode(buf[:i]), Base16384.Encode(buf[:i])) {
t.Fatal("expect:", base14.EncodeToString(buf[:i]), "actual:", Base16384.EncodeToString(buf[:i]))
}
}
}
func TestEncodeBase8192(t *testing.T) {
assert.Equal(t, "눠찁", Base8192.EncodeString("1"))
assert.Equal(t, "눦됀찂", Base8192.EncodeString("12"))
assert.Equal(t, "눦듌찃", Base8192.EncodeString("123"))
assert.Equal(t, "눦듌였찄", Base8192.EncodeString("1234"))
assert.Equal(t, "눦듌옚밀찅", Base8192.EncodeString("12345"))
assert.Equal(t, "눦듌옚뽠찆", Base8192.EncodeString("123456"))
assert.Equal(t, "눦듌옚뽣먀찇", Base8192.EncodeString("1234567"))
assert.Equal(t, "눦듌옚뽣며찈", Base8192.EncodeString("12345678"))
assert.Equal(t, "눦듌옚뽣며멀찉", Base8192.EncodeString("123456789"))
assert.Equal(t, "눦듌옚뽣며멌가찊", Base8192.EncodeString("1234567890"))
assert.Equal(t, "눦듌옚뽣며멌궈찋", Base8192.EncodeString("12345678901"))
if !assert.Equal(t, "눦듌옚뽣며멌궉븀찌", Base8192.EncodeString("123456789012")) {
t.Fatal("123456789012")
}
if !assert.Equal(t, "눦듌옚뽣며멌궉븳", Base8192.EncodeString("1234567890123")) {
t.Fatal("1234567890123")
}
if !assert.Equal(t, "눦듌옚뽣며멌궉븳늀찁", Base8192.EncodeString("12345678901234")) {
t.Fatal("12345678901234")
}
}
func TestEncodeBase256(t *testing.T) {
assert.Equal(t, "ᄱ", Base256.EncodeString("1"))
assert.Equal(t, "ᄱᄲ", Base256.EncodeString("12"))
assert.Equal(t, "ᄱᄲᄳ", Base256.EncodeString("123"))
assert.Equal(t, "ᄱᄲᄳᄴ", Base256.EncodeString("1234"))
assert.Equal(t, "ᄱᄲᄳᄴᄵ", Base256.EncodeString("12345"))
assert.Equal(t, "ᄱᄲᄳᄴᄵᄶ", Base256.EncodeString("123456"))
assert.Equal(t, "ᄱᄲᄳᄴᄵᄶᄷ", Base256.EncodeString("1234567"))
assert.Equal(t, "ᄱᄲᄳᄴᄵᄶᄷᄸ", Base256.EncodeString("12345678"))
assert.Equal(t, "ᄱᄲᄳᄴᄵᄶᄷᄸᄹ", Base256.EncodeString("123456789"))
assert.Equal(t, "ᄱᄲᄳᄴᄵᄶᄷᄸᄹᄰ", Base256.EncodeString("1234567890"))
assert.Equal(t, "ᄱᄲᄳᄴᄵᄶᄷᄸᄹᄰᄱ", Base256.EncodeString("12345678901"))
if !assert.Equal(t, "ᄱᄲᄳᄴᄵᄶᄷᄸᄹᄰᄱᄲ", Base256.EncodeString("123456789012")) {
t.Fatal("123456789012")
}
if !assert.Equal(t, "ᄱᄲᄳᄴᄵᄶᄷᄸᄹᄰᄱᄲᄳ", Base256.EncodeString("1234567890123")) {
t.Fatal("1234567890123")
}
if !assert.Equal(t, "ᄱᄲᄳᄴᄵᄶᄷᄸᄹᄰᄱᄲᄳᄴ", Base256.EncodeString("12345678901234")) {
t.Fatal("12345678901234")
}
}
func TestEncodeBase128(t *testing.T) {
assert.Equal(t, "⑸⒠⓵", Base128.EncodeString("1"))
assert.Equal(t, "⑸⒬⒠⓶", Base128.EncodeString("12"))
assert.Equal(t, "⑸⒬⒦⒐⓷", Base128.EncodeString("123"))
assert.Equal(t, "⑸⒬⒦⒓⒀⓸", Base128.EncodeString("1234"))
assert.Equal(t, "⑸⒬⒦⒓⒁⒴⓹", Base128.EncodeString("12345"))
assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⓺", Base128.EncodeString("123456"))
assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⒗", Base128.EncodeString("1234567"))
assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⒗⑼①⓵", Base128.EncodeString("12345678"))
assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⒗⑼⑮⒀⓶", Base128.EncodeString("123456789"))
assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⒗⑼⑮⒆①⓷", Base128.EncodeString("1234567890"))
assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⒗⑼⑮⒆④⑨⓸", Base128.EncodeString("12345678901"))
if !assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⒗⑼⑮⒆④⑩⒨⓹", Base128.EncodeString("123456789012")) {
t.Fatal("123456789012")
}
if !assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⒗⑼⑮⒆④⑩⒨Ⓠ⓺", Base128.EncodeString("1234567890123")) {
t.Fatal("1234567890123")
}
if !assert.Equal(t, "⑸⒬⒦⒓⒁⒴Ⓦ⒗⑼⑮⒆④⑩⒨Ⓠ⒔", Base128.EncodeString("12345678901234")) {
t.Fatal("12345678901234")
}
}
func TestEncodeBase64Gua(t *testing.T) {
assert.Equal(t, "䷌䷐☰", Base64Gua.EncodeString("1"))
assert.Equal(t, "䷌䷓䷈☱", Base64Gua.EncodeString("12"))
assert.Equal(t, "䷌䷓䷈䷳", Base64Gua.EncodeString("123"))
assert.Equal(t, "䷌䷓䷈䷳䷍䷀☰", Base64Gua.EncodeString("1234"))
assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔☱", Base64Gua.EncodeString("12345"))
assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶", Base64Gua.EncodeString("123456"))
assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶䷍䷰☰", Base64Gua.EncodeString("1234567"))
assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶䷍䷳䷠☱", Base64Gua.EncodeString("12345678"))
assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶䷍䷳䷠䷹", Base64Gua.EncodeString("123456789"))
assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶䷍䷳䷠䷹䷌䷀☰", Base64Gua.EncodeString("1234567890"))
assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶䷍䷳䷠䷹䷌䷃䷄☱", Base64Gua.EncodeString("12345678901"))
if !assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶䷍䷳䷠䷹䷌䷃䷄䷲", Base64Gua.EncodeString("123456789012")) {
t.Fatal("123456789012")
}
if !assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶䷍䷳䷠䷹䷌䷃䷄䷲䷌䷰☰", Base64Gua.EncodeString("1234567890123")) {
t.Fatal("1234567890123")
}
if !assert.Equal(t, "䷌䷓䷈䷳䷍䷃䷔䷶䷍䷳䷠䷹䷌䷃䷄䷲䷌䷳䷐☱", Base64Gua.EncodeString("12345678901234")) {
t.Fatal("12345678901234")
}
}
func TestEncodeBase32(t *testing.T) {
assert.Equal(t, "▆▄■", Base32.EncodeString("1"))
assert.Equal(t, "▆▄▙▀□", Base32.EncodeString("12"))
assert.Equal(t, "▆▄▙▃▆▢", Base32.EncodeString("123"))
assert.Equal(t, "▆▄▙▃▆▍▀▣", Base32.EncodeString("1234"))
assert.Equal(t, "▆▄▙▃▆▍▁▕", Base32.EncodeString("12345"))
assert.Equal(t, "▆▄▙▃▆▍▁▕▆▘■", Base32.EncodeString("123456"))
assert.Equal(t, "▆▄▙▃▆▍▁▕▆▘▛▐□", Base32.EncodeString("1234567"))
assert.Equal(t, "▆▄▙▃▆▍▁▕▆▘▛▓▐▢", Base32.EncodeString("12345678"))
assert.Equal(t, "▆▄▙▃▆▍▁▕▆▘▛▓▐▎█▣", Base32.EncodeString("123456789"))
}
func TestEncodeBase16(t *testing.T) {
assert.Equal(t, "㆓㆑", Base16.EncodeString("1"))
assert.Equal(t, "㆓㆑㆓㆒", Base16.EncodeString("12"))
assert.Equal(t, "㆓㆑㆓㆒㆓㆓", Base16.EncodeString("123"))
assert.Equal(t, "㆓㆑㆓㆒㆓㆓㆓㆔", Base16.EncodeString("1234"))
assert.Equal(t, "㆓㆑㆓㆒㆓㆓㆓㆔㆓㆕", Base16.EncodeString("12345"))
assert.Equal(t, "㆓㆑㆓㆒㆓㆓㆓㆔㆓㆕㆓㆖", Base16.EncodeString("123456"))
assert.Equal(t, "㆓㆑㆓㆒㆓㆓㆓㆔㆓㆕㆓㆖㆓㆗", Base16.EncodeString("1234567"))
assert.Equal(t, "㆓㆑㆓㆒㆓㆓㆓㆔㆓㆕㆓㆖㆓㆗㆓㆘", Base16.EncodeString("12345678"))
assert.Equal(t, "㆓㆑㆓㆒㆓㆓㆓㆔㆓㆕㆓㆖㆓㆗㆓㆘㆓㆙", Base16.EncodeString("123456789"))
}
func TestEncodeBase8Gua(t *testing.T) {
assert.Equal(t, "☱☴☲⚊", Base8Gua.EncodeString("1"))
assert.Equal(t, "☱☴☲☳☱☰⚋", Base8Gua.EncodeString("12"))
assert.Equal(t, "☱☴☲☳☱☰☶☳", Base8Gua.EncodeString("123"))
assert.Equal(t, "☱☴☲☳☱☰☶☳☱☵☰⚊", Base8Gua.EncodeString("1234"))
assert.Equal(t, "☱☴☲☳☱☰☶☳☱☵☰☳☲☴⚋", Base8Gua.EncodeString("12345"))
assert.Equal(t, "☱☴☲☳☱☰☶☳☱☵☰☳☲☴☶☶", Base8Gua.EncodeString("123456"))
}

1
go.mod
View File

@@ -3,6 +3,7 @@ module github.com/fumiama/unibase2n
go 1.18
require (
github.com/fumiama/go-base16384 v1.6.1
github.com/stretchr/testify v1.8.0
golang.org/x/text v0.3.7
)

3
go.sum
View File

@@ -1,6 +1,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fumiama/go-base16384 v1.6.1 h1:4yb4JgmBJDnQtq3XGXXdLrVwEnRpjhMUt4eAcsNeA30=
github.com/fumiama/go-base16384 v1.6.1/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -10,6 +12,7 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

49
len.go
View File

@@ -13,29 +13,9 @@ func (bs Base) EncodeLen(in int) (out, offset int) {
if bits.OnesCount8(bs.bit) == 1 { // 2的幂永无offset (1/2/4/8)
return in << powtab[bs.bit], 0
}
if bs.bit == 6 { // 特判 (6) 3*8=4*6
out = in / 3 * 4 * 2
offset = in % 3
if offset == 0 {
return
}
// 8 = 6+2, 16 = 6+6+4, 再加结尾指示字符
out += (offset + 1 + 1) * 2
return
}
if bs.bit < 8 { // (3/5/7)
out = in / int(bs.bit) * 8 * 2
offset = in % int(bs.bit)
if offset == 0 {
return
}
remain := offset * 8
out += (remain/int(bs.bit) + 1 + 1) * 2
return
}
if bs.bit%2 == 0 { // bit 大于8且可被2整除 (10/12/14)
if bs.bit%2 == 0 { // bit 可被2整除, 64blk (6/10/12/14)
hb := int(bs.bit) >> 1
out = in / hb * 8 * 2
out = in / hb * 8
offset = in % hb
if offset == 0 {
return
@@ -44,8 +24,8 @@ func (bs Base) EncodeLen(in int) (out, offset int) {
out += (remain/int(bs.bit) + 1 + 1) * 2
return
}
// (9/11/13/15)
out = in / int(bs.bit) * 16 * 2
// 其他奇数, 128blk (3/5/7/9/11/13/15)
out = in / int(bs.bit) * 16
offset = in % int(bs.bit)
if offset == 0 {
return
@@ -64,31 +44,18 @@ func (bs Base) DecodeLen(in, offset int) (out int) {
if bits.OnesCount8(bs.bit) == 1 { // 2的幂永无offset (1/2/4/8)
return in >> powtab[bs.bit]
}
if bs.bit == 6 { // 特判 (6) 3*8=4*6
if offset != 0 {
in -= (offset + 1) * 2
}
return (in>>3)*3 + offset
}
if bs.bit < 8 { // (3/5/7)
if offset != 0 {
remain := offset * 8
in -= (remain/int(bs.bit) + 1) * 2
}
return (in>>4)*int(bs.bit) + offset
}
if bs.bit%2 == 0 { // bit 大于8且可被2整除 (10/12/14)
if bs.bit%2 == 0 { // bit 可被2整除, 64blk (6/10/12/14)
hb := int(bs.bit) >> 1
if offset != 0 {
remain := offset * 8
in -= (remain/int(bs.bit) + 1) * 2
}
return (in>>4)*hb + offset
return (in>>3)*hb + offset
}
// (9/11/13/15)
// 其他奇数, 128blk (3/5/7/9/11/13/15)
if offset != 0 {
remain := offset * 8
in -= (remain/int(bs.bit) + 1) * 2
}
return (in>>5)*int(bs.bit) + offset
return (in>>4)*int(bs.bit) + offset
}

View File

@@ -1,6 +1,10 @@
package unibase2n
import "testing"
import (
"testing"
base14 "github.com/fumiama/go-base16384"
)
func TestEnDecodeLen(t *testing.T) {
bs := Base{bit: 1}
@@ -13,3 +17,22 @@ func TestEnDecodeLen(t *testing.T) {
}
}
}
func TestBase16384EnDecodeLen(t *testing.T) {
bs := Base{bit: 14}
for i := 1; i <= 65536; i++ {
myi, _ := bs.EncodeLen(i)
aci := base14.EncodeLen(i)
if myi != aci {
t.Fatal("bit:", bs.bit, "input:", i, "me:", myi, "!= actual:", aci)
}
}
for i := 1; i <= 4096; i++ {
myi, off := bs.EncodeLen(i)
myo := bs.DecodeLen(myi, off)
aco := base14.DecodeLen(myi, off)
if myo != aco {
t.Fatal("bit:", bs.bit, "input:", i, "me:", myo, "!= actual:", aco)
}
}
}

View File

@@ -2,7 +2,9 @@ package unibase2n
import (
"encoding/binary"
"fmt"
"math/bits"
"strconv"
)
type uint128be struct {
@@ -10,35 +12,62 @@ type uint128be struct {
b uint64
}
func readuint128be(b []byte) *uint128be {
return &uint128be{
func readuint128be(b []byte) uint128be {
if len(b) < 16 {
b = append(b, make([]byte, 16-len(b))...)
}
return uint128be{
a: binary.BigEndian.Uint64(b[:8]),
b: binary.BigEndian.Uint64(b[8:16]),
}
}
func (num *uint128be) add(n *uint128be) {
func (num *uint128be) addeq(n uint128be) {
var c uint64
num.b, c = bits.Add64(num.b, n.b, 0)
num.a, _ = bits.Add64(num.a, n.a, c)
return
}
// shr only supports shifting 1 ~ 63 bits
func (num *uint128be) shr(c uint8) {
// shreq only supports shifting 1 ~ 63 bits
func (num *uint128be) shreq(c uint8) {
mask := uint64(1)<<c - 1
aout := (num.a & mask) << (64 - c)
num.a = num.a >> c
num.b = aout | (num.b >> c)
}
func (num *uint128be) and(n *uint128be) {
func (num *uint128be) andeq(n uint128be) {
num.a &= n.a
num.b &= n.b
}
func (num uint128be) and(n uint128be) (r uint128be) {
r.a = num.a & n.a
r.b = num.b & n.b
return
}
func (num *uint128be) oreq(n uint128be) {
num.a |= n.a
num.b |= n.b
}
func (num uint128be) or(n uint128be) (r uint128be) {
r.a = num.a | n.a
r.b = num.b | n.b
return
}
func (num *uint128be) write(b []byte) {
binary.BigEndian.PutUint64(b[:8], num.a)
binary.BigEndian.PutUint64(b[8:16], num.b)
return
}
func (num uint128be) String() string {
if num.a == 0 {
return "0x" + strconv.FormatUint(num.b, 16)
}
return fmt.Sprintf("0x%x%016x", num.a, num.b)
}

View File

@@ -11,19 +11,24 @@ func TestUint128be(t *testing.T) {
zero := readuint128be(make([]byte, 16))
one := readuint128be([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
num := readuint128be(buf[:])
num.add(one)
num.addeq(one)
assert.Equal(t, num, zero)
num.add(readuint128be([]byte{0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}))
num.shr(8)
assert.Equal(t, num, &uint128be{0x001234567890abcd, 0xef1234567890abcd})
num.shr(16)
assert.Equal(t, num, &uint128be{0x0000001234567890, 0xabcdef1234567890})
num.shr(32)
assert.Equal(t, num, &uint128be{0x0000000000000012, 0x34567890abcdef12})
num.shr(1)
num.addeq(readuint128be([]byte{0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}))
num.shreq(8)
assert.Equal(t, num, uint128be{0x001234567890abcd, 0xef1234567890abcd})
assert.Equal(t, num.String(), "0x1234567890abcdef1234567890abcd")
num.shreq(16)
assert.Equal(t, num, uint128be{0x0000001234567890, 0xabcdef1234567890})
num.shreq(32)
assert.Equal(t, num, uint128be{0x0000000000000012, 0x34567890abcdef12})
assert.Equal(t, num.String(), "0x1234567890abcdef12")
num.shreq(1)
// 因为 num.a 低 1 位为 0 所以可以成功
assert.Equal(t, num, &uint128be{0x0000000000000012 >> 1, 0x34567890abcdef12 >> 1})
num.shr(7)
assert.Equal(t, num, uint128be{0x0000000000000012 >> 1, 0x34567890abcdef12 >> 1})
num.shreq(7)
num.write(buf[:])
assert.Equal(t, buf, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef})
assert.Equal(t, num.String(), "0x1234567890abcdef")
num.shreq(8)
assert.Equal(t, num.String(), "0x1234567890abcd")
}