Merge pull request #2523 from terrelln/huf-stack-reduction
Add HUF_writeCTable_wksp() function
This commit is contained in:
commit
b5fd348a85
@ -192,6 +192,7 @@ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
|
|||||||
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
||||||
size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
|
size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
|
||||||
size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
|
size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
|
||||||
|
size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize);
|
||||||
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
||||||
size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
||||||
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
||||||
|
@ -59,7 +59,15 @@ unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS
|
|||||||
* Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
|
* Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
|
||||||
*/
|
*/
|
||||||
#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
|
#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
|
||||||
static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
|
|
||||||
|
typedef struct {
|
||||||
|
FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
|
||||||
|
U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)];
|
||||||
|
unsigned count[HUF_TABLELOG_MAX+1];
|
||||||
|
S16 norm[HUF_TABLELOG_MAX+1];
|
||||||
|
} HUF_CompressWeightsWksp;
|
||||||
|
|
||||||
|
static size_t HUF_compressWeights(void* dst, size_t dstSize, const void* weightTable, size_t wtSize, void* workspace, size_t workspaceSize)
|
||||||
{
|
{
|
||||||
BYTE* const ostart = (BYTE*) dst;
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
BYTE* op = ostart;
|
BYTE* op = ostart;
|
||||||
@ -67,33 +75,30 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight
|
|||||||
|
|
||||||
unsigned maxSymbolValue = HUF_TABLELOG_MAX;
|
unsigned maxSymbolValue = HUF_TABLELOG_MAX;
|
||||||
U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
|
U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
|
||||||
|
HUF_CompressWeightsWksp* wksp = (HUF_CompressWeightsWksp*)workspace;
|
||||||
|
|
||||||
FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
|
if (workspaceSize < sizeof(HUF_CompressWeightsWksp)) return ERROR(GENERIC);
|
||||||
U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)];
|
|
||||||
|
|
||||||
unsigned count[HUF_TABLELOG_MAX+1];
|
|
||||||
S16 norm[HUF_TABLELOG_MAX+1];
|
|
||||||
|
|
||||||
/* init conditions */
|
/* init conditions */
|
||||||
if (wtSize <= 1) return 0; /* Not compressible */
|
if (wtSize <= 1) return 0; /* Not compressible */
|
||||||
|
|
||||||
/* Scan input and build symbol stats */
|
/* Scan input and build symbol stats */
|
||||||
{ unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */
|
{ unsigned const maxCount = HIST_count_simple(wksp->count, &maxSymbolValue, weightTable, wtSize); /* never fails */
|
||||||
if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
|
if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
|
||||||
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
|
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
|
||||||
}
|
}
|
||||||
|
|
||||||
tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
|
tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
|
||||||
CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) );
|
CHECK_F( FSE_normalizeCount(wksp->norm, tableLog, wksp->count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) );
|
||||||
|
|
||||||
/* Write table description header */
|
/* Write table description header */
|
||||||
{ CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), norm, maxSymbolValue, tableLog) );
|
{ CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), wksp->norm, maxSymbolValue, tableLog) );
|
||||||
op += hSize;
|
op += hSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compress */
|
/* Compress */
|
||||||
CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
|
CHECK_F( FSE_buildCTable_wksp(wksp->CTable, wksp->norm, maxSymbolValue, tableLog, wksp->scratchBuffer, sizeof(wksp->scratchBuffer)) );
|
||||||
{ CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, CTable) );
|
{ CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, wksp->CTable) );
|
||||||
if (cSize == 0) return 0; /* not enough space for compressed data */
|
if (cSize == 0) return 0; /* not enough space for compressed data */
|
||||||
op += cSize;
|
op += cSize;
|
||||||
}
|
}
|
||||||
@ -102,29 +107,33 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! HUF_writeCTable() :
|
typedef struct {
|
||||||
`CTable` : Huffman tree to save, using huf representation.
|
HUF_CompressWeightsWksp wksp;
|
||||||
@return : size of saved CTable */
|
|
||||||
size_t HUF_writeCTable (void* dst, size_t maxDstSize,
|
|
||||||
const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
|
|
||||||
{
|
|
||||||
BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
|
BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
|
||||||
BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
|
BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
|
||||||
|
} HUF_WriteCTableWksp;
|
||||||
|
|
||||||
|
size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize,
|
||||||
|
const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog,
|
||||||
|
void* workspace, size_t workspaceSize)
|
||||||
|
{
|
||||||
BYTE* op = (BYTE*)dst;
|
BYTE* op = (BYTE*)dst;
|
||||||
U32 n;
|
U32 n;
|
||||||
|
HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)workspace;
|
||||||
|
|
||||||
/* check conditions */
|
/* check conditions */
|
||||||
|
if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC);
|
||||||
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
||||||
|
|
||||||
/* convert to weight */
|
/* convert to weight */
|
||||||
bitsToWeight[0] = 0;
|
wksp->bitsToWeight[0] = 0;
|
||||||
for (n=1; n<huffLog+1; n++)
|
for (n=1; n<huffLog+1; n++)
|
||||||
bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
|
wksp->bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
|
||||||
for (n=0; n<maxSymbolValue; n++)
|
for (n=0; n<maxSymbolValue; n++)
|
||||||
huffWeight[n] = bitsToWeight[CTable[n].nbBits];
|
wksp->huffWeight[n] = wksp->bitsToWeight[CTable[n].nbBits];
|
||||||
|
|
||||||
/* attempt weights compression by FSE */
|
/* attempt weights compression by FSE */
|
||||||
{ CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
|
{ CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, wksp->huffWeight, maxSymbolValue, &wksp->wksp, sizeof(wksp->wksp)) );
|
||||||
if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
|
if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
|
||||||
op[0] = (BYTE)hSize;
|
op[0] = (BYTE)hSize;
|
||||||
return hSize+1;
|
return hSize+1;
|
||||||
@ -134,12 +143,22 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize,
|
|||||||
if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
|
if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
|
||||||
if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
|
if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
|
||||||
op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
|
op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
|
||||||
huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
|
wksp->huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
|
||||||
for (n=0; n<maxSymbolValue; n+=2)
|
for (n=0; n<maxSymbolValue; n+=2)
|
||||||
op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
|
op[(n/2)+1] = (BYTE)((wksp->huffWeight[n] << 4) + wksp->huffWeight[n+1]);
|
||||||
return ((maxSymbolValue+1)/2) + 1;
|
return ((maxSymbolValue+1)/2) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! HUF_writeCTable() :
|
||||||
|
`CTable` : Huffman tree to save, using huf representation.
|
||||||
|
@return : size of saved CTable */
|
||||||
|
size_t HUF_writeCTable (void* dst, size_t maxDstSize,
|
||||||
|
const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
|
||||||
|
{
|
||||||
|
HUF_WriteCTableWksp wksp;
|
||||||
|
return HUF_writeCTable_wksp(dst, maxDstSize, CTable, maxSymbolValue, huffLog, &wksp, sizeof(wksp));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
|
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
|
||||||
{
|
{
|
||||||
@ -732,7 +751,10 @@ static size_t HUF_compressCTable_internal(
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned count[HUF_SYMBOLVALUE_MAX + 1];
|
unsigned count[HUF_SYMBOLVALUE_MAX + 1];
|
||||||
HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
|
HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
|
||||||
HUF_buildCTable_wksp_tables buildCTable_wksp;
|
union {
|
||||||
|
HUF_buildCTable_wksp_tables buildCTable_wksp;
|
||||||
|
HUF_WriteCTableWksp writeCTable_wksp;
|
||||||
|
} wksps;
|
||||||
} HUF_compress_tables_t;
|
} HUF_compress_tables_t;
|
||||||
|
|
||||||
/* HUF_compress_internal() :
|
/* HUF_compress_internal() :
|
||||||
@ -795,7 +817,7 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
|||||||
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
|
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
|
||||||
{ size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
|
{ size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
|
||||||
maxSymbolValue, huffLog,
|
maxSymbolValue, huffLog,
|
||||||
&table->buildCTable_wksp, sizeof(table->buildCTable_wksp));
|
&table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp));
|
||||||
CHECK_F(maxBits);
|
CHECK_F(maxBits);
|
||||||
huffLog = (U32)maxBits;
|
huffLog = (U32)maxBits;
|
||||||
/* Zero unused symbols in CTable, so we can check it for validity */
|
/* Zero unused symbols in CTable, so we can check it for validity */
|
||||||
@ -804,7 +826,8 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write table description header */
|
/* Write table description header */
|
||||||
{ CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) );
|
{ CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog,
|
||||||
|
&table->wksps.writeCTable_wksp, sizeof(table->wksps.writeCTable_wksp)) );
|
||||||
/* Check if using previous huffman table is beneficial */
|
/* Check if using previous huffman table is beneficial */
|
||||||
if (repeat && *repeat != HUF_repeat_none) {
|
if (repeat && *repeat != HUF_repeat_none) {
|
||||||
size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
|
size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
|
||||||
|
@ -128,9 +128,10 @@ static size_t ZSTD_buildSuperBlockEntropy_literal(void* const src, size_t srcSiz
|
|||||||
{ /* Build and write the CTable */
|
{ /* Build and write the CTable */
|
||||||
size_t const newCSize = HUF_estimateCompressedSize(
|
size_t const newCSize = HUF_estimateCompressedSize(
|
||||||
(HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
|
(HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
|
||||||
size_t const hSize = HUF_writeCTable(
|
size_t const hSize = HUF_writeCTable_wksp(
|
||||||
hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
|
hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
|
||||||
(HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog);
|
(HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog,
|
||||||
|
nodeWksp, nodeWkspSize);
|
||||||
/* Check against repeating the previous CTable */
|
/* Check against repeating the previous CTable */
|
||||||
if (repeat != HUF_repeat_none) {
|
if (repeat != HUF_repeat_none) {
|
||||||
size_t const oldCSize = HUF_estimateCompressedSize(
|
size_t const oldCSize = HUF_estimateCompressedSize(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user