1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * FSE : Finite State Entropy encoder
3*4882a593Smuzhiyun * Copyright (C) 2013-2015, Yann Collet.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or without
8*4882a593Smuzhiyun * modification, are permitted provided that the following conditions are
9*4882a593Smuzhiyun * met:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * * Redistributions of source code must retain the above copyright
12*4882a593Smuzhiyun * notice, this list of conditions and the following disclaimer.
13*4882a593Smuzhiyun * * Redistributions in binary form must reproduce the above
14*4882a593Smuzhiyun * copyright notice, this list of conditions and the following disclaimer
15*4882a593Smuzhiyun * in the documentation and/or other materials provided with the
16*4882a593Smuzhiyun * distribution.
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19*4882a593Smuzhiyun * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20*4882a593Smuzhiyun * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21*4882a593Smuzhiyun * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22*4882a593Smuzhiyun * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23*4882a593Smuzhiyun * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24*4882a593Smuzhiyun * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25*4882a593Smuzhiyun * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26*4882a593Smuzhiyun * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27*4882a593Smuzhiyun * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28*4882a593Smuzhiyun * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify it under
31*4882a593Smuzhiyun * the terms of the GNU General Public License version 2 as published by the
32*4882a593Smuzhiyun * Free Software Foundation. This program is dual-licensed; you may select
33*4882a593Smuzhiyun * either version 2 of the GNU General Public License ("GPL") or BSD license
34*4882a593Smuzhiyun * ("BSD").
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * You can contact the author at :
37*4882a593Smuzhiyun * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
38*4882a593Smuzhiyun */
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* **************************************************************
41*4882a593Smuzhiyun * Compiler specifics
42*4882a593Smuzhiyun ****************************************************************/
43*4882a593Smuzhiyun #define FORCE_INLINE static __always_inline
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /* **************************************************************
46*4882a593Smuzhiyun * Includes
47*4882a593Smuzhiyun ****************************************************************/
48*4882a593Smuzhiyun #include "bitstream.h"
49*4882a593Smuzhiyun #include "fse.h"
50*4882a593Smuzhiyun #include <linux/compiler.h>
51*4882a593Smuzhiyun #include <linux/kernel.h>
52*4882a593Smuzhiyun #include <linux/math64.h>
53*4882a593Smuzhiyun #include <linux/string.h> /* memcpy, memset */
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /* **************************************************************
56*4882a593Smuzhiyun * Error Management
57*4882a593Smuzhiyun ****************************************************************/
58*4882a593Smuzhiyun #define FSE_STATIC_ASSERT(c) \
59*4882a593Smuzhiyun { \
60*4882a593Smuzhiyun enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
61*4882a593Smuzhiyun } /* use only *after* variable declarations */
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* **************************************************************
64*4882a593Smuzhiyun * Templates
65*4882a593Smuzhiyun ****************************************************************/
66*4882a593Smuzhiyun /*
67*4882a593Smuzhiyun designed to be included
68*4882a593Smuzhiyun for type-specific functions (template emulation in C)
69*4882a593Smuzhiyun Objective is to write these functions only once, for improved maintenance
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* safety checks */
73*4882a593Smuzhiyun #ifndef FSE_FUNCTION_EXTENSION
74*4882a593Smuzhiyun #error "FSE_FUNCTION_EXTENSION must be defined"
75*4882a593Smuzhiyun #endif
76*4882a593Smuzhiyun #ifndef FSE_FUNCTION_TYPE
77*4882a593Smuzhiyun #error "FSE_FUNCTION_TYPE must be defined"
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* Function names */
81*4882a593Smuzhiyun #define FSE_CAT(X, Y) X##Y
82*4882a593Smuzhiyun #define FSE_FUNCTION_NAME(X, Y) FSE_CAT(X, Y)
83*4882a593Smuzhiyun #define FSE_TYPE_NAME(X, Y) FSE_CAT(X, Y)
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* Function templates */
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun /* FSE_buildCTable_wksp() :
88*4882a593Smuzhiyun * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
89*4882a593Smuzhiyun * wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
90*4882a593Smuzhiyun * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
91*4882a593Smuzhiyun */
FSE_buildCTable_wksp(FSE_CTable * ct,const short * normalizedCounter,unsigned maxSymbolValue,unsigned tableLog,void * workspace,size_t workspaceSize)92*4882a593Smuzhiyun size_t FSE_buildCTable_wksp(FSE_CTable *ct, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun U32 const tableSize = 1 << tableLog;
95*4882a593Smuzhiyun U32 const tableMask = tableSize - 1;
96*4882a593Smuzhiyun void *const ptr = ct;
97*4882a593Smuzhiyun U16 *const tableU16 = ((U16 *)ptr) + 2;
98*4882a593Smuzhiyun void *const FSCT = ((U32 *)ptr) + 1 /* header */ + (tableLog ? tableSize >> 1 : 1);
99*4882a593Smuzhiyun FSE_symbolCompressionTransform *const symbolTT = (FSE_symbolCompressionTransform *)(FSCT);
100*4882a593Smuzhiyun U32 const step = FSE_TABLESTEP(tableSize);
101*4882a593Smuzhiyun U32 highThreshold = tableSize - 1;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun U32 *cumul;
104*4882a593Smuzhiyun FSE_FUNCTION_TYPE *tableSymbol;
105*4882a593Smuzhiyun size_t spaceUsed32 = 0;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun cumul = (U32 *)workspace + spaceUsed32;
108*4882a593Smuzhiyun spaceUsed32 += FSE_MAX_SYMBOL_VALUE + 2;
109*4882a593Smuzhiyun tableSymbol = (FSE_FUNCTION_TYPE *)((U32 *)workspace + spaceUsed32);
110*4882a593Smuzhiyun spaceUsed32 += ALIGN(sizeof(FSE_FUNCTION_TYPE) * ((size_t)1 << tableLog), sizeof(U32)) >> 2;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if ((spaceUsed32 << 2) > workspaceSize)
113*4882a593Smuzhiyun return ERROR(tableLog_tooLarge);
114*4882a593Smuzhiyun workspace = (U32 *)workspace + spaceUsed32;
115*4882a593Smuzhiyun workspaceSize -= (spaceUsed32 << 2);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* CTable header */
118*4882a593Smuzhiyun tableU16[-2] = (U16)tableLog;
119*4882a593Smuzhiyun tableU16[-1] = (U16)maxSymbolValue;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* For explanations on how to distribute symbol values over the table :
122*4882a593Smuzhiyun * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* symbol start positions */
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun U32 u;
127*4882a593Smuzhiyun cumul[0] = 0;
128*4882a593Smuzhiyun for (u = 1; u <= maxSymbolValue + 1; u++) {
129*4882a593Smuzhiyun if (normalizedCounter[u - 1] == -1) { /* Low proba symbol */
130*4882a593Smuzhiyun cumul[u] = cumul[u - 1] + 1;
131*4882a593Smuzhiyun tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u - 1);
132*4882a593Smuzhiyun } else {
133*4882a593Smuzhiyun cumul[u] = cumul[u - 1] + normalizedCounter[u - 1];
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun cumul[maxSymbolValue + 1] = tableSize + 1;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* Spread symbols */
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun U32 position = 0;
142*4882a593Smuzhiyun U32 symbol;
143*4882a593Smuzhiyun for (symbol = 0; symbol <= maxSymbolValue; symbol++) {
144*4882a593Smuzhiyun int nbOccurences;
145*4882a593Smuzhiyun for (nbOccurences = 0; nbOccurences < normalizedCounter[symbol]; nbOccurences++) {
146*4882a593Smuzhiyun tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
147*4882a593Smuzhiyun position = (position + step) & tableMask;
148*4882a593Smuzhiyun while (position > highThreshold)
149*4882a593Smuzhiyun position = (position + step) & tableMask; /* Low proba area */
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (position != 0)
154*4882a593Smuzhiyun return ERROR(GENERIC); /* Must have gone through all positions */
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* Build table */
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun U32 u;
160*4882a593Smuzhiyun for (u = 0; u < tableSize; u++) {
161*4882a593Smuzhiyun FSE_FUNCTION_TYPE s = tableSymbol[u]; /* note : static analyzer may not understand tableSymbol is properly initialized */
162*4882a593Smuzhiyun tableU16[cumul[s]++] = (U16)(tableSize + u); /* TableU16 : sorted by symbol order; gives next state value */
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* Build Symbol Transformation Table */
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun unsigned total = 0;
169*4882a593Smuzhiyun unsigned s;
170*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++) {
171*4882a593Smuzhiyun switch (normalizedCounter[s]) {
172*4882a593Smuzhiyun case 0: break;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun case -1:
175*4882a593Smuzhiyun case 1:
176*4882a593Smuzhiyun symbolTT[s].deltaNbBits = (tableLog << 16) - (1 << tableLog);
177*4882a593Smuzhiyun symbolTT[s].deltaFindState = total - 1;
178*4882a593Smuzhiyun total++;
179*4882a593Smuzhiyun break;
180*4882a593Smuzhiyun default: {
181*4882a593Smuzhiyun U32 const maxBitsOut = tableLog - BIT_highbit32(normalizedCounter[s] - 1);
182*4882a593Smuzhiyun U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
183*4882a593Smuzhiyun symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
184*4882a593Smuzhiyun symbolTT[s].deltaFindState = total - normalizedCounter[s];
185*4882a593Smuzhiyun total += normalizedCounter[s];
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /*-**************************************************************
195*4882a593Smuzhiyun * FSE NCount encoding-decoding
196*4882a593Smuzhiyun ****************************************************************/
FSE_NCountWriteBound(unsigned maxSymbolValue,unsigned tableLog)197*4882a593Smuzhiyun size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun size_t const maxHeaderSize = (((maxSymbolValue + 1) * tableLog) >> 3) + 3;
200*4882a593Smuzhiyun return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
FSE_writeNCount_generic(void * header,size_t headerBufferSize,const short * normalizedCounter,unsigned maxSymbolValue,unsigned tableLog,unsigned writeIsSafe)203*4882a593Smuzhiyun static size_t FSE_writeNCount_generic(void *header, size_t headerBufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
204*4882a593Smuzhiyun unsigned writeIsSafe)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun BYTE *const ostart = (BYTE *)header;
207*4882a593Smuzhiyun BYTE *out = ostart;
208*4882a593Smuzhiyun BYTE *const oend = ostart + headerBufferSize;
209*4882a593Smuzhiyun int nbBits;
210*4882a593Smuzhiyun const int tableSize = 1 << tableLog;
211*4882a593Smuzhiyun int remaining;
212*4882a593Smuzhiyun int threshold;
213*4882a593Smuzhiyun U32 bitStream;
214*4882a593Smuzhiyun int bitCount;
215*4882a593Smuzhiyun unsigned charnum = 0;
216*4882a593Smuzhiyun int previous0 = 0;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun bitStream = 0;
219*4882a593Smuzhiyun bitCount = 0;
220*4882a593Smuzhiyun /* Table Size */
221*4882a593Smuzhiyun bitStream += (tableLog - FSE_MIN_TABLELOG) << bitCount;
222*4882a593Smuzhiyun bitCount += 4;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* Init */
225*4882a593Smuzhiyun remaining = tableSize + 1; /* +1 for extra accuracy */
226*4882a593Smuzhiyun threshold = tableSize;
227*4882a593Smuzhiyun nbBits = tableLog + 1;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun while (remaining > 1) { /* stops at 1 */
230*4882a593Smuzhiyun if (previous0) {
231*4882a593Smuzhiyun unsigned start = charnum;
232*4882a593Smuzhiyun while (!normalizedCounter[charnum])
233*4882a593Smuzhiyun charnum++;
234*4882a593Smuzhiyun while (charnum >= start + 24) {
235*4882a593Smuzhiyun start += 24;
236*4882a593Smuzhiyun bitStream += 0xFFFFU << bitCount;
237*4882a593Smuzhiyun if ((!writeIsSafe) && (out > oend - 2))
238*4882a593Smuzhiyun return ERROR(dstSize_tooSmall); /* Buffer overflow */
239*4882a593Smuzhiyun out[0] = (BYTE)bitStream;
240*4882a593Smuzhiyun out[1] = (BYTE)(bitStream >> 8);
241*4882a593Smuzhiyun out += 2;
242*4882a593Smuzhiyun bitStream >>= 16;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun while (charnum >= start + 3) {
245*4882a593Smuzhiyun start += 3;
246*4882a593Smuzhiyun bitStream += 3 << bitCount;
247*4882a593Smuzhiyun bitCount += 2;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun bitStream += (charnum - start) << bitCount;
250*4882a593Smuzhiyun bitCount += 2;
251*4882a593Smuzhiyun if (bitCount > 16) {
252*4882a593Smuzhiyun if ((!writeIsSafe) && (out > oend - 2))
253*4882a593Smuzhiyun return ERROR(dstSize_tooSmall); /* Buffer overflow */
254*4882a593Smuzhiyun out[0] = (BYTE)bitStream;
255*4882a593Smuzhiyun out[1] = (BYTE)(bitStream >> 8);
256*4882a593Smuzhiyun out += 2;
257*4882a593Smuzhiyun bitStream >>= 16;
258*4882a593Smuzhiyun bitCount -= 16;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun int count = normalizedCounter[charnum++];
263*4882a593Smuzhiyun int const max = (2 * threshold - 1) - remaining;
264*4882a593Smuzhiyun remaining -= count < 0 ? -count : count;
265*4882a593Smuzhiyun count++; /* +1 for extra accuracy */
266*4882a593Smuzhiyun if (count >= threshold)
267*4882a593Smuzhiyun count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
268*4882a593Smuzhiyun bitStream += count << bitCount;
269*4882a593Smuzhiyun bitCount += nbBits;
270*4882a593Smuzhiyun bitCount -= (count < max);
271*4882a593Smuzhiyun previous0 = (count == 1);
272*4882a593Smuzhiyun if (remaining < 1)
273*4882a593Smuzhiyun return ERROR(GENERIC);
274*4882a593Smuzhiyun while (remaining < threshold)
275*4882a593Smuzhiyun nbBits--, threshold >>= 1;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun if (bitCount > 16) {
278*4882a593Smuzhiyun if ((!writeIsSafe) && (out > oend - 2))
279*4882a593Smuzhiyun return ERROR(dstSize_tooSmall); /* Buffer overflow */
280*4882a593Smuzhiyun out[0] = (BYTE)bitStream;
281*4882a593Smuzhiyun out[1] = (BYTE)(bitStream >> 8);
282*4882a593Smuzhiyun out += 2;
283*4882a593Smuzhiyun bitStream >>= 16;
284*4882a593Smuzhiyun bitCount -= 16;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /* flush remaining bitStream */
289*4882a593Smuzhiyun if ((!writeIsSafe) && (out > oend - 2))
290*4882a593Smuzhiyun return ERROR(dstSize_tooSmall); /* Buffer overflow */
291*4882a593Smuzhiyun out[0] = (BYTE)bitStream;
292*4882a593Smuzhiyun out[1] = (BYTE)(bitStream >> 8);
293*4882a593Smuzhiyun out += (bitCount + 7) / 8;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (charnum > maxSymbolValue + 1)
296*4882a593Smuzhiyun return ERROR(GENERIC);
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun return (out - ostart);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
FSE_writeNCount(void * buffer,size_t bufferSize,const short * normalizedCounter,unsigned maxSymbolValue,unsigned tableLog)301*4882a593Smuzhiyun size_t FSE_writeNCount(void *buffer, size_t bufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun if (tableLog > FSE_MAX_TABLELOG)
304*4882a593Smuzhiyun return ERROR(tableLog_tooLarge); /* Unsupported */
305*4882a593Smuzhiyun if (tableLog < FSE_MIN_TABLELOG)
306*4882a593Smuzhiyun return ERROR(GENERIC); /* Unsupported */
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
309*4882a593Smuzhiyun return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /*-**************************************************************
315*4882a593Smuzhiyun * Counting histogram
316*4882a593Smuzhiyun ****************************************************************/
317*4882a593Smuzhiyun /*! FSE_count_simple
318*4882a593Smuzhiyun This function counts byte values within `src`, and store the histogram into table `count`.
319*4882a593Smuzhiyun It doesn't use any additional memory.
320*4882a593Smuzhiyun But this function is unsafe : it doesn't check that all values within `src` can fit into `count`.
321*4882a593Smuzhiyun For this reason, prefer using a table `count` with 256 elements.
322*4882a593Smuzhiyun @return : count of most numerous element
323*4882a593Smuzhiyun */
FSE_count_simple(unsigned * count,unsigned * maxSymbolValuePtr,const void * src,size_t srcSize)324*4882a593Smuzhiyun size_t FSE_count_simple(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun const BYTE *ip = (const BYTE *)src;
327*4882a593Smuzhiyun const BYTE *const end = ip + srcSize;
328*4882a593Smuzhiyun unsigned maxSymbolValue = *maxSymbolValuePtr;
329*4882a593Smuzhiyun unsigned max = 0;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun memset(count, 0, (maxSymbolValue + 1) * sizeof(*count));
332*4882a593Smuzhiyun if (srcSize == 0) {
333*4882a593Smuzhiyun *maxSymbolValuePtr = 0;
334*4882a593Smuzhiyun return 0;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun while (ip < end)
338*4882a593Smuzhiyun count[*ip++]++;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun while (!count[maxSymbolValue])
341*4882a593Smuzhiyun maxSymbolValue--;
342*4882a593Smuzhiyun *maxSymbolValuePtr = maxSymbolValue;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun U32 s;
346*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++)
347*4882a593Smuzhiyun if (count[s] > max)
348*4882a593Smuzhiyun max = count[s];
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun return (size_t)max;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun /* FSE_count_parallel_wksp() :
355*4882a593Smuzhiyun * Same as FSE_count_parallel(), but using an externally provided scratch buffer.
356*4882a593Smuzhiyun * `workSpace` size must be a minimum of `1024 * sizeof(unsigned)`` */
FSE_count_parallel_wksp(unsigned * count,unsigned * maxSymbolValuePtr,const void * source,size_t sourceSize,unsigned checkMax,unsigned * const workSpace)357*4882a593Smuzhiyun static size_t FSE_count_parallel_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned checkMax,
358*4882a593Smuzhiyun unsigned *const workSpace)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun const BYTE *ip = (const BYTE *)source;
361*4882a593Smuzhiyun const BYTE *const iend = ip + sourceSize;
362*4882a593Smuzhiyun unsigned maxSymbolValue = *maxSymbolValuePtr;
363*4882a593Smuzhiyun unsigned max = 0;
364*4882a593Smuzhiyun U32 *const Counting1 = workSpace;
365*4882a593Smuzhiyun U32 *const Counting2 = Counting1 + 256;
366*4882a593Smuzhiyun U32 *const Counting3 = Counting2 + 256;
367*4882a593Smuzhiyun U32 *const Counting4 = Counting3 + 256;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun memset(Counting1, 0, 4 * 256 * sizeof(unsigned));
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun /* safety checks */
372*4882a593Smuzhiyun if (!sourceSize) {
373*4882a593Smuzhiyun memset(count, 0, maxSymbolValue + 1);
374*4882a593Smuzhiyun *maxSymbolValuePtr = 0;
375*4882a593Smuzhiyun return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun if (!maxSymbolValue)
378*4882a593Smuzhiyun maxSymbolValue = 255; /* 0 == default */
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* by stripes of 16 bytes */
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun U32 cached = ZSTD_read32(ip);
383*4882a593Smuzhiyun ip += 4;
384*4882a593Smuzhiyun while (ip < iend - 15) {
385*4882a593Smuzhiyun U32 c = cached;
386*4882a593Smuzhiyun cached = ZSTD_read32(ip);
387*4882a593Smuzhiyun ip += 4;
388*4882a593Smuzhiyun Counting1[(BYTE)c]++;
389*4882a593Smuzhiyun Counting2[(BYTE)(c >> 8)]++;
390*4882a593Smuzhiyun Counting3[(BYTE)(c >> 16)]++;
391*4882a593Smuzhiyun Counting4[c >> 24]++;
392*4882a593Smuzhiyun c = cached;
393*4882a593Smuzhiyun cached = ZSTD_read32(ip);
394*4882a593Smuzhiyun ip += 4;
395*4882a593Smuzhiyun Counting1[(BYTE)c]++;
396*4882a593Smuzhiyun Counting2[(BYTE)(c >> 8)]++;
397*4882a593Smuzhiyun Counting3[(BYTE)(c >> 16)]++;
398*4882a593Smuzhiyun Counting4[c >> 24]++;
399*4882a593Smuzhiyun c = cached;
400*4882a593Smuzhiyun cached = ZSTD_read32(ip);
401*4882a593Smuzhiyun ip += 4;
402*4882a593Smuzhiyun Counting1[(BYTE)c]++;
403*4882a593Smuzhiyun Counting2[(BYTE)(c >> 8)]++;
404*4882a593Smuzhiyun Counting3[(BYTE)(c >> 16)]++;
405*4882a593Smuzhiyun Counting4[c >> 24]++;
406*4882a593Smuzhiyun c = cached;
407*4882a593Smuzhiyun cached = ZSTD_read32(ip);
408*4882a593Smuzhiyun ip += 4;
409*4882a593Smuzhiyun Counting1[(BYTE)c]++;
410*4882a593Smuzhiyun Counting2[(BYTE)(c >> 8)]++;
411*4882a593Smuzhiyun Counting3[(BYTE)(c >> 16)]++;
412*4882a593Smuzhiyun Counting4[c >> 24]++;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun ip -= 4;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* finish last symbols */
418*4882a593Smuzhiyun while (ip < iend)
419*4882a593Smuzhiyun Counting1[*ip++]++;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun if (checkMax) { /* verify stats will fit into destination table */
422*4882a593Smuzhiyun U32 s;
423*4882a593Smuzhiyun for (s = 255; s > maxSymbolValue; s--) {
424*4882a593Smuzhiyun Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
425*4882a593Smuzhiyun if (Counting1[s])
426*4882a593Smuzhiyun return ERROR(maxSymbolValue_tooSmall);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun U32 s;
432*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++) {
433*4882a593Smuzhiyun count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
434*4882a593Smuzhiyun if (count[s] > max)
435*4882a593Smuzhiyun max = count[s];
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun while (!count[maxSymbolValue])
440*4882a593Smuzhiyun maxSymbolValue--;
441*4882a593Smuzhiyun *maxSymbolValuePtr = maxSymbolValue;
442*4882a593Smuzhiyun return (size_t)max;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun /* FSE_countFast_wksp() :
446*4882a593Smuzhiyun * Same as FSE_countFast(), but using an externally provided scratch buffer.
447*4882a593Smuzhiyun * `workSpace` size must be table of >= `1024` unsigned */
FSE_countFast_wksp(unsigned * count,unsigned * maxSymbolValuePtr,const void * source,size_t sourceSize,unsigned * workSpace)448*4882a593Smuzhiyun size_t FSE_countFast_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun if (sourceSize < 1500)
451*4882a593Smuzhiyun return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
452*4882a593Smuzhiyun return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun /* FSE_count_wksp() :
456*4882a593Smuzhiyun * Same as FSE_count(), but using an externally provided scratch buffer.
457*4882a593Smuzhiyun * `workSpace` size must be table of >= `1024` unsigned */
FSE_count_wksp(unsigned * count,unsigned * maxSymbolValuePtr,const void * source,size_t sourceSize,unsigned * workSpace)458*4882a593Smuzhiyun size_t FSE_count_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun if (*maxSymbolValuePtr < 255)
461*4882a593Smuzhiyun return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace);
462*4882a593Smuzhiyun *maxSymbolValuePtr = 255;
463*4882a593Smuzhiyun return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace);
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun /*-**************************************************************
467*4882a593Smuzhiyun * FSE Compression Code
468*4882a593Smuzhiyun ****************************************************************/
469*4882a593Smuzhiyun /*! FSE_sizeof_CTable() :
470*4882a593Smuzhiyun FSE_CTable is a variable size structure which contains :
471*4882a593Smuzhiyun `U16 tableLog;`
472*4882a593Smuzhiyun `U16 maxSymbolValue;`
473*4882a593Smuzhiyun `U16 nextStateNumber[1 << tableLog];` // This size is variable
474*4882a593Smuzhiyun `FSE_symbolCompressionTransform symbolTT[maxSymbolValue+1];` // This size is variable
475*4882a593Smuzhiyun Allocation is manual (C standard does not support variable-size structures).
476*4882a593Smuzhiyun */
FSE_sizeof_CTable(unsigned maxSymbolValue,unsigned tableLog)477*4882a593Smuzhiyun size_t FSE_sizeof_CTable(unsigned maxSymbolValue, unsigned tableLog)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun if (tableLog > FSE_MAX_TABLELOG)
480*4882a593Smuzhiyun return ERROR(tableLog_tooLarge);
481*4882a593Smuzhiyun return FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue) * sizeof(U32);
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun /* provides the minimum logSize to safely represent a distribution */
FSE_minTableLog(size_t srcSize,unsigned maxSymbolValue)485*4882a593Smuzhiyun static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun U32 minBitsSrc = BIT_highbit32((U32)(srcSize - 1)) + 1;
488*4882a593Smuzhiyun U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
489*4882a593Smuzhiyun U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
490*4882a593Smuzhiyun return minBits;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
FSE_optimalTableLog_internal(unsigned maxTableLog,size_t srcSize,unsigned maxSymbolValue,unsigned minus)493*4882a593Smuzhiyun unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
496*4882a593Smuzhiyun U32 tableLog = maxTableLog;
497*4882a593Smuzhiyun U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
498*4882a593Smuzhiyun if (tableLog == 0)
499*4882a593Smuzhiyun tableLog = FSE_DEFAULT_TABLELOG;
500*4882a593Smuzhiyun if (maxBitsSrc < tableLog)
501*4882a593Smuzhiyun tableLog = maxBitsSrc; /* Accuracy can be reduced */
502*4882a593Smuzhiyun if (minBits > tableLog)
503*4882a593Smuzhiyun tableLog = minBits; /* Need a minimum to safely represent all symbol values */
504*4882a593Smuzhiyun if (tableLog < FSE_MIN_TABLELOG)
505*4882a593Smuzhiyun tableLog = FSE_MIN_TABLELOG;
506*4882a593Smuzhiyun if (tableLog > FSE_MAX_TABLELOG)
507*4882a593Smuzhiyun tableLog = FSE_MAX_TABLELOG;
508*4882a593Smuzhiyun return tableLog;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
FSE_optimalTableLog(unsigned maxTableLog,size_t srcSize,unsigned maxSymbolValue)511*4882a593Smuzhiyun unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun /* Secondary normalization method.
517*4882a593Smuzhiyun To be used when primary method fails. */
518*4882a593Smuzhiyun
FSE_normalizeM2(short * norm,U32 tableLog,const unsigned * count,size_t total,U32 maxSymbolValue)519*4882a593Smuzhiyun static size_t FSE_normalizeM2(short *norm, U32 tableLog, const unsigned *count, size_t total, U32 maxSymbolValue)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun short const NOT_YET_ASSIGNED = -2;
522*4882a593Smuzhiyun U32 s;
523*4882a593Smuzhiyun U32 distributed = 0;
524*4882a593Smuzhiyun U32 ToDistribute;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /* Init */
527*4882a593Smuzhiyun U32 const lowThreshold = (U32)(total >> tableLog);
528*4882a593Smuzhiyun U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++) {
531*4882a593Smuzhiyun if (count[s] == 0) {
532*4882a593Smuzhiyun norm[s] = 0;
533*4882a593Smuzhiyun continue;
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun if (count[s] <= lowThreshold) {
536*4882a593Smuzhiyun norm[s] = -1;
537*4882a593Smuzhiyun distributed++;
538*4882a593Smuzhiyun total -= count[s];
539*4882a593Smuzhiyun continue;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun if (count[s] <= lowOne) {
542*4882a593Smuzhiyun norm[s] = 1;
543*4882a593Smuzhiyun distributed++;
544*4882a593Smuzhiyun total -= count[s];
545*4882a593Smuzhiyun continue;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun norm[s] = NOT_YET_ASSIGNED;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun ToDistribute = (1 << tableLog) - distributed;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun if ((total / ToDistribute) > lowOne) {
553*4882a593Smuzhiyun /* risk of rounding to zero */
554*4882a593Smuzhiyun lowOne = (U32)((total * 3) / (ToDistribute * 2));
555*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++) {
556*4882a593Smuzhiyun if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
557*4882a593Smuzhiyun norm[s] = 1;
558*4882a593Smuzhiyun distributed++;
559*4882a593Smuzhiyun total -= count[s];
560*4882a593Smuzhiyun continue;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun ToDistribute = (1 << tableLog) - distributed;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun if (distributed == maxSymbolValue + 1) {
567*4882a593Smuzhiyun /* all values are pretty poor;
568*4882a593Smuzhiyun probably incompressible data (should have already been detected);
569*4882a593Smuzhiyun find max, then give all remaining points to max */
570*4882a593Smuzhiyun U32 maxV = 0, maxC = 0;
571*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++)
572*4882a593Smuzhiyun if (count[s] > maxC)
573*4882a593Smuzhiyun maxV = s, maxC = count[s];
574*4882a593Smuzhiyun norm[maxV] += (short)ToDistribute;
575*4882a593Smuzhiyun return 0;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun if (total == 0) {
579*4882a593Smuzhiyun /* all of the symbols were low enough for the lowOne or lowThreshold */
580*4882a593Smuzhiyun for (s = 0; ToDistribute > 0; s = (s + 1) % (maxSymbolValue + 1))
581*4882a593Smuzhiyun if (norm[s] > 0)
582*4882a593Smuzhiyun ToDistribute--, norm[s]++;
583*4882a593Smuzhiyun return 0;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun U64 const vStepLog = 62 - tableLog;
588*4882a593Smuzhiyun U64 const mid = (1ULL << (vStepLog - 1)) - 1;
589*4882a593Smuzhiyun U64 const rStep = div_u64((((U64)1 << vStepLog) * ToDistribute) + mid, (U32)total); /* scale on remaining */
590*4882a593Smuzhiyun U64 tmpTotal = mid;
591*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++) {
592*4882a593Smuzhiyun if (norm[s] == NOT_YET_ASSIGNED) {
593*4882a593Smuzhiyun U64 const end = tmpTotal + (count[s] * rStep);
594*4882a593Smuzhiyun U32 const sStart = (U32)(tmpTotal >> vStepLog);
595*4882a593Smuzhiyun U32 const sEnd = (U32)(end >> vStepLog);
596*4882a593Smuzhiyun U32 const weight = sEnd - sStart;
597*4882a593Smuzhiyun if (weight < 1)
598*4882a593Smuzhiyun return ERROR(GENERIC);
599*4882a593Smuzhiyun norm[s] = (short)weight;
600*4882a593Smuzhiyun tmpTotal = end;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun return 0;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
FSE_normalizeCount(short * normalizedCounter,unsigned tableLog,const unsigned * count,size_t total,unsigned maxSymbolValue)608*4882a593Smuzhiyun size_t FSE_normalizeCount(short *normalizedCounter, unsigned tableLog, const unsigned *count, size_t total, unsigned maxSymbolValue)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun /* Sanity checks */
611*4882a593Smuzhiyun if (tableLog == 0)
612*4882a593Smuzhiyun tableLog = FSE_DEFAULT_TABLELOG;
613*4882a593Smuzhiyun if (tableLog < FSE_MIN_TABLELOG)
614*4882a593Smuzhiyun return ERROR(GENERIC); /* Unsupported size */
615*4882a593Smuzhiyun if (tableLog > FSE_MAX_TABLELOG)
616*4882a593Smuzhiyun return ERROR(tableLog_tooLarge); /* Unsupported size */
617*4882a593Smuzhiyun if (tableLog < FSE_minTableLog(total, maxSymbolValue))
618*4882a593Smuzhiyun return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun U32 const rtbTable[] = {0, 473195, 504333, 520860, 550000, 700000, 750000, 830000};
622*4882a593Smuzhiyun U64 const scale = 62 - tableLog;
623*4882a593Smuzhiyun U64 const step = div_u64((U64)1 << 62, (U32)total); /* <== here, one division ! */
624*4882a593Smuzhiyun U64 const vStep = 1ULL << (scale - 20);
625*4882a593Smuzhiyun int stillToDistribute = 1 << tableLog;
626*4882a593Smuzhiyun unsigned s;
627*4882a593Smuzhiyun unsigned largest = 0;
628*4882a593Smuzhiyun short largestP = 0;
629*4882a593Smuzhiyun U32 lowThreshold = (U32)(total >> tableLog);
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++) {
632*4882a593Smuzhiyun if (count[s] == total)
633*4882a593Smuzhiyun return 0; /* rle special case */
634*4882a593Smuzhiyun if (count[s] == 0) {
635*4882a593Smuzhiyun normalizedCounter[s] = 0;
636*4882a593Smuzhiyun continue;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun if (count[s] <= lowThreshold) {
639*4882a593Smuzhiyun normalizedCounter[s] = -1;
640*4882a593Smuzhiyun stillToDistribute--;
641*4882a593Smuzhiyun } else {
642*4882a593Smuzhiyun short proba = (short)((count[s] * step) >> scale);
643*4882a593Smuzhiyun if (proba < 8) {
644*4882a593Smuzhiyun U64 restToBeat = vStep * rtbTable[proba];
645*4882a593Smuzhiyun proba += (count[s] * step) - ((U64)proba << scale) > restToBeat;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun if (proba > largestP)
648*4882a593Smuzhiyun largestP = proba, largest = s;
649*4882a593Smuzhiyun normalizedCounter[s] = proba;
650*4882a593Smuzhiyun stillToDistribute -= proba;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
654*4882a593Smuzhiyun /* corner case, need another normalization method */
655*4882a593Smuzhiyun size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
656*4882a593Smuzhiyun if (FSE_isError(errorCode))
657*4882a593Smuzhiyun return errorCode;
658*4882a593Smuzhiyun } else
659*4882a593Smuzhiyun normalizedCounter[largest] += (short)stillToDistribute;
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun return tableLog;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun /* fake FSE_CTable, for raw (uncompressed) input */
FSE_buildCTable_raw(FSE_CTable * ct,unsigned nbBits)666*4882a593Smuzhiyun size_t FSE_buildCTable_raw(FSE_CTable *ct, unsigned nbBits)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun const unsigned tableSize = 1 << nbBits;
669*4882a593Smuzhiyun const unsigned tableMask = tableSize - 1;
670*4882a593Smuzhiyun const unsigned maxSymbolValue = tableMask;
671*4882a593Smuzhiyun void *const ptr = ct;
672*4882a593Smuzhiyun U16 *const tableU16 = ((U16 *)ptr) + 2;
673*4882a593Smuzhiyun void *const FSCT = ((U32 *)ptr) + 1 /* header */ + (tableSize >> 1); /* assumption : tableLog >= 1 */
674*4882a593Smuzhiyun FSE_symbolCompressionTransform *const symbolTT = (FSE_symbolCompressionTransform *)(FSCT);
675*4882a593Smuzhiyun unsigned s;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /* Sanity checks */
678*4882a593Smuzhiyun if (nbBits < 1)
679*4882a593Smuzhiyun return ERROR(GENERIC); /* min size */
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun /* header */
682*4882a593Smuzhiyun tableU16[-2] = (U16)nbBits;
683*4882a593Smuzhiyun tableU16[-1] = (U16)maxSymbolValue;
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun /* Build table */
686*4882a593Smuzhiyun for (s = 0; s < tableSize; s++)
687*4882a593Smuzhiyun tableU16[s] = (U16)(tableSize + s);
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun /* Build Symbol Transformation Table */
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
692*4882a593Smuzhiyun for (s = 0; s <= maxSymbolValue; s++) {
693*4882a593Smuzhiyun symbolTT[s].deltaNbBits = deltaNbBits;
694*4882a593Smuzhiyun symbolTT[s].deltaFindState = s - 1;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun return 0;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun /* fake FSE_CTable, for rle input (always same symbol) */
FSE_buildCTable_rle(FSE_CTable * ct,BYTE symbolValue)702*4882a593Smuzhiyun size_t FSE_buildCTable_rle(FSE_CTable *ct, BYTE symbolValue)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun void *ptr = ct;
705*4882a593Smuzhiyun U16 *tableU16 = ((U16 *)ptr) + 2;
706*4882a593Smuzhiyun void *FSCTptr = (U32 *)ptr + 2;
707*4882a593Smuzhiyun FSE_symbolCompressionTransform *symbolTT = (FSE_symbolCompressionTransform *)FSCTptr;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun /* header */
710*4882a593Smuzhiyun tableU16[-2] = (U16)0;
711*4882a593Smuzhiyun tableU16[-1] = (U16)symbolValue;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun /* Build table */
714*4882a593Smuzhiyun tableU16[0] = 0;
715*4882a593Smuzhiyun tableU16[1] = 0; /* just in case */
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun /* Build Symbol Transformation Table */
718*4882a593Smuzhiyun symbolTT[symbolValue].deltaNbBits = 0;
719*4882a593Smuzhiyun symbolTT[symbolValue].deltaFindState = 0;
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun return 0;
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun
FSE_compress_usingCTable_generic(void * dst,size_t dstSize,const void * src,size_t srcSize,const FSE_CTable * ct,const unsigned fast)724*4882a593Smuzhiyun static size_t FSE_compress_usingCTable_generic(void *dst, size_t dstSize, const void *src, size_t srcSize, const FSE_CTable *ct, const unsigned fast)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun const BYTE *const istart = (const BYTE *)src;
727*4882a593Smuzhiyun const BYTE *const iend = istart + srcSize;
728*4882a593Smuzhiyun const BYTE *ip = iend;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun BIT_CStream_t bitC;
731*4882a593Smuzhiyun FSE_CState_t CState1, CState2;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun /* init */
734*4882a593Smuzhiyun if (srcSize <= 2)
735*4882a593Smuzhiyun return 0;
736*4882a593Smuzhiyun {
737*4882a593Smuzhiyun size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
738*4882a593Smuzhiyun if (FSE_isError(initError))
739*4882a593Smuzhiyun return 0; /* not enough space available to write a bitstream */
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun #define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun if (srcSize & 1) {
745*4882a593Smuzhiyun FSE_initCState2(&CState1, ct, *--ip);
746*4882a593Smuzhiyun FSE_initCState2(&CState2, ct, *--ip);
747*4882a593Smuzhiyun FSE_encodeSymbol(&bitC, &CState1, *--ip);
748*4882a593Smuzhiyun FSE_FLUSHBITS(&bitC);
749*4882a593Smuzhiyun } else {
750*4882a593Smuzhiyun FSE_initCState2(&CState2, ct, *--ip);
751*4882a593Smuzhiyun FSE_initCState2(&CState1, ct, *--ip);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun /* join to mod 4 */
755*4882a593Smuzhiyun srcSize -= 2;
756*4882a593Smuzhiyun if ((sizeof(bitC.bitContainer) * 8 > FSE_MAX_TABLELOG * 4 + 7) && (srcSize & 2)) { /* test bit 2 */
757*4882a593Smuzhiyun FSE_encodeSymbol(&bitC, &CState2, *--ip);
758*4882a593Smuzhiyun FSE_encodeSymbol(&bitC, &CState1, *--ip);
759*4882a593Smuzhiyun FSE_FLUSHBITS(&bitC);
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun /* 2 or 4 encoding per loop */
763*4882a593Smuzhiyun while (ip > istart) {
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun FSE_encodeSymbol(&bitC, &CState2, *--ip);
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun if (sizeof(bitC.bitContainer) * 8 < FSE_MAX_TABLELOG * 2 + 7) /* this test must be static */
768*4882a593Smuzhiyun FSE_FLUSHBITS(&bitC);
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun FSE_encodeSymbol(&bitC, &CState1, *--ip);
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (sizeof(bitC.bitContainer) * 8 > FSE_MAX_TABLELOG * 4 + 7) { /* this test must be static */
773*4882a593Smuzhiyun FSE_encodeSymbol(&bitC, &CState2, *--ip);
774*4882a593Smuzhiyun FSE_encodeSymbol(&bitC, &CState1, *--ip);
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun FSE_FLUSHBITS(&bitC);
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun FSE_flushCState(&bitC, &CState2);
781*4882a593Smuzhiyun FSE_flushCState(&bitC, &CState1);
782*4882a593Smuzhiyun return BIT_closeCStream(&bitC);
783*4882a593Smuzhiyun }
784*4882a593Smuzhiyun
FSE_compress_usingCTable(void * dst,size_t dstSize,const void * src,size_t srcSize,const FSE_CTable * ct)785*4882a593Smuzhiyun size_t FSE_compress_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const FSE_CTable *ct)
786*4882a593Smuzhiyun {
787*4882a593Smuzhiyun unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun if (fast)
790*4882a593Smuzhiyun return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
791*4882a593Smuzhiyun else
792*4882a593Smuzhiyun return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun
FSE_compressBound(size_t size)795*4882a593Smuzhiyun size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
796