bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret, code_size_histogram &code_size_hist) { if ((!num_syms) || (num_syms > cHuffmanMaxSupportedSyms)) return false; huffman_work_tables& state = *static_cast<huffman_work_tables*>(pContext);; uint max_freq = 0; uint total_freq = 0; uint num_used_syms = 0; for (uint i = 0; i < num_syms; i++) { uint freq = pFreq[i]; if (!freq) pCodesizes[i] = 0; else { total_freq += freq; max_freq = math::maximum(max_freq, freq); sym_freq& sf = state.syms0[num_used_syms]; sf.m_left = (uint16)i; sf.m_right = cUINT16_MAX; sf.m_freq = freq; num_used_syms++; } } total_freq_ret = total_freq; if (num_used_syms == 1) { pCodesizes[state.syms0[0].m_left] = 1; return true; } sym_freq* syms = radix_sort_syms(num_used_syms, state.syms0, state.syms1); int x[cHuffmanMaxSupportedSyms]; for (uint i = 0; i < num_used_syms; i++) x[i] = syms[i].m_freq; calculate_minimum_redundancy(x, num_used_syms); uint max_len = 0; for (uint i = 0; i < num_used_syms; i++) { uint len = x[i]; max_len = math::maximum(len, max_len); code_size_hist.m_num_codes[LZHAM_MIN(len, (uint)code_size_histogram::cMaxUnlimitedHuffCodeSize)]++; pCodesizes[syms[i].m_left] = static_cast<uint8>(len); } max_code_size = max_len; return true; }
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret) { if ((!num_syms) || (num_syms > cHuffmanMaxSupportedSyms)) return false; huffman_work_tables& state = *static_cast<huffman_work_tables*>(pContext);; uint max_freq = 0; uint total_freq = 0; uint num_used_syms = 0; for (uint i = 0; i < num_syms; i++) { uint freq = pFreq[i]; if (!freq) pCodesizes[i] = 0; else { total_freq += freq; max_freq = math::maximum(max_freq, freq); sym_freq& sf = state.syms0[num_used_syms]; sf.m_left = (uint16)i; sf.m_right = LZHAM_UINT16_MAX; sf.m_freq = freq; num_used_syms++; } } total_freq_ret = total_freq; if (num_used_syms == 1) { pCodesizes[state.syms0[0].m_left] = 1; return true; } sym_freq* syms = radix_sort_syms(num_used_syms, state.syms0, state.syms1); #if USE_CALCULATE_MINIMUM_REDUNDANCY int x[cHuffmanMaxSupportedSyms]; for (uint i = 0; i < num_used_syms; i++) x[i] = syms[i].m_freq; calculate_minimum_redundancy(x, num_used_syms); uint max_len = 0; for (uint i = 0; i < num_used_syms; i++) { uint len = x[i]; max_len = math::maximum(len, max_len); pCodesizes[syms[i].m_left] = static_cast<uint8>(len); } max_code_size = max_len; #else // Computes Huffman codelengths in linear time. More readable than calculate_minimum_redundancy(), and approximately the same speed, but not in-place. // Dummy node sym_freq& sf = state.syms0[num_used_syms]; sf.m_left = LZHAM_UINT16_MAX; sf.m_right = LZHAM_UINT16_MAX; sf.m_freq = UINT_MAX; uint next_internal_node = num_used_syms + 1; uint queue_front = 0; uint queue_end = 0; uint next_lowest_sym = 0; uint num_nodes_remaining = num_used_syms; do { uint left_freq = syms[next_lowest_sym].m_freq; uint left_child = next_lowest_sym; if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < left_freq)) { left_child = state.queue[queue_front]; left_freq = syms[left_child].m_freq; queue_front++; } else next_lowest_sym++; uint right_freq = syms[next_lowest_sym].m_freq; uint right_child = next_lowest_sym; if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < right_freq)) { right_child = state.queue[queue_front]; right_freq = syms[right_child].m_freq; queue_front++; } else next_lowest_sym++; LZHAM_ASSERT(next_internal_node < huffman_work_tables::cMaxInternalNodes); const uint internal_node_index = next_internal_node; next_internal_node++; syms[internal_node_index].m_freq = left_freq + right_freq; syms[internal_node_index].m_left = static_cast<uint16>(left_child); syms[internal_node_index].m_right = static_cast<uint16>(right_child); LZHAM_ASSERT(queue_end < huffman_work_tables::cMaxInternalNodes); state.queue[queue_end] = static_cast<uint16>(internal_node_index); queue_end++; num_nodes_remaining--; } while (num_nodes_remaining > 1); LZHAM_ASSERT(next_lowest_sym == num_used_syms); LZHAM_ASSERT((queue_end - queue_front) == 1); uint cur_node_index = state.queue[queue_front]; uint32* pStack = (syms == state.syms0) ? (uint32*)state.syms1 : (uint32*)state.syms0; uint32* pStack_top = pStack; uint max_level = 0; for ( ; ; ) { uint level = cur_node_index >> 16; uint node_index = cur_node_index & 0xFFFF; uint left_child = syms[node_index].m_left; uint right_child = syms[node_index].m_right; uint next_level = (cur_node_index + 0x10000) & 0xFFFF0000; if (left_child < num_used_syms) { max_level = math::maximum(max_level, level); pCodesizes[syms[left_child].m_left] = static_cast<uint8>(level + 1); if (right_child < num_used_syms) { pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1); if (pStack == pStack_top) break; cur_node_index = *--pStack; } else { cur_node_index = next_level | right_child; } } else { if (right_child < num_used_syms) { max_level = math::maximum(max_level, level); pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1); cur_node_index = next_level | left_child; } else { *pStack++ = next_level | left_child; cur_node_index = next_level | right_child; } } } max_code_size = max_level + 1; #endif return true; }