Octane v1.01.20 - The Open Compression Toolkit for C++ | http://octane.sourceforge.net/ |
00001 00002 00003 00004 00005 00006 00007 00008 00009 //--------------------------------------------------------------------------- 00010 00011 //--------------------------------------------------------------------------- 00012 // application includes 00013 #include "huffmancoder.hpp" 00014 // system includes 00015 #include <assert.h> 00016 //--------------------------------------------------------------------------- 00017 00018 00019 00020 00021 00022 00023 //--------------------------------------------------------------------------- 00024 // Functions from OCTANE PUBLIC API 00025 void HuffmanCoder::ShowDebuggingInfo() 00026 { 00027 // show bit strings 00028 ShowBitStrings(); 00029 // show memory used by priority queue 00030 std::cout << " Memory used by Huffman Coder: " << GetMemoryUsed() << " bytes.\n"; 00031 } 00032 00033 unsigned int HuffmanCoder::GetMemoryUsed() 00034 { 00035 // approximate memory usage of the priority queue 00036 unsigned int memoryused=0; 00037 memoryused+=sizeof(symbolsetpq); 00038 if (symbolsetpq.size()!=0) 00039 memoryused+=(symbolsetpq.top())->get_memoryused(); 00040 memoryused+=sizeof(symbolvector); 00041 if (symbolvector.size()!=0) 00042 memoryused+=(unsigned int)(symbolvector.capacity()*sizeof(HuffNode_Leaf*)); 00043 00044 return memoryused; 00045 } 00046 //--------------------------------------------------------------------------- 00047 00048 00049 00050 00051 00052 //--------------------------------------------------------------------------- 00053 // Functions from CODER PUBLIC API 00054 bool HuffmanCoder::WriteSymbolBits(int symbolnum,bitwriter &bw) 00055 { 00056 // write bits for symbol number - this is easy because we've precomputed the bitvectors for every symbol 00057 assert(symbolnum<(int)(symbolvector.size())); 00058 return symbolvector[symbolnum]->AddBitsToBitWriter(bw); 00059 } 00060 00061 bool HuffmanCoder::DecodeSymbolFromInput(int &symbolnum, bitreader &br) 00062 { 00063 // decode a symbol from the input, and set symbolnum to symbol number 00064 // return false on no symbols left in stream 00065 HuffNode* nodep; 00066 bool bitvalue; 00067 00068 // now walk through the input bits 00069 nodep = symbolsetpq.top(); 00070 while (!br.empty()) 00071 { 00072 // grab a bit 00073 bitvalue = br.get_bit(); 00074 00075 // traverse down tree 00076 if (bitvalue==false) 00077 nodep=nodep->get_child0(); 00078 else 00079 nodep=nodep->get_child1(); 00080 if (nodep==NULL) 00081 { 00082 cerr << "ERROR: Internal error traversing huffman tree in huffmancoder.cpp, in HuffmanCoder::DecodeSymbolFromInput()." << endl; 00083 break; 00084 } 00085 00086 // if its leaf we got our symbol 00087 if (nodep->isleaf()) 00088 { 00089 // we hit a leaf, so this is our decoded symbol - return its number 00090 symbolnum=((HuffNode_Leaf*)nodep)->get_symbolid(); 00091 return true; 00092 } 00093 else 00094 { 00095 // just a middle node, so keep traversing 00096 } 00097 } 00098 00099 // no symbols to read 00100 return false; 00101 } 00102 //--------------------------------------------------------------------------- 00103 00104 00105 00106 00107 00108 //--------------------------------------------------------------------------- 00109 // Helpers 00110 void HuffmanCoder::ShowBitStrings() 00111 { 00112 // show bitstrings for debugging 00113 string bitset_string; 00114 THuffmanNodeWeight symbolweight; 00115 int symbolid; 00116 00117 // show the dictionary sorted alphabetically 00118 if (symbolsetpq.size()>0) 00119 { 00120 cout << "SymbolSet Huffman Codes ("<<(unsigned int)(symbolvector.size())<<" entries)\n"; 00121 cout << " " << setiosflags(ios::left) << setw(10) << "symbolid" << " " << setw(16) << "weight" << " " << "bitstring\n"; 00122 cout << " " << setiosflags(ios::left) << setw(10) << "--------" << " " << setw(16) << "------" << " " << "----------\n"; 00123 for (symbolvector_pos=symbolvector.begin();symbolvector_pos!=symbolvector.end();++symbolvector_pos) 00124 { 00125 symbolid=(*symbolvector_pos)->get_symbolid(); 00126 symbolweight = (*symbolvector_pos)->get_weight(); 00127 bitset_string=(*symbolvector_pos)->get_bitcode_string(); 00128 cout << " " << setiosflags(ios::left) << setw(10) << symbolid << " " << setw(16) << symbolweight << " " << bitset_string <<"\n"; 00129 } 00130 cout << "\n"; 00131 } 00132 } 00133 //--------------------------------------------------------------------------- 00134 00135 00136 00137 00138 //--------------------------------------------------------------------------- 00139 // Building and managing the priority queue (huffman tree) 00140 00141 bool HuffmanCoder::BuildUpdateHuffmanTreeAndBitcodes(OctaneModeler *modelerp) 00142 { 00143 // the SymbolSet is ready to be processed into a priority queue and for us to generate bitcodes 00144 // this can safely be called multiple times, so you can engage in a series 00145 // of pruning symbol set, generating bitcodes, and repeating the process to reduce bitcode lengths 00146 HuffNode *topmostp; 00147 HuffNode_Leaf *symbolleafp; 00148 00149 // Free any priority queue 00150 FreeSymbols(); 00151 00152 // Loop through all symbols in modeler and add them as new leaf symbols in a priority queue and fast lookup vector 00153 int symbolcount=modelerp->GetSymbolCount(); 00154 for (int index=0;index<symbolcount;++index) 00155 { 00156 // create symbol as new leaf to priority queue, recording its index in vector with a two-way link 00157 symbolleafp = new HuffNode_Leaf(index,modelerp->GetWeightVectorItem(index)); 00158 // add symbol as leaf in priority queue 00159 symbolsetpq.push(symbolleafp); 00160 // add symbol leaf to vector (note this will never change, its for fast indexed lookup since pq nodes move around) 00161 symbolvector.push_back(symbolleafp); 00162 } 00163 00164 // Build Priority Queue. This loop removes the two smallest HuffNodes from the queue. 00165 // It creates a new internal HuffNode that has those two HuffNodes as children. The new internal HuffNode is then inserted into the priority queue. 00166 // When there is only one HuffNode in the priority queue, the tree is complete. 00167 while ( symbolsetpq.size() > 1 ) 00168 { 00169 // pop topmost but save it so we can add it as left child 00170 topmostp=symbolsetpq.top(); 00171 HuffNode *child0 = topmostp; 00172 symbolsetpq.pop(); 00173 // pop next topmost but save it so we can add it as left child 00174 topmostp=symbolsetpq.top(); 00175 HuffNode *child1 = topmostp; 00176 symbolsetpq.pop(); 00177 // now make a new parent node with these two children 00178 symbolsetpq.push(new HuffNode_Middle(child0,child1)); 00179 } 00180 00181 // Traverse_buildbitcodes tree and build bit codes (create a bitset big enough to hold largest code length) 00182 TraverseHuffmanTreeBuildBitcodes(); 00183 00184 // now a test, show debugging info 00185 // ShowDebuggingInfo(); 00186 00187 // return success 00188 return true; 00189 } 00190 00191 00192 void HuffmanCoder::TraverseHuffmanTreeBuildBitcodes() 00193 { 00194 // begin recursive traverse of the huffman tree, used for building bitcodes 00195 bitset<DEF_HUFFMANPQ_MAXFUNCBITS> current_bitset; 00196 (symbolsetpq.top())->traverse_buildbitcodes(current_bitset,0); 00197 } 00198 00199 00200 void HuffmanCoder::FreeSymbols() 00201 { 00202 // free the priority queue 00203 HuffNode* topmostp; 00204 while ( symbolsetpq.size() >= 1 ) 00205 { 00206 // grab topmost and delete all of its children, then it (there really should be only 1 at top after building huffman tree) 00207 topmostp=symbolsetpq.top(); 00208 // note we tell the node to delete itself and all its children 00209 topmostp->recursive_freechildren(); 00210 delete topmostp; 00211 // now pop it off 00212 symbolsetpq.pop(); 00213 } 00214 // now free the symbol vector 00215 symbolvector.clear(); 00216 } 00217 //--------------------------------------------------------------------------- 00218