xref: /third_party/lzma/C/Ppmd7Enc.c (revision 370b324c)
1/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder
22023-04-02 : Igor Pavlov : Public domain
3This code is based on:
4  PPMd var.H (2001): Dmitry Shkarin : Public domain */
5
6
7#include "Precomp.h"
8
9#include "Ppmd7.h"
10
11#define kTopValue ((UInt32)1 << 24)
12
13#define R (&p->rc.enc)
14
15void Ppmd7z_Init_RangeEnc(CPpmd7 *p)
16{
17  R->Low = 0;
18  R->Range = 0xFFFFFFFF;
19  R->Cache = 0;
20  R->CacheSize = 1;
21}
22
23Z7_NO_INLINE
24static void Ppmd7z_RangeEnc_ShiftLow(CPpmd7 *p)
25{
26  if ((UInt32)R->Low < (UInt32)0xFF000000 || (unsigned)(R->Low >> 32) != 0)
27  {
28    Byte temp = R->Cache;
29    do
30    {
31      IByteOut_Write(R->Stream, (Byte)(temp + (Byte)(R->Low >> 32)));
32      temp = 0xFF;
33    }
34    while (--R->CacheSize != 0);
35    R->Cache = (Byte)((UInt32)R->Low >> 24);
36  }
37  R->CacheSize++;
38  R->Low = (UInt32)((UInt32)R->Low << 8);
39}
40
41#define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8;  Ppmd7z_RangeEnc_ShiftLow(p);
42#define RC_NORM_1(p)    RC_NORM_BASE(p) }
43#define RC_NORM(p)      RC_NORM_BASE(p)  RC_NORM_BASE(p) }}
44
45// we must use only one type of Normalization from two: LOCAL or REMOTE
46#define RC_NORM_LOCAL(p)    // RC_NORM(p)
47#define RC_NORM_REMOTE(p)   RC_NORM(p)
48
49/*
50#define Ppmd7z_RangeEnc_Encode(p, start, _size_) \
51  { UInt32 size = _size_; \
52    R->Low += start * R->Range; \
53    R->Range *= size; \
54    RC_NORM_LOCAL(p); }
55*/
56
57Z7_FORCE_INLINE
58// Z7_NO_INLINE
59static void Ppmd7z_RangeEnc_Encode(CPpmd7 *p, UInt32 start, UInt32 size)
60{
61  R->Low += start * R->Range;
62  R->Range *= size;
63  RC_NORM_LOCAL(p)
64}
65
66void Ppmd7z_Flush_RangeEnc(CPpmd7 *p)
67{
68  unsigned i;
69  for (i = 0; i < 5; i++)
70    Ppmd7z_RangeEnc_ShiftLow(p);
71}
72
73
74
75#define RC_Encode(start, size)  Ppmd7z_RangeEnc_Encode(p, start, size);
76#define RC_EncodeFinal(start, size)  RC_Encode(start, size) RC_NORM_REMOTE(p)
77
78#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
79#define SUFFIX(ctx) CTX((ctx)->Suffix)
80// typedef CPpmd7_Context * CTX_PTR;
81#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
82
83void Ppmd7_UpdateModel(CPpmd7 *p);
84
85#define MASK(sym) ((unsigned char *)charMask)[sym]
86
87Z7_FORCE_INLINE
88static
89void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol)
90{
91  size_t charMask[256 / sizeof(size_t)];
92
93  if (p->MinContext->NumStats != 1)
94  {
95    CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
96    UInt32 sum;
97    unsigned i;
98
99
100
101
102    R->Range /= p->MinContext->Union2.SummFreq;
103
104    if (s->Symbol == symbol)
105    {
106      // R->Range /= p->MinContext->Union2.SummFreq;
107      RC_EncodeFinal(0, s->Freq)
108      p->FoundState = s;
109      Ppmd7_Update1_0(p);
110      return;
111    }
112    p->PrevSuccess = 0;
113    sum = s->Freq;
114    i = (unsigned)p->MinContext->NumStats - 1;
115    do
116    {
117      if ((++s)->Symbol == symbol)
118      {
119        // R->Range /= p->MinContext->Union2.SummFreq;
120        RC_EncodeFinal(sum, s->Freq)
121        p->FoundState = s;
122        Ppmd7_Update1(p);
123        return;
124      }
125      sum += s->Freq;
126    }
127    while (--i);
128
129    // R->Range /= p->MinContext->Union2.SummFreq;
130    RC_Encode(sum, p->MinContext->Union2.SummFreq - sum)
131
132    p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol);
133    PPMD_SetAllBitsIn256Bytes(charMask)
134    // MASK(s->Symbol) = 0;
135    // i = p->MinContext->NumStats - 1;
136    // do { MASK((--s)->Symbol) = 0; } while (--i);
137    {
138      CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
139      MASK(s->Symbol) = 0;
140      do
141      {
142        unsigned sym0 = s2[0].Symbol;
143        unsigned sym1 = s2[1].Symbol;
144        s2 += 2;
145        MASK(sym0) = 0;
146        MASK(sym1) = 0;
147      }
148      while (s2 < s);
149    }
150  }
151  else
152  {
153    UInt16 *prob = Ppmd7_GetBinSumm(p);
154    CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
155    UInt32 pr = *prob;
156    const UInt32 bound = (R->Range >> 14) * pr;
157    pr = PPMD_UPDATE_PROB_1(pr);
158    if (s->Symbol == symbol)
159    {
160      *prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
161      // RangeEnc_EncodeBit_0(p, bound);
162      R->Range = bound;
163      RC_NORM_1(p)
164
165      // p->FoundState = s;
166      // Ppmd7_UpdateBin(p);
167      {
168        const unsigned freq = s->Freq;
169        CPpmd7_Context *c = CTX(SUCCESSOR(s));
170        p->FoundState = s;
171        p->PrevSuccess = 1;
172        p->RunLength++;
173        s->Freq = (Byte)(freq + (freq < 128));
174        // NextContext(p);
175        if (p->OrderFall == 0 && (const Byte *)c > p->Text)
176          p->MaxContext = p->MinContext = c;
177        else
178          Ppmd7_UpdateModel(p);
179      }
180      return;
181    }
182
183    *prob = (UInt16)pr;
184    p->InitEsc = p->ExpEscape[pr >> 10];
185    // RangeEnc_EncodeBit_1(p, bound);
186    R->Low += bound;
187    R->Range -= bound;
188    RC_NORM_LOCAL(p)
189
190    PPMD_SetAllBitsIn256Bytes(charMask)
191    MASK(s->Symbol) = 0;
192    p->PrevSuccess = 0;
193  }
194
195  for (;;)
196  {
197    CPpmd_See *see;
198    CPpmd_State *s;
199    UInt32 sum, escFreq;
200    CPpmd7_Context *mc;
201    unsigned i, numMasked;
202
203    RC_NORM_REMOTE(p)
204
205    mc = p->MinContext;
206    numMasked = mc->NumStats;
207
208    do
209    {
210      p->OrderFall++;
211      if (!mc->Suffix)
212        return; /* EndMarker (symbol = -1) */
213      mc = Ppmd7_GetContext(p, mc->Suffix);
214      i = mc->NumStats;
215    }
216    while (i == numMasked);
217
218    p->MinContext = mc;
219
220    // see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
221    {
222      if (i != 256)
223      {
224        unsigned nonMasked = i - numMasked;
225        see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]]
226            + p->HiBitsFlag
227            + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - i)
228            + 2 * (unsigned)(mc->Union2.SummFreq < 11 * i)
229            + 4 * (unsigned)(numMasked > nonMasked);
230        {
231          // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ
232          unsigned summ = (UInt16)see->Summ; // & 0xFFFF
233          unsigned r = (summ >> see->Shift);
234          see->Summ = (UInt16)(summ - r);
235          escFreq = r + (r == 0);
236        }
237      }
238      else
239      {
240        see = &p->DummySee;
241        escFreq = 1;
242      }
243    }
244
245    s = Ppmd7_GetStats(p, mc);
246    sum = 0;
247    // i = mc->NumStats;
248
249    do
250    {
251      const unsigned cur = s->Symbol;
252      if ((int)cur == symbol)
253      {
254        const UInt32 low = sum;
255        const UInt32 freq = s->Freq;
256        unsigned num2;
257
258        Ppmd_See_UPDATE(see)
259        p->FoundState = s;
260        sum += escFreq;
261
262        num2 = i / 2;
263        i &= 1;
264        sum += freq & (0 - (UInt32)i);
265        if (num2 != 0)
266        {
267          s += i;
268          for (;;)
269          {
270            unsigned sym0 = s[0].Symbol;
271            unsigned sym1 = s[1].Symbol;
272            s += 2;
273            sum += (s[-2].Freq & (unsigned)(MASK(sym0)));
274            sum += (s[-1].Freq & (unsigned)(MASK(sym1)));
275            if (--num2 == 0)
276              break;
277          }
278        }
279
280
281        R->Range /= sum;
282        RC_EncodeFinal(low, freq)
283        Ppmd7_Update2(p);
284        return;
285      }
286      sum += (s->Freq & (unsigned)(MASK(cur)));
287      s++;
288    }
289    while (--i);
290
291    {
292      const UInt32 total = sum + escFreq;
293      see->Summ = (UInt16)(see->Summ + total);
294
295      R->Range /= total;
296      RC_Encode(sum, escFreq)
297    }
298
299    {
300      const CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
301      s--;
302      MASK(s->Symbol) = 0;
303      do
304      {
305        const unsigned sym0 = s2[0].Symbol;
306        const unsigned sym1 = s2[1].Symbol;
307        s2 += 2;
308        MASK(sym0) = 0;
309        MASK(sym1) = 0;
310      }
311      while (s2 < s);
312    }
313  }
314}
315
316
317void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim)
318{
319  for (; buf < lim; buf++)
320  {
321    Ppmd7z_EncodeSymbol(p, *buf);
322  }
323}
324
325#undef kTopValue
326#undef WRITE_BYTE
327#undef RC_NORM_BASE
328#undef RC_NORM_1
329#undef RC_NORM
330#undef RC_NORM_LOCAL
331#undef RC_NORM_REMOTE
332#undef R
333#undef RC_Encode
334#undef RC_EncodeFinal
335#undef SUFFIX
336#undef CTX
337#undef SUCCESSOR
338#undef MASK
339