📄 model.cpp
字号:
/****************************************************************************
* This file is part of PPMd project *
* Written and distributed to public domain by Dmitry Shkarin 1997, *
* 1999-2001 *
* Contents: PPMII model description and encoding/decoding routines *
****************************************************************************/
#include <string.h>
#include "PPMd.h"
#pragma hdrstop
#include "Coder.hpp"
#include "SubAlloc.hpp"
enum { UP_FREQ=5, INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS,
INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124, O_BOUND=9 };
#pragma pack(1)
static struct SEE2_CONTEXT { // SEE-contexts for PPM-contexts with masked symbols
WORD Summ;
BYTE Shift, Count;
void init(UINT InitVal) { Summ=InitVal << (Shift=PERIOD_BITS-4); Count=7; }
UINT getMean() {
UINT RetVal=(Summ >> Shift); Summ -= RetVal;
return RetVal+(RetVal == 0);
}
void update() {
if (Shift < PERIOD_BITS && --Count == 0) {
Summ += Summ; Count=3 << Shift++;
}
}
} _PACK_ATTR SEE2Cont[24][32], DummySEE2Cont;
static struct PPM_CONTEXT { // Notes:
BYTE NumStats, Flags; // 1. NumStats & NumMasked contain
WORD SummFreq; // number of symbols minus 1
struct STATE { // 2. sizeof(WORD) > sizeof(BYTE)
BYTE Symbol, Freq; // 3. contexts example:
PPM_CONTEXT* Successor; // MaxOrder:
} _PACK_ATTR * Stats; // ABCD context
PPM_CONTEXT* Suffix; // BCD suffix
inline void encodeBinSymbol(int symbol);// BCDE successor
inline void encodeSymbol1(int symbol);// other orders:
inline void encodeSymbol2(int symbol);// BCD context
inline void decodeBinSymbol();// CD suffix
inline void decodeSymbol1();// BCDE successor
inline void decodeSymbol2();
inline void update1(STATE* p);
inline void update2(STATE* p);
inline SEE2_CONTEXT* makeEscFreq2();
void rescale();
void refresh(int OldNU,BOOL Scale);
PPM_CONTEXT* cutOff(int Order);
PPM_CONTEXT* removeBinConts(int Order);
STATE& oneState() const { return (STATE&) SummFreq; }
} _PACK_ATTR* MaxContext;
#pragma pack()
static BYTE NS2BSIndx[256], QTable[260]; // constants
static PPM_CONTEXT::STATE* FoundState; // found next state transition
static int InitEsc, OrderFall, RunLength, InitRL, MaxOrder;
static BYTE CharMask[256], NumMasked, PrevSuccess, EscCount, PrintCount;
static WORD BinSumm[25][64]; // binary SEE-contexts
static MR_METHOD MRMethod;
inline void SWAP(PPM_CONTEXT::STATE& s1,PPM_CONTEXT::STATE& s2)
{
WORD t1=(WORD&) s1; PPM_CONTEXT* t2=s1.Successor;
(WORD&) s1 = (WORD&) s2; s1.Successor=s2.Successor;
(WORD&) s2 = t1; s2.Successor=t2;
}
inline void StateCpy(PPM_CONTEXT::STATE& s1,const PPM_CONTEXT::STATE& s2)
{
(WORD&) s1=(WORD&) s2; s1.Successor=s2.Successor;
}
struct PPMD_STARTUP { inline PPMD_STARTUP(); } PPMd_StartUp;
inline PPMD_STARTUP::PPMD_STARTUP() // constants initialization
{
UINT i, k, m, Step;
for (i=0,k=1;i < N1 ;i++,k += 1) Indx2Units[i]=k;
for (k++;i < N1+N2 ;i++,k += 2) Indx2Units[i]=k;
for (k++;i < N1+N2+N3 ;i++,k += 3) Indx2Units[i]=k;
for (k++;i < N1+N2+N3+N4;i++,k += 4) Indx2Units[i]=k;
for (k=i=0;k < 128;k++) {
i += (Indx2Units[i] < k+1); Units2Indx[k]=i;
}
NS2BSIndx[0]=2*0; NS2BSIndx[1]=2*1;
memset(NS2BSIndx+2,2*2,9); memset(NS2BSIndx+11,2*3,256-11);
for (i=0;i < UP_FREQ;i++) QTable[i]=i;
for (m=i=UP_FREQ, k=Step=1;i < 260;i++) {
QTable[i]=m;
if ( !--k ) { k = ++Step; m++; }
}
(DWORD&) DummySEE2Cont=PPMdSignature;
}
static void _STDCALL StartModelRare(int MaxOrder,MR_METHOD MRMethod)
{
UINT i, k, m;
memset(CharMask,0,sizeof(CharMask)); EscCount=PrintCount=1;
if (MaxOrder < 2) { // we are in solid mode
OrderFall=::MaxOrder;
for (PPM_CONTEXT* pc=MaxContext;pc->Suffix != NULL;pc=pc->Suffix)
OrderFall--;
return;
}
OrderFall=::MaxOrder=MaxOrder; ::MRMethod=MRMethod;
InitSubAllocator();
RunLength=InitRL=-((MaxOrder < 12)?MaxOrder:12)-1;
MaxContext = (PPM_CONTEXT*) AllocContext();
MaxContext->Suffix=NULL;
MaxContext->SummFreq=(MaxContext->NumStats=255)+2;
MaxContext->Stats = (PPM_CONTEXT::STATE*) AllocUnits(256/2);
for (PrevSuccess=i=0;i < 256;i++) {
MaxContext->Stats[i].Symbol=i; MaxContext->Stats[i].Freq=1;
MaxContext->Stats[i].Successor=NULL;
}
static const WORD InitBinEsc[]={0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051};
for (i=m=0;m < 25;m++) {
while (QTable[i] == m) i++;
for (k=0;k < 8;k++)
BinSumm[m][k]=BIN_SCALE-InitBinEsc[k]/(i+1);
for (k=8;k < 64;k += 8)
memcpy(BinSumm[m]+k,BinSumm[m],8*sizeof(WORD));
}
for (i=m=0;m < 24;m++) {
while (QTable[i+3] == m+3) i++;
SEE2Cont[m][0].init(2*i+5);
for (k=1;k < 32;k++) SEE2Cont[m][k]=SEE2Cont[m][0];
}
}
void PPM_CONTEXT::refresh(int OldNU,BOOL Scale)
{
int i=NumStats, EscFreq;
STATE* p = Stats = (STATE*) ShrinkUnits(Stats,OldNU,(i+2) >> 1);
Flags=(Flags & (0x10+0x04*Scale))+0x08*(p->Symbol >= 0x40);
EscFreq=SummFreq-p->Freq;
SummFreq = (p->Freq=(p->Freq+Scale) >> Scale);
do {
EscFreq -= (++p)->Freq;
SummFreq += (p->Freq=(p->Freq+Scale) >> Scale);
Flags |= 0x08*(p->Symbol >= 0x40);
} while ( --i );
SummFreq += (EscFreq=(EscFreq+Scale) >> Scale);
}
#define P_CALL(F) ( PrefetchData(p->Successor), \
p->Successor=p->Successor->F(Order+1))
PPM_CONTEXT* PPM_CONTEXT::cutOff(int Order)
{
int i, tmp;
STATE* p;
if ( !NumStats ) {
if ((BYTE*) (p=&oneState())->Successor >= UnitsStart) {
if (Order < MaxOrder) P_CALL(cutOff);
else p->Successor=NULL;
if (!p->Successor && Order > O_BOUND)
goto REMOVE;
return this;
} else {
REMOVE: SpecialFreeUnit(this); return NULL;
}
}
PrefetchData(Stats);
Stats = (STATE*) MoveUnitsUp(Stats,tmp=(NumStats+2) >> 1);
for (p=Stats+(i=NumStats);p >= Stats;p--)
if ((BYTE*) p->Successor < UnitsStart) {
p->Successor=NULL; SWAP(*p,Stats[i--]);
} else if (Order < MaxOrder) P_CALL(cutOff);
else p->Successor=NULL;
if (i != NumStats && Order) {
NumStats=i; p=Stats;
if (i < 0) { FreeUnits(p,tmp); goto REMOVE; }
else if (i == 0) {
Flags=(Flags & 0x10)+0x08*(p->Symbol >= 0x40);
StateCpy(oneState(),*p); FreeUnits(p,tmp);
oneState().Freq=(oneState().Freq+11) >> 3;
} else refresh(tmp,SummFreq > 16*i);
}
return this;
}
PPM_CONTEXT* PPM_CONTEXT::removeBinConts(int Order)
{
STATE* p;
if ( !NumStats ) {
p=&oneState();
if ((BYTE*) p->Successor >= UnitsStart && Order < MaxOrder)
P_CALL(removeBinConts);
else p->Successor=NULL;
if (!p->Successor && (!Suffix->NumStats || Suffix->Flags == 0xFF)) {
FreeUnits(this,1); return NULL;
} else return this;
}
PrefetchData(Stats);
for (p=Stats+NumStats;p >= Stats;p--)
if ((BYTE*) p->Successor >= UnitsStart && Order < MaxOrder)
P_CALL(removeBinConts);
else p->Successor=NULL;
return this;
}
static void RestoreModelRare(PPM_CONTEXT* pc1,PPM_CONTEXT* MinContext,
PPM_CONTEXT* FSuccessor)
{
PPM_CONTEXT* pc;
PPM_CONTEXT::STATE* p;
for (pc=MaxContext, pText=HeapStart;pc != pc1;pc=pc->Suffix)
if (--(pc->NumStats) == 0) {
pc->Flags=(pc->Flags & 0x10)+0x08*(pc->Stats->Symbol >= 0x40);
p=pc->Stats; StateCpy(pc->oneState(),*p);
SpecialFreeUnit(p);
pc->oneState().Freq=(pc->oneState().Freq+11) >> 3;
} else
pc->refresh((pc->NumStats+3) >> 1,FALSE);
for ( ;pc != MinContext;pc=pc->Suffix)
if ( !pc->NumStats )
pc->oneState().Freq -= pc->oneState().Freq >> 1;
else if ((pc->SummFreq += 4) > 128+4*pc->NumStats)
pc->refresh((pc->NumStats+2) >> 1,TRUE);
if (MRMethod > MRM_FREEZE) {
MaxContext=FSuccessor; GlueCount += !(BList[1].Stamp & 1);
} else if (MRMethod == MRM_FREEZE) {
while ( MaxContext->Suffix ) MaxContext=MaxContext->Suffix;
MaxContext->removeBinConts(0); MRMethod=MR_METHOD(MRMethod+1);
GlueCount=0; OrderFall=MaxOrder;
} else if (MRMethod == MRM_RESTART || GetUsedMemory() < (SubAllocatorSize >> 1)) {
StartModelRare(MaxOrder,MRMethod);
EscCount=0; PrintCount=0xFF;
} else {
while ( MaxContext->Suffix ) MaxContext=MaxContext->Suffix;
do {
MaxContext->cutOff(0); ExpandTextArea();
} while (GetUsedMemory() > 3*(SubAllocatorSize >> 2));
GlueCount=0; OrderFall=MaxOrder;
}
}
static PPM_CONTEXT* _FASTCALL CreateSuccessors(BOOL Skip,PPM_CONTEXT::STATE* p,
PPM_CONTEXT* pc);
static PPM_CONTEXT* _FASTCALL ReduceOrder(PPM_CONTEXT::STATE* p,PPM_CONTEXT* pc)
{
PPM_CONTEXT::STATE* p1, * ps[MAX_O], ** pps=ps;
PPM_CONTEXT* pc1=pc, * UpBranch = (PPM_CONTEXT*) pText;
BYTE tmp, sym=FoundState->Symbol;
*pps++ = FoundState; FoundState->Successor=UpBranch;
OrderFall++;
if ( p ) { pc=pc->Suffix; goto LOOP_ENTRY; }
for ( ; ; ) {
if ( !pc->Suffix ) {
if (MRMethod > MRM_FREEZE) {
FROZEN: do { (*--pps)->Successor = pc; } while (pps != ps);
pText=HeapStart+1; OrderFall=1;
}
return pc;
}
pc=pc->Suffix;
if ( pc->NumStats ) {
if ((p=pc->Stats)->Symbol != sym)
do { tmp=p[1].Symbol; p++; } while (tmp != sym);
tmp=2*(p->Freq < MAX_FREQ-9);
p->Freq += tmp; pc->SummFreq += tmp;
} else { p=&(pc->oneState()); p->Freq += (p->Freq < 32); }
LOOP_ENTRY:
if ( p->Successor ) break;
*pps++ = p; p->Successor=UpBranch;
OrderFall++;
}
if (MRMethod > MRM_FREEZE) {
pc = p->Successor; goto FROZEN;
} else if (p->Successor <= UpBranch) {
p1=FoundState; FoundState=p;
p->Successor=CreateSuccessors(FALSE,NULL,pc);
FoundState=p1;
}
if (OrderFall == 1 && pc1 == MaxContext) {
FoundState->Successor=p->Successor; pText--;
}
return p->Successor;
}
void PPM_CONTEXT::rescale()
{
UINT OldNU, Adder, EscFreq, i=NumStats;
STATE tmp, * p1, * p;
for (p=FoundState;p != Stats;p--) SWAP(p[0],p[-1]);
p->Freq += 4; SummFreq += 4;
EscFreq=SummFreq-p->Freq;
Adder=(OrderFall != 0 || MRMethod > MRM_FREEZE);
SummFreq = (p->Freq=(p->Freq+Adder) >> 1);
do {
EscFreq -= (++p)->Freq;
SummFreq += (p->Freq=(p->Freq+Adder) >> 1);
if (p[0].Freq > p[-1].Freq) {
StateCpy(tmp,*(p1=p));
do StateCpy(p1[0],p1[-1]); while (tmp.Freq > (--p1)[-1].Freq);
StateCpy(*p1,tmp);
}
} while ( --i );
if (p->Freq == 0) {
do { i++; } while ((--p)->Freq == 0);
EscFreq += i; OldNU=(NumStats+2) >> 1;
if ((NumStats -= i) == 0) {
StateCpy(tmp,*Stats);
tmp.Freq=(2*tmp.Freq+EscFreq-1)/EscFreq;
if (tmp.Freq > MAX_FREQ/3) tmp.Freq=MAX_FREQ/3;
FreeUnits(Stats,OldNU); StateCpy(oneState(),tmp);
Flags=(Flags & 0x10)+0x08*(tmp.Symbol >= 0x40);
FoundState=&oneState(); return;
}
Stats = (STATE*) ShrinkUnits(Stats,OldNU,(NumStats+2) >> 1);
Flags &= ~0x08; i=NumStats;
Flags |= 0x08*((p=Stats)->Symbol >= 0x40);
do { Flags |= 0x08*((++p)->Symbol >= 0x40); } while ( --i );
}
SummFreq += (EscFreq -= (EscFreq >> 1));
Flags |= 0x04; FoundState=Stats;
}
static PPM_CONTEXT* _FASTCALL CreateSuccessors(BOOL Skip,PPM_CONTEXT::STATE* p,
PPM_CONTEXT* pc)
{
PPM_CONTEXT ct, * UpBranch=FoundState->Successor;
PPM_CONTEXT::STATE* ps[MAX_O], ** pps=ps;
UINT cf, s0;
BYTE tmp, sym=FoundState->Symbol;
if ( !Skip ) {
*pps++ = FoundState;
if ( !pc->Suffix ) goto NO_LOOP;
}
if ( p ) { pc=pc->Suffix; goto LOOP_ENTRY; }
do {
pc=pc->Suffix;
if ( pc->NumStats ) {
if ((p=pc->Stats)->Symbol != sym)
do { tmp=p[1].Symbol; p++; } while (tmp != sym);
tmp=(p->Freq < MAX_FREQ-9);
p->Freq += tmp; pc->SummFreq += tmp;
} else {
p=&(pc->oneState());
p->Freq += (!pc->Suffix->NumStats & (p->Freq < 24));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -