From e88f60b63cb05f56a61060a953c726b7a78c0652 Mon Sep 17 00:00:00 2001
From: pacien
Date: Fri, 30 Nov 2018 17:08:01 +0100
Subject: isolate huffman encoding module
---
src/huffman/huffmandecoder.nim | 35 ++++++++++++++++++
src/huffman/huffmanencoder.nim | 40 +++++++++++++++++++++
src/huffman/huffmantree.nim | 74 ++++++++++++++++++++++++++++++++++++++
src/huffman/huffmantreebuilder.nim | 44 +++++++++++++++++++++++
src/huffmandecoder.nim | 34 ------------------
src/huffmanencoder.nim | 39 --------------------
src/huffmantree.nim | 74 --------------------------------------
src/huffmantreebuilder.nim | 44 -----------------------
src/lzsschain.nim | 2 +-
9 files changed, 194 insertions(+), 192 deletions(-)
create mode 100644 src/huffman/huffmandecoder.nim
create mode 100644 src/huffman/huffmanencoder.nim
create mode 100644 src/huffman/huffmantree.nim
create mode 100644 src/huffman/huffmantreebuilder.nim
delete mode 100644 src/huffmandecoder.nim
delete mode 100644 src/huffmanencoder.nim
delete mode 100644 src/huffmantree.nim
delete mode 100644 src/huffmantreebuilder.nim
(limited to 'src')
diff --git a/src/huffman/huffmandecoder.nim b/src/huffman/huffmandecoder.nim
new file mode 100644
index 0000000..9a58b55
--- /dev/null
+++ b/src/huffman/huffmandecoder.nim
@@ -0,0 +1,35 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import ../bitio/bitreader
+import huffmantree
+
+type HuffmanDecoder*[T: SomeUnsignedInt] = object
+ tree: HuffmanTreeNode[T]
+
+proc decoder*[T](tree: HuffmanTreeNode[T]): HuffmanDecoder[T] =
+ HuffmanDecoder[T](tree: tree)
+
+proc decode*[T](decoder: HuffmanDecoder[T], bitReader: BitReader): T =
+ proc walk(node: HuffmanTreeNode[T]): T =
+ case node.kind:
+ of branch:
+ case bitReader.readBool():
+ of false: walk(node.left)
+ of true: walk(node.right)
+ of leaf:
+ node.value
+ walk(decoder.tree)
diff --git a/src/huffman/huffmanencoder.nim b/src/huffman/huffmanencoder.nim
new file mode 100644
index 0000000..3ed41ec
--- /dev/null
+++ b/src/huffman/huffmanencoder.nim
@@ -0,0 +1,40 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import tables
+import ../integers, ../bitio/bitwriter
+import huffmantree
+
+type HuffmanEncoder*[T, U: SomeUnsignedInt] = object
+ codebook: TableRef[T, U]
+
+proc buildCodebook*[T, U](tree: HuffmanTreeNode[T], codeType: typedesc[U]): TableRef[T, U] =
+ var codebook = newTable[T, U]()
+ proc addCode(node: HuffmanTreeNode[T], path: U, depth: int) =
+ case node.kind:
+ of branch:
+ addCode(node.left, path, depth + 1)
+ addCode(node.right, path or (1.U shl depth), depth + 1)
+ of leaf:
+ codebook[node.value] = path
+ addCode(tree, 0.U, 0)
+ codebook
+
+proc encoder*[T, U](tree: HuffmanTreeNode[T], codeType: typedesc[U]): HuffmanEncoder[T, U] =
+ HuffmanEncoder[T, U](codebook: buildCodebook(tree, codeType))
+
+proc encode*[T, U](decoder: HuffmanEncoder[T, U], value: T): U =
+ decoder.codebook[value]
diff --git a/src/huffman/huffmantree.nim b/src/huffman/huffmantree.nim
new file mode 100644
index 0000000..1140694
--- /dev/null
+++ b/src/huffman/huffmantree.nim
@@ -0,0 +1,74 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import tables, heapqueue
+import ../integers, ../bitio/bitreader, ../bitio/bitwriter
+
+const valueLengthFieldBitLength* = 6 # 64
+
+type HuffmanTreeNodeKind* = enum
+ branch,
+ leaf
+
+type HuffmanTreeNode*[T: SomeUnsignedInt] = ref object
+ case kind*: HuffmanTreeNodeKind
+ of branch:
+ left*, right*: HuffmanTreeNode[T]
+ maxChildValue: T
+ of leaf:
+ value*: T
+
+proc huffmanBranch*[T](left, right: HuffmanTreeNode[T]): HuffmanTreeNode[T] =
+ HuffmanTreeNode[T](
+ kind: branch, left: left, right: right,
+ maxChildValue: max(left.maxValue(), right.maxValue()))
+
+proc huffmanLeaf*[T](value: T): HuffmanTreeNode[T] =
+ HuffmanTreeNode[T](kind: leaf, value: value)
+
+proc `==`*[T](a, b: HuffmanTreeNode[T]): bool =
+ if a.kind != b.kind: return false
+ case a.kind:
+ of branch: a.left == b.left and a.right == b.right
+ of leaf: a.value == b.value
+
+proc maxValue*[T](node: HuffmanTreeNode[T]): T =
+ case node.kind:
+ of branch: node.maxChildValue
+ of leaf: node.value
+
+proc deserialise*[T](bitReader: BitReader, valueType: typedesc[T]): HuffmanTreeNode[T] =
+ let valueBitLength = bitReader.readBits(valueLengthFieldBitLength, uint8).int
+ proc readNode(): HuffmanTreeNode[T] =
+ case bitReader.readBool():
+ of false: huffmanBranch(readNode(), readNode())
+ of true: huffmanLeaf(bitReader.readBits(valueBitLength, valueType))
+ readNode()
+
+proc serialise*[T](tree: HuffmanTreeNode[T], bitWriter: BitWriter) =
+ let maxValue = tree.maxValue()
+ let valueBitLength = maxValue.bitLength()
+ proc writeNode(node: HuffmanTreeNode[T]) =
+ case node.kind:
+ of branch:
+ bitWriter.writeBool(false)
+ writeNode(node.left)
+ writeNode(node.right)
+ of leaf:
+ bitWriter.writeBool(true)
+ bitWriter.writeBits(valueBitLength, node.value)
+ bitWriter.writeBits(valueLengthFieldBitLength, valueBitLength.uint8)
+ writeNode(tree)
diff --git a/src/huffman/huffmantreebuilder.nim b/src/huffman/huffmantreebuilder.nim
new file mode 100644
index 0000000..4169099
--- /dev/null
+++ b/src/huffman/huffmantreebuilder.nim
@@ -0,0 +1,44 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import tables, heapqueue
+import huffmantree
+
+type WeighedHuffmanTreeNode[T] = ref object
+ weight: int
+ huffmanTreeNode: HuffmanTreeNode[T]
+
+proc weighedHuffmanBranch[T](left, right: WeighedHuffmanTreeNode[T]): WeighedHuffmanTreeNode[T] =
+ WeighedHuffmanTreeNode[T](
+ weight: left.weight + right.weight,
+ huffmanTreeNode: huffmanBranch(left.huffmanTreeNode, right.huffmanTreeNode))
+
+proc weighedHuffmanLeaf[T](value: T, weight: int): WeighedHuffmanTreeNode[T] =
+ WeighedHuffmanTreeNode[T](
+ weight: weight,
+ huffmanTreeNode: huffmanLeaf(value))
+
+proc `<`*[T](left, right: WeighedHuffmanTreeNode[T]): bool =
+ left.weight < right.weight
+
+proc symbolQueue[T](stats: CountTableRef[T]): HeapQueue[WeighedHuffmanTreeNode[T]] =
+ result = newHeapQueue[WeighedHuffmanTreeNode[T]]()
+ for item, count in stats.pairs: result.push(weighedHuffmanLeaf(item, count))
+
+proc buildHuffmanTree*[T: SomeUnsignedInt](stats: CountTableRef[T]): HuffmanTreeNode[T] =
+ var symbolQueue = symbolQueue(stats)
+ while symbolQueue.len > 1: symbolQueue.push(weighedHuffmanBranch(symbolQueue.pop(), symbolQueue.pop()))
+ symbolQueue[0].huffmanTreeNode
diff --git a/src/huffmandecoder.nim b/src/huffmandecoder.nim
deleted file mode 100644
index 5cf4ca5..0000000
--- a/src/huffmandecoder.nim
+++ /dev/null
@@ -1,34 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import huffmantree, bitio/bitreader
-
-type HuffmanDecoder*[T: SomeUnsignedInt] = object
- tree: HuffmanTreeNode[T]
-
-proc decoder*[T](tree: HuffmanTreeNode[T]): HuffmanDecoder[T] =
- HuffmanDecoder[T](tree: tree)
-
-proc decode*[T](decoder: HuffmanDecoder[T], bitReader: BitReader): T =
- proc walk(node: HuffmanTreeNode[T]): T =
- case node.kind:
- of branch:
- case bitReader.readBool():
- of false: walk(node.left)
- of true: walk(node.right)
- of leaf:
- node.value
- walk(decoder.tree)
diff --git a/src/huffmanencoder.nim b/src/huffmanencoder.nim
deleted file mode 100644
index 05ed64f..0000000
--- a/src/huffmanencoder.nim
+++ /dev/null
@@ -1,39 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import tables
-import integers, huffmantree, bitio/bitwriter
-
-type HuffmanEncoder*[T, U: SomeUnsignedInt] = object
- codebook: TableRef[T, U]
-
-proc buildCodebook*[T, U](tree: HuffmanTreeNode[T], codeType: typedesc[U]): TableRef[T, U] =
- var codebook = newTable[T, U]()
- proc addCode(node: HuffmanTreeNode[T], path: U, depth: int) =
- case node.kind:
- of branch:
- addCode(node.left, path, depth + 1)
- addCode(node.right, path or (1.U shl depth), depth + 1)
- of leaf:
- codebook[node.value] = path
- addCode(tree, 0.U, 0)
- codebook
-
-proc encoder*[T, U](tree: HuffmanTreeNode[T], codeType: typedesc[U]): HuffmanEncoder[T, U] =
- HuffmanEncoder[T, U](codebook: buildCodebook(tree, codeType))
-
-proc encode*[T, U](decoder: HuffmanEncoder[T, U], value: T): U =
- decoder.codebook[value]
diff --git a/src/huffmantree.nim b/src/huffmantree.nim
deleted file mode 100644
index 6208ecf..0000000
--- a/src/huffmantree.nim
+++ /dev/null
@@ -1,74 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import tables, heapqueue
-import integers, bitio/bitreader, bitio/bitwriter
-
-const valueLengthFieldBitLength* = 6 # 64
-
-type HuffmanTreeNodeKind* = enum
- branch,
- leaf
-
-type HuffmanTreeNode*[T: SomeUnsignedInt] = ref object
- case kind*: HuffmanTreeNodeKind
- of branch:
- left*, right*: HuffmanTreeNode[T]
- maxChildValue: T
- of leaf:
- value*: T
-
-proc huffmanBranch*[T](left, right: HuffmanTreeNode[T]): HuffmanTreeNode[T] =
- HuffmanTreeNode[T](
- kind: branch, left: left, right: right,
- maxChildValue: max(left.maxValue(), right.maxValue()))
-
-proc huffmanLeaf*[T](value: T): HuffmanTreeNode[T] =
- HuffmanTreeNode[T](kind: leaf, value: value)
-
-proc `==`*[T](a, b: HuffmanTreeNode[T]): bool =
- if a.kind != b.kind: return false
- case a.kind:
- of branch: a.left == b.left and a.right == b.right
- of leaf: a.value == b.value
-
-proc maxValue*[T](node: HuffmanTreeNode[T]): T =
- case node.kind:
- of branch: node.maxChildValue
- of leaf: node.value
-
-proc deserialise*[T](bitReader: BitReader, valueType: typedesc[T]): HuffmanTreeNode[T] =
- let valueBitLength = bitReader.readBits(valueLengthFieldBitLength, uint8).int
- proc readNode(): HuffmanTreeNode[T] =
- case bitReader.readBool():
- of false: huffmanBranch(readNode(), readNode())
- of true: huffmanLeaf(bitReader.readBits(valueBitLength, valueType))
- readNode()
-
-proc serialise*[T](tree: HuffmanTreeNode[T], bitWriter: BitWriter) =
- let maxValue = tree.maxValue()
- let valueBitLength = maxValue.bitLength()
- proc writeNode(node: HuffmanTreeNode[T]) =
- case node.kind:
- of branch:
- bitWriter.writeBool(false)
- writeNode(node.left)
- writeNode(node.right)
- of leaf:
- bitWriter.writeBool(true)
- bitWriter.writeBits(valueBitLength, node.value)
- bitWriter.writeBits(valueLengthFieldBitLength, valueBitLength.uint8)
- writeNode(tree)
diff --git a/src/huffmantreebuilder.nim b/src/huffmantreebuilder.nim
deleted file mode 100644
index 5b33d34..0000000
--- a/src/huffmantreebuilder.nim
+++ /dev/null
@@ -1,44 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import tables, heapqueue
-import huffmantree, lzssencoder
-
-type WeighedHuffmanTreeNode[T] = ref object
- weight: int
- huffmanTreeNode: HuffmanTreeNode[T]
-
-proc weighedHuffmanBranch[T](left, right: WeighedHuffmanTreeNode[T]): WeighedHuffmanTreeNode[T] =
- WeighedHuffmanTreeNode[T](
- weight: left.weight + right.weight,
- huffmanTreeNode: huffmanBranch(left.huffmanTreeNode, right.huffmanTreeNode))
-
-proc weighedHuffmanLeaf[T](value: T, weight: int): WeighedHuffmanTreeNode[T] =
- WeighedHuffmanTreeNode[T](
- weight: weight,
- huffmanTreeNode: huffmanLeaf(value))
-
-proc `<`*[T](left, right: WeighedHuffmanTreeNode[T]): bool =
- left.weight < right.weight
-
-proc symbolQueue[T](stats: CountTableRef[T]): HeapQueue[WeighedHuffmanTreeNode[T]] =
- result = newHeapQueue[WeighedHuffmanTreeNode[T]]()
- for item, count in stats.pairs: result.push(weighedHuffmanLeaf(item, count))
-
-proc buildHuffmanTree*[T: SomeUnsignedInt](stats: CountTableRef[T]): HuffmanTreeNode[T] =
- var symbolQueue = symbolQueue(stats)
- while symbolQueue.len > 1: symbolQueue.push(weighedHuffmanBranch(symbolQueue.pop(), symbolQueue.pop()))
- symbolQueue[0].huffmanTreeNode
diff --git a/src/lzsschain.nim b/src/lzsschain.nim
index 073aa5e..44200f2 100644
--- a/src/lzsschain.nim
+++ b/src/lzsschain.nim
@@ -15,7 +15,7 @@
# along with this program. If not, see .
import lists, tables, sugar
-import polyfill, integers, lzssnode, huffmantree
+import polyfill, integers, lzssnode, huffman/huffmantree
const maxChainByteLength = 32_000 * wordBitLength
--
cgit v1.2.3