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