static mem_stat_t update_total_allocated(int block_delta, mem_stat_t byte_delta) { atomic32_t cur_total_blocks; for ( ; ; ) { cur_total_blocks = g_total_blocks; atomic32_t new_total_blocks = static_cast<atomic32_t>(cur_total_blocks + block_delta); LZHAM_ASSERT(new_total_blocks >= 0); if (atomic_compare_exchange32(&g_total_blocks, new_total_blocks, cur_total_blocks) == cur_total_blocks) break; } mem_stat_t cur_total_allocated, new_total_allocated; for ( ; ; ) { cur_total_allocated = g_total_allocated; new_total_allocated = static_cast<mem_stat_t>(cur_total_allocated + byte_delta); LZHAM_ASSERT(new_total_allocated >= 0); if (LZHAM_MEM_COMPARE_EXCHANGE(&g_total_allocated, new_total_allocated, cur_total_allocated) == cur_total_allocated) break; } for ( ; ; ) { mem_stat_t cur_max_allocated = g_max_allocated; mem_stat_t new_max_allocated = LZHAM_MAX(new_total_allocated, cur_max_allocated); if (LZHAM_MEM_COMPARE_EXCHANGE(&g_max_allocated, new_max_allocated, cur_max_allocated) == cur_max_allocated) break; } return new_total_allocated; }
bool task_pool::init(uint num_threads) { LZHAM_ASSERT(num_threads <= cMaxThreads); num_threads = math::minimum<uint>(num_threads, cMaxThreads); deinit(); bool succeeded = true; m_num_threads = 0; while (m_num_threads < num_threads) { m_threads[m_num_threads] = (HANDLE)_beginthreadex(NULL, 32768, thread_func, this, 0, NULL); LZHAM_ASSERT(m_threads[m_num_threads] != 0); if (!m_threads[m_num_threads]) { succeeded = false; break; } m_num_threads++; } if (!succeeded) { deinit(); return false; } return true; }
void CLZDecompBase::init_position_slots(uint dict_size_log2) { LZHAM_ASSERT(dict_size_log2 >= LZHAM_MIN_DICT_SIZE_LOG2); LZHAM_ASSERT(dict_size_log2 <= LZHAM_MAX_DICT_SIZE_LOG2_X64); LZHAM_ASSERT((sizeof(g_table_update_settings) / sizeof(g_table_update_settings[0])) == LZHAM_FASTEST_TABLE_UPDATE_RATE); //for (dict_size_log2 = LZHAM_MIN_DICT_SIZE_LOG2; dict_size_log2 <= LZHAM_MAX_DICT_SIZE_LOG2_X64; dict_size_log2++) { m_dict_size_log2 = dict_size_log2; m_dict_size = 1U << dict_size_log2; m_num_lzx_slots = g_num_lzx_position_slots[dict_size_log2 - LZHAM_MIN_DICT_SIZE_LOG2]; #if 0 int i, j; for (i = 0, j = 0; i < cLZXMaxPositionSlots; i += 2) { m_lzx_position_extra_bits[i] = (uint8)j; m_lzx_position_extra_bits[i + 1] = (uint8)j; if ((i != 0) && (j < 25)) j++; } for (i = 0, j = 0; i < cLZXMaxPositionSlots; i++) { m_lzx_position_base[i] = j; m_lzx_position_extra_mask[i] = (1 << m_lzx_position_extra_bits[i]) - 1; j += (1 << m_lzx_position_extra_bits[i]); } for (uint i = 0; i < cLZXMaxPositionSlots; i++) { printf("0x%X, ", m_lzx_position_base[i]); if ((i & 15) == 15) printf("\n"); } #endif #if 0 m_num_lzx_slots = 0; const uint largest_dist = m_dict_size - 1; for (i = 0; i < cLZXMaxPositionSlots; i++) { if ( (largest_dist >= m_lzx_position_base[i]) && (largest_dist < (m_lzx_position_base[i] + (1 << m_lzx_position_extra_bits[i])) ) ) { m_num_lzx_slots = i + 1; break; } } LZHAM_VERIFY(m_num_lzx_slots); #endif //printf("%u, ", m_num_lzx_slots); } }
static void* lzham_default_realloc(void* p, size_t size, size_t* pActual_size, lzham_bool movable, void* pUser_data) { LZHAM_NOTE_UNUSED(pUser_data); void* p_new; if (!p) { p_new = malloc(size); LZHAM_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (LZHAM_MIN_ALLOC_ALIGNMENT - 1)) == 0 ); if (pActual_size) *pActual_size = p_new ? _msize(p_new) : 0; } else if (!size) { free(p); p_new = NULL; if (pActual_size) *pActual_size = 0; } else { void* p_final_block = p; #ifdef WIN32 p_new = _expand(p, size); #else p_new = NULL; #endif if (p_new) { LZHAM_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (LZHAM_MIN_ALLOC_ALIGNMENT - 1)) == 0 ); p_final_block = p_new; } else if (movable) { p_new = realloc(p, size); if (p_new) { LZHAM_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (LZHAM_MIN_ALLOC_ALIGNMENT - 1)) == 0 ); p_final_block = p_new; } } if (pActual_size) *pActual_size = _msize(p_final_block); } return p_new; }
bool generate_codes(uint num_syms, const uint8* pCodesizes, uint16* pCodes) { uint num_codes[cMaxExpectedHuffCodeSize + 1]; utils::zero_object(num_codes); for (uint i = 0; i < num_syms; i++) { uint c = pCodesizes[i]; LZHAM_ASSERT(c <= cMaxExpectedHuffCodeSize); num_codes[c]++; } uint code = 0; uint next_code[cMaxExpectedHuffCodeSize + 1]; next_code[0] = 0; for (uint i = 1; i <= cMaxExpectedHuffCodeSize; i++) { next_code[i] = code; code = (code + num_codes[i]) << 1; } if (code != (1 << (cMaxExpectedHuffCodeSize + 1))) { uint t = 0; for (uint i = 1; i <= cMaxExpectedHuffCodeSize; i++) { t += num_codes[i]; if (t > 1) { LZHAM_LOG_ERROR(3003); return false; } } } for (uint i = 0; i < num_syms; i++) { uint c = pCodesizes[i]; LZHAM_ASSERT(!c || (next_code[c] <= cUINT16_MAX)); pCodes[i] = static_cast<uint16>(next_code[c]++); LZHAM_ASSERT(!c || (math::total_bits(pCodes[i]) <= pCodesizes[i])); } return true; }
void* lzham_malloc(size_t size, size_t* pActual_size) { size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U); if (!size) size = sizeof(uint32); if (size > MAX_POSSIBLE_BLOCK_SIZE) { lzham_mem_error("lzham_malloc: size too big"); return NULL; } size_t actual_size = size; uint8* p_new = static_cast<uint8*>((*g_pRealloc)(NULL, size, &actual_size, true, g_pUser_data)); if (pActual_size) *pActual_size = actual_size; if ((!p_new) || (actual_size < size)) { lzham_mem_error("lzham_malloc: out of memory"); return NULL; } LZHAM_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (LZHAM_MIN_ALLOC_ALIGNMENT - 1)) == 0); #if LZHAM_MEM_STATS update_total_allocated(1, static_cast<mem_stat_t>(actual_size)); #endif return p_new; }
bool task_pool::init(uint num_threads) { LZHAM_ASSERT(num_threads <= cMaxThreads); num_threads = math::minimum<uint>(num_threads, cMaxThreads); deinit(); bool succeeded = true; m_num_threads = 0; while (m_num_threads < num_threads) { int status = pthread_create(&m_threads[m_num_threads], NULL, thread_func, this); if (status) { succeeded = false; break; } m_num_threads++; } if (!succeeded) { deinit(); return false; } return true; }
void lzham_timer::stop() { LZHAM_ASSERT(m_started); query_counter(&m_stop_time); m_stopped = true; }
// It's the object's responsibility to delete pObj within the execute_task() method, if needed! bool task_pool::queue_task(executable_task* pObj, uint64 data, void* pData_ptr) { LZHAM_ASSERT(m_num_threads); LZHAM_ASSERT(pObj); task tsk; tsk.m_pObj = pObj; tsk.m_data = data; tsk.m_pData_ptr = pData_ptr; tsk.m_flags = cTaskFlagObject; if (!m_task_stack.try_push(tsk)) return false; atomic_increment32(&m_num_outstanding_tasks); m_tasks_available.release(1); return true; }
bool task_pool::queue_task(task_callback_func pFunc, uint64 data, void* pData_ptr) { LZHAM_ASSERT(m_num_threads); LZHAM_ASSERT(pFunc); task tsk; tsk.m_callback = pFunc; tsk.m_data = data; tsk.m_pData_ptr = pData_ptr; tsk.m_flags = 0; if (!m_task_stack.try_push(tsk)) return false; atomic_increment32(&m_num_outstanding_tasks); m_tasks_available.release(1); return true; }
timer_ticks lzham_timer::get_elapsed_us() const { LZHAM_ASSERT(m_started); if (!m_started) return 0; timer_ticks stop_time = m_stop_time; if (!m_stopped) query_counter(&stop_time); timer_ticks delta = stop_time - m_start_time; return (delta * 1000000ULL + (g_freq >> 1U)) / g_freq; }
double lzham_timer::get_elapsed_secs() const { LZHAM_ASSERT(m_started); if (!m_started) return 0; timer_ticks stop_time = m_stop_time; if (!m_stopped) query_counter(&stop_time); timer_ticks delta = stop_time - m_start_time; return delta * g_inv_freq; }
void* lzham_realloc(void* p, size_t size, size_t* pActual_size, bool movable) { if ((ptr_bits_t)p & (LZHAM_MIN_ALLOC_ALIGNMENT - 1)) { lzham_mem_error("lzham_realloc: bad ptr"); return NULL; } if (size > MAX_POSSIBLE_BLOCK_SIZE) { lzham_mem_error("lzham_malloc: size too big"); return NULL; } #if LZHAM_MEM_STATS size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0; #endif size_t actual_size = size; void* p_new = (*g_pRealloc)(p, size, &actual_size, movable, g_pUser_data); if (pActual_size) *pActual_size = actual_size; LZHAM_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (LZHAM_MIN_ALLOC_ALIGNMENT - 1)) == 0); #if LZHAM_MEM_STATS int num_new_blocks = 0; if (p) { if (!p_new) num_new_blocks = -1; } else if (p_new) { num_new_blocks = 1; } update_total_allocated(num_new_blocks, static_cast<mem_stat_t>(actual_size) - static_cast<mem_stat_t>(cur_size)); #endif return p_new; }
bool elemental_vector::increase_capacity(uint min_new_capacity, bool grow_hint, uint element_size, object_mover pMover, bool nofail) { LZHAM_ASSERT(m_size <= m_capacity); #if LZHAM_64BIT_POINTERS LZHAM_ASSUME(sizeof(void*) == sizeof(uint64)); LZHAM_ASSERT(min_new_capacity < (0x400000000ULL / element_size)); #else LZHAM_ASSUME(sizeof(void*) == sizeof(uint32)); LZHAM_ASSERT(min_new_capacity < (0x7FFF0000U / element_size)); #endif if (m_capacity >= min_new_capacity) return true; // new_capacity must be 64-bit when compiling on x64. size_t new_capacity = (size_t)min_new_capacity; if ((grow_hint) && (!math::is_power_of_2(static_cast<uint64>(new_capacity)))) new_capacity = static_cast<uint>(math::next_pow2(static_cast<uint64>(new_capacity))); LZHAM_ASSERT(new_capacity && (new_capacity > m_capacity)); const size_t desired_size = element_size * new_capacity; size_t actual_size; if (!pMover) { void* new_p = lzham_realloc(m_malloc_context, m_p, desired_size, &actual_size, true); if (!new_p) { if (nofail) { LZHAM_LOG_ERROR(5000); return false; } char buf[256]; sprintf_s(buf, sizeof(buf), "vector: lzham_realloc() failed allocating %u bytes", desired_size); LZHAM_FAIL(buf); } m_p = new_p; } else { void* new_p = lzham_malloc(m_malloc_context, desired_size, &actual_size); if (!new_p) { if (nofail) { LZHAM_LOG_ERROR(5001); return false; } LZHAM_LOG_ERROR(5002); char buf[256]; sprintf_s(buf, sizeof(buf), "vector: lzham_malloc() failed allocating %u bytes", desired_size); LZHAM_FAIL(buf); } (*pMover)(new_p, m_p, m_size); if (m_p) lzham_free(m_malloc_context, m_p); m_p = new_p; } if (actual_size > desired_size) m_capacity = static_cast<uint>(actual_size / element_size); else m_capacity = static_cast<uint>(new_capacity); return true; }
bool generate_decoder_tables(uint num_syms, const uint8* pCodesizes, decoder_tables* pTables, uint table_bits, const code_size_histogram &code_size_histo, bool sym_freq_all_ones) { uint min_codes[cMaxExpectedHuffCodeSize]; if ((!num_syms) || (table_bits > cMaxTableBits)) { LZHAM_LOG_ERROR(3004); return false; } pTables->m_num_syms = num_syms; uint sorted_positions[cMaxExpectedHuffCodeSize + 1]; uint next_code = 0; uint total_used_syms = 0; uint max_code_size = 0; uint min_code_size = UINT_MAX; for (uint i = 1; i <= cMaxExpectedHuffCodeSize; i++) { const uint n = code_size_histo.m_num_codes[i]; if (!n) pTables->m_max_codes[i - 1] = 0;//UINT_MAX; else { min_code_size = math::minimum(min_code_size, i); max_code_size = math::maximum(max_code_size, i); min_codes[i - 1] = next_code; pTables->m_max_codes[i - 1] = next_code + n - 1; pTables->m_max_codes[i - 1] = 1 + ((pTables->m_max_codes[i - 1] << (16 - i)) | ((1 << (16 - i)) - 1)); pTables->m_val_ptrs[i - 1] = total_used_syms; sorted_positions[i] = total_used_syms; next_code += n; total_used_syms += n; } next_code <<= 1; } pTables->m_total_used_syms = total_used_syms; if (total_used_syms > pTables->m_cur_sorted_symbol_order_size) { pTables->m_cur_sorted_symbol_order_size = total_used_syms; if (!math::is_power_of_2(total_used_syms)) pTables->m_cur_sorted_symbol_order_size = math::minimum<uint>(num_syms, math::next_pow2(total_used_syms)); if (pTables->m_sorted_symbol_order) { lzham_delete_array(pTables->m_malloc_context, pTables->m_sorted_symbol_order); pTables->m_sorted_symbol_order = NULL; } pTables->m_sorted_symbol_order = lzham_new_array<uint16>(pTables->m_malloc_context, pTables->m_cur_sorted_symbol_order_size); if (!pTables->m_sorted_symbol_order) { LZHAM_LOG_ERROR(3005); return false; } } pTables->m_min_code_size = static_cast<uint8>(min_code_size); pTables->m_max_code_size = static_cast<uint8>(max_code_size); if (sym_freq_all_ones) { if (min_code_size == max_code_size) { memcpy(pTables->m_sorted_symbol_order, g_uint16_sequence, num_syms * sizeof(uint16)); } else { LZHAM_ASSERT((min_code_size + 1) == max_code_size); LZHAM_ASSERT(pCodesizes[0] == max_code_size); LZHAM_ASSERT(pCodesizes[code_size_histo.m_num_codes[max_code_size]] == min_code_size); memcpy(pTables->m_sorted_symbol_order + sorted_positions[max_code_size], g_uint16_sequence, code_size_histo.m_num_codes[max_code_size] * sizeof(uint16)); memcpy(pTables->m_sorted_symbol_order + sorted_positions[min_code_size], g_uint16_sequence + code_size_histo.m_num_codes[max_code_size], code_size_histo.m_num_codes[min_code_size] * sizeof(uint16)); } #ifdef LZHAM_BUILD_DEBUG for (uint i = 0; i < num_syms; i++) { uint c = pCodesizes[i]; LZHAM_ASSERT(code_size_histo.m_num_codes[c]); uint sorted_pos = sorted_positions[c]++; LZHAM_ASSERT(sorted_pos < total_used_syms); LZHAM_ASSERT(pTables->m_sorted_symbol_order[sorted_pos] == i); } #endif } else { for (uint i = 0; i < num_syms; i++) { uint c = pCodesizes[i]; LZHAM_ASSERT(code_size_histo.m_num_codes[c]); uint sorted_pos = sorted_positions[c]++; LZHAM_ASSERT(sorted_pos < total_used_syms); pTables->m_sorted_symbol_order[sorted_pos] = static_cast<uint16>(i); } } if (table_bits <= pTables->m_min_code_size) table_bits = 0; pTables->m_table_bits = table_bits; if (table_bits) { uint table_size = 1 << table_bits; if (table_size > pTables->m_cur_lookup_size) { pTables->m_cur_lookup_size = table_size; if (pTables->m_lookup) { lzham_delete_array(pTables->m_malloc_context, pTables->m_lookup); pTables->m_lookup = NULL; } pTables->m_lookup = lzham_new_array<uint32>(pTables->m_malloc_context, table_size); if (!pTables->m_lookup) { LZHAM_LOG_ERROR(3006); return false; } } memset(pTables->m_lookup, 0xFF, static_cast<uint>(sizeof(pTables->m_lookup[0])) * (1UL << table_bits)); for (uint codesize = 1; codesize <= table_bits; codesize++) { if (!code_size_histo.m_num_codes[codesize]) continue; const uint fillsize = table_bits - codesize; const uint fillnum = 1 << fillsize; const uint min_code = min_codes[codesize - 1]; const uint max_code = pTables->get_unshifted_max_code(codesize); const uint val_ptr = pTables->m_val_ptrs[codesize - 1]; for (uint code = min_code; code <= max_code; code++) { const uint sym_index = pTables->m_sorted_symbol_order[ val_ptr + code - min_code ]; LZHAM_ASSERT( pCodesizes[sym_index] == codesize ); for (uint j = 0; j < fillnum; j++) { const uint t = j + (code << fillsize); LZHAM_ASSERT(t < (1U << table_bits)); LZHAM_ASSERT(pTables->m_lookup[t] == cUINT32_MAX); pTables->m_lookup[t] = sym_index | (codesize << 16U); } } } } for (uint i = 0; i < cMaxExpectedHuffCodeSize; i++) pTables->m_val_ptrs[i] -= min_codes[i]; pTables->m_table_max_code = 0; pTables->m_decode_start_code_size = pTables->m_min_code_size; if (table_bits) { uint i; for (i = table_bits; i >= 1; i--) { if (code_size_histo.m_num_codes[i]) { pTables->m_table_max_code = pTables->m_max_codes[i - 1]; break; } } if (i >= 1) { pTables->m_decode_start_code_size = table_bits + 1; for (i = table_bits + 1; i <= max_code_size; i++) { if (code_size_histo.m_num_codes[i]) { pTables->m_decode_start_code_size = i; break; } } } } // sentinels pTables->m_max_codes[cMaxExpectedHuffCodeSize] = UINT_MAX; pTables->m_val_ptrs[cMaxExpectedHuffCodeSize] = 0xFFFFF; pTables->m_table_shift = 32 - pTables->m_table_bits; return true; }
bool limit_max_code_size(uint num_syms, uint8* pCodesizes, uint max_code_size) { const uint cMaxEverCodeSize = 34; if ((!num_syms) || (num_syms > cMaxSupportedSyms) || (max_code_size < 1) || (max_code_size > cMaxEverCodeSize)) { LZHAM_LOG_ERROR(3000); return false; } uint num_codes[cMaxEverCodeSize + 1]; utils::zero_object(num_codes); bool should_limit = false; for (uint i = 0; i < num_syms; i++) { uint c = pCodesizes[i]; LZHAM_ASSERT(c <= cMaxEverCodeSize); num_codes[c]++; if (c > max_code_size) should_limit = true; } if (!should_limit) return true; uint ofs = 0; uint next_sorted_ofs[cMaxEverCodeSize + 1]; for (uint i = 1; i <= cMaxEverCodeSize; i++) { next_sorted_ofs[i] = ofs; ofs += num_codes[i]; } if ((ofs < 2) || (ofs > cMaxSupportedSyms)) return true; if (ofs > (1U << max_code_size)) { LZHAM_LOG_ERROR(3001); return false; } for (uint i = max_code_size + 1; i <= cMaxEverCodeSize; i++) num_codes[max_code_size] += num_codes[i]; // Technique of adjusting tree to enforce maximum code size from LHArc. // (If you remember what LHArc was, you've been doing this for a LONG time.) uint total = 0; for (uint i = max_code_size; i; --i) total += (num_codes[i] << (max_code_size - i)); if (total == (1U << max_code_size)) return true; do { num_codes[max_code_size]--; uint i; for (i = max_code_size - 1; i; --i) { if (!num_codes[i]) continue; num_codes[i]--; num_codes[i + 1] += 2; break; } if (!i) { LZHAM_LOG_ERROR(3002); return false; } total--; } while (total != (1U << max_code_size)); uint8 new_codesizes[cMaxSupportedSyms]; uint8* p = new_codesizes; for (uint i = 1; i <= max_code_size; i++) { uint n = num_codes[i]; if (n) { memset(p, i, n); p += n; } } for (uint i = 0; i < num_syms; i++) { const uint c = pCodesizes[i]; if (c) { uint next_ofs = next_sorted_ofs[c]; next_sorted_ofs[c] = next_ofs + 1; pCodesizes[i] = static_cast<uint8>(new_codesizes[next_ofs]); } } return true; }
bool generate_decoder_tables(uint num_syms, const uint8* pCodesizes, decoder_tables* pTables, uint table_bits) { uint min_codes[cMaxExpectedCodeSize]; if ((!num_syms) || (table_bits > cMaxTableBits)) return false; pTables->m_num_syms = num_syms; uint num_codes[cMaxExpectedCodeSize + 1]; utils::zero_object(num_codes); for (uint i = 0; i < num_syms; i++) { uint c = pCodesizes[i]; num_codes[c]++; } uint sorted_positions[cMaxExpectedCodeSize + 1]; uint code = 0; uint total_used_syms = 0; uint max_code_size = 0; uint min_code_size = UINT_MAX; for (uint i = 1; i <= cMaxExpectedCodeSize; i++) { const uint n = num_codes[i]; if (!n) pTables->m_max_codes[i - 1] = 0;//UINT_MAX; else { min_code_size = math::minimum(min_code_size, i); max_code_size = math::maximum(max_code_size, i); min_codes[i - 1] = code; pTables->m_max_codes[i - 1] = code + n - 1; pTables->m_max_codes[i - 1] = 1 + ((pTables->m_max_codes[i - 1] << (16 - i)) | ((1 << (16 - i)) - 1)); pTables->m_val_ptrs[i - 1] = total_used_syms; sorted_positions[i] = total_used_syms; code += n; total_used_syms += n; } code <<= 1; } pTables->m_total_used_syms = total_used_syms; if (total_used_syms > pTables->m_cur_sorted_symbol_order_size) { pTables->m_cur_sorted_symbol_order_size = total_used_syms; if (!math::is_power_of_2(total_used_syms)) pTables->m_cur_sorted_symbol_order_size = math::minimum<uint>(num_syms, math::next_pow2(total_used_syms)); if (pTables->m_sorted_symbol_order) { lzham_delete_array(pTables->m_sorted_symbol_order); pTables->m_sorted_symbol_order = NULL; } pTables->m_sorted_symbol_order = lzham_new_array<uint16>(pTables->m_cur_sorted_symbol_order_size); if (!pTables->m_sorted_symbol_order) return false; } pTables->m_min_code_size = static_cast<uint8>(min_code_size); pTables->m_max_code_size = static_cast<uint8>(max_code_size); for (uint i = 0; i < num_syms; i++) { uint c = pCodesizes[i]; if (c) { LZHAM_ASSERT(num_codes[c]); uint sorted_pos = sorted_positions[c]++; LZHAM_ASSERT(sorted_pos < total_used_syms); pTables->m_sorted_symbol_order[sorted_pos] = static_cast<uint16>(i); } } if (table_bits <= pTables->m_min_code_size) table_bits = 0; pTables->m_table_bits = table_bits; if (table_bits) { uint table_size = 1 << table_bits; if (table_size > pTables->m_cur_lookup_size) { pTables->m_cur_lookup_size = table_size; if (pTables->m_lookup) { lzham_delete_array(pTables->m_lookup); pTables->m_lookup = NULL; } pTables->m_lookup = lzham_new_array<uint32>(table_size); if (!pTables->m_lookup) return false; } memset(pTables->m_lookup, 0xFF, static_cast<uint>(sizeof(pTables->m_lookup[0])) * (1UL << table_bits)); for (uint codesize = 1; codesize <= table_bits; codesize++) { if (!num_codes[codesize]) continue; const uint fillsize = table_bits - codesize; const uint fillnum = 1 << fillsize; const uint min_code = min_codes[codesize - 1]; const uint max_code = pTables->get_unshifted_max_code(codesize); const uint val_ptr = pTables->m_val_ptrs[codesize - 1]; for (uint code = min_code; code <= max_code; code++) { const uint sym_index = pTables->m_sorted_symbol_order[ val_ptr + code - min_code ]; LZHAM_ASSERT( pCodesizes[sym_index] == codesize ); for (uint j = 0; j < fillnum; j++) { const uint t = j + (code << fillsize); LZHAM_ASSERT(t < (1U << table_bits)); LZHAM_ASSERT(pTables->m_lookup[t] == UINT32_MAX); pTables->m_lookup[t] = sym_index | (codesize << 16U); } } } } for (uint i = 0; i < cMaxExpectedCodeSize; i++) pTables->m_val_ptrs[i] -= min_codes[i]; pTables->m_table_max_code = 0; pTables->m_decode_start_code_size = pTables->m_min_code_size; if (table_bits) { uint i; for (i = table_bits; i >= 1; i--) { if (num_codes[i]) { pTables->m_table_max_code = pTables->m_max_codes[i - 1]; break; } } if (i >= 1) { pTables->m_decode_start_code_size = table_bits + 1; for (uint i = table_bits + 1; i <= max_code_size; i++) { if (num_codes[i]) { pTables->m_decode_start_code_size = i; break; } } } } // sentinels pTables->m_max_codes[cMaxExpectedCodeSize] = UINT_MAX; pTables->m_val_ptrs[cMaxExpectedCodeSize] = 0xFFFFF; pTables->m_table_shift = 32 - pTables->m_table_bits; 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; }