diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /C/Ppmd.h | |
parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
download | 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.gz 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.bz2 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.zip |
'21.07'21.07
Diffstat (limited to 'C/Ppmd.h')
-rw-r--r-- | C/Ppmd.h | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/C/Ppmd.h b/C/Ppmd.h new file mode 100644 index 0000000..b198792 --- /dev/null +++ b/C/Ppmd.h | |||
@@ -0,0 +1,167 @@ | |||
1 | /* Ppmd.h -- PPMD codec common code | ||
2 | 2021-04-13 : Igor Pavlov : Public domain | ||
3 | This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ | ||
4 | |||
5 | #ifndef __PPMD_H | ||
6 | #define __PPMD_H | ||
7 | |||
8 | #include "CpuArch.h" | ||
9 | |||
10 | EXTERN_C_BEGIN | ||
11 | |||
12 | #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) | ||
13 | /* | ||
14 | PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block. | ||
15 | if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields. | ||
16 | if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields. | ||
17 | if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed, | ||
18 | if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional, | ||
19 | and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit. | ||
20 | PPMD code works slightly faster in (PPMD_32BIT) mode. | ||
21 | */ | ||
22 | #define PPMD_32BIT | ||
23 | #endif | ||
24 | |||
25 | #define PPMD_INT_BITS 7 | ||
26 | #define PPMD_PERIOD_BITS 7 | ||
27 | #define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) | ||
28 | |||
29 | #define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) | ||
30 | #define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) | ||
31 | #define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) | ||
32 | #define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) | ||
33 | |||
34 | #define PPMD_N1 4 | ||
35 | #define PPMD_N2 4 | ||
36 | #define PPMD_N3 4 | ||
37 | #define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) | ||
38 | #define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) | ||
39 | |||
40 | MY_CPU_pragma_pack_push_1 | ||
41 | /* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ | ||
42 | |||
43 | /* SEE-contexts for PPM-contexts with masked symbols */ | ||
44 | typedef struct | ||
45 | { | ||
46 | UInt16 Summ; /* Freq */ | ||
47 | Byte Shift; /* Speed of Freq change; low Shift is for fast change */ | ||
48 | Byte Count; /* Count to next change of Shift */ | ||
49 | } CPpmd_See; | ||
50 | |||
51 | #define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ | ||
52 | { (p)->Summ = (UInt16)((p)->Summ << 1); (p)->Count = (Byte)(3 << (p)->Shift++); } | ||
53 | |||
54 | |||
55 | typedef struct | ||
56 | { | ||
57 | Byte Symbol; | ||
58 | Byte Freq; | ||
59 | UInt16 Successor_0; | ||
60 | UInt16 Successor_1; | ||
61 | } CPpmd_State; | ||
62 | |||
63 | typedef struct CPpmd_State2_ | ||
64 | { | ||
65 | Byte Symbol; | ||
66 | Byte Freq; | ||
67 | } CPpmd_State2; | ||
68 | |||
69 | typedef struct CPpmd_State4_ | ||
70 | { | ||
71 | UInt16 Successor_0; | ||
72 | UInt16 Successor_1; | ||
73 | } CPpmd_State4; | ||
74 | |||
75 | MY_CPU_pragma_pop | ||
76 | |||
77 | /* | ||
78 | PPMD code can write full CPpmd_State structure data to CPpmd*_Context | ||
79 | at (byte offset = 2) instead of some fields of original CPpmd*_Context structure. | ||
80 | |||
81 | If we use pointers to different types, but that point to shared | ||
82 | memory space, we can have aliasing problem (strict aliasing). | ||
83 | |||
84 | XLC compiler in -O2 mode can change the order of memory write instructions | ||
85 | in relation to read instructions, if we have use pointers to different types. | ||
86 | |||
87 | To solve that aliasing problem we use combined CPpmd*_Context structure | ||
88 | with unions that contain the fields from both structures: | ||
89 | the original CPpmd*_Context and CPpmd_State. | ||
90 | So we can access the fields from both structures via one pointer, | ||
91 | and the compiler doesn't change the order of write instructions | ||
92 | in relation to read instructions. | ||
93 | |||
94 | If we don't use memory write instructions to shared memory in | ||
95 | some local code, and we use only reading instructions (read only), | ||
96 | then probably it's safe to use pointers to different types for reading. | ||
97 | */ | ||
98 | |||
99 | |||
100 | |||
101 | #ifdef PPMD_32BIT | ||
102 | |||
103 | #define Ppmd_Ref_Type(type) type * | ||
104 | #define Ppmd_GetRef(p, ptr) (ptr) | ||
105 | #define Ppmd_GetPtr(p, ptr) (ptr) | ||
106 | #define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr) | ||
107 | |||
108 | #else | ||
109 | |||
110 | #define Ppmd_Ref_Type(type) UInt32 | ||
111 | #define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) | ||
112 | #define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs))) | ||
113 | #define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs)) | ||
114 | |||
115 | #endif // PPMD_32BIT | ||
116 | |||
117 | |||
118 | typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref; | ||
119 | typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref; | ||
120 | typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref; | ||
121 | |||
122 | |||
123 | /* | ||
124 | #ifdef MY_CPU_LE_UNALIGN | ||
125 | // the unaligned 32-bit access latency can be too large, if the data is not in L1 cache. | ||
126 | #define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0) | ||
127 | #define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v) | ||
128 | |||
129 | #else | ||
130 | */ | ||
131 | |||
132 | /* | ||
133 | We can write 16-bit halves to 32-bit (Successor) field in any selected order. | ||
134 | But the native order is more consistent way. | ||
135 | So we use the native order, if LE/BE order can be detected here at compile time. | ||
136 | */ | ||
137 | |||
138 | #ifdef MY_CPU_BE | ||
139 | |||
140 | #define Ppmd_GET_SUCCESSOR(p) \ | ||
141 | ( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) ) | ||
142 | |||
143 | #define Ppmd_SET_SUCCESSOR(p, v) { \ | ||
144 | (p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \ | ||
145 | (p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); } | ||
146 | |||
147 | #else | ||
148 | |||
149 | #define Ppmd_GET_SUCCESSOR(p) \ | ||
150 | ( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) ) | ||
151 | |||
152 | #define Ppmd_SET_SUCCESSOR(p, v) { \ | ||
153 | (p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \ | ||
154 | (p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); } | ||
155 | |||
156 | #endif | ||
157 | |||
158 | // #endif | ||
159 | |||
160 | |||
161 | #define PPMD_SetAllBitsIn256Bytes(p) \ | ||
162 | { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \ | ||
163 | p[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; }} | ||
164 | |||
165 | EXTERN_C_END | ||
166 | |||
167 | #endif | ||