1*01826a49SYabin Cui /* ******************************************************************
2*01826a49SYabin Cui * Common functions of New Generation Entropy library
3*01826a49SYabin Cui * Copyright (c) Meta Platforms, Inc. and affiliates.
4*01826a49SYabin Cui *
5*01826a49SYabin Cui * You can contact the author at :
6*01826a49SYabin Cui * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
7*01826a49SYabin Cui * - Public forum : https://groups.google.com/forum/#!forum/lz4c
8*01826a49SYabin Cui *
9*01826a49SYabin Cui * This source code is licensed under both the BSD-style license (found in the
10*01826a49SYabin Cui * LICENSE file in the root directory of this source tree) and the GPLv2 (found
11*01826a49SYabin Cui * in the COPYING file in the root directory of this source tree).
12*01826a49SYabin Cui * You may select, at your option, one of the above-listed licenses.
13*01826a49SYabin Cui ****************************************************************** */
14*01826a49SYabin Cui
15*01826a49SYabin Cui /* *************************************
16*01826a49SYabin Cui * Dependencies
17*01826a49SYabin Cui ***************************************/
18*01826a49SYabin Cui #include "mem.h"
19*01826a49SYabin Cui #include "error_private.h" /* ERR_*, ERROR */
20*01826a49SYabin Cui #define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
21*01826a49SYabin Cui #include "fse.h"
22*01826a49SYabin Cui #include "huf.h"
23*01826a49SYabin Cui #include "bits.h" /* ZSDT_highbit32, ZSTD_countTrailingZeros32 */
24*01826a49SYabin Cui
25*01826a49SYabin Cui
26*01826a49SYabin Cui /*=== Version ===*/
FSE_versionNumber(void)27*01826a49SYabin Cui unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
28*01826a49SYabin Cui
29*01826a49SYabin Cui
30*01826a49SYabin Cui /*=== Error Management ===*/
FSE_isError(size_t code)31*01826a49SYabin Cui unsigned FSE_isError(size_t code) { return ERR_isError(code); }
FSE_getErrorName(size_t code)32*01826a49SYabin Cui const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
33*01826a49SYabin Cui
HUF_isError(size_t code)34*01826a49SYabin Cui unsigned HUF_isError(size_t code) { return ERR_isError(code); }
HUF_getErrorName(size_t code)35*01826a49SYabin Cui const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
36*01826a49SYabin Cui
37*01826a49SYabin Cui
38*01826a49SYabin Cui /*-**************************************************************
39*01826a49SYabin Cui * FSE NCount encoding-decoding
40*01826a49SYabin Cui ****************************************************************/
41*01826a49SYabin Cui FORCE_INLINE_TEMPLATE
FSE_readNCount_body(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)42*01826a49SYabin Cui size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
43*01826a49SYabin Cui const void* headerBuffer, size_t hbSize)
44*01826a49SYabin Cui {
45*01826a49SYabin Cui const BYTE* const istart = (const BYTE*) headerBuffer;
46*01826a49SYabin Cui const BYTE* const iend = istart + hbSize;
47*01826a49SYabin Cui const BYTE* ip = istart;
48*01826a49SYabin Cui int nbBits;
49*01826a49SYabin Cui int remaining;
50*01826a49SYabin Cui int threshold;
51*01826a49SYabin Cui U32 bitStream;
52*01826a49SYabin Cui int bitCount;
53*01826a49SYabin Cui unsigned charnum = 0;
54*01826a49SYabin Cui unsigned const maxSV1 = *maxSVPtr + 1;
55*01826a49SYabin Cui int previous0 = 0;
56*01826a49SYabin Cui
57*01826a49SYabin Cui if (hbSize < 8) {
58*01826a49SYabin Cui /* This function only works when hbSize >= 8 */
59*01826a49SYabin Cui char buffer[8] = {0};
60*01826a49SYabin Cui ZSTD_memcpy(buffer, headerBuffer, hbSize);
61*01826a49SYabin Cui { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
62*01826a49SYabin Cui buffer, sizeof(buffer));
63*01826a49SYabin Cui if (FSE_isError(countSize)) return countSize;
64*01826a49SYabin Cui if (countSize > hbSize) return ERROR(corruption_detected);
65*01826a49SYabin Cui return countSize;
66*01826a49SYabin Cui } }
67*01826a49SYabin Cui assert(hbSize >= 8);
68*01826a49SYabin Cui
69*01826a49SYabin Cui /* init */
70*01826a49SYabin Cui ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */
71*01826a49SYabin Cui bitStream = MEM_readLE32(ip);
72*01826a49SYabin Cui nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
73*01826a49SYabin Cui if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
74*01826a49SYabin Cui bitStream >>= 4;
75*01826a49SYabin Cui bitCount = 4;
76*01826a49SYabin Cui *tableLogPtr = nbBits;
77*01826a49SYabin Cui remaining = (1<<nbBits)+1;
78*01826a49SYabin Cui threshold = 1<<nbBits;
79*01826a49SYabin Cui nbBits++;
80*01826a49SYabin Cui
81*01826a49SYabin Cui for (;;) {
82*01826a49SYabin Cui if (previous0) {
83*01826a49SYabin Cui /* Count the number of repeats. Each time the
84*01826a49SYabin Cui * 2-bit repeat code is 0b11 there is another
85*01826a49SYabin Cui * repeat.
86*01826a49SYabin Cui * Avoid UB by setting the high bit to 1.
87*01826a49SYabin Cui */
88*01826a49SYabin Cui int repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1;
89*01826a49SYabin Cui while (repeats >= 12) {
90*01826a49SYabin Cui charnum += 3 * 12;
91*01826a49SYabin Cui if (LIKELY(ip <= iend-7)) {
92*01826a49SYabin Cui ip += 3;
93*01826a49SYabin Cui } else {
94*01826a49SYabin Cui bitCount -= (int)(8 * (iend - 7 - ip));
95*01826a49SYabin Cui bitCount &= 31;
96*01826a49SYabin Cui ip = iend - 4;
97*01826a49SYabin Cui }
98*01826a49SYabin Cui bitStream = MEM_readLE32(ip) >> bitCount;
99*01826a49SYabin Cui repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1;
100*01826a49SYabin Cui }
101*01826a49SYabin Cui charnum += 3 * repeats;
102*01826a49SYabin Cui bitStream >>= 2 * repeats;
103*01826a49SYabin Cui bitCount += 2 * repeats;
104*01826a49SYabin Cui
105*01826a49SYabin Cui /* Add the final repeat which isn't 0b11. */
106*01826a49SYabin Cui assert((bitStream & 3) < 3);
107*01826a49SYabin Cui charnum += bitStream & 3;
108*01826a49SYabin Cui bitCount += 2;
109*01826a49SYabin Cui
110*01826a49SYabin Cui /* This is an error, but break and return an error
111*01826a49SYabin Cui * at the end, because returning out of a loop makes
112*01826a49SYabin Cui * it harder for the compiler to optimize.
113*01826a49SYabin Cui */
114*01826a49SYabin Cui if (charnum >= maxSV1) break;
115*01826a49SYabin Cui
116*01826a49SYabin Cui /* We don't need to set the normalized count to 0
117*01826a49SYabin Cui * because we already memset the whole buffer to 0.
118*01826a49SYabin Cui */
119*01826a49SYabin Cui
120*01826a49SYabin Cui if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
121*01826a49SYabin Cui assert((bitCount >> 3) <= 3); /* For first condition to work */
122*01826a49SYabin Cui ip += bitCount>>3;
123*01826a49SYabin Cui bitCount &= 7;
124*01826a49SYabin Cui } else {
125*01826a49SYabin Cui bitCount -= (int)(8 * (iend - 4 - ip));
126*01826a49SYabin Cui bitCount &= 31;
127*01826a49SYabin Cui ip = iend - 4;
128*01826a49SYabin Cui }
129*01826a49SYabin Cui bitStream = MEM_readLE32(ip) >> bitCount;
130*01826a49SYabin Cui }
131*01826a49SYabin Cui {
132*01826a49SYabin Cui int const max = (2*threshold-1) - remaining;
133*01826a49SYabin Cui int count;
134*01826a49SYabin Cui
135*01826a49SYabin Cui if ((bitStream & (threshold-1)) < (U32)max) {
136*01826a49SYabin Cui count = bitStream & (threshold-1);
137*01826a49SYabin Cui bitCount += nbBits-1;
138*01826a49SYabin Cui } else {
139*01826a49SYabin Cui count = bitStream & (2*threshold-1);
140*01826a49SYabin Cui if (count >= threshold) count -= max;
141*01826a49SYabin Cui bitCount += nbBits;
142*01826a49SYabin Cui }
143*01826a49SYabin Cui
144*01826a49SYabin Cui count--; /* extra accuracy */
145*01826a49SYabin Cui /* When it matters (small blocks), this is a
146*01826a49SYabin Cui * predictable branch, because we don't use -1.
147*01826a49SYabin Cui */
148*01826a49SYabin Cui if (count >= 0) {
149*01826a49SYabin Cui remaining -= count;
150*01826a49SYabin Cui } else {
151*01826a49SYabin Cui assert(count == -1);
152*01826a49SYabin Cui remaining += count;
153*01826a49SYabin Cui }
154*01826a49SYabin Cui normalizedCounter[charnum++] = (short)count;
155*01826a49SYabin Cui previous0 = !count;
156*01826a49SYabin Cui
157*01826a49SYabin Cui assert(threshold > 1);
158*01826a49SYabin Cui if (remaining < threshold) {
159*01826a49SYabin Cui /* This branch can be folded into the
160*01826a49SYabin Cui * threshold update condition because we
161*01826a49SYabin Cui * know that threshold > 1.
162*01826a49SYabin Cui */
163*01826a49SYabin Cui if (remaining <= 1) break;
164*01826a49SYabin Cui nbBits = ZSTD_highbit32(remaining) + 1;
165*01826a49SYabin Cui threshold = 1 << (nbBits - 1);
166*01826a49SYabin Cui }
167*01826a49SYabin Cui if (charnum >= maxSV1) break;
168*01826a49SYabin Cui
169*01826a49SYabin Cui if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
170*01826a49SYabin Cui ip += bitCount>>3;
171*01826a49SYabin Cui bitCount &= 7;
172*01826a49SYabin Cui } else {
173*01826a49SYabin Cui bitCount -= (int)(8 * (iend - 4 - ip));
174*01826a49SYabin Cui bitCount &= 31;
175*01826a49SYabin Cui ip = iend - 4;
176*01826a49SYabin Cui }
177*01826a49SYabin Cui bitStream = MEM_readLE32(ip) >> bitCount;
178*01826a49SYabin Cui } }
179*01826a49SYabin Cui if (remaining != 1) return ERROR(corruption_detected);
180*01826a49SYabin Cui /* Only possible when there are too many zeros. */
181*01826a49SYabin Cui if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall);
182*01826a49SYabin Cui if (bitCount > 32) return ERROR(corruption_detected);
183*01826a49SYabin Cui *maxSVPtr = charnum-1;
184*01826a49SYabin Cui
185*01826a49SYabin Cui ip += (bitCount+7)>>3;
186*01826a49SYabin Cui return ip-istart;
187*01826a49SYabin Cui }
188*01826a49SYabin Cui
189*01826a49SYabin Cui /* Avoids the FORCE_INLINE of the _body() function. */
FSE_readNCount_body_default(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)190*01826a49SYabin Cui static size_t FSE_readNCount_body_default(
191*01826a49SYabin Cui short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
192*01826a49SYabin Cui const void* headerBuffer, size_t hbSize)
193*01826a49SYabin Cui {
194*01826a49SYabin Cui return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
195*01826a49SYabin Cui }
196*01826a49SYabin Cui
197*01826a49SYabin Cui #if DYNAMIC_BMI2
FSE_readNCount_body_bmi2(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)198*01826a49SYabin Cui BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2(
199*01826a49SYabin Cui short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
200*01826a49SYabin Cui const void* headerBuffer, size_t hbSize)
201*01826a49SYabin Cui {
202*01826a49SYabin Cui return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
203*01826a49SYabin Cui }
204*01826a49SYabin Cui #endif
205*01826a49SYabin Cui
FSE_readNCount_bmi2(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize,int bmi2)206*01826a49SYabin Cui size_t FSE_readNCount_bmi2(
207*01826a49SYabin Cui short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
208*01826a49SYabin Cui const void* headerBuffer, size_t hbSize, int bmi2)
209*01826a49SYabin Cui {
210*01826a49SYabin Cui #if DYNAMIC_BMI2
211*01826a49SYabin Cui if (bmi2) {
212*01826a49SYabin Cui return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
213*01826a49SYabin Cui }
214*01826a49SYabin Cui #endif
215*01826a49SYabin Cui (void)bmi2;
216*01826a49SYabin Cui return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
217*01826a49SYabin Cui }
218*01826a49SYabin Cui
FSE_readNCount(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)219*01826a49SYabin Cui size_t FSE_readNCount(
220*01826a49SYabin Cui short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
221*01826a49SYabin Cui const void* headerBuffer, size_t hbSize)
222*01826a49SYabin Cui {
223*01826a49SYabin Cui return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0);
224*01826a49SYabin Cui }
225*01826a49SYabin Cui
226*01826a49SYabin Cui
227*01826a49SYabin Cui /*! HUF_readStats() :
228*01826a49SYabin Cui Read compact Huffman tree, saved by HUF_writeCTable().
229*01826a49SYabin Cui `huffWeight` is destination buffer.
230*01826a49SYabin Cui `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
231*01826a49SYabin Cui @return : size read from `src` , or an error Code .
232*01826a49SYabin Cui Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
233*01826a49SYabin Cui */
HUF_readStats(BYTE * huffWeight,size_t hwSize,U32 * rankStats,U32 * nbSymbolsPtr,U32 * tableLogPtr,const void * src,size_t srcSize)234*01826a49SYabin Cui size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
235*01826a49SYabin Cui U32* nbSymbolsPtr, U32* tableLogPtr,
236*01826a49SYabin Cui const void* src, size_t srcSize)
237*01826a49SYabin Cui {
238*01826a49SYabin Cui U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
239*01826a49SYabin Cui return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* flags */ 0);
240*01826a49SYabin Cui }
241*01826a49SYabin Cui
242*01826a49SYabin Cui FORCE_INLINE_TEMPLATE size_t
HUF_readStats_body(BYTE * huffWeight,size_t hwSize,U32 * rankStats,U32 * nbSymbolsPtr,U32 * tableLogPtr,const void * src,size_t srcSize,void * workSpace,size_t wkspSize,int bmi2)243*01826a49SYabin Cui HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats,
244*01826a49SYabin Cui U32* nbSymbolsPtr, U32* tableLogPtr,
245*01826a49SYabin Cui const void* src, size_t srcSize,
246*01826a49SYabin Cui void* workSpace, size_t wkspSize,
247*01826a49SYabin Cui int bmi2)
248*01826a49SYabin Cui {
249*01826a49SYabin Cui U32 weightTotal;
250*01826a49SYabin Cui const BYTE* ip = (const BYTE*) src;
251*01826a49SYabin Cui size_t iSize;
252*01826a49SYabin Cui size_t oSize;
253*01826a49SYabin Cui
254*01826a49SYabin Cui if (!srcSize) return ERROR(srcSize_wrong);
255*01826a49SYabin Cui iSize = ip[0];
256*01826a49SYabin Cui /* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
257*01826a49SYabin Cui
258*01826a49SYabin Cui if (iSize >= 128) { /* special header */
259*01826a49SYabin Cui oSize = iSize - 127;
260*01826a49SYabin Cui iSize = ((oSize+1)/2);
261*01826a49SYabin Cui if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
262*01826a49SYabin Cui if (oSize >= hwSize) return ERROR(corruption_detected);
263*01826a49SYabin Cui ip += 1;
264*01826a49SYabin Cui { U32 n;
265*01826a49SYabin Cui for (n=0; n<oSize; n+=2) {
266*01826a49SYabin Cui huffWeight[n] = ip[n/2] >> 4;
267*01826a49SYabin Cui huffWeight[n+1] = ip[n/2] & 15;
268*01826a49SYabin Cui } } }
269*01826a49SYabin Cui else { /* header compressed with FSE (normal case) */
270*01826a49SYabin Cui if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
271*01826a49SYabin Cui /* max (hwSize-1) values decoded, as last one is implied */
272*01826a49SYabin Cui oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2);
273*01826a49SYabin Cui if (FSE_isError(oSize)) return oSize;
274*01826a49SYabin Cui }
275*01826a49SYabin Cui
276*01826a49SYabin Cui /* collect weight stats */
277*01826a49SYabin Cui ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
278*01826a49SYabin Cui weightTotal = 0;
279*01826a49SYabin Cui { U32 n; for (n=0; n<oSize; n++) {
280*01826a49SYabin Cui if (huffWeight[n] > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
281*01826a49SYabin Cui rankStats[huffWeight[n]]++;
282*01826a49SYabin Cui weightTotal += (1 << huffWeight[n]) >> 1;
283*01826a49SYabin Cui } }
284*01826a49SYabin Cui if (weightTotal == 0) return ERROR(corruption_detected);
285*01826a49SYabin Cui
286*01826a49SYabin Cui /* get last non-null symbol weight (implied, total must be 2^n) */
287*01826a49SYabin Cui { U32 const tableLog = ZSTD_highbit32(weightTotal) + 1;
288*01826a49SYabin Cui if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
289*01826a49SYabin Cui *tableLogPtr = tableLog;
290*01826a49SYabin Cui /* determine last weight */
291*01826a49SYabin Cui { U32 const total = 1 << tableLog;
292*01826a49SYabin Cui U32 const rest = total - weightTotal;
293*01826a49SYabin Cui U32 const verif = 1 << ZSTD_highbit32(rest);
294*01826a49SYabin Cui U32 const lastWeight = ZSTD_highbit32(rest) + 1;
295*01826a49SYabin Cui if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
296*01826a49SYabin Cui huffWeight[oSize] = (BYTE)lastWeight;
297*01826a49SYabin Cui rankStats[lastWeight]++;
298*01826a49SYabin Cui } }
299*01826a49SYabin Cui
300*01826a49SYabin Cui /* check tree construction validity */
301*01826a49SYabin Cui if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
302*01826a49SYabin Cui
303*01826a49SYabin Cui /* results */
304*01826a49SYabin Cui *nbSymbolsPtr = (U32)(oSize+1);
305*01826a49SYabin Cui return iSize+1;
306*01826a49SYabin Cui }
307*01826a49SYabin Cui
308*01826a49SYabin Cui /* Avoids the FORCE_INLINE of the _body() function. */
HUF_readStats_body_default(BYTE * huffWeight,size_t hwSize,U32 * rankStats,U32 * nbSymbolsPtr,U32 * tableLogPtr,const void * src,size_t srcSize,void * workSpace,size_t wkspSize)309*01826a49SYabin Cui static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats,
310*01826a49SYabin Cui U32* nbSymbolsPtr, U32* tableLogPtr,
311*01826a49SYabin Cui const void* src, size_t srcSize,
312*01826a49SYabin Cui void* workSpace, size_t wkspSize)
313*01826a49SYabin Cui {
314*01826a49SYabin Cui return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0);
315*01826a49SYabin Cui }
316*01826a49SYabin Cui
317*01826a49SYabin Cui #if DYNAMIC_BMI2
HUF_readStats_body_bmi2(BYTE * huffWeight,size_t hwSize,U32 * rankStats,U32 * nbSymbolsPtr,U32 * tableLogPtr,const void * src,size_t srcSize,void * workSpace,size_t wkspSize)318*01826a49SYabin Cui static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats,
319*01826a49SYabin Cui U32* nbSymbolsPtr, U32* tableLogPtr,
320*01826a49SYabin Cui const void* src, size_t srcSize,
321*01826a49SYabin Cui void* workSpace, size_t wkspSize)
322*01826a49SYabin Cui {
323*01826a49SYabin Cui return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1);
324*01826a49SYabin Cui }
325*01826a49SYabin Cui #endif
326*01826a49SYabin Cui
HUF_readStats_wksp(BYTE * huffWeight,size_t hwSize,U32 * rankStats,U32 * nbSymbolsPtr,U32 * tableLogPtr,const void * src,size_t srcSize,void * workSpace,size_t wkspSize,int flags)327*01826a49SYabin Cui size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats,
328*01826a49SYabin Cui U32* nbSymbolsPtr, U32* tableLogPtr,
329*01826a49SYabin Cui const void* src, size_t srcSize,
330*01826a49SYabin Cui void* workSpace, size_t wkspSize,
331*01826a49SYabin Cui int flags)
332*01826a49SYabin Cui {
333*01826a49SYabin Cui #if DYNAMIC_BMI2
334*01826a49SYabin Cui if (flags & HUF_flags_bmi2) {
335*01826a49SYabin Cui return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
336*01826a49SYabin Cui }
337*01826a49SYabin Cui #endif
338*01826a49SYabin Cui (void)flags;
339*01826a49SYabin Cui return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
340*01826a49SYabin Cui }
341