diff --git a/code.go b/decode.go similarity index 56% rename from code.go rename to decode.go index 67e82e9..45b9fc7 100644 --- a/code.go +++ b/decode.go @@ -1,9 +1,5 @@ package unibase2n -func (bs Base) Encode(data []byte) []byte { - return nil -} - func (bs Base) Decode(data []byte) []byte { return nil } diff --git a/define.go b/define.go index 835344e..6b00ed6 100644 --- a/define.go +++ b/define.go @@ -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) ) diff --git a/encode.go b/encode.go new file mode 100644 index 0000000..e99af75 --- /dev/null +++ b/encode.go @@ -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)<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)<> 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)<> 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[:]) +} diff --git a/encode_test.go b/encode_test.go new file mode 100644 index 0000000..70dfb50 --- /dev/null +++ b/encode_test.go @@ -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")) +} diff --git a/go.mod b/go.mod index 3ce1473..49217db 100644 --- a/go.mod +++ b/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 ) diff --git a/go.sum b/go.sum index d734a74..c388481 100644 --- a/go.sum +++ b/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= diff --git a/len.go b/len.go index cd33d9e..3694e82 100644 --- a/len.go +++ b/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 } diff --git a/len_test.go b/len_test.go index ff3afd9..cdada26 100644 --- a/len_test.go +++ b/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) + } + } +} diff --git a/uint128be.go b/uint128be.go index 4f25bd3..162f02c 100644 --- a/uint128be.go +++ b/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 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) +} diff --git a/uint128be_test.go b/uint128be_test.go index 4a172d0..8b93dcd 100644 --- a/uint128be_test.go +++ b/uint128be_test.go @@ -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") }