-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
chaoguo.deng
committed
Dec 18, 2017
1 parent
5e73175
commit af95adf
Showing
59 changed files
with
2,470 additions
and
1,017 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package huffman | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
const ( | ||
MAX_PACKER_SIZE int = 8192 | ||
) | ||
|
||
type BitPacker struct { | ||
data [MAX_PACKER_SIZE]byte | ||
nbyte uint32 | ||
nbit uint32 | ||
} | ||
|
||
type BitUnpacker struct { | ||
data []byte | ||
pbyte uint32 | ||
pbit uint32 | ||
size uint32 | ||
} | ||
|
||
func NewBitPacker() *BitPacker { | ||
return &BitPacker{ | ||
[MAX_PACKER_SIZE]byte{}, 0, 0, | ||
} | ||
} | ||
|
||
func NewBitUnpacker(data []byte, nbit uint32) *BitUnpacker { | ||
if int(nbit) > len(data)*8 { | ||
return nil | ||
} | ||
return &BitUnpacker{ | ||
data, 0, 0, nbit, | ||
} | ||
} | ||
|
||
func (packer *BitPacker) WriteBits(code uint64, nbit uint32) error { | ||
if int(packer.nbyte) >= MAX_PACKER_SIZE { | ||
return fmt.Errorf("Packer full!") | ||
} | ||
for nbit > 0 { | ||
if int(packer.nbyte) >= MAX_PACKER_SIZE { | ||
return fmt.Errorf("Packer full!") | ||
} | ||
left := 8 - packer.nbit | ||
if nbit < left { | ||
// packer.data[packer.nbyte] <<= nbit | ||
packer.data[packer.nbyte] |= byte(code&uint64(uint32(1<<nbit)-1)) << (left - nbit) | ||
packer.nbit += nbit | ||
return nil | ||
} else { | ||
// packer.data[packer.nbyte] <<= left | ||
packer.data[packer.nbyte] |= byte((code >> (nbit - left)) & uint64(uint32(1<<left)-1)) | ||
packer.nbit = 0 | ||
packer.nbyte += 1 | ||
nbit -= left | ||
code &= uint64((1 << nbit) - 1) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (unpacker *BitUnpacker) Left() uint32 { | ||
return unpacker.size - (unpacker.pbyte*8 + unpacker.pbit) | ||
} | ||
|
||
func (unpacker *BitUnpacker) ReadBits(nbit uint32) (uint64, error) { | ||
if unpacker.Left() < nbit { | ||
return 0, fmt.Errorf("Not enough bits left!") | ||
} | ||
ret := uint64(0) | ||
for nbit > 0 { | ||
left := 8 - unpacker.pbit | ||
if nbit < left { | ||
ret <<= nbit | ||
ret |= uint64((unpacker.data[unpacker.pbyte] >> (left - nbit)) & byte((1<<nbit)-1)) | ||
unpacker.pbit += nbit | ||
return ret, nil | ||
} else { | ||
ret <<= left | ||
ret |= uint64(unpacker.data[unpacker.pbyte] & byte((1<<left)-1)) | ||
unpacker.pbyte += 1 | ||
unpacker.pbit = 0 | ||
nbit -= left | ||
} | ||
} | ||
return ret, nil | ||
} | ||
|
||
func (packer *BitPacker) Size() uint32 { | ||
return packer.nbyte*8 + packer.nbit | ||
} | ||
|
||
func (packer *BitPacker) Data() []byte { | ||
return packer.data[:(packer.Size()+7)/8] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package huffman | ||
|
||
import ( | ||
_ "fmt" | ||
"testing" | ||
) | ||
|
||
func TestWriteBits(t *testing.T) { | ||
packer := NewBitPacker() | ||
packer.WriteBits(0x1, 1) | ||
packer.WriteBits(0x2, 2) | ||
packer.WriteBits(0x3, 2) | ||
packer.WriteBits(0x4, 3) | ||
packer.WriteBits(0x5, 3) | ||
packer.WriteBits(0x6, 3) | ||
expect := []byte{0xdc, 0xb8} | ||
// Now the bits should be 11011100 10111000 | ||
// nbytes = 1, nbit = 6 | ||
if packer.nbyte != 1 { | ||
t.Errorf("Wrong number of bytes, expected %d, got %d", 1, packer.nbyte) | ||
} | ||
if packer.nbit != 6 { | ||
t.Errorf("Wrong number of bits, expected %d, got %d", 6, packer.nbit) | ||
} | ||
if packer.Size() != 14 { | ||
t.Errorf("Wrong size: expected %d, got %d", 14, packer.Size()) | ||
} | ||
data := packer.Data() | ||
for i := 0; i <= int(packer.nbyte); i++ { | ||
if data[i] != expect[i] { | ||
t.Errorf("Wrong byte at %d: expected %x, got %x", i, expect[i], packer.data[i]) | ||
} | ||
} | ||
} | ||
|
||
func TestWriteRead(t *testing.T) { | ||
data := [][]uint32{ | ||
{0x1, 1}, {0x2, 2}, {0x3, 2}, {0x4, 3}, | ||
{0x8, 4}, {0x7, 3}, {0x6, 3}, {0x5, 3}, | ||
{0x9, 4}, {0xa, 4}, {0xb, 4}, {0xc, 4}, | ||
{0x10, 5}, {0xf, 4}, {0xe, 4}, {0xd, 4}, | ||
{0x18, 5}, {0x1f, 5}, {0x42, 7}, {0x17, 7}, | ||
{0x12, 5}, {0x31, 6}, {0x23, 7}, {0x9, 7}, | ||
{0x23, 6}, {0x5f, 7}, {0x14, 7}, {0x5f, 7}, | ||
{0x20, 6}, {0x1a, 6}, {0x45, 7}, {0x5d, 7}, | ||
{0x34, 7}, {0x4f, 7}, {0x46, 7}, {0x5e, 7}, | ||
} | ||
packer := NewBitPacker() | ||
for i := 0; i < len(data); i++ { | ||
packer.WriteBits(uint64(data[i][0]), data[i][1]) | ||
} | ||
/* | ||
d := packer.Data() | ||
for i := 0; i < len(data); i++ { | ||
fmt.Printf("%d: %02x\n", i, d[i]) | ||
}*/ | ||
unpacker := NewBitUnpacker(packer.Data(), packer.Size()) | ||
if unpacker == nil { | ||
t.Errorf("Error in creating unpacker") | ||
return | ||
} | ||
for i := 0; i < len(data); i++ { | ||
bits, err := unpacker.ReadBits(data[i][1]) | ||
if err != nil { | ||
t.Errorf("Error in reading bits: %s", err.Error()) | ||
} | ||
if bits != uint64(data[i][0]) { | ||
t.Errorf("Mismatched unpacked result at %d: expected %d, got %d", | ||
i, data[i][0], bits) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package huffman | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
type Pair struct { | ||
Code uint64 | ||
Nbit uint8 | ||
} | ||
|
||
type Triple struct { | ||
Left int | ||
Right int | ||
Index int | ||
} | ||
|
||
type HuffmanCode struct { | ||
Code []Pair | ||
Node []Triple | ||
} | ||
|
||
type HuffmanEncoder struct { | ||
packer *BitPacker | ||
code *HuffmanCode | ||
} | ||
|
||
type HuffmanDecoder struct { | ||
unpacker *BitUnpacker | ||
code *HuffmanCode | ||
} | ||
|
||
func NewHuffmanEncoder(code *HuffmanCode) *HuffmanEncoder { | ||
return &HuffmanEncoder{NewBitPacker(), code} | ||
} | ||
|
||
func NewHuffmanDecoder(code *HuffmanCode, data []byte) *HuffmanDecoder { | ||
size := uint32(data[0])*256 + uint32(data[1]) | ||
return &HuffmanDecoder{NewBitUnpacker(data[2:], size), code} | ||
} | ||
|
||
func (code *HuffmanCode) Size() int { | ||
return len(code.Code) | ||
} | ||
|
||
func (encoder *HuffmanEncoder) Update(index int) error { | ||
code := encoder.code | ||
if index < 0 || index >= code.Size() { | ||
return fmt.Errorf("Invalid symbol %d, expected < %d", index, code.Size()) | ||
} | ||
err := encoder.packer.WriteBits(code.Code[index].Code, uint32(code.Code[index].Nbit)) | ||
if err != nil { | ||
return fmt.Errorf("Error in writing bits to packer: %s", err.Error()) | ||
} | ||
return nil | ||
} | ||
|
||
func (encoder *HuffmanEncoder) Digest() []byte { | ||
size := encoder.packer.Size() | ||
ret := []byte{byte(size / 256), byte(size % 256)} | ||
ret = append(ret, encoder.packer.Data()[:(size+7)/8]...) | ||
return ret | ||
} | ||
|
||
func (decoder *HuffmanDecoder) Next() (int, error) { | ||
curr := 0 | ||
for decoder.unpacker.Left() > 0 { | ||
bit, err := decoder.unpacker.ReadBits(1) | ||
if err != nil { | ||
return -1, fmt.Errorf("Error in reading bit: %s", err.Error()) | ||
} | ||
if bit == 0 { | ||
curr = decoder.code.Node[curr].Left | ||
} else { | ||
curr = decoder.code.Node[curr].Right | ||
} | ||
if curr < 0 { | ||
return -1, fmt.Errorf("Unexpected bit %d", bit) | ||
} | ||
if decoder.code.Node[curr].Index >= 0 { | ||
return decoder.code.Node[curr].Index, nil | ||
} | ||
} | ||
return -1, fmt.Errorf("Unexpected end of bit string when decoding") | ||
} |
Oops, something went wrong.