chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,360 @@
|
||||
/* 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
|
||||
Reference in New Issue
Block a user