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