1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package org.waarp.compress.zstdunsafe;
35
36 class FseCompressionTable {
37 private final short[] nextState;
38 private final int[] deltaNumberOfBits;
39 private final int[] deltaFindState;
40
41 private int log2Size;
42
43 public FseCompressionTable(final int maxTableLog, final int maxSymbol) {
44 nextState = new short[1 << maxTableLog];
45 deltaNumberOfBits = new int[maxSymbol + 1];
46 deltaFindState = new int[maxSymbol + 1];
47 }
48
49 public static FseCompressionTable newInstance(final short[] normalizedCounts,
50 final int maxSymbol,
51 final int tableLog) {
52 final FseCompressionTable result =
53 new FseCompressionTable(tableLog, maxSymbol);
54 result.initialize(normalizedCounts, maxSymbol, tableLog);
55
56 return result;
57 }
58
59 public void initializeRleTable(final int symbol) {
60 log2Size = 0;
61
62 nextState[0] = 0;
63 nextState[1] = 0;
64
65 deltaFindState[symbol] = 0;
66 deltaNumberOfBits[symbol] = 0;
67 }
68
69 public void initialize(final short[] normalizedCounts, final int maxSymbol,
70 final int tableLog) {
71 final int tableSize = 1 << tableLog;
72
73 final byte[] table = new byte[tableSize];
74 int highThreshold = tableSize - 1;
75
76
77 log2Size = tableLog;
78
79
80
81
82
83 final int[] cumulative = new int[FiniteStateEntropy.MAX_SYMBOL +
84 2];
85 cumulative[0] = 0;
86 for (int i = 1; i <= maxSymbol + 1; i++) {
87 if (normalizedCounts[i - 1] == -1) {
88 cumulative[i] = cumulative[i - 1] + 1;
89 table[highThreshold--] = (byte) (i - 1);
90 } else {
91 cumulative[i] = cumulative[i - 1] + normalizedCounts[i - 1];
92 }
93 }
94 cumulative[maxSymbol + 1] = tableSize + 1;
95
96
97 final int position =
98 spreadSymbols(normalizedCounts, maxSymbol, tableSize, highThreshold,
99 table);
100
101 if (position != 0) {
102 throw new AssertionError("Spread symbols failed");
103 }
104
105
106 for (int i = 0; i < tableSize; i++) {
107 final byte symbol = table[i];
108 nextState[cumulative[symbol]++] = (short) (tableSize +
109 i);
110 }
111
112
113 int total = 0;
114 for (int symbol = 0; symbol <= maxSymbol; symbol++) {
115 switch (normalizedCounts[symbol]) {
116 case 0:
117 deltaNumberOfBits[symbol] = ((tableLog + 1) << 16) - tableSize;
118 break;
119 case -1:
120 case 1:
121 deltaNumberOfBits[symbol] = (tableLog << 16) - tableSize;
122 deltaFindState[symbol] = total - 1;
123 total++;
124 break;
125 default:
126 final int maxBitsOut =
127 tableLog - Util.highestBit(normalizedCounts[symbol] - 1);
128 final int minStatePlus = normalizedCounts[symbol] << maxBitsOut;
129 deltaNumberOfBits[symbol] = (maxBitsOut << 16) - minStatePlus;
130 deltaFindState[symbol] = total - normalizedCounts[symbol];
131 total += normalizedCounts[symbol];
132 break;
133 }
134 }
135 }
136
137 public int begin(final byte symbol) {
138 final int outputBits = (deltaNumberOfBits[symbol] + (1 << 15)) >>> 16;
139 final int base =
140 ((outputBits << 16) - deltaNumberOfBits[symbol]) >>> outputBits;
141 return nextState[base + deltaFindState[symbol]];
142 }
143
144 public int encode(final BitOutputStream stream, final int state,
145 final int symbol) {
146 final int outputBits = (state + deltaNumberOfBits[symbol]) >>> 16;
147 stream.addBits(state, outputBits);
148 return nextState[(state >>> outputBits) + deltaFindState[symbol]];
149 }
150
151 public void finish(final BitOutputStream stream, final int state) {
152 stream.addBits(state, log2Size);
153 stream.flush();
154 }
155
156 private static int calculateStep(final int tableSize) {
157 return (tableSize >>> 1) + (tableSize >>> 3) + 3;
158 }
159
160 public static int spreadSymbols(final short[] normalizedCounters,
161 final int maxSymbolValue, final int tableSize,
162 final int highThreshold,
163 final byte[] symbols) {
164 final int mask = tableSize - 1;
165 final int step = calculateStep(tableSize);
166
167 int position = 0;
168 for (byte symbol = 0; symbol <= maxSymbolValue; symbol++) {
169 for (int i = 0; i < normalizedCounters[symbol]; i++) {
170 symbols[position] = symbol;
171 do {
172 position = (position + step) & mask;
173 } while (position > highThreshold);
174 }
175 }
176 return position;
177 }
178 }