mirror of
https://github.com/ip7z/7zip.git
synced 2025-12-06 07:12:00 +01:00
361 lines
9.4 KiB
C
361 lines
9.4 KiB
C
/* HuffEnc.c -- functions for Huffman encoding
|
|
Igor Pavlov : Public domain */
|
|
|
|
#include "Precomp.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "HuffEnc.h"
|
|
#include "Sort.h"
|
|
#include "CpuArch.h"
|
|
|
|
#define kMaxLen Z7_HUFFMAN_LEN_MAX
|
|
#define NUM_BITS 10
|
|
#define MASK ((1u << NUM_BITS) - 1)
|
|
#define FREQ_MASK (~(UInt32)MASK)
|
|
#define NUM_COUNTERS (48 * 2)
|
|
|
|
#if 1 && (defined(MY_CPU_LE) || defined(MY_CPU_BE))
|
|
#if defined(MY_CPU_LE)
|
|
#define HI_HALF_OFFSET 1
|
|
#else
|
|
#define HI_HALF_OFFSET 0
|
|
#endif
|
|
#define LOAD_PARENT(p) ((unsigned)*((const UInt16 *)(p) + HI_HALF_OFFSET))
|
|
#define STORE_PARENT(p, fb, val) *((UInt16 *)(p) + HI_HALF_OFFSET) = (UInt16)(val);
|
|
#define STORE_PARENT_DIRECT(p, fb, hi) STORE_PARENT(p, fb, hi)
|
|
#define UPDATE_E(eHi) eHi++;
|
|
#else
|
|
#define LOAD_PARENT(p) ((unsigned)(*(p) >> NUM_BITS))
|
|
#define STORE_PARENT_DIRECT(p, fb, hi) *(p) = ((fb) & MASK) | (hi); // set parent field
|
|
#define STORE_PARENT(p, fb, val) STORE_PARENT_DIRECT(p, fb, ((UInt32)(val) << NUM_BITS))
|
|
#define UPDATE_E(eHi) eHi += 1 << NUM_BITS;
|
|
#endif
|
|
|
|
void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, unsigned numSymbols, unsigned maxLen)
|
|
{
|
|
#if NUM_COUNTERS > 2
|
|
unsigned counters[NUM_COUNTERS];
|
|
#endif
|
|
#if 1 && NUM_COUNTERS > (kMaxLen + 4) * 2
|
|
#define lenCounters (counters)
|
|
#define codes (counters + kMaxLen + 4)
|
|
#else
|
|
unsigned lenCounters[kMaxLen + 1];
|
|
UInt32 codes[kMaxLen + 1];
|
|
#endif
|
|
|
|
unsigned num;
|
|
{
|
|
unsigned i;
|
|
// UInt32 sum = 0;
|
|
|
|
#if NUM_COUNTERS > 2
|
|
|
|
#define CTR_ITEM_FOR_FREQ(freq) \
|
|
counters[(freq) >= NUM_COUNTERS - 1 ? NUM_COUNTERS - 1 : (unsigned)(freq)]
|
|
|
|
for (i = 0; i < NUM_COUNTERS; i++)
|
|
counters[i] = 0;
|
|
memset(lens, 0, numSymbols);
|
|
{
|
|
const UInt32 *fp = freqs + numSymbols;
|
|
#define NUM_UNROLLS 1
|
|
#if NUM_UNROLLS > 1 // use 1 if odd (numSymbols) is possisble
|
|
if (numSymbols & 1)
|
|
{
|
|
UInt32 f;
|
|
f = *--fp; CTR_ITEM_FOR_FREQ(f)++;
|
|
// sum += f;
|
|
}
|
|
#endif
|
|
do
|
|
{
|
|
UInt32 f;
|
|
fp -= NUM_UNROLLS;
|
|
f = fp[0]; CTR_ITEM_FOR_FREQ(f)++;
|
|
// sum += f;
|
|
#if NUM_UNROLLS > 1
|
|
f = fp[1]; CTR_ITEM_FOR_FREQ(f)++;
|
|
// sum += f;
|
|
#endif
|
|
}
|
|
while (fp != freqs);
|
|
}
|
|
#if 0
|
|
printf("\nsum=%8u numSymbols =%3u ctrs:", sum, numSymbols);
|
|
{
|
|
unsigned k = 0;
|
|
for (k = 0; k < NUM_COUNTERS; k++)
|
|
printf(" %u", counters[k]);
|
|
}
|
|
#endif
|
|
|
|
num = counters[1];
|
|
counters[1] = 0;
|
|
for (i = 2; i != NUM_COUNTERS; i += 2)
|
|
{
|
|
unsigned c;
|
|
c = (counters )[i]; (counters )[i] = num; num += c;
|
|
c = (counters + 1)[i]; (counters + 1)[i] = num; num += c;
|
|
}
|
|
counters[0] = num; // we want to write (freq==0) symbols to the end of (p) array
|
|
{
|
|
i = 0;
|
|
do
|
|
{
|
|
const UInt32 f = freqs[i];
|
|
#if 0
|
|
if (f == 0) lens[i] = 0; else
|
|
#endif
|
|
p[CTR_ITEM_FOR_FREQ(f)++] = i | (f << NUM_BITS);
|
|
}
|
|
while (++i != numSymbols);
|
|
}
|
|
HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
|
|
|
|
#else // NUM_COUNTERS <= 2
|
|
|
|
num = 0;
|
|
for (i = 0; i < numSymbols; i++)
|
|
{
|
|
const UInt32 freq = freqs[i];
|
|
if (freq == 0)
|
|
lens[i] = 0;
|
|
else
|
|
p[num++] = i | (freq << NUM_BITS);
|
|
}
|
|
HeapSort(p, num);
|
|
|
|
#endif
|
|
}
|
|
|
|
if (num <= 2)
|
|
{
|
|
unsigned minCode = 0;
|
|
unsigned maxCode = 1;
|
|
if (num)
|
|
{
|
|
maxCode = (unsigned)p[(size_t)num - 1] & MASK;
|
|
if (num == 2)
|
|
{
|
|
minCode = (unsigned)p[0] & MASK;
|
|
if (minCode > maxCode)
|
|
{
|
|
const unsigned temp = minCode;
|
|
minCode = maxCode;
|
|
maxCode = temp;
|
|
}
|
|
}
|
|
else if (maxCode == 0)
|
|
maxCode++;
|
|
}
|
|
p[minCode] = 0;
|
|
p[maxCode] = 1;
|
|
lens[minCode] = lens[maxCode] = 1;
|
|
return;
|
|
}
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i <= kMaxLen; i++)
|
|
lenCounters[i] = 0;
|
|
lenCounters[1] = 2; // by default root node has 2 child leaves at level 1.
|
|
}
|
|
// if (num != 2)
|
|
{
|
|
// num > 2
|
|
// the binary tree will contain (num - 1) internal nodes.
|
|
// p[num - 2] will be root node of binary tree.
|
|
UInt32 *b;
|
|
UInt32 *n;
|
|
// first node will have two leaf childs: p[0] and p[1]:
|
|
// p[0] += p[1] & FREQ_MASK; // set frequency sum of child leafs
|
|
// if (pi == n) exit(0);
|
|
// if (pi != n)
|
|
{
|
|
UInt32 fb = (p[1] & FREQ_MASK) + p[0];
|
|
UInt32 f = p[2] & FREQ_MASK;
|
|
const UInt32 *pi = p + 2;
|
|
UInt32 *e = p;
|
|
UInt32 eHi = 0;
|
|
n = p + num;
|
|
b = p;
|
|
// p[0] = fb;
|
|
for (;;)
|
|
{
|
|
// (b <= e)
|
|
UInt32 sum;
|
|
e++;
|
|
UPDATE_E(eHi)
|
|
|
|
// (b < e)
|
|
|
|
// p range : high bits
|
|
// [0, b) : parent : processed nodes that have parent and childs
|
|
// [b, e) : FREQ : non-processed nodes that have no parent but have childs
|
|
// [e, pi) : FREQ : processed leaves for which parent node was created
|
|
// [pi, n) : FREQ : non-processed leaves for which parent node was not created
|
|
|
|
// first child
|
|
// note : (*b < f) is same result as ((*b & FREQ_MASK) < f)
|
|
if (fb < f)
|
|
{
|
|
// node freq is smaller
|
|
sum = fb & FREQ_MASK;
|
|
STORE_PARENT_DIRECT (b, fb, eHi)
|
|
b++;
|
|
fb = *b;
|
|
if (b == e)
|
|
{
|
|
if (++pi == n)
|
|
break;
|
|
sum += f;
|
|
fb &= MASK;
|
|
fb |= sum;
|
|
*e = fb;
|
|
f = *pi & FREQ_MASK;
|
|
continue;
|
|
}
|
|
}
|
|
else if (++pi == n)
|
|
{
|
|
STORE_PARENT_DIRECT (b, fb, eHi)
|
|
b++;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sum = f;
|
|
f = *pi & FREQ_MASK;
|
|
}
|
|
|
|
// (b < e)
|
|
|
|
// second child
|
|
if (fb < f)
|
|
{
|
|
sum += fb;
|
|
sum &= FREQ_MASK;
|
|
STORE_PARENT_DIRECT (b, fb, eHi)
|
|
b++;
|
|
*e = (*e & MASK) | sum; // set frequency sum
|
|
// (b <= e) is possible here
|
|
fb = *b;
|
|
}
|
|
else if (++pi == n)
|
|
break;
|
|
else
|
|
{
|
|
sum += f;
|
|
f = *pi & FREQ_MASK;
|
|
*e = (*e & MASK) | sum; // set frequency sum
|
|
}
|
|
}
|
|
}
|
|
|
|
// printf("\nnum-e=%3u, numSymbols=%3u, num=%3u, b=%3u", n - e, numSymbols, n - p, b - p);
|
|
{
|
|
n -= 2;
|
|
*n &= MASK; // root node : we clear high bits (zero bits mean level == 0)
|
|
if (n != b)
|
|
{
|
|
// We go here, if we have some number of non-created nodes up to root.
|
|
// We process them in simplified code:
|
|
// position of parent for each pair of nodes is known.
|
|
// n[-2], n[-1] : current pair of child nodes
|
|
// (p1) : parent node for current pair.
|
|
UInt32 *p1 = n;
|
|
do
|
|
{
|
|
const unsigned len = LOAD_PARENT(p1) + 1;
|
|
p1--;
|
|
(lenCounters )[len] -= 2; // we remove 2 leaves from level (len)
|
|
(lenCounters + 1)[len] += 2 * 2; // we add 4 leaves at level (len + 1)
|
|
n -= 2;
|
|
STORE_PARENT (n , n[0], len)
|
|
STORE_PARENT (n + 1, n[1], len)
|
|
}
|
|
while (n != b);
|
|
}
|
|
}
|
|
|
|
if (b != p)
|
|
{
|
|
// we detect level of each node (realtive to root),
|
|
// and update lenCounters[].
|
|
// We process only intermediate nodes and we don't process leaves.
|
|
do
|
|
{
|
|
// if (ii < b) : parent_bits_of (p[ii]) == index of parent node : ii < (p[ii])
|
|
// if (ii >= b) : parent_bits_of (p[ii]) == level of this (ii) node in tree
|
|
unsigned len;
|
|
b--;
|
|
len = (unsigned)LOAD_PARENT(p + LOAD_PARENT(b)) + 1;
|
|
STORE_PARENT (b, *b, len)
|
|
if (len >= maxLen)
|
|
{
|
|
// We are not allowed to create node at level (maxLen) and higher,
|
|
// because all leaves must be placed to level (maxLen) or lower.
|
|
// We find nearest allowed leaf and place current node to level of that leaf:
|
|
for (len = maxLen - 1; lenCounters[len] == 0; len--) {}
|
|
}
|
|
lenCounters[len]--; // we remove 1 leaf from level (len)
|
|
(lenCounters + 1)[len] += 2; // we add 2 leaves at level (len + 1)
|
|
}
|
|
while (b != p);
|
|
}
|
|
}
|
|
{
|
|
{
|
|
unsigned len = maxLen;
|
|
const UInt32 *p2 = p;
|
|
do
|
|
{
|
|
unsigned k = lenCounters[len];
|
|
if (k)
|
|
do
|
|
lens[(unsigned)*p2++ & MASK] = (Byte)len;
|
|
while (--k);
|
|
}
|
|
while (--len);
|
|
}
|
|
codes[0] = 0; // we don't want garbage values to be written to p[] array.
|
|
// codes[1] = 0;
|
|
{
|
|
UInt32 code = 0;
|
|
unsigned len;
|
|
for (len = 0; len < kMaxLen; len++)
|
|
(codes + 1)[len] = code = (code + lenCounters[len]) << 1;
|
|
}
|
|
/* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
|
|
{
|
|
const Byte * const limit = lens + numSymbols;
|
|
do
|
|
{
|
|
unsigned len;
|
|
UInt32 c;
|
|
len = lens[0]; c = codes[len]; p[0] = c; codes[len] = c + 1;
|
|
// len = lens[1]; c = codes[len]; p[1] = c; codes[len] = c + 1;
|
|
p += 1;
|
|
lens += 1;
|
|
}
|
|
while (lens != limit);
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef kMaxLen
|
|
#undef NUM_BITS
|
|
#undef MASK
|
|
#undef FREQ_MASK
|
|
#undef NUM_COUNTERS
|
|
#undef CTR_ITEM_FOR_FREQ
|
|
#undef LOAD_PARENT
|
|
#undef STORE_PARENT
|
|
#undef STORE_PARENT_DIRECT
|
|
#undef UPDATE_E
|
|
#undef HI_HALF_OFFSET
|
|
#undef NUM_UNROLLS
|
|
#undef lenCounters
|
|
#undef codes
|