Path: blob/main/sys/contrib/openzfs/module/zstd/lib/compress/fse_compress.c
48774 views
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only1/* ******************************************************************2* FSE : Finite State Entropy encoder3* Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.4*5* You can contact the author at :6* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy7* - Public forum : https://groups.google.com/forum/#!forum/lz4c8*9* This source code is licensed under both the BSD-style license (found in the10* LICENSE file in the root directory of this source tree) and the GPLv2 (found11* in the COPYING file in the root directory of this source tree).12* You may select, at your option, one of the above-listed licenses.13****************************************************************** */1415/* **************************************************************16* Includes17****************************************************************/18#include <stdlib.h> /* malloc, free, qsort */19#include <string.h> /* memcpy, memset */20#include "../common/compiler.h"21#include "../common/mem.h" /* U32, U16, etc. */22#include "../common/debug.h" /* assert, DEBUGLOG */23#include "hist.h" /* HIST_count_wksp */24#include "../common/bitstream.h"25#define FSE_STATIC_LINKING_ONLY26#include "../common/fse.h"27#include "../common/error_private.h"282930/* **************************************************************31* Error Management32****************************************************************/33#define FSE_isError ERR_isError343536/* **************************************************************37* Templates38****************************************************************/39/*40designed to be included41for type-specific functions (template emulation in C)42Objective is to write these functions only once, for improved maintenance43*/4445/* safety checks */46#ifndef FSE_FUNCTION_EXTENSION47# error "FSE_FUNCTION_EXTENSION must be defined"48#endif49#ifndef FSE_FUNCTION_TYPE50# error "FSE_FUNCTION_TYPE must be defined"51#endif5253/* Function names */54#define FSE_CAT(X,Y) X##Y55#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)56#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)575859/* Function templates */6061/* FSE_buildCTable_wksp() :62* Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).63* wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`64* workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements65*/66size_t FSE_buildCTable_wksp(FSE_CTable* ct,67const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,68void* workSpace, size_t wkspSize)69{70U32 const tableSize = 1 << tableLog;71U32 const tableMask = tableSize - 1;72void* const ptr = ct;73U16* const tableU16 = ( (U16*) ptr) + 2;74void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;75FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);76U32 const step = FSE_TABLESTEP(tableSize);77U32 cumul[FSE_MAX_SYMBOL_VALUE+2];7879FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;80U32 highThreshold = tableSize-1;8182/* CTable header */83if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);84tableU16[-2] = (U16) tableLog;85tableU16[-1] = (U16) maxSymbolValue;86assert(tableLog < 16); /* required for threshold strategy to work */8788/* For explanations on how to distribute symbol values over the table :89* http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */9091#ifdef __clang_analyzer__92memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */93#endif9495/* symbol start positions */96{ U32 u;97cumul[0] = 0;98for (u=1; u <= maxSymbolValue+1; u++) {99if (normalizedCounter[u-1]==-1) { /* Low proba symbol */100cumul[u] = cumul[u-1] + 1;101tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);102} else {103cumul[u] = cumul[u-1] + normalizedCounter[u-1];104} }105cumul[maxSymbolValue+1] = tableSize+1;106}107108/* Spread symbols */109{ U32 position = 0;110U32 symbol;111for (symbol=0; symbol<=maxSymbolValue; symbol++) {112int nbOccurrences;113int const freq = normalizedCounter[symbol];114for (nbOccurrences=0; nbOccurrences<freq; nbOccurrences++) {115tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;116position = (position + step) & tableMask;117while (position > highThreshold)118position = (position + step) & tableMask; /* Low proba area */119} }120121assert(position==0); /* Must have initialized all positions */122}123124/* Build table */125{ U32 u; for (u=0; u<tableSize; u++) {126FSE_FUNCTION_TYPE s = tableSymbol[u]; /* note : static analyzer may not understand tableSymbol is properly initialized */127tableU16[cumul[s]++] = (U16) (tableSize+u); /* TableU16 : sorted by symbol order; gives next state value */128} }129130/* Build Symbol Transformation Table */131{ unsigned total = 0;132unsigned s;133for (s=0; s<=maxSymbolValue; s++) {134switch (normalizedCounter[s])135{136case 0:137/* filling nonetheless, for compatibility with FSE_getMaxNbBits() */138symbolTT[s].deltaNbBits = ((tableLog+1) << 16) - (1<<tableLog);139break;140141case -1:142case 1:143symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);144symbolTT[s].deltaFindState = total - 1;145total ++;146break;147default :148{149U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);150U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;151symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;152symbolTT[s].deltaFindState = total - normalizedCounter[s];153total += normalizedCounter[s];154} } } }155156#if 0 /* debug : symbol costs */157DEBUGLOG(5, "\n --- table statistics : ");158{ U32 symbol;159for (symbol=0; symbol<=maxSymbolValue; symbol++) {160DEBUGLOG(5, "%3u: w=%3i, maxBits=%u, fracBits=%.2f",161symbol, normalizedCounter[symbol],162FSE_getMaxNbBits(symbolTT, symbol),163(double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256);164}165}166#endif167168return 0;169}170171172size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)173{174FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */175return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));176}177178179180#ifndef FSE_COMMONDEFS_ONLY181182183/*-**************************************************************184* FSE NCount encoding185****************************************************************/186size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)187{188size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;189return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */190}191192static size_t193FSE_writeNCount_generic (void* header, size_t headerBufferSize,194const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,195unsigned writeIsSafe)196{197BYTE* const ostart = (BYTE*) header;198BYTE* out = ostart;199BYTE* const oend = ostart + headerBufferSize;200int nbBits;201const int tableSize = 1 << tableLog;202int remaining;203int threshold;204U32 bitStream = 0;205int bitCount = 0;206unsigned symbol = 0;207unsigned const alphabetSize = maxSymbolValue + 1;208int previousIs0 = 0;209210/* Table Size */211bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;212bitCount += 4;213214/* Init */215remaining = tableSize+1; /* +1 for extra accuracy */216threshold = tableSize;217nbBits = tableLog+1;218219while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */220if (previousIs0) {221unsigned start = symbol;222while ((symbol < alphabetSize) && !normalizedCounter[symbol]) symbol++;223if (symbol == alphabetSize) break; /* incorrect distribution */224while (symbol >= start+24) {225start+=24;226bitStream += 0xFFFFU << bitCount;227if ((!writeIsSafe) && (out > oend-2))228return ERROR(dstSize_tooSmall); /* Buffer overflow */229out[0] = (BYTE) bitStream;230out[1] = (BYTE)(bitStream>>8);231out+=2;232bitStream>>=16;233}234while (symbol >= start+3) {235start+=3;236bitStream += 3 << bitCount;237bitCount += 2;238}239bitStream += (symbol-start) << bitCount;240bitCount += 2;241if (bitCount>16) {242if ((!writeIsSafe) && (out > oend - 2))243return ERROR(dstSize_tooSmall); /* Buffer overflow */244out[0] = (BYTE)bitStream;245out[1] = (BYTE)(bitStream>>8);246out += 2;247bitStream >>= 16;248bitCount -= 16;249} }250{ int count = normalizedCounter[symbol++];251int const max = (2*threshold-1) - remaining;252remaining -= count < 0 ? -count : count;253count++; /* +1 for extra accuracy */254if (count>=threshold)255count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */256bitStream += count << bitCount;257bitCount += nbBits;258bitCount -= (count<max);259previousIs0 = (count==1);260if (remaining<1) return ERROR(GENERIC);261while (remaining<threshold) { nbBits--; threshold>>=1; }262}263if (bitCount>16) {264if ((!writeIsSafe) && (out > oend - 2))265return ERROR(dstSize_tooSmall); /* Buffer overflow */266out[0] = (BYTE)bitStream;267out[1] = (BYTE)(bitStream>>8);268out += 2;269bitStream >>= 16;270bitCount -= 16;271} }272273if (remaining != 1)274return ERROR(GENERIC); /* incorrect normalized distribution */275assert(symbol <= alphabetSize);276277/* flush remaining bitStream */278if ((!writeIsSafe) && (out > oend - 2))279return ERROR(dstSize_tooSmall); /* Buffer overflow */280out[0] = (BYTE)bitStream;281out[1] = (BYTE)(bitStream>>8);282out+= (bitCount+7) /8;283284return (out-ostart);285}286287288size_t FSE_writeNCount (void* buffer, size_t bufferSize,289const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)290{291if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported */292if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported */293294if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))295return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);296297return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1 /* write in buffer is safe */);298}299300301/*-**************************************************************302* FSE Compression Code303****************************************************************/304305FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)306{307size_t size __attribute__ ((unused));308if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;309size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);310return (FSE_CTable*)malloc(size);311}312313void FSE_freeCTable (FSE_CTable* ct) { free(ct); }314315/* provides the minimum logSize to safely represent a distribution */316static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)317{318U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1;319U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;320U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;321assert(srcSize > 1); /* Not supported, RLE should be used instead */322return minBits;323}324325unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)326{327U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;328U32 tableLog = maxTableLog;329U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);330assert(srcSize > 1); /* Not supported, RLE should be used instead */331if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;332if (maxBitsSrc < tableLog) tableLog = maxBitsSrc; /* Accuracy can be reduced */333if (minBits > tableLog) tableLog = minBits; /* Need a minimum to safely represent all symbol values */334if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;335if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;336return tableLog;337}338339unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)340{341return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);342}343344345/* Secondary normalization method.346To be used when primary method fails. */347348static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)349{350short const NOT_YET_ASSIGNED = -2;351U32 s;352U32 distributed = 0;353U32 ToDistribute;354355/* Init */356U32 const lowThreshold = (U32)(total >> tableLog);357U32 lowOne = (U32)((total * 3) >> (tableLog + 1));358359for (s=0; s<=maxSymbolValue; s++) {360if (count[s] == 0) {361norm[s]=0;362continue;363}364if (count[s] <= lowThreshold) {365norm[s] = -1;366distributed++;367total -= count[s];368continue;369}370if (count[s] <= lowOne) {371norm[s] = 1;372distributed++;373total -= count[s];374continue;375}376377norm[s]=NOT_YET_ASSIGNED;378}379ToDistribute = (1 << tableLog) - distributed;380381if (ToDistribute == 0)382return 0;383384if ((total / ToDistribute) > lowOne) {385/* risk of rounding to zero */386lowOne = (U32)((total * 3) / (ToDistribute * 2));387for (s=0; s<=maxSymbolValue; s++) {388if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {389norm[s] = 1;390distributed++;391total -= count[s];392continue;393} }394ToDistribute = (1 << tableLog) - distributed;395}396397if (distributed == maxSymbolValue+1) {398/* all values are pretty poor;399probably incompressible data (should have already been detected);400find max, then give all remaining points to max */401U32 maxV = 0, maxC = 0;402for (s=0; s<=maxSymbolValue; s++)403if (count[s] > maxC) { maxV=s; maxC=count[s]; }404norm[maxV] += (short)ToDistribute;405return 0;406}407408if (total == 0) {409/* all of the symbols were low enough for the lowOne or lowThreshold */410for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))411if (norm[s] > 0) { ToDistribute--; norm[s]++; }412return 0;413}414415{ U64 const vStepLog = 62 - tableLog;416U64 const mid = (1ULL << (vStepLog-1)) - 1;417U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total; /* scale on remaining */418U64 tmpTotal = mid;419for (s=0; s<=maxSymbolValue; s++) {420if (norm[s]==NOT_YET_ASSIGNED) {421U64 const end = tmpTotal + (count[s] * rStep);422U32 const sStart = (U32)(tmpTotal >> vStepLog);423U32 const sEnd = (U32)(end >> vStepLog);424U32 const weight = sEnd - sStart;425if (weight < 1)426return ERROR(GENERIC);427norm[s] = (short)weight;428tmpTotal = end;429} } }430431return 0;432}433434435size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,436const unsigned* count, size_t total,437unsigned maxSymbolValue)438{439/* Sanity checks */440if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;441if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported size */442if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */443if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */444445{ static U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };446U64 const scale = 62 - tableLog;447U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */448U64 const vStep = 1ULL<<(scale-20);449int stillToDistribute = 1<<tableLog;450unsigned s;451unsigned largest=0;452short largestP=0;453U32 lowThreshold = (U32)(total >> tableLog);454455for (s=0; s<=maxSymbolValue; s++) {456if (count[s] == total) return 0; /* rle special case */457if (count[s] == 0) { normalizedCounter[s]=0; continue; }458if (count[s] <= lowThreshold) {459normalizedCounter[s] = -1;460stillToDistribute--;461} else {462short proba = (short)((count[s]*step) >> scale);463if (proba<8) {464U64 restToBeat = vStep * rtbTable[proba];465proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;466}467if (proba > largestP) { largestP=proba; largest=s; }468normalizedCounter[s] = proba;469stillToDistribute -= proba;470} }471if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {472/* corner case, need another normalization method */473size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);474if (FSE_isError(errorCode)) return errorCode;475}476else normalizedCounter[largest] += (short)stillToDistribute;477}478479#if 0480{ /* Print Table (debug) */481U32 s;482U32 nTotal = 0;483for (s=0; s<=maxSymbolValue; s++)484RAWLOG(2, "%3i: %4i \n", s, normalizedCounter[s]);485for (s=0; s<=maxSymbolValue; s++)486nTotal += abs(normalizedCounter[s]);487if (nTotal != (1U<<tableLog))488RAWLOG(2, "Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);489getchar();490}491#endif492493return tableLog;494}495496497/* fake FSE_CTable, for raw (uncompressed) input */498size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits)499{500const unsigned tableSize = 1 << nbBits;501const unsigned tableMask = tableSize - 1;502const unsigned maxSymbolValue = tableMask;503void* const ptr = ct;504U16* const tableU16 = ( (U16*) ptr) + 2;505void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */506FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);507unsigned s;508509/* Sanity checks */510if (nbBits < 1) return ERROR(GENERIC); /* min size */511512/* header */513tableU16[-2] = (U16) nbBits;514tableU16[-1] = (U16) maxSymbolValue;515516/* Build table */517for (s=0; s<tableSize; s++)518tableU16[s] = (U16)(tableSize + s);519520/* Build Symbol Transformation Table */521{ const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);522for (s=0; s<=maxSymbolValue; s++) {523symbolTT[s].deltaNbBits = deltaNbBits;524symbolTT[s].deltaFindState = s-1;525} }526527return 0;528}529530/* fake FSE_CTable, for rle input (always same symbol) */531size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)532{533void* ptr = ct;534U16* tableU16 = ( (U16*) ptr) + 2;535void* FSCTptr = (U32*)ptr + 2;536FSE_symbolCompressionTransform* symbolTT = (FSE_symbolCompressionTransform*) FSCTptr;537538/* header */539tableU16[-2] = (U16) 0;540tableU16[-1] = (U16) symbolValue;541542/* Build table */543tableU16[0] = 0;544tableU16[1] = 0; /* just in case */545546/* Build Symbol Transformation Table */547symbolTT[symbolValue].deltaNbBits = 0;548symbolTT[symbolValue].deltaFindState = 0;549550return 0;551}552553554static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,555const void* src, size_t srcSize,556const FSE_CTable* ct, const unsigned fast)557{558const BYTE* const istart = (const BYTE*) src;559const BYTE* const iend = istart + srcSize;560const BYTE* ip=iend;561562BIT_CStream_t bitC;563FSE_CState_t CState1, CState2;564565/* init */566if (srcSize <= 2) return 0;567{ size_t const initError = BIT_initCStream(&bitC, dst, dstSize);568if (FSE_isError(initError)) return 0; /* not enough space available to write a bitstream */ }569570#define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))571572if (srcSize & 1) {573FSE_initCState2(&CState1, ct, *--ip);574FSE_initCState2(&CState2, ct, *--ip);575FSE_encodeSymbol(&bitC, &CState1, *--ip);576FSE_FLUSHBITS(&bitC);577} else {578FSE_initCState2(&CState2, ct, *--ip);579FSE_initCState2(&CState1, ct, *--ip);580}581582/* join to mod 4 */583srcSize -= 2;584if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) { /* test bit 2 */585FSE_encodeSymbol(&bitC, &CState2, *--ip);586FSE_encodeSymbol(&bitC, &CState1, *--ip);587FSE_FLUSHBITS(&bitC);588}589590/* 2 or 4 encoding per loop */591while ( ip>istart ) {592593FSE_encodeSymbol(&bitC, &CState2, *--ip);594595if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 ) /* this test must be static */596FSE_FLUSHBITS(&bitC);597598FSE_encodeSymbol(&bitC, &CState1, *--ip);599600if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) { /* this test must be static */601FSE_encodeSymbol(&bitC, &CState2, *--ip);602FSE_encodeSymbol(&bitC, &CState1, *--ip);603}604605FSE_FLUSHBITS(&bitC);606}607608FSE_flushCState(&bitC, &CState2);609FSE_flushCState(&bitC, &CState1);610return BIT_closeCStream(&bitC);611}612613size_t FSE_compress_usingCTable (void* dst, size_t dstSize,614const void* src, size_t srcSize,615const FSE_CTable* ct)616{617unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));618619if (fast)620return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);621else622return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);623}624625626size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }627628/* FSE_compress_wksp() :629* Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).630* `wkspSize` size must be `(1<<tableLog)`.631*/632size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)633{634BYTE* const ostart = (BYTE*) dst;635BYTE* op = ostart;636BYTE* const oend = ostart + dstSize;637638unsigned count[FSE_MAX_SYMBOL_VALUE+1];639S16 norm[FSE_MAX_SYMBOL_VALUE+1];640FSE_CTable* CTable = (FSE_CTable*)workSpace;641size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);642void* scratchBuffer = (void*)(CTable + CTableSize);643size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));644645/* init conditions */646if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);647if (srcSize <= 1) return 0; /* Not compressible */648if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;649if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;650651/* Scan input and build symbol stats */652{ CHECK_V_F(maxCount, HIST_count_wksp(count, &maxSymbolValue, src, srcSize, scratchBuffer, scratchBufferSize) );653if (maxCount == srcSize) return 1; /* only a single symbol in src : rle */654if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */655if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */656}657658tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);659CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );660661/* Write table description header */662{ CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );663op += nc_err;664}665666/* Compress */667CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );668{ CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );669if (cSize == 0) return 0; /* not enough space for compressed data */670op += cSize;671}672673/* check compressibility */674if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;675676return op-ostart;677}678679typedef struct {680FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];681BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];682} fseWkspMax_t;683684size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)685{686fseWkspMax_t scratchBuffer;687DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */688if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);689return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));690}691692size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize)693{694return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);695}696697698#endif /* FSE_COMMONDEFS_ONLY */699700701