// Compress/PPMD/Context.h // This code is based on Dmitry Shkarin's PPMdH code #ifndef __COMPRESS_PPMD_CONTEXT_H #define __COMPRESS_PPMD_CONTEXT_H #include "../../../Common/Types.h" #include "../RangeCoder/RangeCoder.h" #include "PPMDSubAlloc.h" namespace NCompress { namespace NPPMD { const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS, INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124; #pragma pack(1) struct SEE2_CONTEXT { // SEE-contexts for PPM-contexts with masked symbols UInt16 Summ; Byte Shift, Count; void init(int InitVal) { Summ=InitVal << (Shift=PERIOD_BITS-4); Count=4; } unsigned int getMean() { unsigned int RetVal=(Summ >> Shift); Summ -= RetVal; return RetVal+(RetVal == 0); } void update() { if (Shift < PERIOD_BITS && --Count == 0) { Summ += Summ; Count = 3 << Shift++; } } }; struct PPM_CONTEXT { UInt16 NumStats,SummFreq; // sizeof(UInt16) > sizeof(Byte) struct STATE { Byte Symbol, Freq; PPM_CONTEXT* Successor; } _PACK_ATTR * Stats; PPM_CONTEXT* Suffix; PPM_CONTEXT* createChild(CSubAllocator &subAllocator, STATE* pStats, STATE& FirstState) { PPM_CONTEXT* pc = (PPM_CONTEXT*) subAllocator.AllocContext(); if (pc) { pc->NumStats = 1; pc->oneState() = FirstState; pc->Suffix = this; pStats->Successor = pc; } return pc; } STATE& oneState() const { return (STATE&) SummFreq; } }; #pragma pack() ///////////////////////////////// const UInt16 InitBinEsc[] = {0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; struct CInfo { CSubAllocator SubAllocator; SEE2_CONTEXT _PACK_ATTR SEE2Cont[25][16], DummySEE2Cont; PPM_CONTEXT _PACK_ATTR * MinContext, * MaxContext; PPM_CONTEXT::STATE* FoundState; // found next state transition int NumMasked, InitEsc, OrderFall, RunLength, InitRL, MaxOrder; Byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; Byte EscCount, PrintCount, PrevSuccess, HiBitsFlag; UInt16 BinSumm[128][64]; // binary SEE-contexts UInt16 &GetBinSumm(const PPM_CONTEXT::STATE &rs, int numStates) { HiBitsFlag = HB2Flag[FoundState->Symbol]; return BinSumm[rs.Freq - 1][ PrevSuccess + NS2BSIndx[numStates - 1] + HiBitsFlag + 2 * HB2Flag[rs.Symbol] + ((RunLength >> 26) & 0x20)]; } void RestartModelRare() { int i, k, m; memset(CharMask,0,sizeof(CharMask)); SubAllocator.InitSubAllocator(); InitRL = -((MaxOrder < 12) ? MaxOrder : 12) - 1; MinContext = MaxContext = (PPM_CONTEXT*) SubAllocator.AllocContext(); MinContext->Suffix = NULL; OrderFall = MaxOrder; MinContext->SummFreq = (MinContext->NumStats = 256) + 1; FoundState = MinContext->Stats = (PPM_CONTEXT::STATE*) SubAllocator.AllocUnits(256 / 2); for (RunLength = InitRL, PrevSuccess = i = 0; i < 256; i++) { MinContext->Stats[i].Symbol = i; MinContext->Stats[i].Freq = 1; MinContext->Stats[i].Successor = NULL; } for (i = 0; i < 128; i++) for (k = 0; k < 8; k++) for ( m=0; m < 64; m += 8) BinSumm[i][k + m] = BIN_SCALE - InitBinEsc[k] / (i + 2); for (i = 0; i < 25; i++) for (k = 0; k < 16; k++) SEE2Cont[i][k].init(5*i+10); } void StartModelRare(int MaxOrder) { int i, k, m ,Step; EscCount=PrintCount=1; if (MaxOrder < 2) { memset(CharMask,0,sizeof(CharMask)); OrderFall = this->MaxOrder; MinContext = MaxContext; while (MinContext->Suffix != NULL) { MinContext = MinContext->Suffix; OrderFall--; } FoundState = MinContext->Stats; MinContext = MaxContext; } else { this->MaxOrder = MaxOrder; RestartModelRare(); 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 < 3; i++) NS2Indx[i] = i; for (m = i, k = Step = 1; i < 256; i++) { NS2Indx[i] =m; if ( !--k ) { k = ++Step; m++; } } memset(HB2Flag, 0, 0x40); memset(HB2Flag + 0x40, 0x08, 0x100 - 0x40); DummySEE2Cont.Shift = PERIOD_BITS; } } PPM_CONTEXT* CreateSuccessors(bool skip, PPM_CONTEXT::STATE* p1) { // static UpState declaration bypasses IntelC bug // static PPM_CONTEXT::STATE UpState; PPM_CONTEXT::STATE UpState; PPM_CONTEXT* pc = MinContext, * UpBranch = FoundState->Successor; PPM_CONTEXT::STATE * p, * ps[MAX_O], ** pps = ps; if ( !skip ) { *pps++ = FoundState; if ( !pc->Suffix ) goto NO_LOOP; } if ( p1 ) { p = p1; pc = pc->Suffix; goto LOOP_ENTRY; } do { pc = pc->Suffix; if (pc->NumStats != 1) { if ((p = pc->Stats)->Symbol != FoundState->Symbol) do { p++; } while (p->Symbol != FoundState->Symbol); } else p = &(pc->oneState()); LOOP_ENTRY: if (p->Successor != UpBranch) { pc = p->Successor; break; } *pps++ = p; } while ( pc->Suffix ); NO_LOOP: if (pps == ps) return pc; UpState.Symbol = *(Byte*) UpBranch; UpState.Successor = (PPM_CONTEXT*) (((Byte*) UpBranch)+1); if (pc->NumStats != 1) { if ((p = pc->Stats)->Symbol != UpState.Symbol) do { p++; } while (p->Symbol != UpState.Symbol); unsigned int cf = p->Freq-1; unsigned int s0 = pc->SummFreq - pc->NumStats - cf; UpState.Freq = 1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))); } else UpState.Freq = pc->oneState().Freq; do { pc = pc->createChild(SubAllocator, *--pps, UpState); if ( !pc ) return NULL; } while (pps != ps); return pc; } void UpdateModel() { PPM_CONTEXT::STATE fs = *FoundState, * p = NULL; PPM_CONTEXT* pc, * Successor; unsigned int ns1, ns, cf, sf, s0; if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL) { if (pc->NumStats != 1) { if ((p = pc->Stats)->Symbol != fs.Symbol) { do { p++; } while (p->Symbol != fs.Symbol); if (p[0].Freq >= p[-1].Freq) { _PPMD_SWAP(p[0],p[-1]); p--; } } if (p->Freq < MAX_FREQ-9) { p->Freq += 2; pc->SummFreq += 2; } } else { p = &(pc->oneState()); p->Freq += (p->Freq < 32); } } if ( !OrderFall ) { MinContext = MaxContext = FoundState->Successor = CreateSuccessors(true, p); if ( !MinContext ) goto RESTART_MODEL; return; } *SubAllocator.pText++ = fs.Symbol; Successor = (PPM_CONTEXT*) SubAllocator.pText; if (SubAllocator.pText >= SubAllocator.UnitsStart) goto RESTART_MODEL; if ( fs.Successor ) { if ((Byte*) fs.Successor <= SubAllocator.pText && (fs.Successor=CreateSuccessors(false, p)) == NULL) goto RESTART_MODEL; if ( !--OrderFall ) { Successor = fs.Successor; SubAllocator.pText -= (MaxContext != MinContext); } } else { FoundState->Successor = Successor; fs.Successor = MinContext; } s0 = MinContext->SummFreq - (ns = MinContext->NumStats) - (fs.Freq - 1); for (pc = MaxContext; pc != MinContext; pc = pc->Suffix) { if ((ns1 = pc->NumStats) != 1) { if ((ns1 & 1) == 0) { pc->Stats = (PPM_CONTEXT::STATE*) SubAllocator.ExpandUnits(pc->Stats, ns1 >> 1); if ( !pc->Stats ) goto RESTART_MODEL; } pc->SummFreq += (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (pc->SummFreq <= 8 * ns1)); } else { p = (PPM_CONTEXT::STATE*) SubAllocator.AllocUnits(1); if ( !p ) goto RESTART_MODEL; *p = pc->oneState(); pc->Stats = p; if (p->Freq < MAX_FREQ / 4 - 1) p->Freq += p->Freq; else p->Freq = MAX_FREQ - 4; pc->SummFreq = p->Freq + InitEsc + (ns > 3); } cf = 2 * fs.Freq * (pc->SummFreq+6); sf = s0 + pc->SummFreq; if (cf < 6 * sf) { cf = 1 + (cf > sf)+(cf >= 4 * sf); pc->SummFreq += 3; } else { cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); pc->SummFreq += cf; } p = pc->Stats + ns1; p->Successor = Successor; p->Symbol = fs.Symbol; p->Freq = cf; pc->NumStats = ++ns1; } MaxContext = MinContext = fs.Successor; return; RESTART_MODEL: RestartModelRare(); EscCount = 0; PrintCount = 0xFF; } void ClearMask() { EscCount = 1; memset(CharMask, 0, sizeof(CharMask)); // if (++PrintCount == 0) // PrintInfo(DecodedFile,EncodedFile); } void update1(PPM_CONTEXT::STATE* p) { (FoundState = p)->Freq += 4; MinContext->SummFreq += 4; if (p[0].Freq > p[-1].Freq) { _PPMD_SWAP(p[0],p[-1]); FoundState = --p; if (p->Freq > MAX_FREQ) rescale(); } } void update2(PPM_CONTEXT::STATE* p) { (FoundState = p)->Freq += 4; MinContext->SummFreq += 4; if (p->Freq > MAX_FREQ) rescale(); EscCount++; RunLength = InitRL; } SEE2_CONTEXT* makeEscFreq2(int Diff, UInt32 &scale) { SEE2_CONTEXT* psee2c; if (MinContext->NumStats != 256) { psee2c = SEE2Cont[NS2Indx[Diff-1]] + (Diff < MinContext->Suffix->NumStats - MinContext->NumStats)+ 2 * (MinContext->SummFreq < 11 * MinContext->NumStats) + 4 * (NumMasked > Diff) + HiBitsFlag; scale = psee2c->getMean(); } else { psee2c = &DummySEE2Cont; scale = 1; } return psee2c; } void rescale() { int OldNS = MinContext->NumStats, i = MinContext->NumStats - 1, Adder, EscFreq; PPM_CONTEXT::STATE* p1, * p; for (p = FoundState; p != MinContext->Stats; p--) _PPMD_SWAP(p[0], p[-1]); MinContext->Stats->Freq += 4; MinContext->SummFreq += 4; EscFreq = MinContext->SummFreq - p->Freq; Adder = (OrderFall != 0); MinContext->SummFreq = (p->Freq = (p->Freq + Adder) >> 1); do { EscFreq -= (++p)->Freq; MinContext->SummFreq += (p->Freq = (p->Freq + Adder) >> 1); if (p[0].Freq > p[-1].Freq) { PPM_CONTEXT::STATE tmp = *(p1 = p); do { p1[0] = p1[-1]; } while (--p1 != MinContext->Stats && tmp.Freq > p1[-1].Freq); *p1 = tmp; } } while ( --i ); if (p->Freq == 0) { do { i++; } while ((--p)->Freq == 0); EscFreq += i; if ((MinContext->NumStats -= i) == 1) { PPM_CONTEXT::STATE tmp = *MinContext->Stats; do { tmp.Freq -= (tmp.Freq >> 1); EscFreq >>= 1; } while (EscFreq > 1); SubAllocator.FreeUnits(MinContext->Stats, (OldNS+1) >> 1); *(FoundState = &MinContext->oneState()) = tmp; return; } } MinContext->SummFreq += (EscFreq -= (EscFreq >> 1)); int n0 = (OldNS+1) >> 1, n1 = (MinContext->NumStats + 1) >> 1; if (n0 != n1) MinContext->Stats = (PPM_CONTEXT::STATE*) SubAllocator.ShrinkUnits(MinContext->Stats, n0, n1); FoundState = MinContext->Stats; } void NextContext() { if (!OrderFall && (Byte*) FoundState->Successor > SubAllocator.pText) MinContext = MaxContext = FoundState->Successor; else { UpdateModel(); if (EscCount == 0) ClearMask(); } } }; // Tabulated escapes for exponential symbol distribution const Byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; #define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT)) }} #endif