xref: /aosp_15_r20/external/lzma/C/HuffEnc.c (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker /* HuffEnc.c -- functions for Huffman encoding
2*f6dc9357SAndroid Build Coastguard Worker 2023-09-07 : Igor Pavlov : Public domain */
3*f6dc9357SAndroid Build Coastguard Worker 
4*f6dc9357SAndroid Build Coastguard Worker #include "Precomp.h"
5*f6dc9357SAndroid Build Coastguard Worker 
6*f6dc9357SAndroid Build Coastguard Worker #include "HuffEnc.h"
7*f6dc9357SAndroid Build Coastguard Worker #include "Sort.h"
8*f6dc9357SAndroid Build Coastguard Worker 
9*f6dc9357SAndroid Build Coastguard Worker #define kMaxLen 16
10*f6dc9357SAndroid Build Coastguard Worker #define NUM_BITS 10
11*f6dc9357SAndroid Build Coastguard Worker #define MASK ((1u << NUM_BITS) - 1)
12*f6dc9357SAndroid Build Coastguard Worker 
13*f6dc9357SAndroid Build Coastguard Worker #define NUM_COUNTERS 64
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker #define HUFFMAN_SPEED_OPT
16*f6dc9357SAndroid Build Coastguard Worker 
Huffman_Generate(const UInt32 * freqs,UInt32 * p,Byte * lens,UInt32 numSymbols,UInt32 maxLen)17*f6dc9357SAndroid Build Coastguard Worker void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
18*f6dc9357SAndroid Build Coastguard Worker {
19*f6dc9357SAndroid Build Coastguard Worker   UInt32 num = 0;
20*f6dc9357SAndroid Build Coastguard Worker   /* if (maxLen > 10) maxLen = 10; */
21*f6dc9357SAndroid Build Coastguard Worker   {
22*f6dc9357SAndroid Build Coastguard Worker     UInt32 i;
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker     #ifdef HUFFMAN_SPEED_OPT
25*f6dc9357SAndroid Build Coastguard Worker 
26*f6dc9357SAndroid Build Coastguard Worker     UInt32 counters[NUM_COUNTERS];
27*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < NUM_COUNTERS; i++)
28*f6dc9357SAndroid Build Coastguard Worker       counters[i] = 0;
29*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < numSymbols; i++)
30*f6dc9357SAndroid Build Coastguard Worker     {
31*f6dc9357SAndroid Build Coastguard Worker       UInt32 freq = freqs[i];
32*f6dc9357SAndroid Build Coastguard Worker       counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
33*f6dc9357SAndroid Build Coastguard Worker     }
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker     for (i = 1; i < NUM_COUNTERS; i++)
36*f6dc9357SAndroid Build Coastguard Worker     {
37*f6dc9357SAndroid Build Coastguard Worker       UInt32 temp = counters[i];
38*f6dc9357SAndroid Build Coastguard Worker       counters[i] = num;
39*f6dc9357SAndroid Build Coastguard Worker       num += temp;
40*f6dc9357SAndroid Build Coastguard Worker     }
41*f6dc9357SAndroid Build Coastguard Worker 
42*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < numSymbols; i++)
43*f6dc9357SAndroid Build Coastguard Worker     {
44*f6dc9357SAndroid Build Coastguard Worker       UInt32 freq = freqs[i];
45*f6dc9357SAndroid Build Coastguard Worker       if (freq == 0)
46*f6dc9357SAndroid Build Coastguard Worker         lens[i] = 0;
47*f6dc9357SAndroid Build Coastguard Worker       else
48*f6dc9357SAndroid Build Coastguard Worker         p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS);
49*f6dc9357SAndroid Build Coastguard Worker     }
50*f6dc9357SAndroid Build Coastguard Worker     counters[0] = 0;
51*f6dc9357SAndroid Build Coastguard Worker     HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker     #else
54*f6dc9357SAndroid Build Coastguard Worker 
55*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < numSymbols; i++)
56*f6dc9357SAndroid Build Coastguard Worker     {
57*f6dc9357SAndroid Build Coastguard Worker       UInt32 freq = freqs[i];
58*f6dc9357SAndroid Build Coastguard Worker       if (freq == 0)
59*f6dc9357SAndroid Build Coastguard Worker         lens[i] = 0;
60*f6dc9357SAndroid Build Coastguard Worker       else
61*f6dc9357SAndroid Build Coastguard Worker         p[num++] = i | (freq << NUM_BITS);
62*f6dc9357SAndroid Build Coastguard Worker     }
63*f6dc9357SAndroid Build Coastguard Worker     HeapSort(p, num);
64*f6dc9357SAndroid Build Coastguard Worker 
65*f6dc9357SAndroid Build Coastguard Worker     #endif
66*f6dc9357SAndroid Build Coastguard Worker   }
67*f6dc9357SAndroid Build Coastguard Worker 
68*f6dc9357SAndroid Build Coastguard Worker   if (num < 2)
69*f6dc9357SAndroid Build Coastguard Worker   {
70*f6dc9357SAndroid Build Coastguard Worker     unsigned minCode = 0;
71*f6dc9357SAndroid Build Coastguard Worker     unsigned maxCode = 1;
72*f6dc9357SAndroid Build Coastguard Worker     if (num == 1)
73*f6dc9357SAndroid Build Coastguard Worker     {
74*f6dc9357SAndroid Build Coastguard Worker       maxCode = (unsigned)p[0] & MASK;
75*f6dc9357SAndroid Build Coastguard Worker       if (maxCode == 0)
76*f6dc9357SAndroid Build Coastguard Worker         maxCode++;
77*f6dc9357SAndroid Build Coastguard Worker     }
78*f6dc9357SAndroid Build Coastguard Worker     p[minCode] = 0;
79*f6dc9357SAndroid Build Coastguard Worker     p[maxCode] = 1;
80*f6dc9357SAndroid Build Coastguard Worker     lens[minCode] = lens[maxCode] = 1;
81*f6dc9357SAndroid Build Coastguard Worker     return;
82*f6dc9357SAndroid Build Coastguard Worker   }
83*f6dc9357SAndroid Build Coastguard Worker 
84*f6dc9357SAndroid Build Coastguard Worker   {
85*f6dc9357SAndroid Build Coastguard Worker     UInt32 b, e, i;
86*f6dc9357SAndroid Build Coastguard Worker 
87*f6dc9357SAndroid Build Coastguard Worker     i = b = e = 0;
88*f6dc9357SAndroid Build Coastguard Worker     do
89*f6dc9357SAndroid Build Coastguard Worker     {
90*f6dc9357SAndroid Build Coastguard Worker       UInt32 n, m, freq;
91*f6dc9357SAndroid Build Coastguard Worker       n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
92*f6dc9357SAndroid Build Coastguard Worker       freq = (p[n] & ~MASK);
93*f6dc9357SAndroid Build Coastguard Worker       p[n] = (p[n] & MASK) | (e << NUM_BITS);
94*f6dc9357SAndroid Build Coastguard Worker       m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
95*f6dc9357SAndroid Build Coastguard Worker       freq += (p[m] & ~MASK);
96*f6dc9357SAndroid Build Coastguard Worker       p[m] = (p[m] & MASK) | (e << NUM_BITS);
97*f6dc9357SAndroid Build Coastguard Worker       p[e] = (p[e] & MASK) | freq;
98*f6dc9357SAndroid Build Coastguard Worker       e++;
99*f6dc9357SAndroid Build Coastguard Worker     }
100*f6dc9357SAndroid Build Coastguard Worker     while (num - e > 1);
101*f6dc9357SAndroid Build Coastguard Worker 
102*f6dc9357SAndroid Build Coastguard Worker     {
103*f6dc9357SAndroid Build Coastguard Worker       UInt32 lenCounters[kMaxLen + 1];
104*f6dc9357SAndroid Build Coastguard Worker       for (i = 0; i <= kMaxLen; i++)
105*f6dc9357SAndroid Build Coastguard Worker         lenCounters[i] = 0;
106*f6dc9357SAndroid Build Coastguard Worker 
107*f6dc9357SAndroid Build Coastguard Worker       p[--e] &= MASK;
108*f6dc9357SAndroid Build Coastguard Worker       lenCounters[1] = 2;
109*f6dc9357SAndroid Build Coastguard Worker       while (e != 0)
110*f6dc9357SAndroid Build Coastguard Worker       {
111*f6dc9357SAndroid Build Coastguard Worker         UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
112*f6dc9357SAndroid Build Coastguard Worker         p[e] = (p[e] & MASK) | (len << NUM_BITS);
113*f6dc9357SAndroid Build Coastguard Worker         if (len >= maxLen)
114*f6dc9357SAndroid Build Coastguard Worker           for (len = maxLen - 1; lenCounters[len] == 0; len--);
115*f6dc9357SAndroid Build Coastguard Worker         lenCounters[len]--;
116*f6dc9357SAndroid Build Coastguard Worker         lenCounters[(size_t)len + 1] += 2;
117*f6dc9357SAndroid Build Coastguard Worker       }
118*f6dc9357SAndroid Build Coastguard Worker 
119*f6dc9357SAndroid Build Coastguard Worker       {
120*f6dc9357SAndroid Build Coastguard Worker         UInt32 len;
121*f6dc9357SAndroid Build Coastguard Worker         i = 0;
122*f6dc9357SAndroid Build Coastguard Worker         for (len = maxLen; len != 0; len--)
123*f6dc9357SAndroid Build Coastguard Worker         {
124*f6dc9357SAndroid Build Coastguard Worker           UInt32 k;
125*f6dc9357SAndroid Build Coastguard Worker           for (k = lenCounters[len]; k != 0; k--)
126*f6dc9357SAndroid Build Coastguard Worker             lens[p[i++] & MASK] = (Byte)len;
127*f6dc9357SAndroid Build Coastguard Worker         }
128*f6dc9357SAndroid Build Coastguard Worker       }
129*f6dc9357SAndroid Build Coastguard Worker 
130*f6dc9357SAndroid Build Coastguard Worker       {
131*f6dc9357SAndroid Build Coastguard Worker         UInt32 nextCodes[kMaxLen + 1];
132*f6dc9357SAndroid Build Coastguard Worker         {
133*f6dc9357SAndroid Build Coastguard Worker           UInt32 code = 0;
134*f6dc9357SAndroid Build Coastguard Worker           UInt32 len;
135*f6dc9357SAndroid Build Coastguard Worker           for (len = 1; len <= kMaxLen; len++)
136*f6dc9357SAndroid Build Coastguard Worker             nextCodes[len] = code = (code + lenCounters[(size_t)len - 1]) << 1;
137*f6dc9357SAndroid Build Coastguard Worker         }
138*f6dc9357SAndroid Build Coastguard Worker         /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
139*f6dc9357SAndroid Build Coastguard Worker 
140*f6dc9357SAndroid Build Coastguard Worker         {
141*f6dc9357SAndroid Build Coastguard Worker           UInt32 k;
142*f6dc9357SAndroid Build Coastguard Worker           for (k = 0; k < numSymbols; k++)
143*f6dc9357SAndroid Build Coastguard Worker             p[k] = nextCodes[lens[k]]++;
144*f6dc9357SAndroid Build Coastguard Worker         }
145*f6dc9357SAndroid Build Coastguard Worker       }
146*f6dc9357SAndroid Build Coastguard Worker     }
147*f6dc9357SAndroid Build Coastguard Worker   }
148*f6dc9357SAndroid Build Coastguard Worker }
149*f6dc9357SAndroid Build Coastguard Worker 
150*f6dc9357SAndroid Build Coastguard Worker #undef kMaxLen
151*f6dc9357SAndroid Build Coastguard Worker #undef NUM_BITS
152*f6dc9357SAndroid Build Coastguard Worker #undef MASK
153*f6dc9357SAndroid Build Coastguard Worker #undef NUM_COUNTERS
154*f6dc9357SAndroid Build Coastguard Worker #undef HUFFMAN_SPEED_OPT
155