162306a36Sopenharmony_ci/* ****************************************************************** 262306a36Sopenharmony_ci * FSE : Finite State Entropy decoder 362306a36Sopenharmony_ci * Copyright (c) Yann Collet, Facebook, Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * You can contact the author at : 662306a36Sopenharmony_ci * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy 762306a36Sopenharmony_ci * - Public forum : https://groups.google.com/forum/#!forum/lz4c 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This source code is licensed under both the BSD-style license (found in the 1062306a36Sopenharmony_ci * LICENSE file in the root directory of this source tree) and the GPLv2 (found 1162306a36Sopenharmony_ci * in the COPYING file in the root directory of this source tree). 1262306a36Sopenharmony_ci * You may select, at your option, one of the above-listed licenses. 1362306a36Sopenharmony_ci****************************************************************** */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* ************************************************************** 1762306a36Sopenharmony_ci* Includes 1862306a36Sopenharmony_ci****************************************************************/ 1962306a36Sopenharmony_ci#include "debug.h" /* assert */ 2062306a36Sopenharmony_ci#include "bitstream.h" 2162306a36Sopenharmony_ci#include "compiler.h" 2262306a36Sopenharmony_ci#define FSE_STATIC_LINKING_ONLY 2362306a36Sopenharmony_ci#include "fse.h" 2462306a36Sopenharmony_ci#include "error_private.h" 2562306a36Sopenharmony_ci#define ZSTD_DEPS_NEED_MALLOC 2662306a36Sopenharmony_ci#include "zstd_deps.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* ************************************************************** 3062306a36Sopenharmony_ci* Error Management 3162306a36Sopenharmony_ci****************************************************************/ 3262306a36Sopenharmony_ci#define FSE_isError ERR_isError 3362306a36Sopenharmony_ci#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* ************************************************************** 3762306a36Sopenharmony_ci* Templates 3862306a36Sopenharmony_ci****************************************************************/ 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci designed to be included 4162306a36Sopenharmony_ci for type-specific functions (template emulation in C) 4262306a36Sopenharmony_ci Objective is to write these functions only once, for improved maintenance 4362306a36Sopenharmony_ci*/ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* safety checks */ 4662306a36Sopenharmony_ci#ifndef FSE_FUNCTION_EXTENSION 4762306a36Sopenharmony_ci# error "FSE_FUNCTION_EXTENSION must be defined" 4862306a36Sopenharmony_ci#endif 4962306a36Sopenharmony_ci#ifndef FSE_FUNCTION_TYPE 5062306a36Sopenharmony_ci# error "FSE_FUNCTION_TYPE must be defined" 5162306a36Sopenharmony_ci#endif 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Function names */ 5462306a36Sopenharmony_ci#define FSE_CAT(X,Y) X##Y 5562306a36Sopenharmony_ci#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) 5662306a36Sopenharmony_ci#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* Function templates */ 6062306a36Sopenharmony_ciFSE_DTable* FSE_createDTable (unsigned tableLog) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; 6362306a36Sopenharmony_ci return (FSE_DTable*)ZSTD_malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_civoid FSE_freeDTable (FSE_DTable* dt) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci ZSTD_free(dt); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ 7462306a36Sopenharmony_ci FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); 7562306a36Sopenharmony_ci U16* symbolNext = (U16*)workSpace; 7662306a36Sopenharmony_ci BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci U32 const maxSV1 = maxSymbolValue + 1; 7962306a36Sopenharmony_ci U32 const tableSize = 1 << tableLog; 8062306a36Sopenharmony_ci U32 highThreshold = tableSize-1; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Sanity Checks */ 8362306a36Sopenharmony_ci if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge); 8462306a36Sopenharmony_ci if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); 8562306a36Sopenharmony_ci if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Init, lay down lowprob symbols */ 8862306a36Sopenharmony_ci { FSE_DTableHeader DTableH; 8962306a36Sopenharmony_ci DTableH.tableLog = (U16)tableLog; 9062306a36Sopenharmony_ci DTableH.fastMode = 1; 9162306a36Sopenharmony_ci { S16 const largeLimit= (S16)(1 << (tableLog-1)); 9262306a36Sopenharmony_ci U32 s; 9362306a36Sopenharmony_ci for (s=0; s<maxSV1; s++) { 9462306a36Sopenharmony_ci if (normalizedCounter[s]==-1) { 9562306a36Sopenharmony_ci tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s; 9662306a36Sopenharmony_ci symbolNext[s] = 1; 9762306a36Sopenharmony_ci } else { 9862306a36Sopenharmony_ci if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0; 9962306a36Sopenharmony_ci symbolNext[s] = normalizedCounter[s]; 10062306a36Sopenharmony_ci } } } 10162306a36Sopenharmony_ci ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* Spread symbols */ 10562306a36Sopenharmony_ci if (highThreshold == tableSize - 1) { 10662306a36Sopenharmony_ci size_t const tableMask = tableSize-1; 10762306a36Sopenharmony_ci size_t const step = FSE_TABLESTEP(tableSize); 10862306a36Sopenharmony_ci /* First lay down the symbols in order. 10962306a36Sopenharmony_ci * We use a uint64_t to lay down 8 bytes at a time. This reduces branch 11062306a36Sopenharmony_ci * misses since small blocks generally have small table logs, so nearly 11162306a36Sopenharmony_ci * all symbols have counts <= 8. We ensure we have 8 bytes at the end of 11262306a36Sopenharmony_ci * our buffer to handle the over-write. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci { 11562306a36Sopenharmony_ci U64 const add = 0x0101010101010101ull; 11662306a36Sopenharmony_ci size_t pos = 0; 11762306a36Sopenharmony_ci U64 sv = 0; 11862306a36Sopenharmony_ci U32 s; 11962306a36Sopenharmony_ci for (s=0; s<maxSV1; ++s, sv += add) { 12062306a36Sopenharmony_ci int i; 12162306a36Sopenharmony_ci int const n = normalizedCounter[s]; 12262306a36Sopenharmony_ci MEM_write64(spread + pos, sv); 12362306a36Sopenharmony_ci for (i = 8; i < n; i += 8) { 12462306a36Sopenharmony_ci MEM_write64(spread + pos + i, sv); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci pos += n; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci /* Now we spread those positions across the table. 13062306a36Sopenharmony_ci * The benefit of doing it in two stages is that we avoid the the 13162306a36Sopenharmony_ci * variable size inner loop, which caused lots of branch misses. 13262306a36Sopenharmony_ci * Now we can run through all the positions without any branch misses. 13362306a36Sopenharmony_ci * We unroll the loop twice, since that is what emperically worked best. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci { 13662306a36Sopenharmony_ci size_t position = 0; 13762306a36Sopenharmony_ci size_t s; 13862306a36Sopenharmony_ci size_t const unroll = 2; 13962306a36Sopenharmony_ci assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ 14062306a36Sopenharmony_ci for (s = 0; s < (size_t)tableSize; s += unroll) { 14162306a36Sopenharmony_ci size_t u; 14262306a36Sopenharmony_ci for (u = 0; u < unroll; ++u) { 14362306a36Sopenharmony_ci size_t const uPosition = (position + (u * step)) & tableMask; 14462306a36Sopenharmony_ci tableDecode[uPosition].symbol = spread[s + u]; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci position = (position + (unroll * step)) & tableMask; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci assert(position == 0); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } else { 15162306a36Sopenharmony_ci U32 const tableMask = tableSize-1; 15262306a36Sopenharmony_ci U32 const step = FSE_TABLESTEP(tableSize); 15362306a36Sopenharmony_ci U32 s, position = 0; 15462306a36Sopenharmony_ci for (s=0; s<maxSV1; s++) { 15562306a36Sopenharmony_ci int i; 15662306a36Sopenharmony_ci for (i=0; i<normalizedCounter[s]; i++) { 15762306a36Sopenharmony_ci tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s; 15862306a36Sopenharmony_ci position = (position + step) & tableMask; 15962306a36Sopenharmony_ci while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */ 16062306a36Sopenharmony_ci } } 16162306a36Sopenharmony_ci if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Build Decoding table */ 16562306a36Sopenharmony_ci { U32 u; 16662306a36Sopenharmony_ci for (u=0; u<tableSize; u++) { 16762306a36Sopenharmony_ci FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol); 16862306a36Sopenharmony_ci U32 const nextState = symbolNext[symbol]++; 16962306a36Sopenharmony_ci tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) ); 17062306a36Sopenharmony_ci tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize); 17162306a36Sopenharmony_ci } } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cisize_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci return FSE_buildDTable_internal(dt, normalizedCounter, maxSymbolValue, tableLog, workSpace, wkspSize); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci#ifndef FSE_COMMONDEFS_ONLY 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/*-******************************************************* 18562306a36Sopenharmony_ci* Decompression (Byte symbols) 18662306a36Sopenharmony_ci*********************************************************/ 18762306a36Sopenharmony_cisize_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci void* ptr = dt; 19062306a36Sopenharmony_ci FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; 19162306a36Sopenharmony_ci void* dPtr = dt + 1; 19262306a36Sopenharmony_ci FSE_decode_t* const cell = (FSE_decode_t*)dPtr; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci DTableH->tableLog = 0; 19562306a36Sopenharmony_ci DTableH->fastMode = 0; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci cell->newState = 0; 19862306a36Sopenharmony_ci cell->symbol = symbolValue; 19962306a36Sopenharmony_ci cell->nbBits = 0; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cisize_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci void* ptr = dt; 20862306a36Sopenharmony_ci FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; 20962306a36Sopenharmony_ci void* dPtr = dt + 1; 21062306a36Sopenharmony_ci FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; 21162306a36Sopenharmony_ci const unsigned tableSize = 1 << nbBits; 21262306a36Sopenharmony_ci const unsigned tableMask = tableSize - 1; 21362306a36Sopenharmony_ci const unsigned maxSV1 = tableMask+1; 21462306a36Sopenharmony_ci unsigned s; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Sanity checks */ 21762306a36Sopenharmony_ci if (nbBits < 1) return ERROR(GENERIC); /* min size */ 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Build Decoding Table */ 22062306a36Sopenharmony_ci DTableH->tableLog = (U16)nbBits; 22162306a36Sopenharmony_ci DTableH->fastMode = 1; 22262306a36Sopenharmony_ci for (s=0; s<maxSV1; s++) { 22362306a36Sopenharmony_ci dinfo[s].newState = 0; 22462306a36Sopenharmony_ci dinfo[s].symbol = (BYTE)s; 22562306a36Sopenharmony_ci dinfo[s].nbBits = (BYTE)nbBits; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ciFORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic( 23262306a36Sopenharmony_ci void* dst, size_t maxDstSize, 23362306a36Sopenharmony_ci const void* cSrc, size_t cSrcSize, 23462306a36Sopenharmony_ci const FSE_DTable* dt, const unsigned fast) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci BYTE* const ostart = (BYTE*) dst; 23762306a36Sopenharmony_ci BYTE* op = ostart; 23862306a36Sopenharmony_ci BYTE* const omax = op + maxDstSize; 23962306a36Sopenharmony_ci BYTE* const olimit = omax-3; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci BIT_DStream_t bitD; 24262306a36Sopenharmony_ci FSE_DState_t state1; 24362306a36Sopenharmony_ci FSE_DState_t state2; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* Init */ 24662306a36Sopenharmony_ci CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize)); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci FSE_initDState(&state1, &bitD, dt); 24962306a36Sopenharmony_ci FSE_initDState(&state2, &bitD, dt); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD) 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 4 symbols per loop */ 25462306a36Sopenharmony_ci for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) { 25562306a36Sopenharmony_ci op[0] = FSE_GETSYMBOL(&state1); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ 25862306a36Sopenharmony_ci BIT_reloadDStream(&bitD); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci op[1] = FSE_GETSYMBOL(&state2); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ 26362306a36Sopenharmony_ci { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci op[2] = FSE_GETSYMBOL(&state1); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ 26862306a36Sopenharmony_ci BIT_reloadDStream(&bitD); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci op[3] = FSE_GETSYMBOL(&state2); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* tail */ 27462306a36Sopenharmony_ci /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ 27562306a36Sopenharmony_ci while (1) { 27662306a36Sopenharmony_ci if (op>(omax-2)) return ERROR(dstSize_tooSmall); 27762306a36Sopenharmony_ci *op++ = FSE_GETSYMBOL(&state1); 27862306a36Sopenharmony_ci if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { 27962306a36Sopenharmony_ci *op++ = FSE_GETSYMBOL(&state2); 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (op>(omax-2)) return ERROR(dstSize_tooSmall); 28462306a36Sopenharmony_ci *op++ = FSE_GETSYMBOL(&state2); 28562306a36Sopenharmony_ci if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { 28662306a36Sopenharmony_ci *op++ = FSE_GETSYMBOL(&state1); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci } } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return op-ostart; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cisize_t FSE_decompress_usingDTable(void* dst, size_t originalSize, 29562306a36Sopenharmony_ci const void* cSrc, size_t cSrcSize, 29662306a36Sopenharmony_ci const FSE_DTable* dt) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci const void* ptr = dt; 29962306a36Sopenharmony_ci const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; 30062306a36Sopenharmony_ci const U32 fastMode = DTableH->fastMode; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* select fast mode (static) */ 30362306a36Sopenharmony_ci if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); 30462306a36Sopenharmony_ci return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cisize_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci return FSE_decompress_wksp_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, /* bmi2 */ 0); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_citypedef struct { 31462306a36Sopenharmony_ci short ncount[FSE_MAX_SYMBOL_VALUE + 1]; 31562306a36Sopenharmony_ci FSE_DTable dtable[]; /* Dynamically sized */ 31662306a36Sopenharmony_ci} FSE_DecompressWksp; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ciFORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body( 32062306a36Sopenharmony_ci void* dst, size_t dstCapacity, 32162306a36Sopenharmony_ci const void* cSrc, size_t cSrcSize, 32262306a36Sopenharmony_ci unsigned maxLog, void* workSpace, size_t wkspSize, 32362306a36Sopenharmony_ci int bmi2) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci const BYTE* const istart = (const BYTE*)cSrc; 32662306a36Sopenharmony_ci const BYTE* ip = istart; 32762306a36Sopenharmony_ci unsigned tableLog; 32862306a36Sopenharmony_ci unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; 32962306a36Sopenharmony_ci FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0); 33262306a36Sopenharmony_ci if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* normal FSE decoding mode */ 33562306a36Sopenharmony_ci { 33662306a36Sopenharmony_ci size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2); 33762306a36Sopenharmony_ci if (FSE_isError(NCountLength)) return NCountLength; 33862306a36Sopenharmony_ci if (tableLog > maxLog) return ERROR(tableLog_tooLarge); 33962306a36Sopenharmony_ci assert(NCountLength <= cSrcSize); 34062306a36Sopenharmony_ci ip += NCountLength; 34162306a36Sopenharmony_ci cSrcSize -= NCountLength; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge); 34562306a36Sopenharmony_ci workSpace = wksp->dtable + FSE_DTABLE_SIZE_U32(tableLog); 34662306a36Sopenharmony_ci wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) ); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci { 35162306a36Sopenharmony_ci const void* ptr = wksp->dtable; 35262306a36Sopenharmony_ci const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; 35362306a36Sopenharmony_ci const U32 fastMode = DTableH->fastMode; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* select fast mode (static) */ 35662306a36Sopenharmony_ci if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1); 35762306a36Sopenharmony_ci return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/* Avoids the FORCE_INLINE of the _body() function. */ 36262306a36Sopenharmony_cistatic size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci#if DYNAMIC_BMI2 36862306a36Sopenharmony_ciBMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci#endif 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cisize_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci#if DYNAMIC_BMI2 37762306a36Sopenharmony_ci if (bmi2) { 37862306a36Sopenharmony_ci return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci#endif 38162306a36Sopenharmony_ci (void)bmi2; 38262306a36Sopenharmony_ci return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_citypedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci#endif /* FSE_COMMONDEFS_ONLY */ 391