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:
@@ -1,9 +1,5 @@
|
||||
package unibase2n
|
||||
|
||||
func (bs Base) Encode(data []byte) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs Base) Decode(data []byte) []byte {
|
||||
return nil
|
||||
}
|
||||
@@ -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
212
encode.go
Normal 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
147
encode_test.go
Normal 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
1
go.mod
@@ -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
3
go.sum
@@ -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
49
len.go
@@ -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
|
||||
}
|
||||
|
||||
25
len_test.go
25
len_test.go
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
41
uint128be.go
41
uint128be.go
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user