/* Ppmd.h -- PPMD codec common code12023-03-05 : Igor Pavlov : Public domain2This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */34#ifndef ZIP7_INC_PPMD_H5#define ZIP7_INC_PPMD_H67#include "CpuArch.h"89EXTERN_C_BEGIN1011#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)12/*13PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block.14if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields.15if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields.16if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed,17if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional,18and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit.19PPMD code works slightly faster in (PPMD_32BIT) mode.20*/21#define PPMD_32BIT22#endif2324#define PPMD_INT_BITS 725#define PPMD_PERIOD_BITS 726#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))2728#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))29#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)30#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))31#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))3233#define PPMD_N1 434#define PPMD_N2 435#define PPMD_N3 436#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)37#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)3839MY_CPU_pragma_pack_push_140/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */4142/* SEE-contexts for PPM-contexts with masked symbols */43typedef struct44{45UInt16 Summ; /* Freq */46Byte Shift; /* Speed of Freq change; low Shift is for fast change */47Byte Count; /* Count to next change of Shift */48} CPpmd_See;4950#define Ppmd_See_UPDATE(p) \51{ if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \52{ (p)->Summ = (UInt16)((p)->Summ << 1); \53(p)->Count = (Byte)(3 << (p)->Shift++); }}545556typedef struct57{58Byte Symbol;59Byte Freq;60UInt16 Successor_0;61UInt16 Successor_1;62} CPpmd_State;6364typedef struct CPpmd_State2_65{66Byte Symbol;67Byte Freq;68} CPpmd_State2;6970typedef struct CPpmd_State4_71{72UInt16 Successor_0;73UInt16 Successor_1;74} CPpmd_State4;7576MY_CPU_pragma_pop7778/*79PPMD code can write full CPpmd_State structure data to CPpmd*_Context80at (byte offset = 2) instead of some fields of original CPpmd*_Context structure.8182If we use pointers to different types, but that point to shared83memory space, we can have aliasing problem (strict aliasing).8485XLC compiler in -O2 mode can change the order of memory write instructions86in relation to read instructions, if we have use pointers to different types.8788To solve that aliasing problem we use combined CPpmd*_Context structure89with unions that contain the fields from both structures:90the original CPpmd*_Context and CPpmd_State.91So we can access the fields from both structures via one pointer,92and the compiler doesn't change the order of write instructions93in relation to read instructions.9495If we don't use memory write instructions to shared memory in96some local code, and we use only reading instructions (read only),97then probably it's safe to use pointers to different types for reading.98*/99100101102#ifdef PPMD_32BIT103104#define Ppmd_Ref_Type(type) type *105#define Ppmd_GetRef(p, ptr) (ptr)106#define Ppmd_GetPtr(p, ptr) (ptr)107#define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr)108109#else110111#define Ppmd_Ref_Type(type) UInt32112#define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))113#define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs)))114#define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs))115116#endif // PPMD_32BIT117118119typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref;120typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref;121typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref;122123124/*125#ifdef MY_CPU_LE_UNALIGN126// the unaligned 32-bit access latency can be too large, if the data is not in L1 cache.127#define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0)128#define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v)129130#else131*/132133/*134We can write 16-bit halves to 32-bit (Successor) field in any selected order.135But the native order is more consistent way.136So we use the native order, if LE/BE order can be detected here at compile time.137*/138139#ifdef MY_CPU_BE140141#define Ppmd_GET_SUCCESSOR(p) \142( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) )143144#define Ppmd_SET_SUCCESSOR(p, v) { \145(p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \146(p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); }147148#else149150#define Ppmd_GET_SUCCESSOR(p) \151( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) )152153#define Ppmd_SET_SUCCESSOR(p, v) { \154(p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \155(p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); }156157#endif158159// #endif160161162#define PPMD_SetAllBitsIn256Bytes(p) \163{ size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \164p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }}165166EXTERN_C_END167168#endif169170171