xref: /freebsd/sys/contrib/zstd/lib/compress/fse_compress.c (revision a0483764f3d68669e9b7db074bcbd45b050166bb)
10c16b537SWarner Losh /* ******************************************************************
20c16b537SWarner Losh    FSE : Finite State Entropy encoder
30f743729SConrad Meyer    Copyright (C) 2013-present, Yann Collet.
40c16b537SWarner Losh 
50c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
60c16b537SWarner Losh 
70c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
80c16b537SWarner Losh    modification, are permitted provided that the following conditions are
90c16b537SWarner Losh    met:
100c16b537SWarner Losh 
110c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
120c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
130c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
140c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
150c16b537SWarner Losh    in the documentation and/or other materials provided with the
160c16b537SWarner Losh    distribution.
170c16b537SWarner Losh 
180c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
190c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
200c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
210c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
220c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
230c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
240c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
250c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
260c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
270c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
280c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
290c16b537SWarner Losh 
300c16b537SWarner Losh     You can contact the author at :
310c16b537SWarner Losh     - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
320c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
330c16b537SWarner Losh ****************************************************************** */
340c16b537SWarner Losh 
350c16b537SWarner Losh /* **************************************************************
360c16b537SWarner Losh *  Includes
370c16b537SWarner Losh ****************************************************************/
380c16b537SWarner Losh #include <stdlib.h>     /* malloc, free, qsort */
390c16b537SWarner Losh #include <string.h>     /* memcpy, memset */
400c16b537SWarner Losh #include "compiler.h"
410f743729SConrad Meyer #include "mem.h"        /* U32, U16, etc. */
420f743729SConrad Meyer #include "debug.h"      /* assert, DEBUGLOG */
430f743729SConrad Meyer #include "hist.h"       /* HIST_count_wksp */
440f743729SConrad Meyer #include "bitstream.h"
450c16b537SWarner Losh #define FSE_STATIC_LINKING_ONLY
460c16b537SWarner Losh #include "fse.h"
470c16b537SWarner Losh #include "error_private.h"
480c16b537SWarner Losh 
490c16b537SWarner Losh 
500c16b537SWarner Losh /* **************************************************************
510c16b537SWarner Losh *  Error Management
520c16b537SWarner Losh ****************************************************************/
530c16b537SWarner Losh #define FSE_isError ERR_isError
540c16b537SWarner Losh 
550c16b537SWarner Losh 
560c16b537SWarner Losh /* **************************************************************
570c16b537SWarner Losh *  Templates
580c16b537SWarner Losh ****************************************************************/
590c16b537SWarner Losh /*
600c16b537SWarner Losh   designed to be included
610c16b537SWarner Losh   for type-specific functions (template emulation in C)
620c16b537SWarner Losh   Objective is to write these functions only once, for improved maintenance
630c16b537SWarner Losh */
640c16b537SWarner Losh 
650c16b537SWarner Losh /* safety checks */
660c16b537SWarner Losh #ifndef FSE_FUNCTION_EXTENSION
670c16b537SWarner Losh #  error "FSE_FUNCTION_EXTENSION must be defined"
680c16b537SWarner Losh #endif
690c16b537SWarner Losh #ifndef FSE_FUNCTION_TYPE
700c16b537SWarner Losh #  error "FSE_FUNCTION_TYPE must be defined"
710c16b537SWarner Losh #endif
720c16b537SWarner Losh 
730c16b537SWarner Losh /* Function names */
740c16b537SWarner Losh #define FSE_CAT(X,Y) X##Y
750c16b537SWarner Losh #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
760c16b537SWarner Losh #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
770c16b537SWarner Losh 
780c16b537SWarner Losh 
790c16b537SWarner Losh /* Function templates */
800c16b537SWarner Losh 
810c16b537SWarner Losh /* FSE_buildCTable_wksp() :
820c16b537SWarner Losh  * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
830c16b537SWarner Losh  * wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
840c16b537SWarner Losh  * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
850c16b537SWarner Losh  */
860f743729SConrad Meyer size_t FSE_buildCTable_wksp(FSE_CTable* ct,
870f743729SConrad Meyer                       const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
880f743729SConrad Meyer                             void* workSpace, size_t wkspSize)
890c16b537SWarner Losh {
900c16b537SWarner Losh     U32 const tableSize = 1 << tableLog;
910c16b537SWarner Losh     U32 const tableMask = tableSize - 1;
920c16b537SWarner Losh     void* const ptr = ct;
930c16b537SWarner Losh     U16* const tableU16 = ( (U16*) ptr) + 2;
940c16b537SWarner Losh     void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;
950c16b537SWarner Losh     FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
960c16b537SWarner Losh     U32 const step = FSE_TABLESTEP(tableSize);
970c16b537SWarner Losh     U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
980c16b537SWarner Losh 
990c16b537SWarner Losh     FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
1000c16b537SWarner Losh     U32 highThreshold = tableSize-1;
1010c16b537SWarner Losh 
1020c16b537SWarner Losh     /* CTable header */
1030c16b537SWarner Losh     if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
1040c16b537SWarner Losh     tableU16[-2] = (U16) tableLog;
1050c16b537SWarner Losh     tableU16[-1] = (U16) maxSymbolValue;
1060f743729SConrad Meyer     assert(tableLog < 16);   /* required for threshold strategy to work */
1070c16b537SWarner Losh 
1080c16b537SWarner Losh     /* For explanations on how to distribute symbol values over the table :
1090c16b537SWarner Losh      * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
1100c16b537SWarner Losh 
1110f743729SConrad Meyer      #ifdef __clang_analyzer__
1120f743729SConrad Meyer      memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize);   /* useless initialization, just to keep scan-build happy */
1130f743729SConrad Meyer      #endif
1140f743729SConrad Meyer 
1150c16b537SWarner Losh     /* symbol start positions */
1160c16b537SWarner Losh     {   U32 u;
1170c16b537SWarner Losh         cumul[0] = 0;
1180c16b537SWarner Losh         for (u=1; u <= maxSymbolValue+1; u++) {
1190c16b537SWarner Losh             if (normalizedCounter[u-1]==-1) {  /* Low proba symbol */
1200c16b537SWarner Losh                 cumul[u] = cumul[u-1] + 1;
1210c16b537SWarner Losh                 tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);
1220c16b537SWarner Losh             } else {
1230c16b537SWarner Losh                 cumul[u] = cumul[u-1] + normalizedCounter[u-1];
1240c16b537SWarner Losh         }   }
1250c16b537SWarner Losh         cumul[maxSymbolValue+1] = tableSize+1;
1260c16b537SWarner Losh     }
1270c16b537SWarner Losh 
1280c16b537SWarner Losh     /* Spread symbols */
1290c16b537SWarner Losh     {   U32 position = 0;
1300c16b537SWarner Losh         U32 symbol;
1310c16b537SWarner Losh         for (symbol=0; symbol<=maxSymbolValue; symbol++) {
1320c16b537SWarner Losh             int nbOccurences;
1330f743729SConrad Meyer             int const freq = normalizedCounter[symbol];
1340f743729SConrad Meyer             for (nbOccurences=0; nbOccurences<freq; nbOccurences++) {
1350c16b537SWarner Losh                 tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
1360c16b537SWarner Losh                 position = (position + step) & tableMask;
1370f743729SConrad Meyer                 while (position > highThreshold)
1380f743729SConrad Meyer                     position = (position + step) & tableMask;   /* Low proba area */
1390c16b537SWarner Losh         }   }
1400c16b537SWarner Losh 
1410f743729SConrad Meyer         assert(position==0);  /* Must have initialized all positions */
1420c16b537SWarner Losh     }
1430c16b537SWarner Losh 
1440c16b537SWarner Losh     /* Build table */
1450c16b537SWarner Losh     {   U32 u; for (u=0; u<tableSize; u++) {
1460c16b537SWarner Losh         FSE_FUNCTION_TYPE s = tableSymbol[u];   /* note : static analyzer may not understand tableSymbol is properly initialized */
1470c16b537SWarner Losh         tableU16[cumul[s]++] = (U16) (tableSize+u);   /* TableU16 : sorted by symbol order; gives next state value */
1480c16b537SWarner Losh     }   }
1490c16b537SWarner Losh 
1500c16b537SWarner Losh     /* Build Symbol Transformation Table */
1510c16b537SWarner Losh     {   unsigned total = 0;
1520c16b537SWarner Losh         unsigned s;
1530c16b537SWarner Losh         for (s=0; s<=maxSymbolValue; s++) {
1540c16b537SWarner Losh             switch (normalizedCounter[s])
1550c16b537SWarner Losh             {
1560f743729SConrad Meyer             case  0:
1570f743729SConrad Meyer                 /* filling nonetheless, for compatibility with FSE_getMaxNbBits() */
1580f743729SConrad Meyer                 symbolTT[s].deltaNbBits = ((tableLog+1) << 16) - (1<<tableLog);
1590f743729SConrad Meyer                 break;
1600c16b537SWarner Losh 
1610c16b537SWarner Losh             case -1:
1620c16b537SWarner Losh             case  1:
1630c16b537SWarner Losh                 symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);
1640c16b537SWarner Losh                 symbolTT[s].deltaFindState = total - 1;
1650c16b537SWarner Losh                 total ++;
1660c16b537SWarner Losh                 break;
1670c16b537SWarner Losh             default :
1680c16b537SWarner Losh                 {
1690c16b537SWarner Losh                     U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);
1700c16b537SWarner Losh                     U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
1710c16b537SWarner Losh                     symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
1720c16b537SWarner Losh                     symbolTT[s].deltaFindState = total - normalizedCounter[s];
1730c16b537SWarner Losh                     total +=  normalizedCounter[s];
1740c16b537SWarner Losh     }   }   }   }
1750c16b537SWarner Losh 
1760f743729SConrad Meyer #if 0  /* debug : symbol costs */
1770f743729SConrad Meyer     DEBUGLOG(5, "\n --- table statistics : ");
1780f743729SConrad Meyer     {   U32 symbol;
1790f743729SConrad Meyer         for (symbol=0; symbol<=maxSymbolValue; symbol++) {
1800f743729SConrad Meyer             DEBUGLOG(5, "%3u: w=%3i,   maxBits=%u, fracBits=%.2f",
1810f743729SConrad Meyer                 symbol, normalizedCounter[symbol],
1820f743729SConrad Meyer                 FSE_getMaxNbBits(symbolTT, symbol),
1830f743729SConrad Meyer                 (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256);
1840f743729SConrad Meyer         }
1850f743729SConrad Meyer     }
1860f743729SConrad Meyer #endif
1870f743729SConrad Meyer 
1880c16b537SWarner Losh     return 0;
1890c16b537SWarner Losh }
1900c16b537SWarner Losh 
1910c16b537SWarner Losh 
1920c16b537SWarner Losh size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
1930c16b537SWarner Losh {
1940c16b537SWarner Losh     FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE];   /* memset() is not necessary, even if static analyzer complain about it */
1950c16b537SWarner Losh     return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));
1960c16b537SWarner Losh }
1970c16b537SWarner Losh 
1980c16b537SWarner Losh 
1990c16b537SWarner Losh 
2000c16b537SWarner Losh #ifndef FSE_COMMONDEFS_ONLY
2010c16b537SWarner Losh 
2020f743729SConrad Meyer 
2030c16b537SWarner Losh /*-**************************************************************
2040f743729SConrad Meyer *  FSE NCount encoding
2050c16b537SWarner Losh ****************************************************************/
2060c16b537SWarner Losh size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
2070c16b537SWarner Losh {
2080c16b537SWarner Losh     size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;
2090c16b537SWarner Losh     return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND;  /* maxSymbolValue==0 ? use default */
2100c16b537SWarner Losh }
2110c16b537SWarner Losh 
2120f743729SConrad Meyer static size_t
2130f743729SConrad Meyer FSE_writeNCount_generic (void* header, size_t headerBufferSize,
2140c16b537SWarner Losh                    const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
2150c16b537SWarner Losh                          unsigned writeIsSafe)
2160c16b537SWarner Losh {
2170c16b537SWarner Losh     BYTE* const ostart = (BYTE*) header;
2180c16b537SWarner Losh     BYTE* out = ostart;
2190c16b537SWarner Losh     BYTE* const oend = ostart + headerBufferSize;
2200c16b537SWarner Losh     int nbBits;
2210c16b537SWarner Losh     const int tableSize = 1 << tableLog;
2220c16b537SWarner Losh     int remaining;
2230c16b537SWarner Losh     int threshold;
2240f743729SConrad Meyer     U32 bitStream = 0;
2250f743729SConrad Meyer     int bitCount = 0;
2260f743729SConrad Meyer     unsigned symbol = 0;
2270f743729SConrad Meyer     unsigned const alphabetSize = maxSymbolValue + 1;
2280f743729SConrad Meyer     int previousIs0 = 0;
2290c16b537SWarner Losh 
2300c16b537SWarner Losh     /* Table Size */
2310c16b537SWarner Losh     bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;
2320c16b537SWarner Losh     bitCount  += 4;
2330c16b537SWarner Losh 
2340c16b537SWarner Losh     /* Init */
2350c16b537SWarner Losh     remaining = tableSize+1;   /* +1 for extra accuracy */
2360c16b537SWarner Losh     threshold = tableSize;
2370c16b537SWarner Losh     nbBits = tableLog+1;
2380c16b537SWarner Losh 
2390f743729SConrad Meyer     while ((symbol < alphabetSize) && (remaining>1)) {  /* stops at 1 */
2400f743729SConrad Meyer         if (previousIs0) {
2410f743729SConrad Meyer             unsigned start = symbol;
2420f743729SConrad Meyer             while ((symbol < alphabetSize) && !normalizedCounter[symbol]) symbol++;
2430f743729SConrad Meyer             if (symbol == alphabetSize) break;   /* incorrect distribution */
2440f743729SConrad Meyer             while (symbol >= start+24) {
2450c16b537SWarner Losh                 start+=24;
2460c16b537SWarner Losh                 bitStream += 0xFFFFU << bitCount;
2470f743729SConrad Meyer                 if ((!writeIsSafe) && (out > oend-2))
2480f743729SConrad Meyer                     return ERROR(dstSize_tooSmall);   /* Buffer overflow */
2490c16b537SWarner Losh                 out[0] = (BYTE) bitStream;
2500c16b537SWarner Losh                 out[1] = (BYTE)(bitStream>>8);
2510c16b537SWarner Losh                 out+=2;
2520c16b537SWarner Losh                 bitStream>>=16;
2530c16b537SWarner Losh             }
2540f743729SConrad Meyer             while (symbol >= start+3) {
2550c16b537SWarner Losh                 start+=3;
2560c16b537SWarner Losh                 bitStream += 3 << bitCount;
2570c16b537SWarner Losh                 bitCount += 2;
2580c16b537SWarner Losh             }
2590f743729SConrad Meyer             bitStream += (symbol-start) << bitCount;
2600c16b537SWarner Losh             bitCount += 2;
2610c16b537SWarner Losh             if (bitCount>16) {
2620f743729SConrad Meyer                 if ((!writeIsSafe) && (out > oend - 2))
2630f743729SConrad Meyer                     return ERROR(dstSize_tooSmall);   /* Buffer overflow */
2640c16b537SWarner Losh                 out[0] = (BYTE)bitStream;
2650c16b537SWarner Losh                 out[1] = (BYTE)(bitStream>>8);
2660c16b537SWarner Losh                 out += 2;
2670c16b537SWarner Losh                 bitStream >>= 16;
2680c16b537SWarner Losh                 bitCount -= 16;
2690c16b537SWarner Losh         }   }
2700f743729SConrad Meyer         {   int count = normalizedCounter[symbol++];
2710c16b537SWarner Losh             int const max = (2*threshold-1) - remaining;
2720c16b537SWarner Losh             remaining -= count < 0 ? -count : count;
2730c16b537SWarner Losh             count++;   /* +1 for extra accuracy */
2740f743729SConrad Meyer             if (count>=threshold)
2750f743729SConrad Meyer                 count += max;   /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
2760c16b537SWarner Losh             bitStream += count << bitCount;
2770c16b537SWarner Losh             bitCount  += nbBits;
2780c16b537SWarner Losh             bitCount  -= (count<max);
2790f743729SConrad Meyer             previousIs0  = (count==1);
2800c16b537SWarner Losh             if (remaining<1) return ERROR(GENERIC);
28119fcbaf1SConrad Meyer             while (remaining<threshold) { nbBits--; threshold>>=1; }
2820c16b537SWarner Losh         }
2830c16b537SWarner Losh         if (bitCount>16) {
2840f743729SConrad Meyer             if ((!writeIsSafe) && (out > oend - 2))
2850f743729SConrad Meyer                 return ERROR(dstSize_tooSmall);   /* Buffer overflow */
2860c16b537SWarner Losh             out[0] = (BYTE)bitStream;
2870c16b537SWarner Losh             out[1] = (BYTE)(bitStream>>8);
2880c16b537SWarner Losh             out += 2;
2890c16b537SWarner Losh             bitStream >>= 16;
2900c16b537SWarner Losh             bitCount -= 16;
2910c16b537SWarner Losh     }   }
2920c16b537SWarner Losh 
2930f743729SConrad Meyer     if (remaining != 1)
2940f743729SConrad Meyer         return ERROR(GENERIC);  /* incorrect normalized distribution */
2950f743729SConrad Meyer     assert(symbol <= alphabetSize);
2960f743729SConrad Meyer 
2970c16b537SWarner Losh     /* flush remaining bitStream */
2980f743729SConrad Meyer     if ((!writeIsSafe) && (out > oend - 2))
2990f743729SConrad Meyer         return ERROR(dstSize_tooSmall);   /* Buffer overflow */
3000c16b537SWarner Losh     out[0] = (BYTE)bitStream;
3010c16b537SWarner Losh     out[1] = (BYTE)(bitStream>>8);
3020c16b537SWarner Losh     out+= (bitCount+7) /8;
3030c16b537SWarner Losh 
3040c16b537SWarner Losh     return (out-ostart);
3050c16b537SWarner Losh }
3060c16b537SWarner Losh 
3070c16b537SWarner Losh 
3080f743729SConrad Meyer size_t FSE_writeNCount (void* buffer, size_t bufferSize,
3090f743729SConrad Meyer                   const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
3100c16b537SWarner Losh {
3110c16b537SWarner Losh     if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);   /* Unsupported */
3120c16b537SWarner Losh     if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC);   /* Unsupported */
3130c16b537SWarner Losh 
3140c16b537SWarner Losh     if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
3150c16b537SWarner Losh         return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
3160c16b537SWarner Losh 
3170f743729SConrad Meyer     return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1 /* write in buffer is safe */);
3180c16b537SWarner Losh }
3190c16b537SWarner Losh 
3200c16b537SWarner Losh 
3210c16b537SWarner Losh /*-**************************************************************
3220c16b537SWarner Losh *  FSE Compression Code
3230c16b537SWarner Losh ****************************************************************/
3240c16b537SWarner Losh 
3250c16b537SWarner Losh FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
3260c16b537SWarner Losh {
3270c16b537SWarner Losh     size_t size;
3280c16b537SWarner Losh     if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
3290c16b537SWarner Losh     size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
3300c16b537SWarner Losh     return (FSE_CTable*)malloc(size);
3310c16b537SWarner Losh }
3320c16b537SWarner Losh 
3330c16b537SWarner Losh void FSE_freeCTable (FSE_CTable* ct) { free(ct); }
3340c16b537SWarner Losh 
3350c16b537SWarner Losh /* provides the minimum logSize to safely represent a distribution */
3360c16b537SWarner Losh static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
3370c16b537SWarner Losh {
3380f743729SConrad Meyer     U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1;
3390c16b537SWarner Losh     U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
3400c16b537SWarner Losh     U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
3410c16b537SWarner Losh     assert(srcSize > 1); /* Not supported, RLE should be used instead */
3420c16b537SWarner Losh     return minBits;
3430c16b537SWarner Losh }
3440c16b537SWarner Losh 
3450c16b537SWarner Losh unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
3460c16b537SWarner Losh {
3470c16b537SWarner Losh     U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
3480c16b537SWarner Losh     U32 tableLog = maxTableLog;
3490c16b537SWarner Losh     U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
3500c16b537SWarner Losh     assert(srcSize > 1); /* Not supported, RLE should be used instead */
3510c16b537SWarner Losh     if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
3520c16b537SWarner Losh     if (maxBitsSrc < tableLog) tableLog = maxBitsSrc;   /* Accuracy can be reduced */
3530c16b537SWarner Losh     if (minBits > tableLog) tableLog = minBits;   /* Need a minimum to safely represent all symbol values */
3540c16b537SWarner Losh     if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;
3550c16b537SWarner Losh     if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;
3560c16b537SWarner Losh     return tableLog;
3570c16b537SWarner Losh }
3580c16b537SWarner Losh 
3590c16b537SWarner Losh unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
3600c16b537SWarner Losh {
3610c16b537SWarner Losh     return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
3620c16b537SWarner Losh }
3630c16b537SWarner Losh 
3640c16b537SWarner Losh 
3650c16b537SWarner Losh /* Secondary normalization method.
3660c16b537SWarner Losh    To be used when primary method fails. */
3670c16b537SWarner Losh 
3680c16b537SWarner Losh static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
3690c16b537SWarner Losh {
3700c16b537SWarner Losh     short const NOT_YET_ASSIGNED = -2;
3710c16b537SWarner Losh     U32 s;
3720c16b537SWarner Losh     U32 distributed = 0;
3730c16b537SWarner Losh     U32 ToDistribute;
3740c16b537SWarner Losh 
3750c16b537SWarner Losh     /* Init */
3760c16b537SWarner Losh     U32 const lowThreshold = (U32)(total >> tableLog);
3770c16b537SWarner Losh     U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
3780c16b537SWarner Losh 
3790c16b537SWarner Losh     for (s=0; s<=maxSymbolValue; s++) {
3800c16b537SWarner Losh         if (count[s] == 0) {
3810c16b537SWarner Losh             norm[s]=0;
3820c16b537SWarner Losh             continue;
3830c16b537SWarner Losh         }
3840c16b537SWarner Losh         if (count[s] <= lowThreshold) {
3850c16b537SWarner Losh             norm[s] = -1;
3860c16b537SWarner Losh             distributed++;
3870c16b537SWarner Losh             total -= count[s];
3880c16b537SWarner Losh             continue;
3890c16b537SWarner Losh         }
3900c16b537SWarner Losh         if (count[s] <= lowOne) {
3910c16b537SWarner Losh             norm[s] = 1;
3920c16b537SWarner Losh             distributed++;
3930c16b537SWarner Losh             total -= count[s];
3940c16b537SWarner Losh             continue;
3950c16b537SWarner Losh         }
3960c16b537SWarner Losh 
3970c16b537SWarner Losh         norm[s]=NOT_YET_ASSIGNED;
3980c16b537SWarner Losh     }
3990c16b537SWarner Losh     ToDistribute = (1 << tableLog) - distributed;
4000c16b537SWarner Losh 
4010f743729SConrad Meyer     if (ToDistribute == 0)
4020f743729SConrad Meyer         return 0;
4030f743729SConrad Meyer 
4040c16b537SWarner Losh     if ((total / ToDistribute) > lowOne) {
4050c16b537SWarner Losh         /* risk of rounding to zero */
4060c16b537SWarner Losh         lowOne = (U32)((total * 3) / (ToDistribute * 2));
4070c16b537SWarner Losh         for (s=0; s<=maxSymbolValue; s++) {
4080c16b537SWarner Losh             if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
4090c16b537SWarner Losh                 norm[s] = 1;
4100c16b537SWarner Losh                 distributed++;
4110c16b537SWarner Losh                 total -= count[s];
4120c16b537SWarner Losh                 continue;
4130c16b537SWarner Losh         }   }
4140c16b537SWarner Losh         ToDistribute = (1 << tableLog) - distributed;
4150c16b537SWarner Losh     }
4160c16b537SWarner Losh 
4170c16b537SWarner Losh     if (distributed == maxSymbolValue+1) {
4180c16b537SWarner Losh         /* all values are pretty poor;
4190c16b537SWarner Losh            probably incompressible data (should have already been detected);
4200c16b537SWarner Losh            find max, then give all remaining points to max */
4210c16b537SWarner Losh         U32 maxV = 0, maxC = 0;
4220c16b537SWarner Losh         for (s=0; s<=maxSymbolValue; s++)
42319fcbaf1SConrad Meyer             if (count[s] > maxC) { maxV=s; maxC=count[s]; }
4240c16b537SWarner Losh         norm[maxV] += (short)ToDistribute;
4250c16b537SWarner Losh         return 0;
4260c16b537SWarner Losh     }
4270c16b537SWarner Losh 
4280c16b537SWarner Losh     if (total == 0) {
4290c16b537SWarner Losh         /* all of the symbols were low enough for the lowOne or lowThreshold */
4300c16b537SWarner Losh         for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
43119fcbaf1SConrad Meyer             if (norm[s] > 0) { ToDistribute--; norm[s]++; }
4320c16b537SWarner Losh         return 0;
4330c16b537SWarner Losh     }
4340c16b537SWarner Losh 
4350c16b537SWarner Losh     {   U64 const vStepLog = 62 - tableLog;
4360c16b537SWarner Losh         U64 const mid = (1ULL << (vStepLog-1)) - 1;
4370c16b537SWarner Losh         U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total;   /* scale on remaining */
4380c16b537SWarner Losh         U64 tmpTotal = mid;
4390c16b537SWarner Losh         for (s=0; s<=maxSymbolValue; s++) {
4400c16b537SWarner Losh             if (norm[s]==NOT_YET_ASSIGNED) {
4410c16b537SWarner Losh                 U64 const end = tmpTotal + (count[s] * rStep);
4420c16b537SWarner Losh                 U32 const sStart = (U32)(tmpTotal >> vStepLog);
4430c16b537SWarner Losh                 U32 const sEnd = (U32)(end >> vStepLog);
4440c16b537SWarner Losh                 U32 const weight = sEnd - sStart;
4450c16b537SWarner Losh                 if (weight < 1)
4460c16b537SWarner Losh                     return ERROR(GENERIC);
4470c16b537SWarner Losh                 norm[s] = (short)weight;
4480c16b537SWarner Losh                 tmpTotal = end;
4490c16b537SWarner Losh     }   }   }
4500c16b537SWarner Losh 
4510c16b537SWarner Losh     return 0;
4520c16b537SWarner Losh }
4530c16b537SWarner Losh 
4540c16b537SWarner Losh 
4550c16b537SWarner Losh size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
4560c16b537SWarner Losh                            const unsigned* count, size_t total,
4570c16b537SWarner Losh                            unsigned maxSymbolValue)
4580c16b537SWarner Losh {
4590c16b537SWarner Losh     /* Sanity checks */
4600c16b537SWarner Losh     if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
4610c16b537SWarner Losh     if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC);   /* Unsupported size */
4620c16b537SWarner Losh     if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);   /* Unsupported size */
4630c16b537SWarner Losh     if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC);   /* Too small tableLog, compression potentially impossible */
4640c16b537SWarner Losh 
4650c16b537SWarner Losh     {   static U32 const rtbTable[] = {     0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
4660c16b537SWarner Losh         U64 const scale = 62 - tableLog;
4670c16b537SWarner Losh         U64 const step = ((U64)1<<62) / total;   /* <== here, one division ! */
4680c16b537SWarner Losh         U64 const vStep = 1ULL<<(scale-20);
4690c16b537SWarner Losh         int stillToDistribute = 1<<tableLog;
4700c16b537SWarner Losh         unsigned s;
4710c16b537SWarner Losh         unsigned largest=0;
4720c16b537SWarner Losh         short largestP=0;
4730c16b537SWarner Losh         U32 lowThreshold = (U32)(total >> tableLog);
4740c16b537SWarner Losh 
4750c16b537SWarner Losh         for (s=0; s<=maxSymbolValue; s++) {
4760c16b537SWarner Losh             if (count[s] == total) return 0;   /* rle special case */
4770c16b537SWarner Losh             if (count[s] == 0) { normalizedCounter[s]=0; continue; }
4780c16b537SWarner Losh             if (count[s] <= lowThreshold) {
4790c16b537SWarner Losh                 normalizedCounter[s] = -1;
4800c16b537SWarner Losh                 stillToDistribute--;
4810c16b537SWarner Losh             } else {
4820c16b537SWarner Losh                 short proba = (short)((count[s]*step) >> scale);
4830c16b537SWarner Losh                 if (proba<8) {
4840c16b537SWarner Losh                     U64 restToBeat = vStep * rtbTable[proba];
4850c16b537SWarner Losh                     proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
4860c16b537SWarner Losh                 }
48719fcbaf1SConrad Meyer                 if (proba > largestP) { largestP=proba; largest=s; }
4880c16b537SWarner Losh                 normalizedCounter[s] = proba;
4890c16b537SWarner Losh                 stillToDistribute -= proba;
4900c16b537SWarner Losh         }   }
4910c16b537SWarner Losh         if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
4920c16b537SWarner Losh             /* corner case, need another normalization method */
4930c16b537SWarner Losh             size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
4940c16b537SWarner Losh             if (FSE_isError(errorCode)) return errorCode;
4950c16b537SWarner Losh         }
4960c16b537SWarner Losh         else normalizedCounter[largest] += (short)stillToDistribute;
4970c16b537SWarner Losh     }
4980c16b537SWarner Losh 
4990c16b537SWarner Losh #if 0
5000c16b537SWarner Losh     {   /* Print Table (debug) */
5010c16b537SWarner Losh         U32 s;
5020c16b537SWarner Losh         U32 nTotal = 0;
5030c16b537SWarner Losh         for (s=0; s<=maxSymbolValue; s++)
5040f743729SConrad Meyer             RAWLOG(2, "%3i: %4i \n", s, normalizedCounter[s]);
5050c16b537SWarner Losh         for (s=0; s<=maxSymbolValue; s++)
5060c16b537SWarner Losh             nTotal += abs(normalizedCounter[s]);
5070c16b537SWarner Losh         if (nTotal != (1U<<tableLog))
5080f743729SConrad Meyer             RAWLOG(2, "Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
5090c16b537SWarner Losh         getchar();
5100c16b537SWarner Losh     }
5110c16b537SWarner Losh #endif
5120c16b537SWarner Losh 
5130c16b537SWarner Losh     return tableLog;
5140c16b537SWarner Losh }
5150c16b537SWarner Losh 
5160c16b537SWarner Losh 
5170c16b537SWarner Losh /* fake FSE_CTable, for raw (uncompressed) input */
5180c16b537SWarner Losh size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits)
5190c16b537SWarner Losh {
5200c16b537SWarner Losh     const unsigned tableSize = 1 << nbBits;
5210c16b537SWarner Losh     const unsigned tableMask = tableSize - 1;
5220c16b537SWarner Losh     const unsigned maxSymbolValue = tableMask;
5230c16b537SWarner Losh     void* const ptr = ct;
5240c16b537SWarner Losh     U16* const tableU16 = ( (U16*) ptr) + 2;
5250c16b537SWarner Losh     void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1);   /* assumption : tableLog >= 1 */
5260c16b537SWarner Losh     FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
5270c16b537SWarner Losh     unsigned s;
5280c16b537SWarner Losh 
5290c16b537SWarner Losh     /* Sanity checks */
5300c16b537SWarner Losh     if (nbBits < 1) return ERROR(GENERIC);             /* min size */
5310c16b537SWarner Losh 
5320c16b537SWarner Losh     /* header */
5330c16b537SWarner Losh     tableU16[-2] = (U16) nbBits;
5340c16b537SWarner Losh     tableU16[-1] = (U16) maxSymbolValue;
5350c16b537SWarner Losh 
5360c16b537SWarner Losh     /* Build table */
5370c16b537SWarner Losh     for (s=0; s<tableSize; s++)
5380c16b537SWarner Losh         tableU16[s] = (U16)(tableSize + s);
5390c16b537SWarner Losh 
5400c16b537SWarner Losh     /* Build Symbol Transformation Table */
5410c16b537SWarner Losh     {   const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
5420c16b537SWarner Losh         for (s=0; s<=maxSymbolValue; s++) {
5430c16b537SWarner Losh             symbolTT[s].deltaNbBits = deltaNbBits;
5440c16b537SWarner Losh             symbolTT[s].deltaFindState = s-1;
5450c16b537SWarner Losh     }   }
5460c16b537SWarner Losh 
5470c16b537SWarner Losh     return 0;
5480c16b537SWarner Losh }
5490c16b537SWarner Losh 
5500c16b537SWarner Losh /* fake FSE_CTable, for rle input (always same symbol) */
5510c16b537SWarner Losh size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
5520c16b537SWarner Losh {
5530c16b537SWarner Losh     void* ptr = ct;
5540c16b537SWarner Losh     U16* tableU16 = ( (U16*) ptr) + 2;
5550c16b537SWarner Losh     void* FSCTptr = (U32*)ptr + 2;
5560c16b537SWarner Losh     FSE_symbolCompressionTransform* symbolTT = (FSE_symbolCompressionTransform*) FSCTptr;
5570c16b537SWarner Losh 
5580c16b537SWarner Losh     /* header */
5590c16b537SWarner Losh     tableU16[-2] = (U16) 0;
5600c16b537SWarner Losh     tableU16[-1] = (U16) symbolValue;
5610c16b537SWarner Losh 
5620c16b537SWarner Losh     /* Build table */
5630c16b537SWarner Losh     tableU16[0] = 0;
5640c16b537SWarner Losh     tableU16[1] = 0;   /* just in case */
5650c16b537SWarner Losh 
5660c16b537SWarner Losh     /* Build Symbol Transformation Table */
5670c16b537SWarner Losh     symbolTT[symbolValue].deltaNbBits = 0;
5680c16b537SWarner Losh     symbolTT[symbolValue].deltaFindState = 0;
5690c16b537SWarner Losh 
5700c16b537SWarner Losh     return 0;
5710c16b537SWarner Losh }
5720c16b537SWarner Losh 
5730c16b537SWarner Losh 
5740c16b537SWarner Losh static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,
5750c16b537SWarner Losh                            const void* src, size_t srcSize,
5760c16b537SWarner Losh                            const FSE_CTable* ct, const unsigned fast)
5770c16b537SWarner Losh {
5780c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) src;
5790c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
5800c16b537SWarner Losh     const BYTE* ip=iend;
5810c16b537SWarner Losh 
5820c16b537SWarner Losh     BIT_CStream_t bitC;
5830c16b537SWarner Losh     FSE_CState_t CState1, CState2;
5840c16b537SWarner Losh 
5850c16b537SWarner Losh     /* init */
5860c16b537SWarner Losh     if (srcSize <= 2) return 0;
5870c16b537SWarner Losh     { size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
5880c16b537SWarner Losh       if (FSE_isError(initError)) return 0; /* not enough space available to write a bitstream */ }
5890c16b537SWarner Losh 
5900c16b537SWarner Losh #define FSE_FLUSHBITS(s)  (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
5910c16b537SWarner Losh 
5920c16b537SWarner Losh     if (srcSize & 1) {
5930c16b537SWarner Losh         FSE_initCState2(&CState1, ct, *--ip);
5940c16b537SWarner Losh         FSE_initCState2(&CState2, ct, *--ip);
5950c16b537SWarner Losh         FSE_encodeSymbol(&bitC, &CState1, *--ip);
5960c16b537SWarner Losh         FSE_FLUSHBITS(&bitC);
5970c16b537SWarner Losh     } else {
5980c16b537SWarner Losh         FSE_initCState2(&CState2, ct, *--ip);
5990c16b537SWarner Losh         FSE_initCState2(&CState1, ct, *--ip);
6000c16b537SWarner Losh     }
6010c16b537SWarner Losh 
6020c16b537SWarner Losh     /* join to mod 4 */
6030c16b537SWarner Losh     srcSize -= 2;
6040c16b537SWarner Losh     if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) {  /* test bit 2 */
6050c16b537SWarner Losh         FSE_encodeSymbol(&bitC, &CState2, *--ip);
6060c16b537SWarner Losh         FSE_encodeSymbol(&bitC, &CState1, *--ip);
6070c16b537SWarner Losh         FSE_FLUSHBITS(&bitC);
6080c16b537SWarner Losh     }
6090c16b537SWarner Losh 
6100c16b537SWarner Losh     /* 2 or 4 encoding per loop */
6110c16b537SWarner Losh     while ( ip>istart ) {
6120c16b537SWarner Losh 
6130c16b537SWarner Losh         FSE_encodeSymbol(&bitC, &CState2, *--ip);
6140c16b537SWarner Losh 
6150c16b537SWarner Losh         if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 )   /* this test must be static */
6160c16b537SWarner Losh             FSE_FLUSHBITS(&bitC);
6170c16b537SWarner Losh 
6180c16b537SWarner Losh         FSE_encodeSymbol(&bitC, &CState1, *--ip);
6190c16b537SWarner Losh 
6200c16b537SWarner Losh         if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) {  /* this test must be static */
6210c16b537SWarner Losh             FSE_encodeSymbol(&bitC, &CState2, *--ip);
6220c16b537SWarner Losh             FSE_encodeSymbol(&bitC, &CState1, *--ip);
6230c16b537SWarner Losh         }
6240c16b537SWarner Losh 
6250c16b537SWarner Losh         FSE_FLUSHBITS(&bitC);
6260c16b537SWarner Losh     }
6270c16b537SWarner Losh 
6280c16b537SWarner Losh     FSE_flushCState(&bitC, &CState2);
6290c16b537SWarner Losh     FSE_flushCState(&bitC, &CState1);
6300c16b537SWarner Losh     return BIT_closeCStream(&bitC);
6310c16b537SWarner Losh }
6320c16b537SWarner Losh 
6330c16b537SWarner Losh size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
6340c16b537SWarner Losh                            const void* src, size_t srcSize,
6350c16b537SWarner Losh                            const FSE_CTable* ct)
6360c16b537SWarner Losh {
6370c16b537SWarner Losh     unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
6380c16b537SWarner Losh 
6390c16b537SWarner Losh     if (fast)
6400c16b537SWarner Losh         return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
6410c16b537SWarner Losh     else
6420c16b537SWarner Losh         return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
6430c16b537SWarner Losh }
6440c16b537SWarner Losh 
6450c16b537SWarner Losh 
6460c16b537SWarner Losh size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
6470c16b537SWarner Losh 
6480c16b537SWarner Losh #define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
6490c16b537SWarner Losh #define CHECK_F(f)   { CHECK_V_F(_var_err__, f); }
6500c16b537SWarner Losh 
6510c16b537SWarner Losh /* FSE_compress_wksp() :
6520c16b537SWarner Losh  * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
6530c16b537SWarner Losh  * `wkspSize` size must be `(1<<tableLog)`.
6540c16b537SWarner Losh  */
6550c16b537SWarner Losh 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)
6560c16b537SWarner Losh {
6570c16b537SWarner Losh     BYTE* const ostart = (BYTE*) dst;
6580c16b537SWarner Losh     BYTE* op = ostart;
6590c16b537SWarner Losh     BYTE* const oend = ostart + dstSize;
6600c16b537SWarner Losh 
661*a0483764SConrad Meyer     unsigned count[FSE_MAX_SYMBOL_VALUE+1];
6620c16b537SWarner Losh     S16   norm[FSE_MAX_SYMBOL_VALUE+1];
6630c16b537SWarner Losh     FSE_CTable* CTable = (FSE_CTable*)workSpace;
6640c16b537SWarner Losh     size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);
6650c16b537SWarner Losh     void* scratchBuffer = (void*)(CTable + CTableSize);
6660c16b537SWarner Losh     size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));
6670c16b537SWarner Losh 
6680c16b537SWarner Losh     /* init conditions */
6690c16b537SWarner Losh     if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
6700c16b537SWarner Losh     if (srcSize <= 1) return 0;  /* Not compressible */
6710c16b537SWarner Losh     if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
6720c16b537SWarner Losh     if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
6730c16b537SWarner Losh 
6740c16b537SWarner Losh     /* Scan input and build symbol stats */
675*a0483764SConrad Meyer     {   CHECK_V_F(maxCount, HIST_count_wksp(count, &maxSymbolValue, src, srcSize, scratchBuffer, scratchBufferSize) );
6760c16b537SWarner Losh         if (maxCount == srcSize) return 1;   /* only a single symbol in src : rle */
6770c16b537SWarner Losh         if (maxCount == 1) return 0;         /* each symbol present maximum once => not compressible */
6780c16b537SWarner Losh         if (maxCount < (srcSize >> 7)) return 0;   /* Heuristic : not compressible enough */
6790c16b537SWarner Losh     }
6800c16b537SWarner Losh 
6810c16b537SWarner Losh     tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
6820c16b537SWarner Losh     CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
6830c16b537SWarner Losh 
6840c16b537SWarner Losh     /* Write table description header */
6850c16b537SWarner Losh     {   CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
6860c16b537SWarner Losh         op += nc_err;
6870c16b537SWarner Losh     }
6880c16b537SWarner Losh 
6890c16b537SWarner Losh     /* Compress */
6900c16b537SWarner Losh     CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );
6910c16b537SWarner Losh     {   CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );
6920c16b537SWarner Losh         if (cSize == 0) return 0;   /* not enough space for compressed data */
6930c16b537SWarner Losh         op += cSize;
6940c16b537SWarner Losh     }
6950c16b537SWarner Losh 
6960c16b537SWarner Losh     /* check compressibility */
6970c16b537SWarner Losh     if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;
6980c16b537SWarner Losh 
6990c16b537SWarner Losh     return op-ostart;
7000c16b537SWarner Losh }
7010c16b537SWarner Losh 
7020c16b537SWarner Losh typedef struct {
7030c16b537SWarner Losh     FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
7040c16b537SWarner Losh     BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];
7050c16b537SWarner Losh } fseWkspMax_t;
7060c16b537SWarner Losh 
7070c16b537SWarner Losh size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
7080c16b537SWarner Losh {
7090c16b537SWarner Losh     fseWkspMax_t scratchBuffer;
7100f743729SConrad Meyer     DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE));   /* compilation failures here means scratchBuffer is not large enough */
7110c16b537SWarner Losh     if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
7120c16b537SWarner Losh     return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));
7130c16b537SWarner Losh }
7140c16b537SWarner Losh 
7150c16b537SWarner Losh size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
7160c16b537SWarner Losh {
7170c16b537SWarner Losh     return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);
7180c16b537SWarner Losh }
7190c16b537SWarner Losh 
7200c16b537SWarner Losh 
7210c16b537SWarner Losh #endif   /* FSE_COMMONDEFS_ONLY */
722