1e0c1b49fSNick Terrell /* ******************************************************************
2e0c1b49fSNick Terrell * FSE : Finite State Entropy codec
3e0c1b49fSNick Terrell * Public Prototypes declaration
4e0c1b49fSNick Terrell * Copyright (c) Yann Collet, Facebook, Inc.
5e0c1b49fSNick Terrell *
6e0c1b49fSNick Terrell * You can contact the author at :
7e0c1b49fSNick Terrell * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
8e0c1b49fSNick Terrell *
9e0c1b49fSNick Terrell * This source code is licensed under both the BSD-style license (found in the
10e0c1b49fSNick Terrell * LICENSE file in the root directory of this source tree) and the GPLv2 (found
11e0c1b49fSNick Terrell * in the COPYING file in the root directory of this source tree).
12e0c1b49fSNick Terrell * You may select, at your option, one of the above-listed licenses.
13e0c1b49fSNick Terrell ****************************************************************** */
14e0c1b49fSNick Terrell
15e0c1b49fSNick Terrell
16e0c1b49fSNick Terrell #ifndef FSE_H
17e0c1b49fSNick Terrell #define FSE_H
18e0c1b49fSNick Terrell
19e0c1b49fSNick Terrell
20e0c1b49fSNick Terrell /*-*****************************************
21e0c1b49fSNick Terrell * Dependencies
22e0c1b49fSNick Terrell ******************************************/
23e0c1b49fSNick Terrell #include "zstd_deps.h" /* size_t, ptrdiff_t */
24e0c1b49fSNick Terrell
25e0c1b49fSNick Terrell
26e0c1b49fSNick Terrell /*-*****************************************
27e0c1b49fSNick Terrell * FSE_PUBLIC_API : control library symbols visibility
28e0c1b49fSNick Terrell ******************************************/
29e0c1b49fSNick Terrell #if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
30e0c1b49fSNick Terrell # define FSE_PUBLIC_API __attribute__ ((visibility ("default")))
31e0c1b49fSNick Terrell #elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
32e0c1b49fSNick Terrell # define FSE_PUBLIC_API __declspec(dllexport)
33e0c1b49fSNick Terrell #elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
34e0c1b49fSNick Terrell # define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
35e0c1b49fSNick Terrell #else
36e0c1b49fSNick Terrell # define FSE_PUBLIC_API
37e0c1b49fSNick Terrell #endif
38e0c1b49fSNick Terrell
39e0c1b49fSNick Terrell /*------ Version ------*/
40e0c1b49fSNick Terrell #define FSE_VERSION_MAJOR 0
41e0c1b49fSNick Terrell #define FSE_VERSION_MINOR 9
42e0c1b49fSNick Terrell #define FSE_VERSION_RELEASE 0
43e0c1b49fSNick Terrell
44e0c1b49fSNick Terrell #define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
45e0c1b49fSNick Terrell #define FSE_QUOTE(str) #str
46e0c1b49fSNick Terrell #define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
47e0c1b49fSNick Terrell #define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
48e0c1b49fSNick Terrell
49e0c1b49fSNick Terrell #define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
50e0c1b49fSNick Terrell FSE_PUBLIC_API unsigned FSE_versionNumber(void); /*< library version number; to be used when checking dll version */
51e0c1b49fSNick Terrell
52e0c1b49fSNick Terrell
53e0c1b49fSNick Terrell /*-****************************************
54e0c1b49fSNick Terrell * FSE simple functions
55e0c1b49fSNick Terrell ******************************************/
56e0c1b49fSNick Terrell /*! FSE_compress() :
57e0c1b49fSNick Terrell Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
58e0c1b49fSNick Terrell 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
59e0c1b49fSNick Terrell @return : size of compressed data (<= dstCapacity).
60e0c1b49fSNick Terrell Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
61e0c1b49fSNick Terrell if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
62e0c1b49fSNick Terrell if FSE_isError(return), compression failed (more details using FSE_getErrorName())
63e0c1b49fSNick Terrell */
64e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity,
65e0c1b49fSNick Terrell const void* src, size_t srcSize);
66e0c1b49fSNick Terrell
67e0c1b49fSNick Terrell /*! FSE_decompress():
68e0c1b49fSNick Terrell Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
69e0c1b49fSNick Terrell into already allocated destination buffer 'dst', of size 'dstCapacity'.
70e0c1b49fSNick Terrell @return : size of regenerated data (<= maxDstSize),
71e0c1b49fSNick Terrell or an error code, which can be tested using FSE_isError() .
72e0c1b49fSNick Terrell
73e0c1b49fSNick Terrell ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!
74e0c1b49fSNick Terrell Why ? : making this distinction requires a header.
75e0c1b49fSNick Terrell Header management is intentionally delegated to the user layer, which can better manage special cases.
76e0c1b49fSNick Terrell */
77e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity,
78e0c1b49fSNick Terrell const void* cSrc, size_t cSrcSize);
79e0c1b49fSNick Terrell
80e0c1b49fSNick Terrell
81e0c1b49fSNick Terrell /*-*****************************************
82e0c1b49fSNick Terrell * Tool functions
83e0c1b49fSNick Terrell ******************************************/
84e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
85e0c1b49fSNick Terrell
86e0c1b49fSNick Terrell /* Error Management */
87e0c1b49fSNick Terrell FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
88e0c1b49fSNick Terrell FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
89e0c1b49fSNick Terrell
90e0c1b49fSNick Terrell
91e0c1b49fSNick Terrell /*-*****************************************
92e0c1b49fSNick Terrell * FSE advanced functions
93e0c1b49fSNick Terrell ******************************************/
94e0c1b49fSNick Terrell /*! FSE_compress2() :
95e0c1b49fSNick Terrell Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
96e0c1b49fSNick Terrell Both parameters can be defined as '0' to mean : use default value
97e0c1b49fSNick Terrell @return : size of compressed data
98e0c1b49fSNick Terrell Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
99e0c1b49fSNick Terrell if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
100e0c1b49fSNick Terrell if FSE_isError(return), it's an error code.
101e0c1b49fSNick Terrell */
102e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
103e0c1b49fSNick Terrell
104e0c1b49fSNick Terrell
105e0c1b49fSNick Terrell /*-*****************************************
106e0c1b49fSNick Terrell * FSE detailed API
107e0c1b49fSNick Terrell ******************************************/
108e0c1b49fSNick Terrell /*!
109e0c1b49fSNick Terrell FSE_compress() does the following:
110e0c1b49fSNick Terrell 1. count symbol occurrence from source[] into table count[] (see hist.h)
111e0c1b49fSNick Terrell 2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
112e0c1b49fSNick Terrell 3. save normalized counters to memory buffer using writeNCount()
113e0c1b49fSNick Terrell 4. build encoding table 'CTable' from normalized counters
114e0c1b49fSNick Terrell 5. encode the data stream using encoding table 'CTable'
115e0c1b49fSNick Terrell
116e0c1b49fSNick Terrell FSE_decompress() does the following:
117e0c1b49fSNick Terrell 1. read normalized counters with readNCount()
118e0c1b49fSNick Terrell 2. build decoding table 'DTable' from normalized counters
119e0c1b49fSNick Terrell 3. decode the data stream using decoding table 'DTable'
120e0c1b49fSNick Terrell
121e0c1b49fSNick Terrell The following API allows targeting specific sub-functions for advanced tasks.
122e0c1b49fSNick Terrell For example, it's possible to compress several blocks using the same 'CTable',
123e0c1b49fSNick Terrell or to save and provide normalized distribution using external method.
124e0c1b49fSNick Terrell */
125e0c1b49fSNick Terrell
126e0c1b49fSNick Terrell /* *** COMPRESSION *** */
127e0c1b49fSNick Terrell
128e0c1b49fSNick Terrell /*! FSE_optimalTableLog():
129e0c1b49fSNick Terrell dynamically downsize 'tableLog' when conditions are met.
130e0c1b49fSNick Terrell It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
131e0c1b49fSNick Terrell @return : recommended tableLog (necessarily <= 'maxTableLog') */
132e0c1b49fSNick Terrell FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
133e0c1b49fSNick Terrell
134e0c1b49fSNick Terrell /*! FSE_normalizeCount():
135e0c1b49fSNick Terrell normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
136e0c1b49fSNick Terrell 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
137e0c1b49fSNick Terrell useLowProbCount is a boolean parameter which trades off compressed size for
138e0c1b49fSNick Terrell faster header decoding. When it is set to 1, the compressed data will be slightly
139e0c1b49fSNick Terrell smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be
140e0c1b49fSNick Terrell faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0
141e0c1b49fSNick Terrell is a good default, since header deserialization makes a big speed difference.
142e0c1b49fSNick Terrell Otherwise, useLowProbCount=1 is a good default, since the speed difference is small.
143e0c1b49fSNick Terrell @return : tableLog,
144e0c1b49fSNick Terrell or an errorCode, which can be tested using FSE_isError() */
145e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
146e0c1b49fSNick Terrell const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount);
147e0c1b49fSNick Terrell
148e0c1b49fSNick Terrell /*! FSE_NCountWriteBound():
149e0c1b49fSNick Terrell Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
150e0c1b49fSNick Terrell Typically useful for allocation purpose. */
151e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
152e0c1b49fSNick Terrell
153e0c1b49fSNick Terrell /*! FSE_writeNCount():
154e0c1b49fSNick Terrell Compactly save 'normalizedCounter' into 'buffer'.
155e0c1b49fSNick Terrell @return : size of the compressed table,
156e0c1b49fSNick Terrell or an errorCode, which can be tested using FSE_isError(). */
157e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
158e0c1b49fSNick Terrell const short* normalizedCounter,
159e0c1b49fSNick Terrell unsigned maxSymbolValue, unsigned tableLog);
160e0c1b49fSNick Terrell
161e0c1b49fSNick Terrell /*! Constructor and Destructor of FSE_CTable.
162e0c1b49fSNick Terrell Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
163e0c1b49fSNick Terrell typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
164e0c1b49fSNick Terrell FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
165e0c1b49fSNick Terrell FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct);
166e0c1b49fSNick Terrell
167e0c1b49fSNick Terrell /*! FSE_buildCTable():
168e0c1b49fSNick Terrell Builds `ct`, which must be already allocated, using FSE_createCTable().
169e0c1b49fSNick Terrell @return : 0, or an errorCode, which can be tested using FSE_isError() */
170e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
171e0c1b49fSNick Terrell
172e0c1b49fSNick Terrell /*! FSE_compress_usingCTable():
173e0c1b49fSNick Terrell Compress `src` using `ct` into `dst` which must be already allocated.
174e0c1b49fSNick Terrell @return : size of compressed data (<= `dstCapacity`),
175e0c1b49fSNick Terrell or 0 if compressed data could not fit into `dst`,
176e0c1b49fSNick Terrell or an errorCode, which can be tested using FSE_isError() */
177e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
178e0c1b49fSNick Terrell
179e0c1b49fSNick Terrell /*!
180e0c1b49fSNick Terrell Tutorial :
181e0c1b49fSNick Terrell ----------
182e0c1b49fSNick Terrell The first step is to count all symbols. FSE_count() does this job very fast.
183e0c1b49fSNick Terrell Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
184e0c1b49fSNick Terrell 'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
185e0c1b49fSNick Terrell maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
186e0c1b49fSNick Terrell FSE_count() will return the number of occurrence of the most frequent symbol.
187e0c1b49fSNick Terrell This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
188e0c1b49fSNick Terrell If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
189e0c1b49fSNick Terrell
190e0c1b49fSNick Terrell The next step is to normalize the frequencies.
191e0c1b49fSNick Terrell FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
192e0c1b49fSNick Terrell It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
193e0c1b49fSNick Terrell You can use 'tableLog'==0 to mean "use default tableLog value".
194e0c1b49fSNick Terrell If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
195e0c1b49fSNick Terrell which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
196e0c1b49fSNick Terrell
197e0c1b49fSNick Terrell The result of FSE_normalizeCount() will be saved into a table,
198e0c1b49fSNick Terrell called 'normalizedCounter', which is a table of signed short.
199e0c1b49fSNick Terrell 'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
200e0c1b49fSNick Terrell The return value is tableLog if everything proceeded as expected.
201e0c1b49fSNick Terrell It is 0 if there is a single symbol within distribution.
202e0c1b49fSNick Terrell If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
203e0c1b49fSNick Terrell
204e0c1b49fSNick Terrell 'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
205e0c1b49fSNick Terrell 'buffer' must be already allocated.
206e0c1b49fSNick Terrell For guaranteed success, buffer size must be at least FSE_headerBound().
207e0c1b49fSNick Terrell The result of the function is the number of bytes written into 'buffer'.
208e0c1b49fSNick Terrell If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
209e0c1b49fSNick Terrell
210e0c1b49fSNick Terrell 'normalizedCounter' can then be used to create the compression table 'CTable'.
211e0c1b49fSNick Terrell The space required by 'CTable' must be already allocated, using FSE_createCTable().
212e0c1b49fSNick Terrell You can then use FSE_buildCTable() to fill 'CTable'.
213e0c1b49fSNick Terrell If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
214e0c1b49fSNick Terrell
215e0c1b49fSNick Terrell 'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
216e0c1b49fSNick Terrell Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
217e0c1b49fSNick Terrell The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
218e0c1b49fSNick Terrell If it returns '0', compressed data could not fit into 'dst'.
219e0c1b49fSNick Terrell If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
220e0c1b49fSNick Terrell */
221e0c1b49fSNick Terrell
222e0c1b49fSNick Terrell
223e0c1b49fSNick Terrell /* *** DECOMPRESSION *** */
224e0c1b49fSNick Terrell
225e0c1b49fSNick Terrell /*! FSE_readNCount():
226e0c1b49fSNick Terrell Read compactly saved 'normalizedCounter' from 'rBuffer'.
227e0c1b49fSNick Terrell @return : size read from 'rBuffer',
228e0c1b49fSNick Terrell or an errorCode, which can be tested using FSE_isError().
229e0c1b49fSNick Terrell maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
230e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
231e0c1b49fSNick Terrell unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
232e0c1b49fSNick Terrell const void* rBuffer, size_t rBuffSize);
233e0c1b49fSNick Terrell
234e0c1b49fSNick Terrell /*! FSE_readNCount_bmi2():
235e0c1b49fSNick Terrell * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise.
236e0c1b49fSNick Terrell */
237e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter,
238e0c1b49fSNick Terrell unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
239e0c1b49fSNick Terrell const void* rBuffer, size_t rBuffSize, int bmi2);
240e0c1b49fSNick Terrell
241e0c1b49fSNick Terrell /*! Constructor and Destructor of FSE_DTable.
242e0c1b49fSNick Terrell Note that its size depends on 'tableLog' */
243e0c1b49fSNick Terrell typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
244e0c1b49fSNick Terrell FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog);
245e0c1b49fSNick Terrell FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt);
246e0c1b49fSNick Terrell
247e0c1b49fSNick Terrell /*! FSE_buildDTable():
248e0c1b49fSNick Terrell Builds 'dt', which must be already allocated, using FSE_createDTable().
249e0c1b49fSNick Terrell return : 0, or an errorCode, which can be tested using FSE_isError() */
250e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
251e0c1b49fSNick Terrell
252e0c1b49fSNick Terrell /*! FSE_decompress_usingDTable():
253e0c1b49fSNick Terrell Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
254e0c1b49fSNick Terrell into `dst` which must be already allocated.
255e0c1b49fSNick Terrell @return : size of regenerated data (necessarily <= `dstCapacity`),
256e0c1b49fSNick Terrell or an errorCode, which can be tested using FSE_isError() */
257e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
258e0c1b49fSNick Terrell
259e0c1b49fSNick Terrell /*!
260e0c1b49fSNick Terrell Tutorial :
261e0c1b49fSNick Terrell ----------
262e0c1b49fSNick Terrell (Note : these functions only decompress FSE-compressed blocks.
263e0c1b49fSNick Terrell If block is uncompressed, use memcpy() instead
264e0c1b49fSNick Terrell If block is a single repeated byte, use memset() instead )
265e0c1b49fSNick Terrell
266e0c1b49fSNick Terrell The first step is to obtain the normalized frequencies of symbols.
267e0c1b49fSNick Terrell This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
268e0c1b49fSNick Terrell 'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
269e0c1b49fSNick Terrell In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
270e0c1b49fSNick Terrell or size the table to handle worst case situations (typically 256).
271e0c1b49fSNick Terrell FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
272e0c1b49fSNick Terrell The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
273e0c1b49fSNick Terrell Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
274e0c1b49fSNick Terrell If there is an error, the function will return an error code, which can be tested using FSE_isError().
275e0c1b49fSNick Terrell
276e0c1b49fSNick Terrell The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
277e0c1b49fSNick Terrell This is performed by the function FSE_buildDTable().
278e0c1b49fSNick Terrell The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
279e0c1b49fSNick Terrell If there is an error, the function will return an error code, which can be tested using FSE_isError().
280e0c1b49fSNick Terrell
281e0c1b49fSNick Terrell `FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
282e0c1b49fSNick Terrell `cSrcSize` must be strictly correct, otherwise decompression will fail.
283e0c1b49fSNick Terrell FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
284e0c1b49fSNick Terrell If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
285e0c1b49fSNick Terrell */
286e0c1b49fSNick Terrell
287e0c1b49fSNick Terrell #endif /* FSE_H */
288e0c1b49fSNick Terrell
289e0c1b49fSNick Terrell #if !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
290e0c1b49fSNick Terrell #define FSE_H_FSE_STATIC_LINKING_ONLY
291e0c1b49fSNick Terrell
292e0c1b49fSNick Terrell /* *** Dependency *** */
293e0c1b49fSNick Terrell #include "bitstream.h"
294e0c1b49fSNick Terrell
295e0c1b49fSNick Terrell
296e0c1b49fSNick Terrell /* *****************************************
297e0c1b49fSNick Terrell * Static allocation
298e0c1b49fSNick Terrell *******************************************/
299e0c1b49fSNick Terrell /* FSE buffer bounds */
300e0c1b49fSNick Terrell #define FSE_NCOUNTBOUND 512
301e0c1b49fSNick Terrell #define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */)
302e0c1b49fSNick Terrell #define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
303e0c1b49fSNick Terrell
304e0c1b49fSNick Terrell /* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
305e0c1b49fSNick Terrell #define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2))
306e0c1b49fSNick Terrell #define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog)))
307e0c1b49fSNick Terrell
308e0c1b49fSNick Terrell /* or use the size to malloc() space directly. Pay attention to alignment restrictions though */
309e0c1b49fSNick Terrell #define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable))
310e0c1b49fSNick Terrell #define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable))
311e0c1b49fSNick Terrell
312e0c1b49fSNick Terrell
313e0c1b49fSNick Terrell /* *****************************************
314e0c1b49fSNick Terrell * FSE advanced API
315e0c1b49fSNick Terrell ***************************************** */
316e0c1b49fSNick Terrell
317e0c1b49fSNick Terrell unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
318e0c1b49fSNick Terrell /*< same as FSE_optimalTableLog(), which used `minus==2` */
319e0c1b49fSNick Terrell
320e0c1b49fSNick Terrell /* FSE_compress_wksp() :
321e0c1b49fSNick Terrell * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
322e0c1b49fSNick Terrell * FSE_COMPRESS_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
323e0c1b49fSNick Terrell */
324e0c1b49fSNick Terrell #define FSE_COMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
325e0c1b49fSNick Terrell size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
326e0c1b49fSNick Terrell
327e0c1b49fSNick Terrell size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
328e0c1b49fSNick Terrell /*< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
329e0c1b49fSNick Terrell
330e0c1b49fSNick Terrell size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
331e0c1b49fSNick Terrell /*< build a fake FSE_CTable, designed to compress always the same symbolValue */
332e0c1b49fSNick Terrell
333e0c1b49fSNick Terrell /* FSE_buildCTable_wksp() :
334e0c1b49fSNick Terrell * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
335e0c1b49fSNick Terrell * `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`.
336*2aa14b1aSNick Terrell * See FSE_buildCTable_wksp() for breakdown of workspace usage.
337e0c1b49fSNick Terrell */
338*2aa14b1aSNick Terrell #define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */)
339e0c1b49fSNick Terrell #define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog))
340e0c1b49fSNick Terrell size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
341e0c1b49fSNick Terrell
342e0c1b49fSNick Terrell #define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8)
343e0c1b49fSNick Terrell #define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned))
344e0c1b49fSNick Terrell FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
345e0c1b49fSNick Terrell /*< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */
346e0c1b49fSNick Terrell
347e0c1b49fSNick Terrell size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
348e0c1b49fSNick Terrell /*< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
349e0c1b49fSNick Terrell
350e0c1b49fSNick Terrell size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
351e0c1b49fSNick Terrell /*< build a fake FSE_DTable, designed to always generate the same symbolValue */
352e0c1b49fSNick Terrell
353e0c1b49fSNick Terrell #define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1)
354e0c1b49fSNick Terrell #define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned))
355e0c1b49fSNick Terrell size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize);
356e0c1b49fSNick Terrell /*< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */
357e0c1b49fSNick Terrell
358e0c1b49fSNick Terrell size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2);
359e0c1b49fSNick Terrell /*< Same as FSE_decompress_wksp() but with dynamic BMI2 support. Pass 1 if your CPU supports BMI2 or 0 if it doesn't. */
360e0c1b49fSNick Terrell
361e0c1b49fSNick Terrell typedef enum {
362e0c1b49fSNick Terrell FSE_repeat_none, /*< Cannot use the previous table */
363e0c1b49fSNick Terrell FSE_repeat_check, /*< Can use the previous table but it must be checked */
364e0c1b49fSNick Terrell FSE_repeat_valid /*< Can use the previous table and it is assumed to be valid */
365e0c1b49fSNick Terrell } FSE_repeat;
366e0c1b49fSNick Terrell
367e0c1b49fSNick Terrell /* *****************************************
368e0c1b49fSNick Terrell * FSE symbol compression API
369e0c1b49fSNick Terrell *******************************************/
370e0c1b49fSNick Terrell /*!
371e0c1b49fSNick Terrell This API consists of small unitary functions, which highly benefit from being inlined.
372e0c1b49fSNick Terrell Hence their body are included in next section.
373e0c1b49fSNick Terrell */
374e0c1b49fSNick Terrell typedef struct {
375e0c1b49fSNick Terrell ptrdiff_t value;
376e0c1b49fSNick Terrell const void* stateTable;
377e0c1b49fSNick Terrell const void* symbolTT;
378e0c1b49fSNick Terrell unsigned stateLog;
379e0c1b49fSNick Terrell } FSE_CState_t;
380e0c1b49fSNick Terrell
381e0c1b49fSNick Terrell static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
382e0c1b49fSNick Terrell
383e0c1b49fSNick Terrell static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
384e0c1b49fSNick Terrell
385e0c1b49fSNick Terrell static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
386e0c1b49fSNick Terrell
387e0c1b49fSNick Terrell /*<
388e0c1b49fSNick Terrell These functions are inner components of FSE_compress_usingCTable().
389e0c1b49fSNick Terrell They allow the creation of custom streams, mixing multiple tables and bit sources.
390e0c1b49fSNick Terrell
391e0c1b49fSNick Terrell A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
392e0c1b49fSNick Terrell So the first symbol you will encode is the last you will decode, like a LIFO stack.
393e0c1b49fSNick Terrell
394e0c1b49fSNick Terrell You will need a few variables to track your CStream. They are :
395e0c1b49fSNick Terrell
396e0c1b49fSNick Terrell FSE_CTable ct; // Provided by FSE_buildCTable()
397e0c1b49fSNick Terrell BIT_CStream_t bitStream; // bitStream tracking structure
398e0c1b49fSNick Terrell FSE_CState_t state; // State tracking structure (can have several)
399e0c1b49fSNick Terrell
400e0c1b49fSNick Terrell
401e0c1b49fSNick Terrell The first thing to do is to init bitStream and state.
402e0c1b49fSNick Terrell size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
403e0c1b49fSNick Terrell FSE_initCState(&state, ct);
404e0c1b49fSNick Terrell
405e0c1b49fSNick Terrell Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
406e0c1b49fSNick Terrell You can then encode your input data, byte after byte.
407e0c1b49fSNick Terrell FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
408e0c1b49fSNick Terrell Remember decoding will be done in reverse direction.
409e0c1b49fSNick Terrell FSE_encodeByte(&bitStream, &state, symbol);
410e0c1b49fSNick Terrell
411e0c1b49fSNick Terrell At any time, you can also add any bit sequence.
412e0c1b49fSNick Terrell Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
413e0c1b49fSNick Terrell BIT_addBits(&bitStream, bitField, nbBits);
414e0c1b49fSNick Terrell
415e0c1b49fSNick Terrell The above methods don't commit data to memory, they just store it into local register, for speed.
416e0c1b49fSNick Terrell Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
417e0c1b49fSNick Terrell Writing data to memory is a manual operation, performed by the flushBits function.
418e0c1b49fSNick Terrell BIT_flushBits(&bitStream);
419e0c1b49fSNick Terrell
420e0c1b49fSNick Terrell Your last FSE encoding operation shall be to flush your last state value(s).
421e0c1b49fSNick Terrell FSE_flushState(&bitStream, &state);
422e0c1b49fSNick Terrell
423e0c1b49fSNick Terrell Finally, you must close the bitStream.
424e0c1b49fSNick Terrell The function returns the size of CStream in bytes.
425e0c1b49fSNick Terrell If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
426e0c1b49fSNick Terrell If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
427e0c1b49fSNick Terrell size_t size = BIT_closeCStream(&bitStream);
428e0c1b49fSNick Terrell */
429e0c1b49fSNick Terrell
430e0c1b49fSNick Terrell
431e0c1b49fSNick Terrell /* *****************************************
432e0c1b49fSNick Terrell * FSE symbol decompression API
433e0c1b49fSNick Terrell *******************************************/
434e0c1b49fSNick Terrell typedef struct {
435e0c1b49fSNick Terrell size_t state;
436e0c1b49fSNick Terrell const void* table; /* precise table may vary, depending on U16 */
437e0c1b49fSNick Terrell } FSE_DState_t;
438e0c1b49fSNick Terrell
439e0c1b49fSNick Terrell
440e0c1b49fSNick Terrell static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
441e0c1b49fSNick Terrell
442e0c1b49fSNick Terrell static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
443e0c1b49fSNick Terrell
444e0c1b49fSNick Terrell static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
445e0c1b49fSNick Terrell
446e0c1b49fSNick Terrell /*<
447e0c1b49fSNick Terrell Let's now decompose FSE_decompress_usingDTable() into its unitary components.
448e0c1b49fSNick Terrell You will decode FSE-encoded symbols from the bitStream,
449e0c1b49fSNick Terrell and also any other bitFields you put in, **in reverse order**.
450e0c1b49fSNick Terrell
451e0c1b49fSNick Terrell You will need a few variables to track your bitStream. They are :
452e0c1b49fSNick Terrell
453e0c1b49fSNick Terrell BIT_DStream_t DStream; // Stream context
454e0c1b49fSNick Terrell FSE_DState_t DState; // State context. Multiple ones are possible
455e0c1b49fSNick Terrell FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
456e0c1b49fSNick Terrell
457e0c1b49fSNick Terrell The first thing to do is to init the bitStream.
458e0c1b49fSNick Terrell errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
459e0c1b49fSNick Terrell
460e0c1b49fSNick Terrell You should then retrieve your initial state(s)
461e0c1b49fSNick Terrell (in reverse flushing order if you have several ones) :
462e0c1b49fSNick Terrell errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
463e0c1b49fSNick Terrell
464e0c1b49fSNick Terrell You can then decode your data, symbol after symbol.
465e0c1b49fSNick Terrell For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
466e0c1b49fSNick Terrell Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
467e0c1b49fSNick Terrell unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
468e0c1b49fSNick Terrell
469e0c1b49fSNick Terrell You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
470e0c1b49fSNick Terrell Note : maximum allowed nbBits is 25, for 32-bits compatibility
471e0c1b49fSNick Terrell size_t bitField = BIT_readBits(&DStream, nbBits);
472e0c1b49fSNick Terrell
473e0c1b49fSNick Terrell All above operations only read from local register (which size depends on size_t).
474e0c1b49fSNick Terrell Refueling the register from memory is manually performed by the reload method.
475e0c1b49fSNick Terrell endSignal = FSE_reloadDStream(&DStream);
476e0c1b49fSNick Terrell
477e0c1b49fSNick Terrell BIT_reloadDStream() result tells if there is still some more data to read from DStream.
478e0c1b49fSNick Terrell BIT_DStream_unfinished : there is still some data left into the DStream.
479e0c1b49fSNick Terrell BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
480e0c1b49fSNick Terrell BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
481e0c1b49fSNick Terrell BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
482e0c1b49fSNick Terrell
483e0c1b49fSNick Terrell When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
484e0c1b49fSNick Terrell to properly detect the exact end of stream.
485e0c1b49fSNick Terrell After each decoded symbol, check if DStream is fully consumed using this simple test :
486e0c1b49fSNick Terrell BIT_reloadDStream(&DStream) >= BIT_DStream_completed
487e0c1b49fSNick Terrell
488e0c1b49fSNick Terrell When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
489e0c1b49fSNick Terrell Checking if DStream has reached its end is performed by :
490e0c1b49fSNick Terrell BIT_endOfDStream(&DStream);
491e0c1b49fSNick Terrell Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
492e0c1b49fSNick Terrell FSE_endOfDState(&DState);
493e0c1b49fSNick Terrell */
494e0c1b49fSNick Terrell
495e0c1b49fSNick Terrell
496e0c1b49fSNick Terrell /* *****************************************
497e0c1b49fSNick Terrell * FSE unsafe API
498e0c1b49fSNick Terrell *******************************************/
499e0c1b49fSNick Terrell static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
500e0c1b49fSNick Terrell /* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
501e0c1b49fSNick Terrell
502e0c1b49fSNick Terrell
503e0c1b49fSNick Terrell /* *****************************************
504e0c1b49fSNick Terrell * Implementation of inlined functions
505e0c1b49fSNick Terrell *******************************************/
506e0c1b49fSNick Terrell typedef struct {
507e0c1b49fSNick Terrell int deltaFindState;
508e0c1b49fSNick Terrell U32 deltaNbBits;
509e0c1b49fSNick Terrell } FSE_symbolCompressionTransform; /* total 8 bytes */
510e0c1b49fSNick Terrell
FSE_initCState(FSE_CState_t * statePtr,const FSE_CTable * ct)511e0c1b49fSNick Terrell MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
512e0c1b49fSNick Terrell {
513e0c1b49fSNick Terrell const void* ptr = ct;
514e0c1b49fSNick Terrell const U16* u16ptr = (const U16*) ptr;
515e0c1b49fSNick Terrell const U32 tableLog = MEM_read16(ptr);
516e0c1b49fSNick Terrell statePtr->value = (ptrdiff_t)1<<tableLog;
517e0c1b49fSNick Terrell statePtr->stateTable = u16ptr+2;
518e0c1b49fSNick Terrell statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1);
519e0c1b49fSNick Terrell statePtr->stateLog = tableLog;
520e0c1b49fSNick Terrell }
521e0c1b49fSNick Terrell
522e0c1b49fSNick Terrell
523e0c1b49fSNick Terrell /*! FSE_initCState2() :
524e0c1b49fSNick Terrell * Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
525e0c1b49fSNick Terrell * uses the smallest state value possible, saving the cost of this symbol */
FSE_initCState2(FSE_CState_t * statePtr,const FSE_CTable * ct,U32 symbol)526e0c1b49fSNick Terrell MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
527e0c1b49fSNick Terrell {
528e0c1b49fSNick Terrell FSE_initCState(statePtr, ct);
529e0c1b49fSNick Terrell { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
530e0c1b49fSNick Terrell const U16* stateTable = (const U16*)(statePtr->stateTable);
531e0c1b49fSNick Terrell U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
532e0c1b49fSNick Terrell statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
533e0c1b49fSNick Terrell statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
534e0c1b49fSNick Terrell }
535e0c1b49fSNick Terrell }
536e0c1b49fSNick Terrell
FSE_encodeSymbol(BIT_CStream_t * bitC,FSE_CState_t * statePtr,unsigned symbol)537e0c1b49fSNick Terrell MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol)
538e0c1b49fSNick Terrell {
539e0c1b49fSNick Terrell FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
540e0c1b49fSNick Terrell const U16* const stateTable = (const U16*)(statePtr->stateTable);
541e0c1b49fSNick Terrell U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
542e0c1b49fSNick Terrell BIT_addBits(bitC, statePtr->value, nbBitsOut);
543e0c1b49fSNick Terrell statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
544e0c1b49fSNick Terrell }
545e0c1b49fSNick Terrell
FSE_flushCState(BIT_CStream_t * bitC,const FSE_CState_t * statePtr)546e0c1b49fSNick Terrell MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
547e0c1b49fSNick Terrell {
548e0c1b49fSNick Terrell BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
549e0c1b49fSNick Terrell BIT_flushBits(bitC);
550e0c1b49fSNick Terrell }
551e0c1b49fSNick Terrell
552e0c1b49fSNick Terrell
553e0c1b49fSNick Terrell /* FSE_getMaxNbBits() :
554e0c1b49fSNick Terrell * Approximate maximum cost of a symbol, in bits.
555e0c1b49fSNick Terrell * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
556e0c1b49fSNick Terrell * note 1 : assume symbolValue is valid (<= maxSymbolValue)
557e0c1b49fSNick Terrell * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
FSE_getMaxNbBits(const void * symbolTTPtr,U32 symbolValue)558e0c1b49fSNick Terrell MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
559e0c1b49fSNick Terrell {
560e0c1b49fSNick Terrell const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
561e0c1b49fSNick Terrell return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16;
562e0c1b49fSNick Terrell }
563e0c1b49fSNick Terrell
564e0c1b49fSNick Terrell /* FSE_bitCost() :
565e0c1b49fSNick Terrell * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
566e0c1b49fSNick Terrell * note 1 : assume symbolValue is valid (<= maxSymbolValue)
567e0c1b49fSNick Terrell * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
FSE_bitCost(const void * symbolTTPtr,U32 tableLog,U32 symbolValue,U32 accuracyLog)568e0c1b49fSNick Terrell MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog)
569e0c1b49fSNick Terrell {
570e0c1b49fSNick Terrell const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
571e0c1b49fSNick Terrell U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16;
572e0c1b49fSNick Terrell U32 const threshold = (minNbBits+1) << 16;
573e0c1b49fSNick Terrell assert(tableLog < 16);
574e0c1b49fSNick Terrell assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */
575e0c1b49fSNick Terrell { U32 const tableSize = 1 << tableLog;
576e0c1b49fSNick Terrell U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize);
577e0c1b49fSNick Terrell U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */
578e0c1b49fSNick Terrell U32 const bitMultiplier = 1 << accuracyLog;
579e0c1b49fSNick Terrell assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold);
580e0c1b49fSNick Terrell assert(normalizedDeltaFromThreshold <= bitMultiplier);
581e0c1b49fSNick Terrell return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold;
582e0c1b49fSNick Terrell }
583e0c1b49fSNick Terrell }
584e0c1b49fSNick Terrell
585e0c1b49fSNick Terrell
586e0c1b49fSNick Terrell /* ====== Decompression ====== */
587e0c1b49fSNick Terrell
588e0c1b49fSNick Terrell typedef struct {
589e0c1b49fSNick Terrell U16 tableLog;
590e0c1b49fSNick Terrell U16 fastMode;
591e0c1b49fSNick Terrell } FSE_DTableHeader; /* sizeof U32 */
592e0c1b49fSNick Terrell
593e0c1b49fSNick Terrell typedef struct
594e0c1b49fSNick Terrell {
595e0c1b49fSNick Terrell unsigned short newState;
596e0c1b49fSNick Terrell unsigned char symbol;
597e0c1b49fSNick Terrell unsigned char nbBits;
598e0c1b49fSNick Terrell } FSE_decode_t; /* size == U32 */
599e0c1b49fSNick Terrell
FSE_initDState(FSE_DState_t * DStatePtr,BIT_DStream_t * bitD,const FSE_DTable * dt)600e0c1b49fSNick Terrell MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
601e0c1b49fSNick Terrell {
602e0c1b49fSNick Terrell const void* ptr = dt;
603e0c1b49fSNick Terrell const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
604e0c1b49fSNick Terrell DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
605e0c1b49fSNick Terrell BIT_reloadDStream(bitD);
606e0c1b49fSNick Terrell DStatePtr->table = dt + 1;
607e0c1b49fSNick Terrell }
608e0c1b49fSNick Terrell
FSE_peekSymbol(const FSE_DState_t * DStatePtr)609e0c1b49fSNick Terrell MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
610e0c1b49fSNick Terrell {
611e0c1b49fSNick Terrell FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
612e0c1b49fSNick Terrell return DInfo.symbol;
613e0c1b49fSNick Terrell }
614e0c1b49fSNick Terrell
FSE_updateState(FSE_DState_t * DStatePtr,BIT_DStream_t * bitD)615e0c1b49fSNick Terrell MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
616e0c1b49fSNick Terrell {
617e0c1b49fSNick Terrell FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
618e0c1b49fSNick Terrell U32 const nbBits = DInfo.nbBits;
619e0c1b49fSNick Terrell size_t const lowBits = BIT_readBits(bitD, nbBits);
620e0c1b49fSNick Terrell DStatePtr->state = DInfo.newState + lowBits;
621e0c1b49fSNick Terrell }
622e0c1b49fSNick Terrell
FSE_decodeSymbol(FSE_DState_t * DStatePtr,BIT_DStream_t * bitD)623e0c1b49fSNick Terrell MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
624e0c1b49fSNick Terrell {
625e0c1b49fSNick Terrell FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
626e0c1b49fSNick Terrell U32 const nbBits = DInfo.nbBits;
627e0c1b49fSNick Terrell BYTE const symbol = DInfo.symbol;
628e0c1b49fSNick Terrell size_t const lowBits = BIT_readBits(bitD, nbBits);
629e0c1b49fSNick Terrell
630e0c1b49fSNick Terrell DStatePtr->state = DInfo.newState + lowBits;
631e0c1b49fSNick Terrell return symbol;
632e0c1b49fSNick Terrell }
633e0c1b49fSNick Terrell
634e0c1b49fSNick Terrell /*! FSE_decodeSymbolFast() :
635e0c1b49fSNick Terrell unsafe, only works if no symbol has a probability > 50% */
FSE_decodeSymbolFast(FSE_DState_t * DStatePtr,BIT_DStream_t * bitD)636e0c1b49fSNick Terrell MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
637e0c1b49fSNick Terrell {
638e0c1b49fSNick Terrell FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
639e0c1b49fSNick Terrell U32 const nbBits = DInfo.nbBits;
640e0c1b49fSNick Terrell BYTE const symbol = DInfo.symbol;
641e0c1b49fSNick Terrell size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
642e0c1b49fSNick Terrell
643e0c1b49fSNick Terrell DStatePtr->state = DInfo.newState + lowBits;
644e0c1b49fSNick Terrell return symbol;
645e0c1b49fSNick Terrell }
646e0c1b49fSNick Terrell
FSE_endOfDState(const FSE_DState_t * DStatePtr)647e0c1b49fSNick Terrell MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
648e0c1b49fSNick Terrell {
649e0c1b49fSNick Terrell return DStatePtr->state == 0;
650e0c1b49fSNick Terrell }
651e0c1b49fSNick Terrell
652e0c1b49fSNick Terrell
653e0c1b49fSNick Terrell
654e0c1b49fSNick Terrell #ifndef FSE_COMMONDEFS_ONLY
655e0c1b49fSNick Terrell
656e0c1b49fSNick Terrell /* **************************************************************
657e0c1b49fSNick Terrell * Tuning parameters
658e0c1b49fSNick Terrell ****************************************************************/
659e0c1b49fSNick Terrell /*!MEMORY_USAGE :
660e0c1b49fSNick Terrell * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
661e0c1b49fSNick Terrell * Increasing memory usage improves compression ratio
662e0c1b49fSNick Terrell * Reduced memory usage can improve speed, due to cache effect
663e0c1b49fSNick Terrell * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
664e0c1b49fSNick Terrell #ifndef FSE_MAX_MEMORY_USAGE
665e0c1b49fSNick Terrell # define FSE_MAX_MEMORY_USAGE 14
666e0c1b49fSNick Terrell #endif
667e0c1b49fSNick Terrell #ifndef FSE_DEFAULT_MEMORY_USAGE
668e0c1b49fSNick Terrell # define FSE_DEFAULT_MEMORY_USAGE 13
669e0c1b49fSNick Terrell #endif
670e0c1b49fSNick Terrell #if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE)
671e0c1b49fSNick Terrell # error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE"
672e0c1b49fSNick Terrell #endif
673e0c1b49fSNick Terrell
674e0c1b49fSNick Terrell /*!FSE_MAX_SYMBOL_VALUE :
675e0c1b49fSNick Terrell * Maximum symbol value authorized.
676e0c1b49fSNick Terrell * Required for proper stack allocation */
677e0c1b49fSNick Terrell #ifndef FSE_MAX_SYMBOL_VALUE
678e0c1b49fSNick Terrell # define FSE_MAX_SYMBOL_VALUE 255
679e0c1b49fSNick Terrell #endif
680e0c1b49fSNick Terrell
681e0c1b49fSNick Terrell /* **************************************************************
682e0c1b49fSNick Terrell * template functions type & suffix
683e0c1b49fSNick Terrell ****************************************************************/
684e0c1b49fSNick Terrell #define FSE_FUNCTION_TYPE BYTE
685e0c1b49fSNick Terrell #define FSE_FUNCTION_EXTENSION
686e0c1b49fSNick Terrell #define FSE_DECODE_TYPE FSE_decode_t
687e0c1b49fSNick Terrell
688e0c1b49fSNick Terrell
689e0c1b49fSNick Terrell #endif /* !FSE_COMMONDEFS_ONLY */
690e0c1b49fSNick Terrell
691e0c1b49fSNick Terrell
692e0c1b49fSNick Terrell /* ***************************************************************
693e0c1b49fSNick Terrell * Constants
694e0c1b49fSNick Terrell *****************************************************************/
695e0c1b49fSNick Terrell #define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
696e0c1b49fSNick Terrell #define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
697e0c1b49fSNick Terrell #define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
698e0c1b49fSNick Terrell #define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
699e0c1b49fSNick Terrell #define FSE_MIN_TABLELOG 5
700e0c1b49fSNick Terrell
701e0c1b49fSNick Terrell #define FSE_TABLELOG_ABSOLUTE_MAX 15
702e0c1b49fSNick Terrell #if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
703e0c1b49fSNick Terrell # error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
704e0c1b49fSNick Terrell #endif
705e0c1b49fSNick Terrell
706e0c1b49fSNick Terrell #define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3)
707e0c1b49fSNick Terrell
708e0c1b49fSNick Terrell
709e0c1b49fSNick Terrell #endif /* FSE_STATIC_LINKING_ONLY */
710e0c1b49fSNick Terrell
711e0c1b49fSNick Terrell
712