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