xref: /freebsd/sys/contrib/zstd/lib/common/entropy_common.c (revision 5ff13fbc199bdf5f0572845351c68ee5ca828e71)
137f1f268SConrad Meyer /* ******************************************************************
237f1f268SConrad Meyer  * Common functions of New Generation Entropy library
3*5ff13fbcSAllan Jude  * Copyright (c) Yann Collet, Facebook, Inc.
437f1f268SConrad Meyer  *
537f1f268SConrad Meyer  *  You can contact the author at :
637f1f268SConrad Meyer  *  - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
737f1f268SConrad Meyer  *  - Public forum : https://groups.google.com/forum/#!forum/lz4c
837f1f268SConrad Meyer  *
937f1f268SConrad Meyer  * This source code is licensed under both the BSD-style license (found in the
1037f1f268SConrad Meyer  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
1137f1f268SConrad Meyer  * in the COPYING file in the root directory of this source tree).
1237f1f268SConrad Meyer  * You may select, at your option, one of the above-listed licenses.
1337f1f268SConrad Meyer ****************************************************************** */
140c16b537SWarner Losh 
150c16b537SWarner Losh /* *************************************
160c16b537SWarner Losh *  Dependencies
170c16b537SWarner Losh ***************************************/
180c16b537SWarner Losh #include "mem.h"
190c16b537SWarner Losh #include "error_private.h"       /* ERR_*, ERROR */
200c16b537SWarner Losh #define FSE_STATIC_LINKING_ONLY  /* FSE_MIN_TABLELOG */
210c16b537SWarner Losh #include "fse.h"
220c16b537SWarner Losh #define HUF_STATIC_LINKING_ONLY  /* HUF_TABLELOG_ABSOLUTEMAX */
230c16b537SWarner Losh #include "huf.h"
240c16b537SWarner Losh 
250c16b537SWarner Losh 
260c16b537SWarner Losh /*===   Version   ===*/
FSE_versionNumber(void)270c16b537SWarner Losh unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
280c16b537SWarner Losh 
290c16b537SWarner Losh 
300c16b537SWarner Losh /*===   Error Management   ===*/
FSE_isError(size_t code)310c16b537SWarner Losh unsigned FSE_isError(size_t code) { return ERR_isError(code); }
FSE_getErrorName(size_t code)320c16b537SWarner Losh const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
330c16b537SWarner Losh 
HUF_isError(size_t code)340c16b537SWarner Losh unsigned HUF_isError(size_t code) { return ERR_isError(code); }
HUF_getErrorName(size_t code)350c16b537SWarner Losh const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
360c16b537SWarner Losh 
370c16b537SWarner Losh 
380c16b537SWarner Losh /*-**************************************************************
390c16b537SWarner Losh *  FSE NCount encoding-decoding
400c16b537SWarner Losh ****************************************************************/
FSE_ctz(U32 val)41f7cd7fe5SConrad Meyer static U32 FSE_ctz(U32 val)
42f7cd7fe5SConrad Meyer {
43f7cd7fe5SConrad Meyer     assert(val != 0);
44f7cd7fe5SConrad Meyer     {
45f7cd7fe5SConrad Meyer #   if defined(_MSC_VER)   /* Visual */
46*5ff13fbcSAllan Jude         if (val != 0) {
47*5ff13fbcSAllan Jude             unsigned long r;
48*5ff13fbcSAllan Jude             _BitScanForward(&r, val);
49*5ff13fbcSAllan Jude             return (unsigned)r;
50*5ff13fbcSAllan Jude         } else {
51*5ff13fbcSAllan Jude             /* Should not reach this code path */
52*5ff13fbcSAllan Jude             __assume(0);
53*5ff13fbcSAllan Jude         }
54f7cd7fe5SConrad Meyer #   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* GCC Intrinsic */
55f7cd7fe5SConrad Meyer         return __builtin_ctz(val);
56f7cd7fe5SConrad Meyer #   elif defined(__ICCARM__)    /* IAR Intrinsic */
57f7cd7fe5SConrad Meyer         return __CTZ(val);
58f7cd7fe5SConrad Meyer #   else   /* Software version */
59f7cd7fe5SConrad Meyer         U32 count = 0;
60f7cd7fe5SConrad Meyer         while ((val & 1) == 0) {
61f7cd7fe5SConrad Meyer             val >>= 1;
62f7cd7fe5SConrad Meyer             ++count;
63f7cd7fe5SConrad Meyer         }
64f7cd7fe5SConrad Meyer         return count;
65f7cd7fe5SConrad Meyer #   endif
66f7cd7fe5SConrad Meyer     }
67f7cd7fe5SConrad Meyer }
68f7cd7fe5SConrad Meyer 
69f7cd7fe5SConrad Meyer FORCE_INLINE_TEMPLATE
FSE_readNCount_body(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)70f7cd7fe5SConrad Meyer size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
710c16b537SWarner Losh                            const void* headerBuffer, size_t hbSize)
720c16b537SWarner Losh {
730c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) headerBuffer;
740c16b537SWarner Losh     const BYTE* const iend = istart + hbSize;
750c16b537SWarner Losh     const BYTE* ip = istart;
760c16b537SWarner Losh     int nbBits;
770c16b537SWarner Losh     int remaining;
780c16b537SWarner Losh     int threshold;
790c16b537SWarner Losh     U32 bitStream;
800c16b537SWarner Losh     int bitCount;
810c16b537SWarner Losh     unsigned charnum = 0;
82f7cd7fe5SConrad Meyer     unsigned const maxSV1 = *maxSVPtr + 1;
830c16b537SWarner Losh     int previous0 = 0;
840c16b537SWarner Losh 
85f7cd7fe5SConrad Meyer     if (hbSize < 8) {
86f7cd7fe5SConrad Meyer         /* This function only works when hbSize >= 8 */
87f7cd7fe5SConrad Meyer         char buffer[8] = {0};
88f7cd7fe5SConrad Meyer         ZSTD_memcpy(buffer, headerBuffer, hbSize);
890f743729SConrad Meyer         {   size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
900f743729SConrad Meyer                                                     buffer, sizeof(buffer));
910f743729SConrad Meyer             if (FSE_isError(countSize)) return countSize;
920f743729SConrad Meyer             if (countSize > hbSize) return ERROR(corruption_detected);
930f743729SConrad Meyer             return countSize;
940f743729SConrad Meyer     }   }
95f7cd7fe5SConrad Meyer     assert(hbSize >= 8);
960f743729SConrad Meyer 
970f743729SConrad Meyer     /* init */
98f7cd7fe5SConrad Meyer     ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0]));   /* all symbols not present in NCount have a frequency of 0 */
990c16b537SWarner Losh     bitStream = MEM_readLE32(ip);
1000c16b537SWarner Losh     nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG;   /* extract tableLog */
1010c16b537SWarner Losh     if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
1020c16b537SWarner Losh     bitStream >>= 4;
1030c16b537SWarner Losh     bitCount = 4;
1040c16b537SWarner Losh     *tableLogPtr = nbBits;
1050c16b537SWarner Losh     remaining = (1<<nbBits)+1;
1060c16b537SWarner Losh     threshold = 1<<nbBits;
1070c16b537SWarner Losh     nbBits++;
1080c16b537SWarner Losh 
109f7cd7fe5SConrad Meyer     for (;;) {
1100c16b537SWarner Losh         if (previous0) {
111f7cd7fe5SConrad Meyer             /* Count the number of repeats. Each time the
112f7cd7fe5SConrad Meyer              * 2-bit repeat code is 0b11 there is another
113f7cd7fe5SConrad Meyer              * repeat.
114f7cd7fe5SConrad Meyer              * Avoid UB by setting the high bit to 1.
115f7cd7fe5SConrad Meyer              */
116f7cd7fe5SConrad Meyer             int repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
117f7cd7fe5SConrad Meyer             while (repeats >= 12) {
118f7cd7fe5SConrad Meyer                 charnum += 3 * 12;
119f7cd7fe5SConrad Meyer                 if (LIKELY(ip <= iend-7)) {
120f7cd7fe5SConrad Meyer                     ip += 3;
1210c16b537SWarner Losh                 } else {
122f7cd7fe5SConrad Meyer                     bitCount -= (int)(8 * (iend - 7 - ip));
123f7cd7fe5SConrad Meyer                     bitCount &= 31;
124f7cd7fe5SConrad Meyer                     ip = iend - 4;
1250c16b537SWarner Losh                 }
126f7cd7fe5SConrad Meyer                 bitStream = MEM_readLE32(ip) >> bitCount;
127f7cd7fe5SConrad Meyer                 repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
128f7cd7fe5SConrad Meyer             }
129f7cd7fe5SConrad Meyer             charnum += 3 * repeats;
130f7cd7fe5SConrad Meyer             bitStream >>= 2 * repeats;
131f7cd7fe5SConrad Meyer             bitCount += 2 * repeats;
132f7cd7fe5SConrad Meyer 
133f7cd7fe5SConrad Meyer             /* Add the final repeat which isn't 0b11. */
134f7cd7fe5SConrad Meyer             assert((bitStream & 3) < 3);
135f7cd7fe5SConrad Meyer             charnum += bitStream & 3;
1360c16b537SWarner Losh             bitCount += 2;
137f7cd7fe5SConrad Meyer 
138f7cd7fe5SConrad Meyer             /* This is an error, but break and return an error
139f7cd7fe5SConrad Meyer              * at the end, because returning out of a loop makes
140f7cd7fe5SConrad Meyer              * it harder for the compiler to optimize.
141f7cd7fe5SConrad Meyer              */
142f7cd7fe5SConrad Meyer             if (charnum >= maxSV1) break;
143f7cd7fe5SConrad Meyer 
144f7cd7fe5SConrad Meyer             /* We don't need to set the normalized count to 0
145f7cd7fe5SConrad Meyer              * because we already memset the whole buffer to 0.
146f7cd7fe5SConrad Meyer              */
147f7cd7fe5SConrad Meyer 
148f7cd7fe5SConrad Meyer             if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
1490f743729SConrad Meyer                 assert((bitCount >> 3) <= 3); /* For first condition to work */
1500c16b537SWarner Losh                 ip += bitCount>>3;
1510c16b537SWarner Losh                 bitCount &= 7;
1520c16b537SWarner Losh             } else {
153f7cd7fe5SConrad Meyer                 bitCount -= (int)(8 * (iend - 4 - ip));
154f7cd7fe5SConrad Meyer                 bitCount &= 31;
155f7cd7fe5SConrad Meyer                 ip = iend - 4;
156f7cd7fe5SConrad Meyer             }
157f7cd7fe5SConrad Meyer             bitStream = MEM_readLE32(ip) >> bitCount;
158f7cd7fe5SConrad Meyer         }
159f7cd7fe5SConrad Meyer         {
160f7cd7fe5SConrad Meyer             int const max = (2*threshold-1) - remaining;
1610c16b537SWarner Losh             int count;
1620c16b537SWarner Losh 
1630c16b537SWarner Losh             if ((bitStream & (threshold-1)) < (U32)max) {
1640c16b537SWarner Losh                 count = bitStream & (threshold-1);
1650c16b537SWarner Losh                 bitCount += nbBits-1;
1660c16b537SWarner Losh             } else {
1670c16b537SWarner Losh                 count = bitStream & (2*threshold-1);
1680c16b537SWarner Losh                 if (count >= threshold) count -= max;
1690c16b537SWarner Losh                 bitCount += nbBits;
1700c16b537SWarner Losh             }
1710c16b537SWarner Losh 
1720c16b537SWarner Losh             count--;   /* extra accuracy */
173f7cd7fe5SConrad Meyer             /* When it matters (small blocks), this is a
174f7cd7fe5SConrad Meyer              * predictable branch, because we don't use -1.
175f7cd7fe5SConrad Meyer              */
176f7cd7fe5SConrad Meyer             if (count >= 0) {
177f7cd7fe5SConrad Meyer                 remaining -= count;
178f7cd7fe5SConrad Meyer             } else {
179f7cd7fe5SConrad Meyer                 assert(count == -1);
180f7cd7fe5SConrad Meyer                 remaining += count;
181f7cd7fe5SConrad Meyer             }
1820c16b537SWarner Losh             normalizedCounter[charnum++] = (short)count;
1830c16b537SWarner Losh             previous0 = !count;
1840c16b537SWarner Losh 
185f7cd7fe5SConrad Meyer             assert(threshold > 1);
186f7cd7fe5SConrad Meyer             if (remaining < threshold) {
187f7cd7fe5SConrad Meyer                 /* This branch can be folded into the
188f7cd7fe5SConrad Meyer                  * threshold update condition because we
189f7cd7fe5SConrad Meyer                  * know that threshold > 1.
190f7cd7fe5SConrad Meyer                  */
191f7cd7fe5SConrad Meyer                 if (remaining <= 1) break;
192f7cd7fe5SConrad Meyer                 nbBits = BIT_highbit32(remaining) + 1;
193f7cd7fe5SConrad Meyer                 threshold = 1 << (nbBits - 1);
194f7cd7fe5SConrad Meyer             }
195f7cd7fe5SConrad Meyer             if (charnum >= maxSV1) break;
196f7cd7fe5SConrad Meyer 
197f7cd7fe5SConrad Meyer             if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
1980c16b537SWarner Losh                 ip += bitCount>>3;
1990c16b537SWarner Losh                 bitCount &= 7;
2000c16b537SWarner Losh             } else {
2010c16b537SWarner Losh                 bitCount -= (int)(8 * (iend - 4 - ip));
202f7cd7fe5SConrad Meyer                 bitCount &= 31;
2030c16b537SWarner Losh                 ip = iend - 4;
2040c16b537SWarner Losh             }
205f7cd7fe5SConrad Meyer             bitStream = MEM_readLE32(ip) >> bitCount;
206f7cd7fe5SConrad Meyer     }   }
2070c16b537SWarner Losh     if (remaining != 1) return ERROR(corruption_detected);
208f7cd7fe5SConrad Meyer     /* Only possible when there are too many zeros. */
209f7cd7fe5SConrad Meyer     if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall);
2100c16b537SWarner Losh     if (bitCount > 32) return ERROR(corruption_detected);
2110c16b537SWarner Losh     *maxSVPtr = charnum-1;
2120c16b537SWarner Losh 
2130c16b537SWarner Losh     ip += (bitCount+7)>>3;
2140c16b537SWarner Losh     return ip-istart;
2150c16b537SWarner Losh }
2160c16b537SWarner Losh 
217f7cd7fe5SConrad Meyer /* Avoids the FORCE_INLINE of the _body() function. */
FSE_readNCount_body_default(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)218f7cd7fe5SConrad Meyer static size_t FSE_readNCount_body_default(
219f7cd7fe5SConrad Meyer         short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
220f7cd7fe5SConrad Meyer         const void* headerBuffer, size_t hbSize)
221f7cd7fe5SConrad Meyer {
222f7cd7fe5SConrad Meyer     return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
223f7cd7fe5SConrad Meyer }
224f7cd7fe5SConrad Meyer 
225f7cd7fe5SConrad Meyer #if DYNAMIC_BMI2
FSE_readNCount_body_bmi2(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)226*5ff13fbcSAllan Jude BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2(
227f7cd7fe5SConrad Meyer         short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
228f7cd7fe5SConrad Meyer         const void* headerBuffer, size_t hbSize)
229f7cd7fe5SConrad Meyer {
230f7cd7fe5SConrad Meyer     return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
231f7cd7fe5SConrad Meyer }
232f7cd7fe5SConrad Meyer #endif
233f7cd7fe5SConrad Meyer 
FSE_readNCount_bmi2(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize,int bmi2)234f7cd7fe5SConrad Meyer size_t FSE_readNCount_bmi2(
235f7cd7fe5SConrad Meyer         short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
236f7cd7fe5SConrad Meyer         const void* headerBuffer, size_t hbSize, int bmi2)
237f7cd7fe5SConrad Meyer {
238f7cd7fe5SConrad Meyer #if DYNAMIC_BMI2
239f7cd7fe5SConrad Meyer     if (bmi2) {
240f7cd7fe5SConrad Meyer         return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
241f7cd7fe5SConrad Meyer     }
242f7cd7fe5SConrad Meyer #endif
243f7cd7fe5SConrad Meyer     (void)bmi2;
244f7cd7fe5SConrad Meyer     return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
245f7cd7fe5SConrad Meyer }
246f7cd7fe5SConrad Meyer 
FSE_readNCount(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)247f7cd7fe5SConrad Meyer size_t FSE_readNCount(
248f7cd7fe5SConrad Meyer         short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
249f7cd7fe5SConrad Meyer         const void* headerBuffer, size_t hbSize)
250f7cd7fe5SConrad Meyer {
251f7cd7fe5SConrad Meyer     return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0);
252f7cd7fe5SConrad Meyer }
253f7cd7fe5SConrad Meyer 
2540c16b537SWarner Losh 
2550c16b537SWarner Losh /*! HUF_readStats() :
2560c16b537SWarner Losh     Read compact Huffman tree, saved by HUF_writeCTable().
2570c16b537SWarner Losh     `huffWeight` is destination buffer.
2580c16b537SWarner Losh     `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
2590c16b537SWarner Losh     @return : size read from `src` , or an error Code .
2600c16b537SWarner Losh     Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
2610c16b537SWarner Losh */
HUF_readStats(BYTE * huffWeight,size_t hwSize,U32 * rankStats,U32 * nbSymbolsPtr,U32 * tableLogPtr,const void * src,size_t srcSize)2620c16b537SWarner Losh size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
2630c16b537SWarner Losh                      U32* nbSymbolsPtr, U32* tableLogPtr,
2640c16b537SWarner Losh                      const void* src, size_t srcSize)
2650c16b537SWarner Losh {
266f7cd7fe5SConrad Meyer     U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
267f7cd7fe5SConrad Meyer     return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* bmi2 */ 0);
268f7cd7fe5SConrad Meyer }
269f7cd7fe5SConrad Meyer 
270f7cd7fe5SConrad Meyer 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)271f7cd7fe5SConrad Meyer HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats,
272f7cd7fe5SConrad Meyer                    U32* nbSymbolsPtr, U32* tableLogPtr,
273f7cd7fe5SConrad Meyer                    const void* src, size_t srcSize,
274f7cd7fe5SConrad Meyer                    void* workSpace, size_t wkspSize,
275f7cd7fe5SConrad Meyer                    int bmi2)
276f7cd7fe5SConrad Meyer {
2770c16b537SWarner Losh     U32 weightTotal;
2780c16b537SWarner Losh     const BYTE* ip = (const BYTE*) src;
2790c16b537SWarner Losh     size_t iSize;
2800c16b537SWarner Losh     size_t oSize;
2810c16b537SWarner Losh 
2820c16b537SWarner Losh     if (!srcSize) return ERROR(srcSize_wrong);
2830c16b537SWarner Losh     iSize = ip[0];
284f7cd7fe5SConrad Meyer     /* ZSTD_memset(huffWeight, 0, hwSize);   *//* is not necessary, even though some analyzer complain ... */
2850c16b537SWarner Losh 
2860c16b537SWarner Losh     if (iSize >= 128) {  /* special header */
2870c16b537SWarner Losh         oSize = iSize - 127;
2880c16b537SWarner Losh         iSize = ((oSize+1)/2);
2890c16b537SWarner Losh         if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
2900c16b537SWarner Losh         if (oSize >= hwSize) return ERROR(corruption_detected);
2910c16b537SWarner Losh         ip += 1;
2920c16b537SWarner Losh         {   U32 n;
2930c16b537SWarner Losh             for (n=0; n<oSize; n+=2) {
2940c16b537SWarner Losh                 huffWeight[n]   = ip[n/2] >> 4;
2950c16b537SWarner Losh                 huffWeight[n+1] = ip[n/2] & 15;
2960c16b537SWarner Losh     }   }   }
2970c16b537SWarner Losh     else  {   /* header compressed with FSE (normal case) */
2980c16b537SWarner Losh         if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
299f7cd7fe5SConrad Meyer         /* max (hwSize-1) values decoded, as last one is implied */
300f7cd7fe5SConrad Meyer         oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2);
3010c16b537SWarner Losh         if (FSE_isError(oSize)) return oSize;
3020c16b537SWarner Losh     }
3030c16b537SWarner Losh 
3040c16b537SWarner Losh     /* collect weight stats */
305f7cd7fe5SConrad Meyer     ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
3060c16b537SWarner Losh     weightTotal = 0;
3070c16b537SWarner Losh     {   U32 n; for (n=0; n<oSize; n++) {
308*5ff13fbcSAllan Jude             if (huffWeight[n] > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
3090c16b537SWarner Losh             rankStats[huffWeight[n]]++;
3100c16b537SWarner Losh             weightTotal += (1 << huffWeight[n]) >> 1;
3110c16b537SWarner Losh     }   }
3120c16b537SWarner Losh     if (weightTotal == 0) return ERROR(corruption_detected);
3130c16b537SWarner Losh 
3140c16b537SWarner Losh     /* get last non-null symbol weight (implied, total must be 2^n) */
3150c16b537SWarner Losh     {   U32 const tableLog = BIT_highbit32(weightTotal) + 1;
3160c16b537SWarner Losh         if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
3170c16b537SWarner Losh         *tableLogPtr = tableLog;
3180c16b537SWarner Losh         /* determine last weight */
3190c16b537SWarner Losh         {   U32 const total = 1 << tableLog;
3200c16b537SWarner Losh             U32 const rest = total - weightTotal;
3210c16b537SWarner Losh             U32 const verif = 1 << BIT_highbit32(rest);
3220c16b537SWarner Losh             U32 const lastWeight = BIT_highbit32(rest) + 1;
3230c16b537SWarner Losh             if (verif != rest) return ERROR(corruption_detected);    /* last value must be a clean power of 2 */
3240c16b537SWarner Losh             huffWeight[oSize] = (BYTE)lastWeight;
3250c16b537SWarner Losh             rankStats[lastWeight]++;
3260c16b537SWarner Losh     }   }
3270c16b537SWarner Losh 
3280c16b537SWarner Losh     /* check tree construction validity */
3290c16b537SWarner Losh     if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected);   /* by construction : at least 2 elts of rank 1, must be even */
3300c16b537SWarner Losh 
3310c16b537SWarner Losh     /* results */
3320c16b537SWarner Losh     *nbSymbolsPtr = (U32)(oSize+1);
3330c16b537SWarner Losh     return iSize+1;
3340c16b537SWarner Losh }
335f7cd7fe5SConrad Meyer 
336f7cd7fe5SConrad Meyer /* 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)337f7cd7fe5SConrad Meyer static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats,
338f7cd7fe5SConrad Meyer                      U32* nbSymbolsPtr, U32* tableLogPtr,
339f7cd7fe5SConrad Meyer                      const void* src, size_t srcSize,
340f7cd7fe5SConrad Meyer                      void* workSpace, size_t wkspSize)
341f7cd7fe5SConrad Meyer {
342f7cd7fe5SConrad Meyer     return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0);
343f7cd7fe5SConrad Meyer }
344f7cd7fe5SConrad Meyer 
345f7cd7fe5SConrad Meyer #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)346*5ff13fbcSAllan Jude static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats,
347f7cd7fe5SConrad Meyer                      U32* nbSymbolsPtr, U32* tableLogPtr,
348f7cd7fe5SConrad Meyer                      const void* src, size_t srcSize,
349f7cd7fe5SConrad Meyer                      void* workSpace, size_t wkspSize)
350f7cd7fe5SConrad Meyer {
351f7cd7fe5SConrad Meyer     return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1);
352f7cd7fe5SConrad Meyer }
353f7cd7fe5SConrad Meyer #endif
354f7cd7fe5SConrad Meyer 
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 bmi2)355f7cd7fe5SConrad Meyer size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats,
356f7cd7fe5SConrad Meyer                      U32* nbSymbolsPtr, U32* tableLogPtr,
357f7cd7fe5SConrad Meyer                      const void* src, size_t srcSize,
358f7cd7fe5SConrad Meyer                      void* workSpace, size_t wkspSize,
359f7cd7fe5SConrad Meyer                      int bmi2)
360f7cd7fe5SConrad Meyer {
361f7cd7fe5SConrad Meyer #if DYNAMIC_BMI2
362f7cd7fe5SConrad Meyer     if (bmi2) {
363f7cd7fe5SConrad Meyer         return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
364f7cd7fe5SConrad Meyer     }
365f7cd7fe5SConrad Meyer #endif
366f7cd7fe5SConrad Meyer     (void)bmi2;
367f7cd7fe5SConrad Meyer     return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
368f7cd7fe5SConrad Meyer }
369