ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
huffman.cpp
1namespace alib { namespace bitbuffer { namespace ac_v1 {
2
3#if !DOXYGEN
4//#define TEMP_PT(...) __VA_ARGS__
5# define TEMP_PT(...)
6#endif
7
8namespace
9{
10/// Internal struct representing nodes of the huffman code tree.
11class Node {
12 /// Shortcut to the symbol-struct.
14
15 protected:
16 /// Either a pointer to a left subtree or to a symbol.
17 /// The latter makes the node a leaf.
19 Symbol* symbol; ///< The symbol represented by this node (if not \c nullptr).
20 Node* left; ///< The left subtree.
21
22 LeftPointer() = default; ///< Non-initializing default constructor.
23
24 /// Constructs this union with a symbol pointer.
25 /// @param s The symbol to set.
27 : symbol( s ) {}
28
29 /// Constructs this union with a cursor.
30 /// @param l The node to set.
32 : left ( l ) {}
33 };
34
35 LeftPointer left; ///< If #".right" is set, then this is a pointer to the left subtree,
36 ///< otherwise a pointer to a symbol.
37 Node* right; ///< The right subtree.
38
39
40 public:
41 size_t frequency; ///< The frequency of the symbol or the sum of the two subtrees.
42
43 /// Default constructor used when defining arrays of nodes on stack memory.
44 Node() =default;
45
46 /// Constructs a node representing a symbol (leaf).
47 /// Left and right pointers are set to nullptr
48 /// @param s Pointer to the symbol in #"symbols", that this node represents.
50 : left (s)
51 , right (nullptr)
52 , frequency (s->frequency) {}
53
54 /// Constructs a node as an internal non-leaf node.
55 /// Left and right pointers are set to as given.
56 /// @param l Pointer to the left node.
57 /// @param r Pointer to the right node.
58 Node(Node* l, Node* r)
59 : left (l)
60 , right (r)
61 , frequency (l->frequency + r->frequency) {}
62
63 /// Determines if this is a leaf node.
64 /// @returns \c true if this is a leaf node.
65 bool isLeaf() const { return right == nullptr; }
66
67 /// Must be called only for leaf nodes.
68 /// @returns The pointer to the symbol.
69 Symbol* getSymbol() const { return left.symbol; }
70
71 /// Must be called only for non-leaf nodes.
72 /// @returns The left node.
73 Node* getLeft() const { return left.left; }
74
75 /// @returns The right node.
76 Node* getRight() const { return right; }
77}; //struct Node
78} // anonymous namespace
79
80
82 constexpr int maxNodesNeeded= 256 + 255;
83 Node nodePool[maxNodesNeeded];
84
85 // buildTree
86 Node* tree;
87 {
88 struct cmpHN { bool operator()(Node* l, Node* r) { return (l->frequency > r->frequency); } };
89
90 // create a list of nodes, sorted by frequency (least in front)
91 // Note: for this, we first create fixed array on the stack, where we fill the
92 // nodes unsorted. Then we move this into the priority queue, what sorts them
93 // once. (unfortunately the move copies the array, but still it is faster than
94 // if the heap was sorted with each insert)
95 int npNext= 0;
96 FixedCapacityVector<Node*, 256> underlyingNodeVector;
97 for (std::size_t i = 0; i < 256 ; ++i)
98 if( (symbols + i)->frequency > 0 )
99 underlyingNodeVector.push_back( new (nodePool + npNext++) Node(symbols + i) );
100 FixedSizePriorityQueue<Node*, 256, cmpHN> sortedNodes(cmpHN(), std::move(underlyingNodeVector));
101
102ALIB_DBG( dbgAllValuesAreSame= (sortedNodes.size() == 1); )
103 // Merge two front nodes into one, until one node remains
104 while (sortedNodes.size() > 1) {
105 // Extract two least freq nodes
106 Node* left = sortedNodes.top(); sortedNodes.pop();
107 Node* right= sortedNodes.top(); sortedNodes.pop();
108
109 // New internal node with frequency equal to the sum of the two nodes frequencies.
110 // The two extracted nodes become left and right children
111 sortedNodes.push(new ( nodePool + npNext++ ) Node(left, right) );
112 }
113
114 tree= sortedNodes.top();
115 ALIB_ASSERT_ERROR( npNext <= maxNodesNeeded , "BITBUFFER/AC/HFMN", "This can never happen" )
116 }
117
118 // generate codes and write tree information to bit buffer
119 {
120 struct Stack {
121 Node* node;
122 int walked;
123 };
124
125 int depth = 0;
126 Stack stack[MAX_CODE_LENGTH];
127 stack[0] = Stack{ tree, 0 };
128 uint32_t words[MAX_WORDS] = {};
129
130TEMP_PT(Log_Warning("------ Huffman Encoding Table ----------") )
131
132 // 'recursion loop'
133 while(depth>=0) {
134 auto* node= stack[depth].node;
135
136 auto wordNo= depth / WORD_SIZE;
137 auto bitNo = depth % WORD_SIZE;
138
139 // leaf?
140 if( node->isLeaf() ) {
141 // write '1' for leaf and symbol value
142 bw.WriteBits<9>( 1 | static_cast<unsigned>(node->getSymbol() - symbols) << 1 );
143
144 // store word length and words to symbol's data
145 node->getSymbol()->wordLength= depth;
146 for( int i= 0 ; i <= wordNo ; ++i )
147 node->getSymbol()->words[i]= words[i];
148
149TEMP_PT( NString512 bits; bits << Bin(node->symbol->words[0], node->symbol->wordLength);
150 bits.Reverse();
151 Lox_Warning("HM I: {:3}: {:<15} (len={!ATAB:2}, freq={:>5})",
152 (node->symbol - symbols),
153 bits,
154 node->symbol->wordLength,
155 node->symbol->frequency ) )
156
157 // clear last bit and step up
158 words[wordNo]&= ~(uint32_t(1) << ( bitNo ) );
159 --depth;
160 continue;
161 }
162
163 // write '0' for not being a leave
164 bw.WriteBits<1>( 0u );
165
166 // process left child
167 if( stack[depth].walked == 0) {
168 stack[depth].walked++;
169 stack[depth+1]= Stack{ node->getLeft() , 0};
170 depth++;
171 continue;
172 }
173
174 // process right child
175 if( stack[depth].walked == 1) {
176 stack[depth].walked++;
177 words[wordNo] |= (1 << ( bitNo ) );
178 stack[depth+1]= Stack{ node->getRight() , 0};
179 depth++;
180 continue;
181 }
182
183 // clear last bit and step up
184 words[wordNo]&= ~(uint32_t(1) << ( bitNo ) );
185 --depth;
186 }
187TEMP_PT( Log_Warning("------End of Huffman Encoding Table ----------") )
188} }
189
191TEMP_PT( Log_Warning("------ Huffman Decoding Table ----------") )
192TEMP_PT( String512 dbgWord; )
193 struct Stack {
194 Node* node;
195 int read; // 0: none, 1: left, 2: both
196 };
197
198 int depth;
200 stack[depth= 0]= Stack{ &tree, 0 };
201 while(depth>=0) {
202 auto* node= stack[depth].node;
203 // leaf?
204 if( br.ReadBits<1>() ) {
205 node->symbol= uint8_t(br.ReadBits<8>());
206TEMP_PT( Log_Warning("HM D: {:3}: {:5} (len={})",
207 (node->symbol),
208 dbgWord,
209 dbgWord.Length() ) )
210
211 --depth;
212TEMP_PT( dbgWord.DeleteEnd(1); )
213 continue;
214 }
215
216 // left 'recursion'
217 if( stack[depth].read == 0) {
218 ++stack[depth].read;
219 node->left= new ( nodePool + npNext++ ) Node();
220TEMP_PT( dbgWord << '0'; )
221 stack[depth+1]= Stack{ node->left , 0 };
222 ++depth;
223 continue;
224 }
225
226 // right 'recursion'
227 if( stack[depth].read == 1) {
228 ++stack[depth].read;
229TEMP_PT( dbgWord << '1'; )
230 node->right= new ( nodePool + npNext++ ) Node();
231 stack[depth+1]= Stack{ node->right , 0 };
232 ++depth;
233 continue;
234 }
235
236TEMP_PT( dbgWord.DeleteEnd(1); )
237 --depth;
238 }
239
240ALIB_ASSERT_ERROR( npNext <= MAX_NODES, "BITBUFFER/AC/HFMN", "This can never happen" )
241
242TEMP_PT( Log_Warning("------End of Huffman Decoding Table ----------") )
243}
244
245
246
247
248#undef TEMP_PT
249
250}}} // namespace [alib::bitbuffer::ac_v1]
#define ALIB_DBG(...)
#define ALIB_ASSERT_ERROR(cond, domain,...)
#define Log_Warning(...)
#define Lox_Warning(...)
int npNext
The next node in #".nodePool" to use.
Definition huffman.hpp:127
static constexpr int MAX_NODES
The maximum number of nodes in the tree.
Definition huffman.hpp:122
Node tree
The root node of the symbol tree.
Definition huffman.hpp:125
Node nodePool[MAX_NODES]
Pre-allocated node objects.
Definition huffman.hpp:126
BitReader & br
The bit reader given in the constructor.
Definition huffman.hpp:124
BitWriter & bw
The bit writer to use for encoding the data.
Definition huffman.hpp:47
static constexpr int MAX_CODE_LENGTH
Definition huffman.hpp:34
Symbol symbols[256]
The symbol table.
Definition huffman.hpp:48
void Generate()
Generates the huffman encoding table and writes this information to the bit writer.
Definition huffman.cpp:81
HuffmanEncoder::Symbol Symbol
Shortcut to the symbol-struct.
Definition huffman.cpp:13
size_t frequency
The frequency of the symbol or the sum of the two subtrees.
Definition huffman.cpp:41
Node()=default
Default constructor used when defining arrays of nodes on stack memory.
Definition alox.cpp:14
std::priority_queue< T, FixedCapacityVector< T, TSize >, TCompare > FixedSizePriorityQueue
strings::TBin< character > Bin
Type alias in namespace #"%alib".
Definition format.hpp:567
containers::FixedCapacityVector< T, TSize > FixedCapacityVector
Type alias in namespace #"%alib".
NLocalString< 512 > NString512
Type alias name for #"TLocalString;TLocalString<nchar,512>".
LocalString< 512 > String512
Type alias name for #"TLocalString;TLocalString<character,512>".
Internal struct representing nodes of the huffman code tree.
Definition huffman.hpp:110
Symbol * symbol
The symbol represented by this node (if not nullptr).
Definition huffman.cpp:19