zstd-ruby 1.4.9.0 → 1.5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +8 -0
- data/README.md +1 -1
- data/ext/zstdruby/libzstd/BUCK +5 -7
- data/ext/zstdruby/libzstd/Makefile +42 -13
- data/ext/zstdruby/libzstd/README.md +8 -4
- data/ext/zstdruby/libzstd/common/bitstream.h +1 -1
- data/ext/zstdruby/libzstd/common/compiler.h +1 -1
- data/ext/zstdruby/libzstd/common/cpu.h +1 -1
- data/ext/zstdruby/libzstd/common/debug.c +1 -1
- data/ext/zstdruby/libzstd/common/debug.h +1 -1
- data/ext/zstdruby/libzstd/common/entropy_common.c +1 -1
- data/ext/zstdruby/libzstd/common/error_private.c +1 -1
- data/ext/zstdruby/libzstd/common/error_private.h +3 -3
- data/ext/zstdruby/libzstd/common/fse.h +2 -2
- data/ext/zstdruby/libzstd/common/fse_decompress.c +25 -15
- data/ext/zstdruby/libzstd/common/huf.h +3 -2
- data/ext/zstdruby/libzstd/common/mem.h +3 -5
- data/ext/zstdruby/libzstd/common/pool.c +1 -1
- data/ext/zstdruby/libzstd/common/pool.h +1 -1
- data/ext/zstdruby/libzstd/common/xxhash.c +2 -4
- data/ext/zstdruby/libzstd/common/xxhash.h +1 -1
- data/ext/zstdruby/libzstd/common/zstd_common.c +1 -1
- data/ext/zstdruby/libzstd/common/zstd_deps.h +1 -1
- data/ext/zstdruby/libzstd/common/zstd_internal.h +21 -9
- data/ext/zstdruby/libzstd/common/zstd_trace.h +7 -5
- data/ext/zstdruby/libzstd/compress/fse_compress.c +1 -1
- data/ext/zstdruby/libzstd/compress/hist.c +1 -1
- data/ext/zstdruby/libzstd/compress/hist.h +1 -1
- data/ext/zstdruby/libzstd/compress/huf_compress.c +51 -28
- data/ext/zstdruby/libzstd/compress/zstd_compress.c +1373 -275
- data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +164 -21
- data/ext/zstdruby/libzstd/compress/zstd_compress_literals.c +2 -2
- data/ext/zstdruby/libzstd/compress/zstd_compress_literals.h +1 -1
- data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.c +14 -6
- data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.h +1 -1
- data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.c +5 -282
- data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.h +1 -1
- data/ext/zstdruby/libzstd/compress/zstd_cwksp.h +147 -46
- data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +3 -3
- data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +1 -1
- data/ext/zstdruby/libzstd/compress/zstd_fast.c +4 -4
- data/ext/zstdruby/libzstd/compress/zstd_fast.h +1 -1
- data/ext/zstdruby/libzstd/compress/zstd_lazy.c +914 -142
- data/ext/zstdruby/libzstd/compress/zstd_lazy.h +39 -1
- data/ext/zstdruby/libzstd/compress/zstd_ldm.c +51 -15
- data/ext/zstdruby/libzstd/compress/zstd_ldm.h +2 -1
- data/ext/zstdruby/libzstd/compress/zstd_ldm_geartab.h +1 -1
- data/ext/zstdruby/libzstd/compress/zstd_opt.c +1 -1
- data/ext/zstdruby/libzstd/compress/zstd_opt.h +1 -1
- data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +15 -6
- data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +5 -5
- data/ext/zstdruby/libzstd/decompress/huf_decompress.c +44 -43
- data/ext/zstdruby/libzstd/decompress/zstd_ddict.c +1 -1
- data/ext/zstdruby/libzstd/decompress/zstd_ddict.h +1 -1
- data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +3 -4
- data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.c +44 -36
- data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.h +1 -1
- data/ext/zstdruby/libzstd/decompress/zstd_decompress_internal.h +1 -2
- data/ext/zstdruby/libzstd/deprecated/zbuff.h +1 -1
- data/ext/zstdruby/libzstd/deprecated/zbuff_common.c +1 -1
- data/ext/zstdruby/libzstd/deprecated/zbuff_compress.c +1 -1
- data/ext/zstdruby/libzstd/deprecated/zbuff_decompress.c +1 -1
- data/ext/zstdruby/libzstd/dictBuilder/cover.c +7 -6
- data/ext/zstdruby/libzstd/dictBuilder/cover.h +6 -5
- data/ext/zstdruby/libzstd/dictBuilder/fastcover.c +7 -6
- data/ext/zstdruby/libzstd/dictBuilder/zdict.c +8 -7
- data/ext/zstdruby/libzstd/dll/example/Makefile +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_legacy.h +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v01.c +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v01.h +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v02.c +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v02.h +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v03.c +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v03.h +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v04.c +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v04.h +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v05.c +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v05.h +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v06.c +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v06.h +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v07.c +1 -1
- data/ext/zstdruby/libzstd/legacy/zstd_v07.h +1 -1
- data/ext/zstdruby/libzstd/{dictBuilder/zdict.h → zdict.h} +148 -2
- data/ext/zstdruby/libzstd/zstd.h +165 -83
- data/ext/zstdruby/libzstd/{common/zstd_errors.h → zstd_errors.h} +1 -1
- data/lib/zstd-ruby/version.rb +1 -1
- metadata +5 -5
- data/ext/zstdruby/libzstd/common/zstd_trace.c +0 -42
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* xxHash - Fast Hash algorithm
|
3
|
-
* Copyright (c)
|
3
|
+
* Copyright (c) Yann Collet, Facebook, Inc.
|
4
4
|
*
|
5
5
|
* You can contact the author at :
|
6
6
|
* - xxHash homepage: http://www.xxhash.com
|
@@ -30,9 +30,7 @@
|
|
30
30
|
* Prefer these methods in priority order (0 > 1 > 2)
|
31
31
|
*/
|
32
32
|
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
|
33
|
-
# if defined(
|
34
|
-
# define XXH_FORCE_MEMORY_ACCESS 2
|
35
|
-
# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
|
33
|
+
# if (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
|
36
34
|
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) || \
|
37
35
|
defined(__ICCARM__)
|
38
36
|
# define XXH_FORCE_MEMORY_ACCESS 1
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* xxHash - Extremely Fast Hash algorithm
|
3
3
|
* Header File
|
4
|
-
* Copyright (c)
|
4
|
+
* Copyright (c) Yann Collet, Facebook, Inc.
|
5
5
|
*
|
6
6
|
* You can contact the author at :
|
7
7
|
* - xxHash source repository : https://github.com/Cyan4973/xxHash
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c)
|
2
|
+
* Copyright (c) Yann Collet, Facebook, Inc.
|
3
3
|
* All rights reserved.
|
4
4
|
*
|
5
5
|
* This source code is licensed under both the BSD-style license (found in the
|
@@ -36,6 +36,11 @@
|
|
36
36
|
# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
|
37
37
|
#endif
|
38
38
|
#include "xxhash.h" /* XXH_reset, update, digest */
|
39
|
+
#ifndef ZSTD_NO_TRACE
|
40
|
+
# include "zstd_trace.h"
|
41
|
+
#else
|
42
|
+
# define ZSTD_TRACE 0
|
43
|
+
#endif
|
39
44
|
|
40
45
|
#if defined (__cplusplus)
|
41
46
|
extern "C" {
|
@@ -347,11 +352,18 @@ typedef enum {
|
|
347
352
|
* Private declarations
|
348
353
|
*********************************************/
|
349
354
|
typedef struct seqDef_s {
|
350
|
-
U32 offset; /*
|
355
|
+
U32 offset; /* offset == rawOffset + ZSTD_REP_NUM, or equivalently, offCode + 1 */
|
351
356
|
U16 litLength;
|
352
357
|
U16 matchLength;
|
353
358
|
} seqDef;
|
354
359
|
|
360
|
+
/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */
|
361
|
+
typedef enum {
|
362
|
+
ZSTD_llt_none = 0, /* no longLengthType */
|
363
|
+
ZSTD_llt_literalLength = 1, /* represents a long literal */
|
364
|
+
ZSTD_llt_matchLength = 2 /* represents a long match */
|
365
|
+
} ZSTD_longLengthType_e;
|
366
|
+
|
355
367
|
typedef struct {
|
356
368
|
seqDef* sequencesStart;
|
357
369
|
seqDef* sequences; /* ptr to end of sequences */
|
@@ -363,12 +375,12 @@ typedef struct {
|
|
363
375
|
size_t maxNbSeq;
|
364
376
|
size_t maxNbLit;
|
365
377
|
|
366
|
-
/* longLengthPos and
|
378
|
+
/* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength
|
367
379
|
* in the seqStore that has a value larger than U16 (if it exists). To do so, we increment
|
368
|
-
* the existing value of the litLength or matchLength by 0x10000.
|
380
|
+
* the existing value of the litLength or matchLength by 0x10000.
|
369
381
|
*/
|
370
|
-
|
371
|
-
U32
|
382
|
+
ZSTD_longLengthType_e longLengthType;
|
383
|
+
U32 longLengthPos; /* Index of the sequence to apply long length modification to */
|
372
384
|
} seqStore_t;
|
373
385
|
|
374
386
|
typedef struct {
|
@@ -378,7 +390,7 @@ typedef struct {
|
|
378
390
|
|
379
391
|
/**
|
380
392
|
* Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences
|
381
|
-
* indicated by longLengthPos and
|
393
|
+
* indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength.
|
382
394
|
*/
|
383
395
|
MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq)
|
384
396
|
{
|
@@ -386,10 +398,10 @@ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore
|
|
386
398
|
seqLen.litLength = seq->litLength;
|
387
399
|
seqLen.matchLength = seq->matchLength + MINMATCH;
|
388
400
|
if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) {
|
389
|
-
if (seqStore->
|
401
|
+
if (seqStore->longLengthType == ZSTD_llt_literalLength) {
|
390
402
|
seqLen.litLength += 0xFFFF;
|
391
403
|
}
|
392
|
-
if (seqStore->
|
404
|
+
if (seqStore->longLengthType == ZSTD_llt_matchLength) {
|
393
405
|
seqLen.matchLength += 0xFFFF;
|
394
406
|
}
|
395
407
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c)
|
2
|
+
* Copyright (c) Facebook, Inc.
|
3
3
|
* All rights reserved.
|
4
4
|
*
|
5
5
|
* This source code is licensed under both the BSD-style license (found in the
|
@@ -114,14 +114,15 @@ typedef unsigned long long ZSTD_TraceCtx;
|
|
114
114
|
* @returns Non-zero if tracing is enabled. The return value is
|
115
115
|
* passed to ZSTD_trace_compress_end().
|
116
116
|
*/
|
117
|
-
ZSTD_TraceCtx ZSTD_trace_compress_begin(
|
117
|
+
ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin(
|
118
|
+
struct ZSTD_CCtx_s const* cctx);
|
118
119
|
|
119
120
|
/**
|
120
121
|
* Trace the end of a compression call.
|
121
122
|
* @param ctx The return value of ZSTD_trace_compress_begin().
|
122
123
|
* @param trace The zstd tracing info.
|
123
124
|
*/
|
124
|
-
void ZSTD_trace_compress_end(
|
125
|
+
ZSTD_WEAK_ATTR void ZSTD_trace_compress_end(
|
125
126
|
ZSTD_TraceCtx ctx,
|
126
127
|
ZSTD_Trace const* trace);
|
127
128
|
|
@@ -132,14 +133,15 @@ void ZSTD_trace_compress_end(
|
|
132
133
|
* @returns Non-zero if tracing is enabled. The return value is
|
133
134
|
* passed to ZSTD_trace_compress_end().
|
134
135
|
*/
|
135
|
-
ZSTD_TraceCtx ZSTD_trace_decompress_begin(
|
136
|
+
ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin(
|
137
|
+
struct ZSTD_DCtx_s const* dctx);
|
136
138
|
|
137
139
|
/**
|
138
140
|
* Trace the end of a decompression call.
|
139
141
|
* @param ctx The return value of ZSTD_trace_decompress_begin().
|
140
142
|
* @param trace The zstd tracing info.
|
141
143
|
*/
|
142
|
-
void ZSTD_trace_decompress_end(
|
144
|
+
ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end(
|
143
145
|
ZSTD_TraceCtx ctx,
|
144
146
|
ZSTD_Trace const* trace);
|
145
147
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/* ******************************************************************
|
2
2
|
* FSE : Finite State Entropy encoder
|
3
|
-
* Copyright (c)
|
3
|
+
* Copyright (c) Yann Collet, Facebook, Inc.
|
4
4
|
*
|
5
5
|
* You can contact the author at :
|
6
6
|
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/* ******************************************************************
|
2
2
|
* hist : Histogram functions
|
3
3
|
* part of Finite State Entropy project
|
4
|
-
* Copyright (c)
|
4
|
+
* Copyright (c) Yann Collet, Facebook, Inc.
|
5
5
|
*
|
6
6
|
* You can contact the author at :
|
7
7
|
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/* ******************************************************************
|
2
2
|
* hist : Histogram functions
|
3
3
|
* part of Finite State Entropy project
|
4
|
-
* Copyright (c)
|
4
|
+
* Copyright (c) Yann Collet, Facebook, Inc.
|
5
5
|
*
|
6
6
|
* You can contact the author at :
|
7
7
|
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/* ******************************************************************
|
2
2
|
* Huffman encoder, part of New Generation Entropy library
|
3
|
-
* Copyright (c)
|
3
|
+
* Copyright (c) Yann Collet, Facebook, Inc.
|
4
4
|
*
|
5
5
|
* You can contact the author at :
|
6
6
|
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
@@ -59,7 +59,15 @@ unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS
|
|
59
59
|
* Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
|
60
60
|
*/
|
61
61
|
#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
|
62
|
-
|
62
|
+
|
63
|
+
typedef struct {
|
64
|
+
FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
|
65
|
+
U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)];
|
66
|
+
unsigned count[HUF_TABLELOG_MAX+1];
|
67
|
+
S16 norm[HUF_TABLELOG_MAX+1];
|
68
|
+
} HUF_CompressWeightsWksp;
|
69
|
+
|
70
|
+
static size_t HUF_compressWeights(void* dst, size_t dstSize, const void* weightTable, size_t wtSize, void* workspace, size_t workspaceSize)
|
63
71
|
{
|
64
72
|
BYTE* const ostart = (BYTE*) dst;
|
65
73
|
BYTE* op = ostart;
|
@@ -67,33 +75,30 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight
|
|
67
75
|
|
68
76
|
unsigned maxSymbolValue = HUF_TABLELOG_MAX;
|
69
77
|
U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
|
78
|
+
HUF_CompressWeightsWksp* wksp = (HUF_CompressWeightsWksp*)workspace;
|
70
79
|
|
71
|
-
|
72
|
-
U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)];
|
73
|
-
|
74
|
-
unsigned count[HUF_TABLELOG_MAX+1];
|
75
|
-
S16 norm[HUF_TABLELOG_MAX+1];
|
80
|
+
if (workspaceSize < sizeof(HUF_CompressWeightsWksp)) return ERROR(GENERIC);
|
76
81
|
|
77
82
|
/* init conditions */
|
78
83
|
if (wtSize <= 1) return 0; /* Not compressible */
|
79
84
|
|
80
85
|
/* Scan input and build symbol stats */
|
81
|
-
{ unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */
|
86
|
+
{ unsigned const maxCount = HIST_count_simple(wksp->count, &maxSymbolValue, weightTable, wtSize); /* never fails */
|
82
87
|
if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
|
83
88
|
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
|
84
89
|
}
|
85
90
|
|
86
91
|
tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
|
87
|
-
CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) );
|
92
|
+
CHECK_F( FSE_normalizeCount(wksp->norm, tableLog, wksp->count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) );
|
88
93
|
|
89
94
|
/* Write table description header */
|
90
|
-
{ CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), norm, maxSymbolValue, tableLog) );
|
95
|
+
{ CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), wksp->norm, maxSymbolValue, tableLog) );
|
91
96
|
op += hSize;
|
92
97
|
}
|
93
98
|
|
94
99
|
/* Compress */
|
95
|
-
CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
|
96
|
-
{ CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, CTable) );
|
100
|
+
CHECK_F( FSE_buildCTable_wksp(wksp->CTable, wksp->norm, maxSymbolValue, tableLog, wksp->scratchBuffer, sizeof(wksp->scratchBuffer)) );
|
101
|
+
{ CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, wksp->CTable) );
|
97
102
|
if (cSize == 0) return 0; /* not enough space for compressed data */
|
98
103
|
op += cSize;
|
99
104
|
}
|
@@ -102,29 +107,33 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight
|
|
102
107
|
}
|
103
108
|
|
104
109
|
|
105
|
-
|
106
|
-
|
107
|
-
@return : size of saved CTable */
|
108
|
-
size_t HUF_writeCTable (void* dst, size_t maxDstSize,
|
109
|
-
const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
|
110
|
-
{
|
110
|
+
typedef struct {
|
111
|
+
HUF_CompressWeightsWksp wksp;
|
111
112
|
BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
|
112
113
|
BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
|
114
|
+
} HUF_WriteCTableWksp;
|
115
|
+
|
116
|
+
size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize,
|
117
|
+
const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog,
|
118
|
+
void* workspace, size_t workspaceSize)
|
119
|
+
{
|
113
120
|
BYTE* op = (BYTE*)dst;
|
114
121
|
U32 n;
|
122
|
+
HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)workspace;
|
115
123
|
|
116
|
-
|
124
|
+
/* check conditions */
|
125
|
+
if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC);
|
117
126
|
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
|
118
127
|
|
119
128
|
/* convert to weight */
|
120
|
-
bitsToWeight[0] = 0;
|
129
|
+
wksp->bitsToWeight[0] = 0;
|
121
130
|
for (n=1; n<huffLog+1; n++)
|
122
|
-
bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
|
131
|
+
wksp->bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
|
123
132
|
for (n=0; n<maxSymbolValue; n++)
|
124
|
-
huffWeight[n] = bitsToWeight[CTable[n].nbBits];
|
133
|
+
wksp->huffWeight[n] = wksp->bitsToWeight[CTable[n].nbBits];
|
125
134
|
|
126
135
|
/* attempt weights compression by FSE */
|
127
|
-
{ CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
|
136
|
+
{ CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, wksp->huffWeight, maxSymbolValue, &wksp->wksp, sizeof(wksp->wksp)) );
|
128
137
|
if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
|
129
138
|
op[0] = (BYTE)hSize;
|
130
139
|
return hSize+1;
|
@@ -134,12 +143,22 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize,
|
|
134
143
|
if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
|
135
144
|
if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
|
136
145
|
op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
|
137
|
-
huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
|
146
|
+
wksp->huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
|
138
147
|
for (n=0; n<maxSymbolValue; n+=2)
|
139
|
-
op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
|
148
|
+
op[(n/2)+1] = (BYTE)((wksp->huffWeight[n] << 4) + wksp->huffWeight[n+1]);
|
140
149
|
return ((maxSymbolValue+1)/2) + 1;
|
141
150
|
}
|
142
151
|
|
152
|
+
/*! HUF_writeCTable() :
|
153
|
+
`CTable` : Huffman tree to save, using huf representation.
|
154
|
+
@return : size of saved CTable */
|
155
|
+
size_t HUF_writeCTable (void* dst, size_t maxDstSize,
|
156
|
+
const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
|
157
|
+
{
|
158
|
+
HUF_WriteCTableWksp wksp;
|
159
|
+
return HUF_writeCTable_wksp(dst, maxDstSize, CTable, maxSymbolValue, huffLog, &wksp, sizeof(wksp));
|
160
|
+
}
|
161
|
+
|
143
162
|
|
144
163
|
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
|
145
164
|
{
|
@@ -732,7 +751,10 @@ static size_t HUF_compressCTable_internal(
|
|
732
751
|
typedef struct {
|
733
752
|
unsigned count[HUF_SYMBOLVALUE_MAX + 1];
|
734
753
|
HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
|
735
|
-
|
754
|
+
union {
|
755
|
+
HUF_buildCTable_wksp_tables buildCTable_wksp;
|
756
|
+
HUF_WriteCTableWksp writeCTable_wksp;
|
757
|
+
} wksps;
|
736
758
|
} HUF_compress_tables_t;
|
737
759
|
|
738
760
|
/* HUF_compress_internal() :
|
@@ -795,7 +817,7 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
|
795
817
|
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
|
796
818
|
{ size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
|
797
819
|
maxSymbolValue, huffLog,
|
798
|
-
&table->buildCTable_wksp, sizeof(table->buildCTable_wksp));
|
820
|
+
&table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp));
|
799
821
|
CHECK_F(maxBits);
|
800
822
|
huffLog = (U32)maxBits;
|
801
823
|
/* Zero unused symbols in CTable, so we can check it for validity */
|
@@ -804,7 +826,8 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
|
804
826
|
}
|
805
827
|
|
806
828
|
/* Write table description header */
|
807
|
-
{ CHECK_V_F(hSize,
|
829
|
+
{ CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog,
|
830
|
+
&table->wksps.writeCTable_wksp, sizeof(table->wksps.writeCTable_wksp)) );
|
808
831
|
/* Check if using previous huffman table is beneficial */
|
809
832
|
if (repeat && *repeat != HUF_repeat_none) {
|
810
833
|
size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c)
|
2
|
+
* Copyright (c) Yann Collet, Facebook, Inc.
|
3
3
|
* All rights reserved.
|
4
4
|
*
|
5
5
|
* This source code is licensed under both the BSD-style license (found in the
|
@@ -14,7 +14,6 @@
|
|
14
14
|
#include "../common/zstd_deps.h" /* INT_MAX, ZSTD_memset, ZSTD_memcpy */
|
15
15
|
#include "../common/cpu.h"
|
16
16
|
#include "../common/mem.h"
|
17
|
-
#include "../common/zstd_trace.h"
|
18
17
|
#include "hist.h" /* HIST_countFast_wksp */
|
19
18
|
#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
|
20
19
|
#include "../common/fse.h"
|
@@ -73,6 +72,10 @@ struct ZSTD_CDict_s {
|
|
73
72
|
ZSTD_customMem customMem;
|
74
73
|
U32 dictID;
|
75
74
|
int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */
|
75
|
+
ZSTD_useRowMatchFinderMode_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use
|
76
|
+
* row-based matchfinder. Unless the cdict is reloaded, we will use
|
77
|
+
* the same greedy/lazy matchfinder at compression time.
|
78
|
+
*/
|
76
79
|
}; /* typedef'd to ZSTD_CDict within "zstd.h" */
|
77
80
|
|
78
81
|
ZSTD_CCtx* ZSTD_createCCtx(void)
|
@@ -203,6 +206,49 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
|
|
203
206
|
/* private API call, for dictBuilder only */
|
204
207
|
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
|
205
208
|
|
209
|
+
/* Returns true if the strategy supports using a row based matchfinder */
|
210
|
+
static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) {
|
211
|
+
return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2);
|
212
|
+
}
|
213
|
+
|
214
|
+
/* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder
|
215
|
+
* for this compression.
|
216
|
+
*/
|
217
|
+
static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_useRowMatchFinderMode_e mode) {
|
218
|
+
assert(mode != ZSTD_urm_auto);
|
219
|
+
return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_urm_enableRowMatchFinder);
|
220
|
+
}
|
221
|
+
|
222
|
+
/* Returns row matchfinder usage enum given an initial mode and cParams */
|
223
|
+
static ZSTD_useRowMatchFinderMode_e ZSTD_resolveRowMatchFinderMode(ZSTD_useRowMatchFinderMode_e mode,
|
224
|
+
const ZSTD_compressionParameters* const cParams) {
|
225
|
+
#if !defined(ZSTD_NO_INTRINSICS) && (defined(__SSE2__) || defined(__ARM_NEON))
|
226
|
+
int const kHasSIMD128 = 1;
|
227
|
+
#else
|
228
|
+
int const kHasSIMD128 = 0;
|
229
|
+
#endif
|
230
|
+
if (mode != ZSTD_urm_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */
|
231
|
+
mode = ZSTD_urm_disableRowMatchFinder;
|
232
|
+
if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode;
|
233
|
+
if (kHasSIMD128) {
|
234
|
+
if (cParams->windowLog > 14) mode = ZSTD_urm_enableRowMatchFinder;
|
235
|
+
} else {
|
236
|
+
if (cParams->windowLog > 17) mode = ZSTD_urm_enableRowMatchFinder;
|
237
|
+
}
|
238
|
+
return mode;
|
239
|
+
}
|
240
|
+
|
241
|
+
/* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */
|
242
|
+
static int ZSTD_allocateChainTable(const ZSTD_strategy strategy,
|
243
|
+
const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
|
244
|
+
const U32 forDDSDict) {
|
245
|
+
assert(useRowMatchFinder != ZSTD_urm_auto);
|
246
|
+
/* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate.
|
247
|
+
* We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder.
|
248
|
+
*/
|
249
|
+
return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder));
|
250
|
+
}
|
251
|
+
|
206
252
|
/* Returns 1 if compression parameters are such that we should
|
207
253
|
* enable long distance matching (wlog >= 27, strategy >= btopt).
|
208
254
|
* Returns 0 otherwise.
|
@@ -211,6 +257,14 @@ static U32 ZSTD_CParams_shouldEnableLdm(const ZSTD_compressionParameters* const
|
|
211
257
|
return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27;
|
212
258
|
}
|
213
259
|
|
260
|
+
/* Returns 1 if compression parameters are such that we should
|
261
|
+
* enable blockSplitter (wlog >= 17, strategy >= btopt).
|
262
|
+
* Returns 0 otherwise.
|
263
|
+
*/
|
264
|
+
static U32 ZSTD_CParams_useBlockSplitter(const ZSTD_compressionParameters* const cParams) {
|
265
|
+
return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17;
|
266
|
+
}
|
267
|
+
|
214
268
|
static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
|
215
269
|
ZSTD_compressionParameters cParams)
|
216
270
|
{
|
@@ -219,6 +273,7 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
|
|
219
273
|
ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT);
|
220
274
|
cctxParams.cParams = cParams;
|
221
275
|
|
276
|
+
/* Adjust advanced params according to cParams */
|
222
277
|
if (ZSTD_CParams_shouldEnableLdm(&cParams)) {
|
223
278
|
DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including LDM into cctx params");
|
224
279
|
cctxParams.ldmParams.enableLdm = 1;
|
@@ -228,6 +283,12 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
|
|
228
283
|
assert(cctxParams.ldmParams.hashRateLog < 32);
|
229
284
|
}
|
230
285
|
|
286
|
+
if (ZSTD_CParams_useBlockSplitter(&cParams)) {
|
287
|
+
DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including block splitting into cctx params");
|
288
|
+
cctxParams.splitBlocks = 1;
|
289
|
+
}
|
290
|
+
|
291
|
+
cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams);
|
231
292
|
assert(!ZSTD_checkCParams(cParams));
|
232
293
|
return cctxParams;
|
233
294
|
}
|
@@ -286,6 +347,8 @@ static void ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, ZSTD_par
|
|
286
347
|
* But, set it for tracing anyway.
|
287
348
|
*/
|
288
349
|
cctxParams->compressionLevel = compressionLevel;
|
350
|
+
cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, ¶ms->cParams);
|
351
|
+
DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d", cctxParams->useRowMatchFinder);
|
289
352
|
}
|
290
353
|
|
291
354
|
size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
|
@@ -486,6 +549,21 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
|
|
486
549
|
bounds.upperBound = 1;
|
487
550
|
return bounds;
|
488
551
|
|
552
|
+
case ZSTD_c_splitBlocks:
|
553
|
+
bounds.lowerBound = 0;
|
554
|
+
bounds.upperBound = 1;
|
555
|
+
return bounds;
|
556
|
+
|
557
|
+
case ZSTD_c_useRowMatchFinder:
|
558
|
+
bounds.lowerBound = (int)ZSTD_urm_auto;
|
559
|
+
bounds.upperBound = (int)ZSTD_urm_enableRowMatchFinder;
|
560
|
+
return bounds;
|
561
|
+
|
562
|
+
case ZSTD_c_deterministicRefPrefix:
|
563
|
+
bounds.lowerBound = 0;
|
564
|
+
bounds.upperBound = 1;
|
565
|
+
return bounds;
|
566
|
+
|
489
567
|
default:
|
490
568
|
bounds.error = ERROR(parameter_unsupported);
|
491
569
|
return bounds;
|
@@ -547,6 +625,9 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
|
|
547
625
|
case ZSTD_c_stableOutBuffer:
|
548
626
|
case ZSTD_c_blockDelimiters:
|
549
627
|
case ZSTD_c_validateSequences:
|
628
|
+
case ZSTD_c_splitBlocks:
|
629
|
+
case ZSTD_c_useRowMatchFinder:
|
630
|
+
case ZSTD_c_deterministicRefPrefix:
|
550
631
|
default:
|
551
632
|
return 0;
|
552
633
|
}
|
@@ -599,6 +680,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
|
|
599
680
|
case ZSTD_c_stableOutBuffer:
|
600
681
|
case ZSTD_c_blockDelimiters:
|
601
682
|
case ZSTD_c_validateSequences:
|
683
|
+
case ZSTD_c_splitBlocks:
|
684
|
+
case ZSTD_c_useRowMatchFinder:
|
685
|
+
case ZSTD_c_deterministicRefPrefix:
|
602
686
|
break;
|
603
687
|
|
604
688
|
default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
|
@@ -810,6 +894,21 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
|
|
810
894
|
CCtxParams->validateSequences = value;
|
811
895
|
return CCtxParams->validateSequences;
|
812
896
|
|
897
|
+
case ZSTD_c_splitBlocks:
|
898
|
+
BOUNDCHECK(ZSTD_c_splitBlocks, value);
|
899
|
+
CCtxParams->splitBlocks = value;
|
900
|
+
return CCtxParams->splitBlocks;
|
901
|
+
|
902
|
+
case ZSTD_c_useRowMatchFinder:
|
903
|
+
BOUNDCHECK(ZSTD_c_useRowMatchFinder, value);
|
904
|
+
CCtxParams->useRowMatchFinder = (ZSTD_useRowMatchFinderMode_e)value;
|
905
|
+
return CCtxParams->useRowMatchFinder;
|
906
|
+
|
907
|
+
case ZSTD_c_deterministicRefPrefix:
|
908
|
+
BOUNDCHECK(ZSTD_c_deterministicRefPrefix, value);
|
909
|
+
CCtxParams->deterministicRefPrefix = !!value;
|
910
|
+
return CCtxParams->deterministicRefPrefix;
|
911
|
+
|
813
912
|
default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
|
814
913
|
}
|
815
914
|
}
|
@@ -933,6 +1032,15 @@ size_t ZSTD_CCtxParams_getParameter(
|
|
933
1032
|
case ZSTD_c_validateSequences :
|
934
1033
|
*value = (int)CCtxParams->validateSequences;
|
935
1034
|
break;
|
1035
|
+
case ZSTD_c_splitBlocks :
|
1036
|
+
*value = (int)CCtxParams->splitBlocks;
|
1037
|
+
break;
|
1038
|
+
case ZSTD_c_useRowMatchFinder :
|
1039
|
+
*value = (int)CCtxParams->useRowMatchFinder;
|
1040
|
+
break;
|
1041
|
+
case ZSTD_c_deterministicRefPrefix:
|
1042
|
+
*value = (int)CCtxParams->deterministicRefPrefix;
|
1043
|
+
break;
|
936
1044
|
default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
|
937
1045
|
}
|
938
1046
|
return 0;
|
@@ -1299,9 +1407,14 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
|
|
1299
1407
|
|
1300
1408
|
static size_t
|
1301
1409
|
ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
|
1410
|
+
const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
|
1411
|
+
const U32 enableDedicatedDictSearch,
|
1302
1412
|
const U32 forCCtx)
|
1303
1413
|
{
|
1304
|
-
|
1414
|
+
/* chain table size should be 0 for fast or row-hash strategies */
|
1415
|
+
size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, enableDedicatedDictSearch && !forCCtx)
|
1416
|
+
? ((size_t)1 << cParams->chainLog)
|
1417
|
+
: 0;
|
1305
1418
|
size_t const hSize = ((size_t)1) << cParams->hashLog;
|
1306
1419
|
U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
|
1307
1420
|
size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
|
@@ -1311,24 +1424,34 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
|
|
1311
1424
|
+ hSize * sizeof(U32)
|
1312
1425
|
+ h3Size * sizeof(U32);
|
1313
1426
|
size_t const optPotentialSpace =
|
1314
|
-
|
1315
|
-
+
|
1316
|
-
+
|
1317
|
-
+
|
1318
|
-
+
|
1319
|
-
+
|
1427
|
+
ZSTD_cwksp_aligned_alloc_size((MaxML+1) * sizeof(U32))
|
1428
|
+
+ ZSTD_cwksp_aligned_alloc_size((MaxLL+1) * sizeof(U32))
|
1429
|
+
+ ZSTD_cwksp_aligned_alloc_size((MaxOff+1) * sizeof(U32))
|
1430
|
+
+ ZSTD_cwksp_aligned_alloc_size((1<<Litbits) * sizeof(U32))
|
1431
|
+
+ ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
|
1432
|
+
+ ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
|
1433
|
+
size_t const lazyAdditionalSpace = ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)
|
1434
|
+
? ZSTD_cwksp_aligned_alloc_size(hSize*sizeof(U16))
|
1435
|
+
: 0;
|
1320
1436
|
size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
|
1321
1437
|
? optPotentialSpace
|
1322
1438
|
: 0;
|
1439
|
+
size_t const slackSpace = ZSTD_cwksp_slack_space_required();
|
1440
|
+
|
1441
|
+
/* tables are guaranteed to be sized in multiples of 64 bytes (or 16 uint32_t) */
|
1442
|
+
ZSTD_STATIC_ASSERT(ZSTD_HASHLOG_MIN >= 4 && ZSTD_WINDOWLOG_MIN >= 4 && ZSTD_CHAINLOG_MIN >= 4);
|
1443
|
+
assert(useRowMatchFinder != ZSTD_urm_auto);
|
1444
|
+
|
1323
1445
|
DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
|
1324
1446
|
(U32)chainSize, (U32)hSize, (U32)h3Size);
|
1325
|
-
return tableSpace + optSpace;
|
1447
|
+
return tableSpace + optSpace + slackSpace + lazyAdditionalSpace;
|
1326
1448
|
}
|
1327
1449
|
|
1328
1450
|
static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
1329
1451
|
const ZSTD_compressionParameters* cParams,
|
1330
1452
|
const ldmParams_t* ldmParams,
|
1331
1453
|
const int isStatic,
|
1454
|
+
const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
|
1332
1455
|
const size_t buffInSize,
|
1333
1456
|
const size_t buffOutSize,
|
1334
1457
|
const U64 pledgedSrcSize)
|
@@ -1338,16 +1461,16 @@ static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
|
1338
1461
|
U32 const divider = (cParams->minMatch==3) ? 3 : 4;
|
1339
1462
|
size_t const maxNbSeq = blockSize / divider;
|
1340
1463
|
size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
|
1341
|
-
+
|
1464
|
+
+ ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef))
|
1342
1465
|
+ 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
|
1343
1466
|
size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE);
|
1344
1467
|
size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
|
1345
|
-
size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, /* forCCtx */ 1);
|
1468
|
+
size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1);
|
1346
1469
|
|
1347
1470
|
size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams);
|
1348
1471
|
size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize);
|
1349
1472
|
size_t const ldmSeqSpace = ldmParams->enableLdm ?
|
1350
|
-
|
1473
|
+
ZSTD_cwksp_aligned_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0;
|
1351
1474
|
|
1352
1475
|
|
1353
1476
|
size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize)
|
@@ -1373,25 +1496,45 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
|
1373
1496
|
{
|
1374
1497
|
ZSTD_compressionParameters const cParams =
|
1375
1498
|
ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
|
1499
|
+
ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder,
|
1500
|
+
&cParams);
|
1376
1501
|
|
1377
1502
|
RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
|
1378
1503
|
/* estimateCCtxSize is for one-shot compression. So no buffers should
|
1379
1504
|
* be needed. However, we still allocate two 0-sized buffers, which can
|
1380
1505
|
* take space under ASAN. */
|
1381
1506
|
return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
1382
|
-
&cParams, ¶ms->ldmParams, 1, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
|
1507
|
+
&cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
|
1383
1508
|
}
|
1384
1509
|
|
1385
1510
|
size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
|
1386
1511
|
{
|
1387
|
-
ZSTD_CCtx_params
|
1388
|
-
|
1512
|
+
ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams);
|
1513
|
+
if (ZSTD_rowMatchFinderSupported(cParams.strategy)) {
|
1514
|
+
/* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */
|
1515
|
+
size_t noRowCCtxSize;
|
1516
|
+
size_t rowCCtxSize;
|
1517
|
+
initialParams.useRowMatchFinder = ZSTD_urm_disableRowMatchFinder;
|
1518
|
+
noRowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
|
1519
|
+
initialParams.useRowMatchFinder = ZSTD_urm_enableRowMatchFinder;
|
1520
|
+
rowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
|
1521
|
+
return MAX(noRowCCtxSize, rowCCtxSize);
|
1522
|
+
} else {
|
1523
|
+
return ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
|
1524
|
+
}
|
1389
1525
|
}
|
1390
1526
|
|
1391
1527
|
static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
|
1392
1528
|
{
|
1393
|
-
|
1394
|
-
|
1529
|
+
int tier = 0;
|
1530
|
+
size_t largestSize = 0;
|
1531
|
+
static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN};
|
1532
|
+
for (; tier < 4; ++tier) {
|
1533
|
+
/* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */
|
1534
|
+
ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict);
|
1535
|
+
largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize);
|
1536
|
+
}
|
1537
|
+
return largestSize;
|
1395
1538
|
}
|
1396
1539
|
|
1397
1540
|
size_t ZSTD_estimateCCtxSize(int compressionLevel)
|
@@ -1399,6 +1542,7 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel)
|
|
1399
1542
|
int level;
|
1400
1543
|
size_t memBudget = 0;
|
1401
1544
|
for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
|
1545
|
+
/* Ensure monotonically increasing memory usage as compression level increases */
|
1402
1546
|
size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
|
1403
1547
|
if (newMB > memBudget) memBudget = newMB;
|
1404
1548
|
}
|
@@ -1417,17 +1561,29 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
|
1417
1561
|
size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered)
|
1418
1562
|
? ZSTD_compressBound(blockSize) + 1
|
1419
1563
|
: 0;
|
1564
|
+
ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, ¶ms->cParams);
|
1420
1565
|
|
1421
1566
|
return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
1422
|
-
&cParams, ¶ms->ldmParams, 1, inBuffSize, outBuffSize,
|
1567
|
+
&cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize,
|
1423
1568
|
ZSTD_CONTENTSIZE_UNKNOWN);
|
1424
1569
|
}
|
1425
1570
|
}
|
1426
1571
|
|
1427
1572
|
size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
|
1428
1573
|
{
|
1429
|
-
ZSTD_CCtx_params
|
1430
|
-
|
1574
|
+
ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams);
|
1575
|
+
if (ZSTD_rowMatchFinderSupported(cParams.strategy)) {
|
1576
|
+
/* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */
|
1577
|
+
size_t noRowCCtxSize;
|
1578
|
+
size_t rowCCtxSize;
|
1579
|
+
initialParams.useRowMatchFinder = ZSTD_urm_disableRowMatchFinder;
|
1580
|
+
noRowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
|
1581
|
+
initialParams.useRowMatchFinder = ZSTD_urm_enableRowMatchFinder;
|
1582
|
+
rowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
|
1583
|
+
return MAX(noRowCCtxSize, rowCCtxSize);
|
1584
|
+
} else {
|
1585
|
+
return ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
|
1586
|
+
}
|
1431
1587
|
}
|
1432
1588
|
|
1433
1589
|
static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
|
@@ -1552,20 +1708,27 @@ typedef enum {
|
|
1552
1708
|
ZSTD_resetTarget_CCtx
|
1553
1709
|
} ZSTD_resetTarget_e;
|
1554
1710
|
|
1711
|
+
|
1555
1712
|
static size_t
|
1556
1713
|
ZSTD_reset_matchState(ZSTD_matchState_t* ms,
|
1557
1714
|
ZSTD_cwksp* ws,
|
1558
1715
|
const ZSTD_compressionParameters* cParams,
|
1716
|
+
const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
|
1559
1717
|
const ZSTD_compResetPolicy_e crp,
|
1560
1718
|
const ZSTD_indexResetPolicy_e forceResetIndex,
|
1561
1719
|
const ZSTD_resetTarget_e forWho)
|
1562
1720
|
{
|
1563
|
-
|
1721
|
+
/* disable chain table allocation for fast or row-based strategies */
|
1722
|
+
size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder,
|
1723
|
+
ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict))
|
1724
|
+
? ((size_t)1 << cParams->chainLog)
|
1725
|
+
: 0;
|
1564
1726
|
size_t const hSize = ((size_t)1) << cParams->hashLog;
|
1565
1727
|
U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
|
1566
1728
|
size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
|
1567
1729
|
|
1568
1730
|
DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset);
|
1731
|
+
assert(useRowMatchFinder != ZSTD_urm_auto);
|
1569
1732
|
if (forceResetIndex == ZSTDirp_reset) {
|
1570
1733
|
ZSTD_window_init(&ms->window);
|
1571
1734
|
ZSTD_cwksp_mark_tables_dirty(ws);
|
@@ -1604,11 +1767,23 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms,
|
|
1604
1767
|
ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
|
1605
1768
|
}
|
1606
1769
|
|
1770
|
+
if (ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)) {
|
1771
|
+
{ /* Row match finder needs an additional table of hashes ("tags") */
|
1772
|
+
size_t const tagTableSize = hSize*sizeof(U16);
|
1773
|
+
ms->tagTable = (U16*)ZSTD_cwksp_reserve_aligned(ws, tagTableSize);
|
1774
|
+
if (ms->tagTable) ZSTD_memset(ms->tagTable, 0, tagTableSize);
|
1775
|
+
}
|
1776
|
+
{ /* Switch to 32-entry rows if searchLog is 5 (or more) */
|
1777
|
+
U32 const rowLog = cParams->searchLog < 5 ? 4 : 5;
|
1778
|
+
assert(cParams->hashLog > rowLog);
|
1779
|
+
ms->rowHashLog = cParams->hashLog - rowLog;
|
1780
|
+
}
|
1781
|
+
}
|
1782
|
+
|
1607
1783
|
ms->cParams = *cParams;
|
1608
1784
|
|
1609
1785
|
RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
|
1610
1786
|
"failed a workspace allocation in ZSTD_reset_matchState");
|
1611
|
-
|
1612
1787
|
return 0;
|
1613
1788
|
}
|
1614
1789
|
|
@@ -1625,61 +1800,85 @@ static int ZSTD_indexTooCloseToMax(ZSTD_window_t w)
|
|
1625
1800
|
return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN);
|
1626
1801
|
}
|
1627
1802
|
|
1803
|
+
/** ZSTD_dictTooBig():
|
1804
|
+
* When dictionaries are larger than ZSTD_CHUNKSIZE_MAX they can't be loaded in
|
1805
|
+
* one go generically. So we ensure that in that case we reset the tables to zero,
|
1806
|
+
* so that we can load as much of the dictionary as possible.
|
1807
|
+
*/
|
1808
|
+
static int ZSTD_dictTooBig(size_t const loadedDictSize)
|
1809
|
+
{
|
1810
|
+
return loadedDictSize > ZSTD_CHUNKSIZE_MAX;
|
1811
|
+
}
|
1812
|
+
|
1628
1813
|
/*! ZSTD_resetCCtx_internal() :
|
1629
|
-
|
1814
|
+
* @param loadedDictSize The size of the dictionary to be loaded
|
1815
|
+
* into the context, if any. If no dictionary is used, or the
|
1816
|
+
* dictionary is being attached / copied, then pass 0.
|
1817
|
+
* note : `params` are assumed fully validated at this stage.
|
1818
|
+
*/
|
1630
1819
|
static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
1631
|
-
ZSTD_CCtx_params params,
|
1820
|
+
ZSTD_CCtx_params const* params,
|
1632
1821
|
U64 const pledgedSrcSize,
|
1822
|
+
size_t const loadedDictSize,
|
1633
1823
|
ZSTD_compResetPolicy_e const crp,
|
1634
1824
|
ZSTD_buffered_policy_e const zbuff)
|
1635
1825
|
{
|
1636
1826
|
ZSTD_cwksp* const ws = &zc->workspace;
|
1637
|
-
DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
|
1638
|
-
(U32)pledgedSrcSize, params
|
1639
|
-
assert(!ZSTD_isError(ZSTD_checkCParams(params
|
1827
|
+
DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d",
|
1828
|
+
(U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder);
|
1829
|
+
assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
|
1640
1830
|
|
1641
1831
|
zc->isFirstBlock = 1;
|
1642
1832
|
|
1643
|
-
|
1833
|
+
/* Set applied params early so we can modify them for LDM,
|
1834
|
+
* and point params at the applied params.
|
1835
|
+
*/
|
1836
|
+
zc->appliedParams = *params;
|
1837
|
+
params = &zc->appliedParams;
|
1838
|
+
|
1839
|
+
assert(params->useRowMatchFinder != ZSTD_urm_auto);
|
1840
|
+
if (params->ldmParams.enableLdm) {
|
1644
1841
|
/* Adjust long distance matching parameters */
|
1645
|
-
ZSTD_ldm_adjustParameters(&
|
1646
|
-
assert(params
|
1647
|
-
assert(params
|
1842
|
+
ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, ¶ms->cParams);
|
1843
|
+
assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog);
|
1844
|
+
assert(params->ldmParams.hashRateLog < 32);
|
1648
1845
|
}
|
1649
1846
|
|
1650
|
-
{ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params
|
1847
|
+
{ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize));
|
1651
1848
|
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
|
1652
|
-
U32 const divider = (params
|
1849
|
+
U32 const divider = (params->cParams.minMatch==3) ? 3 : 4;
|
1653
1850
|
size_t const maxNbSeq = blockSize / divider;
|
1654
|
-
size_t const buffOutSize = (zbuff == ZSTDb_buffered && params
|
1851
|
+
size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered)
|
1655
1852
|
? ZSTD_compressBound(blockSize) + 1
|
1656
1853
|
: 0;
|
1657
|
-
size_t const buffInSize = (zbuff == ZSTDb_buffered && params
|
1854
|
+
size_t const buffInSize = (zbuff == ZSTDb_buffered && params->inBufferMode == ZSTD_bm_buffered)
|
1658
1855
|
? windowSize + blockSize
|
1659
1856
|
: 0;
|
1660
|
-
size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params
|
1857
|
+
size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize);
|
1661
1858
|
|
1662
1859
|
int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window);
|
1860
|
+
int const dictTooBig = ZSTD_dictTooBig(loadedDictSize);
|
1663
1861
|
ZSTD_indexResetPolicy_e needsIndexReset =
|
1664
|
-
(
|
1862
|
+
(indexTooClose || dictTooBig || !zc->initialized) ? ZSTDirp_reset : ZSTDirp_continue;
|
1665
1863
|
|
1666
1864
|
size_t const neededSpace =
|
1667
1865
|
ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
1668
|
-
¶ms
|
1866
|
+
¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder,
|
1669
1867
|
buffInSize, buffOutSize, pledgedSrcSize);
|
1868
|
+
int resizeWorkspace;
|
1869
|
+
|
1670
1870
|
FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!");
|
1671
1871
|
|
1672
1872
|
if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
|
1673
1873
|
|
1674
|
-
/* Check if workspace is large enough, alloc a new one if needed */
|
1675
|
-
{
|
1874
|
+
{ /* Check if workspace is large enough, alloc a new one if needed */
|
1676
1875
|
int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
|
1677
1876
|
int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
|
1678
|
-
|
1877
|
+
resizeWorkspace = workspaceTooSmall || workspaceWasteful;
|
1679
1878
|
DEBUGLOG(4, "Need %zu B workspace", neededSpace);
|
1680
1879
|
DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
|
1681
1880
|
|
1682
|
-
if (
|
1881
|
+
if (resizeWorkspace) {
|
1683
1882
|
DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB",
|
1684
1883
|
ZSTD_cwksp_sizeof(ws) >> 10,
|
1685
1884
|
neededSpace >> 10);
|
@@ -1707,8 +1906,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|
1707
1906
|
ZSTD_cwksp_clear(ws);
|
1708
1907
|
|
1709
1908
|
/* init params */
|
1710
|
-
zc->
|
1711
|
-
zc->blockState.matchState.cParams = params.cParams;
|
1909
|
+
zc->blockState.matchState.cParams = params->cParams;
|
1712
1910
|
zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
1713
1911
|
zc->consumedSrcSize = 0;
|
1714
1912
|
zc->producedCSize = 0;
|
@@ -1739,11 +1937,11 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|
1739
1937
|
zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize);
|
1740
1938
|
|
1741
1939
|
/* ldm bucketOffsets table */
|
1742
|
-
if (params
|
1940
|
+
if (params->ldmParams.enableLdm) {
|
1743
1941
|
/* TODO: avoid memset? */
|
1744
1942
|
size_t const numBuckets =
|
1745
|
-
((size_t)1) << (params
|
1746
|
-
params
|
1943
|
+
((size_t)1) << (params->ldmParams.hashLog -
|
1944
|
+
params->ldmParams.bucketSizeLog);
|
1747
1945
|
zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets);
|
1748
1946
|
ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets);
|
1749
1947
|
}
|
@@ -1759,32 +1957,28 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|
1759
1957
|
FORWARD_IF_ERROR(ZSTD_reset_matchState(
|
1760
1958
|
&zc->blockState.matchState,
|
1761
1959
|
ws,
|
1762
|
-
¶ms
|
1960
|
+
¶ms->cParams,
|
1961
|
+
params->useRowMatchFinder,
|
1763
1962
|
crp,
|
1764
1963
|
needsIndexReset,
|
1765
1964
|
ZSTD_resetTarget_CCtx), "");
|
1766
1965
|
|
1767
1966
|
/* ldm hash table */
|
1768
|
-
if (params
|
1967
|
+
if (params->ldmParams.enableLdm) {
|
1769
1968
|
/* TODO: avoid memset? */
|
1770
|
-
size_t const ldmHSize = ((size_t)1) << params
|
1969
|
+
size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog;
|
1771
1970
|
zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
|
1772
1971
|
ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
|
1773
1972
|
zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
|
1774
1973
|
zc->maxNbLdmSequences = maxNbLdmSeq;
|
1775
1974
|
|
1776
1975
|
ZSTD_window_init(&zc->ldmState.window);
|
1777
|
-
ZSTD_window_clear(&zc->ldmState.window);
|
1778
1976
|
zc->ldmState.loadedDictEnd = 0;
|
1779
1977
|
}
|
1780
1978
|
|
1781
|
-
|
1782
|
-
* up to 3 extra bytes for alignment. See the comments in zstd_cwksp.h
|
1783
|
-
*/
|
1784
|
-
assert(ZSTD_cwksp_used(ws) >= neededSpace &&
|
1785
|
-
ZSTD_cwksp_used(ws) <= neededSpace + 3);
|
1786
|
-
|
1979
|
+
assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace, resizeWorkspace));
|
1787
1980
|
DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
|
1981
|
+
|
1788
1982
|
zc->initialized = 1;
|
1789
1983
|
|
1790
1984
|
return 0;
|
@@ -1840,6 +2034,8 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
|
|
1840
2034
|
U64 pledgedSrcSize,
|
1841
2035
|
ZSTD_buffered_policy_e zbuff)
|
1842
2036
|
{
|
2037
|
+
DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu",
|
2038
|
+
(unsigned long long)pledgedSrcSize);
|
1843
2039
|
{
|
1844
2040
|
ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams;
|
1845
2041
|
unsigned const windowLog = params.cParams.windowLog;
|
@@ -1855,7 +2051,9 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
|
|
1855
2051
|
params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize,
|
1856
2052
|
cdict->dictContentSize, ZSTD_cpm_attachDict);
|
1857
2053
|
params.cParams.windowLog = windowLog;
|
1858
|
-
|
2054
|
+
params.useRowMatchFinder = cdict->useRowMatchFinder; /* cdict overrides */
|
2055
|
+
FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize,
|
2056
|
+
/* loadedDictSize */ 0,
|
1859
2057
|
ZSTDcrp_makeClean, zbuff), "");
|
1860
2058
|
assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy);
|
1861
2059
|
}
|
@@ -1899,15 +2097,17 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
|
|
1899
2097
|
const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
|
1900
2098
|
|
1901
2099
|
assert(!cdict->matchState.dedicatedDictSearch);
|
1902
|
-
|
1903
|
-
|
2100
|
+
DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu",
|
2101
|
+
(unsigned long long)pledgedSrcSize);
|
1904
2102
|
|
1905
2103
|
{ unsigned const windowLog = params.cParams.windowLog;
|
1906
2104
|
assert(windowLog != 0);
|
1907
2105
|
/* Copy only compression parameters related to tables. */
|
1908
2106
|
params.cParams = *cdict_cParams;
|
1909
2107
|
params.cParams.windowLog = windowLog;
|
1910
|
-
|
2108
|
+
params.useRowMatchFinder = cdict->useRowMatchFinder;
|
2109
|
+
FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize,
|
2110
|
+
/* loadedDictSize */ 0,
|
1911
2111
|
ZSTDcrp_leaveDirty, zbuff), "");
|
1912
2112
|
assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
|
1913
2113
|
assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
|
@@ -1915,17 +2115,30 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
|
|
1915
2115
|
}
|
1916
2116
|
|
1917
2117
|
ZSTD_cwksp_mark_tables_dirty(&cctx->workspace);
|
2118
|
+
assert(params.useRowMatchFinder != ZSTD_urm_auto);
|
1918
2119
|
|
1919
2120
|
/* copy tables */
|
1920
|
-
{ size_t const chainSize = (cdict_cParams->strategy
|
2121
|
+
{ size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */)
|
2122
|
+
? ((size_t)1 << cdict_cParams->chainLog)
|
2123
|
+
: 0;
|
1921
2124
|
size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
|
1922
2125
|
|
1923
2126
|
ZSTD_memcpy(cctx->blockState.matchState.hashTable,
|
1924
2127
|
cdict->matchState.hashTable,
|
1925
2128
|
hSize * sizeof(U32));
|
1926
|
-
|
2129
|
+
/* Do not copy cdict's chainTable if cctx has parameters such that it would not use chainTable */
|
2130
|
+
if (ZSTD_allocateChainTable(cctx->appliedParams.cParams.strategy, cctx->appliedParams.useRowMatchFinder, 0 /* forDDSDict */)) {
|
2131
|
+
ZSTD_memcpy(cctx->blockState.matchState.chainTable,
|
1927
2132
|
cdict->matchState.chainTable,
|
1928
2133
|
chainSize * sizeof(U32));
|
2134
|
+
}
|
2135
|
+
/* copy tag table */
|
2136
|
+
if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) {
|
2137
|
+
size_t const tagTableSize = hSize*sizeof(U16);
|
2138
|
+
ZSTD_memcpy(cctx->blockState.matchState.tagTable,
|
2139
|
+
cdict->matchState.tagTable,
|
2140
|
+
tagTableSize);
|
2141
|
+
}
|
1929
2142
|
}
|
1930
2143
|
|
1931
2144
|
/* Zero the hashTable3, since the cdict never fills it */
|
@@ -1989,16 +2202,18 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
|
1989
2202
|
U64 pledgedSrcSize,
|
1990
2203
|
ZSTD_buffered_policy_e zbuff)
|
1991
2204
|
{
|
1992
|
-
DEBUGLOG(5, "ZSTD_copyCCtx_internal");
|
1993
2205
|
RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
|
1994
2206
|
"Can't copy a ctx that's not in init stage.");
|
1995
|
-
|
2207
|
+
DEBUGLOG(5, "ZSTD_copyCCtx_internal");
|
1996
2208
|
ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
|
1997
2209
|
{ ZSTD_CCtx_params params = dstCCtx->requestedParams;
|
1998
2210
|
/* Copy only compression parameters related to tables. */
|
1999
2211
|
params.cParams = srcCCtx->appliedParams.cParams;
|
2212
|
+
assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_urm_auto);
|
2213
|
+
params.useRowMatchFinder = srcCCtx->appliedParams.useRowMatchFinder;
|
2000
2214
|
params.fParams = fParams;
|
2001
|
-
ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
|
2215
|
+
ZSTD_resetCCtx_internal(dstCCtx, ¶ms, pledgedSrcSize,
|
2216
|
+
/* loadedDictSize */ 0,
|
2002
2217
|
ZSTDcrp_leaveDirty, zbuff);
|
2003
2218
|
assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
|
2004
2219
|
assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
|
@@ -2010,7 +2225,11 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
|
2010
2225
|
ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace);
|
2011
2226
|
|
2012
2227
|
/* copy tables */
|
2013
|
-
{ size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy
|
2228
|
+
{ size_t const chainSize = ZSTD_allocateChainTable(srcCCtx->appliedParams.cParams.strategy,
|
2229
|
+
srcCCtx->appliedParams.useRowMatchFinder,
|
2230
|
+
0 /* forDDSDict */)
|
2231
|
+
? ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog)
|
2232
|
+
: 0;
|
2014
2233
|
size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
|
2015
2234
|
int const h3log = srcCCtx->blockState.matchState.hashLog3;
|
2016
2235
|
size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
|
@@ -2124,7 +2343,7 @@ static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* par
|
|
2124
2343
|
ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
|
2125
2344
|
}
|
2126
2345
|
|
2127
|
-
if (params->cParams.strategy
|
2346
|
+
if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) {
|
2128
2347
|
U32 const chainSize = (U32)1 << params->cParams.chainLog;
|
2129
2348
|
if (params->cParams.strategy == ZSTD_btlazy2)
|
2130
2349
|
ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
|
@@ -2161,9 +2380,9 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
|
|
2161
2380
|
ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
|
2162
2381
|
mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
|
2163
2382
|
}
|
2164
|
-
if (seqStorePtr->
|
2383
|
+
if (seqStorePtr->longLengthType==ZSTD_llt_literalLength)
|
2165
2384
|
llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
|
2166
|
-
if (seqStorePtr->
|
2385
|
+
if (seqStorePtr->longLengthType==ZSTD_llt_matchLength)
|
2167
2386
|
mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
|
2168
2387
|
}
|
2169
2388
|
|
@@ -2177,10 +2396,158 @@ static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
|
|
2177
2396
|
return (cctxParams->targetCBlockSize != 0);
|
2178
2397
|
}
|
2179
2398
|
|
2180
|
-
/*
|
2181
|
-
*
|
2399
|
+
/* ZSTD_blockSplitterEnabled():
|
2400
|
+
* Returns if block splitting param is being used
|
2401
|
+
* If used, compression will do best effort to split a block in order to improve compression ratio.
|
2402
|
+
* Returns 1 if true, 0 otherwise. */
|
2403
|
+
static int ZSTD_blockSplitterEnabled(ZSTD_CCtx_params* cctxParams)
|
2404
|
+
{
|
2405
|
+
DEBUGLOG(5, "ZSTD_blockSplitterEnabled(splitBlocks=%d)", cctxParams->splitBlocks);
|
2406
|
+
return (cctxParams->splitBlocks != 0);
|
2407
|
+
}
|
2408
|
+
|
2409
|
+
/* Type returned by ZSTD_buildSequencesStatistics containing finalized symbol encoding types
|
2410
|
+
* and size of the sequences statistics
|
2411
|
+
*/
|
2412
|
+
typedef struct {
|
2413
|
+
U32 LLtype;
|
2414
|
+
U32 Offtype;
|
2415
|
+
U32 MLtype;
|
2416
|
+
size_t size;
|
2417
|
+
size_t lastCountSize; /* Accounts for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */
|
2418
|
+
} ZSTD_symbolEncodingTypeStats_t;
|
2419
|
+
|
2420
|
+
/* ZSTD_buildSequencesStatistics():
|
2421
|
+
* Returns a ZSTD_symbolEncodingTypeStats_t, or a zstd error code in the `size` field.
|
2422
|
+
* Modifies `nextEntropy` to have the appropriate values as a side effect.
|
2423
|
+
* nbSeq must be greater than 0.
|
2424
|
+
*
|
2425
|
+
* entropyWkspSize must be of size at least ENTROPY_WORKSPACE_SIZE - (MaxSeq + 1)*sizeof(U32)
|
2426
|
+
*/
|
2427
|
+
static ZSTD_symbolEncodingTypeStats_t
|
2428
|
+
ZSTD_buildSequencesStatistics(seqStore_t* seqStorePtr, size_t nbSeq,
|
2429
|
+
const ZSTD_fseCTables_t* prevEntropy, ZSTD_fseCTables_t* nextEntropy,
|
2430
|
+
BYTE* dst, const BYTE* const dstEnd,
|
2431
|
+
ZSTD_strategy strategy, unsigned* countWorkspace,
|
2432
|
+
void* entropyWorkspace, size_t entropyWkspSize) {
|
2433
|
+
BYTE* const ostart = dst;
|
2434
|
+
const BYTE* const oend = dstEnd;
|
2435
|
+
BYTE* op = ostart;
|
2436
|
+
FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
|
2437
|
+
FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
|
2438
|
+
FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
|
2439
|
+
const BYTE* const ofCodeTable = seqStorePtr->ofCode;
|
2440
|
+
const BYTE* const llCodeTable = seqStorePtr->llCode;
|
2441
|
+
const BYTE* const mlCodeTable = seqStorePtr->mlCode;
|
2442
|
+
ZSTD_symbolEncodingTypeStats_t stats;
|
2443
|
+
|
2444
|
+
stats.lastCountSize = 0;
|
2445
|
+
/* convert length/distances into codes */
|
2446
|
+
ZSTD_seqToCodes(seqStorePtr);
|
2447
|
+
assert(op <= oend);
|
2448
|
+
assert(nbSeq != 0); /* ZSTD_selectEncodingType() divides by nbSeq */
|
2449
|
+
/* build CTable for Literal Lengths */
|
2450
|
+
{ unsigned max = MaxLL;
|
2451
|
+
size_t const mostFrequent = HIST_countFast_wksp(countWorkspace, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
|
2452
|
+
DEBUGLOG(5, "Building LL table");
|
2453
|
+
nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
|
2454
|
+
stats.LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode,
|
2455
|
+
countWorkspace, max, mostFrequent, nbSeq,
|
2456
|
+
LLFSELog, prevEntropy->litlengthCTable,
|
2457
|
+
LL_defaultNorm, LL_defaultNormLog,
|
2458
|
+
ZSTD_defaultAllowed, strategy);
|
2459
|
+
assert(set_basic < set_compressed && set_rle < set_compressed);
|
2460
|
+
assert(!(stats.LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
2461
|
+
{ size_t const countSize = ZSTD_buildCTable(
|
2462
|
+
op, (size_t)(oend - op),
|
2463
|
+
CTable_LitLength, LLFSELog, (symbolEncodingType_e)stats.LLtype,
|
2464
|
+
countWorkspace, max, llCodeTable, nbSeq,
|
2465
|
+
LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
2466
|
+
prevEntropy->litlengthCTable,
|
2467
|
+
sizeof(prevEntropy->litlengthCTable),
|
2468
|
+
entropyWorkspace, entropyWkspSize);
|
2469
|
+
if (ZSTD_isError(countSize)) {
|
2470
|
+
DEBUGLOG(3, "ZSTD_buildCTable for LitLens failed");
|
2471
|
+
stats.size = countSize;
|
2472
|
+
return stats;
|
2473
|
+
}
|
2474
|
+
if (stats.LLtype == set_compressed)
|
2475
|
+
stats.lastCountSize = countSize;
|
2476
|
+
op += countSize;
|
2477
|
+
assert(op <= oend);
|
2478
|
+
} }
|
2479
|
+
/* build CTable for Offsets */
|
2480
|
+
{ unsigned max = MaxOff;
|
2481
|
+
size_t const mostFrequent = HIST_countFast_wksp(
|
2482
|
+
countWorkspace, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
|
2483
|
+
/* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
|
2484
|
+
ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
|
2485
|
+
DEBUGLOG(5, "Building OF table");
|
2486
|
+
nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
|
2487
|
+
stats.Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode,
|
2488
|
+
countWorkspace, max, mostFrequent, nbSeq,
|
2489
|
+
OffFSELog, prevEntropy->offcodeCTable,
|
2490
|
+
OF_defaultNorm, OF_defaultNormLog,
|
2491
|
+
defaultPolicy, strategy);
|
2492
|
+
assert(!(stats.Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
2493
|
+
{ size_t const countSize = ZSTD_buildCTable(
|
2494
|
+
op, (size_t)(oend - op),
|
2495
|
+
CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)stats.Offtype,
|
2496
|
+
countWorkspace, max, ofCodeTable, nbSeq,
|
2497
|
+
OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
2498
|
+
prevEntropy->offcodeCTable,
|
2499
|
+
sizeof(prevEntropy->offcodeCTable),
|
2500
|
+
entropyWorkspace, entropyWkspSize);
|
2501
|
+
if (ZSTD_isError(countSize)) {
|
2502
|
+
DEBUGLOG(3, "ZSTD_buildCTable for Offsets failed");
|
2503
|
+
stats.size = countSize;
|
2504
|
+
return stats;
|
2505
|
+
}
|
2506
|
+
if (stats.Offtype == set_compressed)
|
2507
|
+
stats.lastCountSize = countSize;
|
2508
|
+
op += countSize;
|
2509
|
+
assert(op <= oend);
|
2510
|
+
} }
|
2511
|
+
/* build CTable for MatchLengths */
|
2512
|
+
{ unsigned max = MaxML;
|
2513
|
+
size_t const mostFrequent = HIST_countFast_wksp(
|
2514
|
+
countWorkspace, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
|
2515
|
+
DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
|
2516
|
+
nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
|
2517
|
+
stats.MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode,
|
2518
|
+
countWorkspace, max, mostFrequent, nbSeq,
|
2519
|
+
MLFSELog, prevEntropy->matchlengthCTable,
|
2520
|
+
ML_defaultNorm, ML_defaultNormLog,
|
2521
|
+
ZSTD_defaultAllowed, strategy);
|
2522
|
+
assert(!(stats.MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
2523
|
+
{ size_t const countSize = ZSTD_buildCTable(
|
2524
|
+
op, (size_t)(oend - op),
|
2525
|
+
CTable_MatchLength, MLFSELog, (symbolEncodingType_e)stats.MLtype,
|
2526
|
+
countWorkspace, max, mlCodeTable, nbSeq,
|
2527
|
+
ML_defaultNorm, ML_defaultNormLog, MaxML,
|
2528
|
+
prevEntropy->matchlengthCTable,
|
2529
|
+
sizeof(prevEntropy->matchlengthCTable),
|
2530
|
+
entropyWorkspace, entropyWkspSize);
|
2531
|
+
if (ZSTD_isError(countSize)) {
|
2532
|
+
DEBUGLOG(3, "ZSTD_buildCTable for MatchLengths failed");
|
2533
|
+
stats.size = countSize;
|
2534
|
+
return stats;
|
2535
|
+
}
|
2536
|
+
if (stats.MLtype == set_compressed)
|
2537
|
+
stats.lastCountSize = countSize;
|
2538
|
+
op += countSize;
|
2539
|
+
assert(op <= oend);
|
2540
|
+
} }
|
2541
|
+
stats.size = (size_t)(op-ostart);
|
2542
|
+
return stats;
|
2543
|
+
}
|
2544
|
+
|
2545
|
+
/* ZSTD_entropyCompressSeqStore_internal():
|
2546
|
+
* compresses both literals and sequences
|
2547
|
+
* Returns compressed size of block, or a zstd error.
|
2548
|
+
*/
|
2182
2549
|
MEM_STATIC size_t
|
2183
|
-
|
2550
|
+
ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
|
2184
2551
|
const ZSTD_entropyCTables_t* prevEntropy,
|
2185
2552
|
ZSTD_entropyCTables_t* nextEntropy,
|
2186
2553
|
const ZSTD_CCtx_params* cctxParams,
|
@@ -2194,22 +2561,20 @@ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
|
|
2194
2561
|
FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
|
2195
2562
|
FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
|
2196
2563
|
FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
|
2197
|
-
U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
|
2198
2564
|
const seqDef* const sequences = seqStorePtr->sequencesStart;
|
2565
|
+
const size_t nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
|
2199
2566
|
const BYTE* const ofCodeTable = seqStorePtr->ofCode;
|
2200
2567
|
const BYTE* const llCodeTable = seqStorePtr->llCode;
|
2201
2568
|
const BYTE* const mlCodeTable = seqStorePtr->mlCode;
|
2202
2569
|
BYTE* const ostart = (BYTE*)dst;
|
2203
2570
|
BYTE* const oend = ostart + dstCapacity;
|
2204
2571
|
BYTE* op = ostart;
|
2205
|
-
size_t
|
2206
|
-
BYTE* seqHead;
|
2207
|
-
BYTE* lastNCount = NULL;
|
2572
|
+
size_t lastCountSize;
|
2208
2573
|
|
2209
2574
|
entropyWorkspace = count + (MaxSeq + 1);
|
2210
2575
|
entropyWkspSize -= (MaxSeq + 1) * sizeof(*count);
|
2211
2576
|
|
2212
|
-
DEBUGLOG(4, "
|
2577
|
+
DEBUGLOG(4, "ZSTD_entropyCompressSeqStore_internal (nbSeq=%zu)", nbSeq);
|
2213
2578
|
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
2214
2579
|
assert(entropyWkspSize >= HUF_WORKSPACE_SIZE);
|
2215
2580
|
|
@@ -2249,95 +2614,20 @@ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
|
|
2249
2614
|
ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
|
2250
2615
|
return (size_t)(op - ostart);
|
2251
2616
|
}
|
2252
|
-
|
2253
|
-
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2266
|
-
LLFSELog, prevEntropy->fse.litlengthCTable,
|
2267
|
-
LL_defaultNorm, LL_defaultNormLog,
|
2268
|
-
ZSTD_defaultAllowed, strategy);
|
2269
|
-
assert(set_basic < set_compressed && set_rle < set_compressed);
|
2270
|
-
assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
2271
|
-
{ size_t const countSize = ZSTD_buildCTable(
|
2272
|
-
op, (size_t)(oend - op),
|
2273
|
-
CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
|
2274
|
-
count, max, llCodeTable, nbSeq,
|
2275
|
-
LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
2276
|
-
prevEntropy->fse.litlengthCTable,
|
2277
|
-
sizeof(prevEntropy->fse.litlengthCTable),
|
2278
|
-
entropyWorkspace, entropyWkspSize);
|
2279
|
-
FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
|
2280
|
-
if (LLtype == set_compressed)
|
2281
|
-
lastNCount = op;
|
2282
|
-
op += countSize;
|
2283
|
-
assert(op <= oend);
|
2284
|
-
} }
|
2285
|
-
/* build CTable for Offsets */
|
2286
|
-
{ unsigned max = MaxOff;
|
2287
|
-
size_t const mostFrequent = HIST_countFast_wksp(
|
2288
|
-
count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
|
2289
|
-
/* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
|
2290
|
-
ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
|
2291
|
-
DEBUGLOG(5, "Building OF table");
|
2292
|
-
nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
|
2293
|
-
Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
|
2294
|
-
count, max, mostFrequent, nbSeq,
|
2295
|
-
OffFSELog, prevEntropy->fse.offcodeCTable,
|
2296
|
-
OF_defaultNorm, OF_defaultNormLog,
|
2297
|
-
defaultPolicy, strategy);
|
2298
|
-
assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
2299
|
-
{ size_t const countSize = ZSTD_buildCTable(
|
2300
|
-
op, (size_t)(oend - op),
|
2301
|
-
CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
|
2302
|
-
count, max, ofCodeTable, nbSeq,
|
2303
|
-
OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
2304
|
-
prevEntropy->fse.offcodeCTable,
|
2305
|
-
sizeof(prevEntropy->fse.offcodeCTable),
|
2306
|
-
entropyWorkspace, entropyWkspSize);
|
2307
|
-
FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
|
2308
|
-
if (Offtype == set_compressed)
|
2309
|
-
lastNCount = op;
|
2310
|
-
op += countSize;
|
2311
|
-
assert(op <= oend);
|
2312
|
-
} }
|
2313
|
-
/* build CTable for MatchLengths */
|
2314
|
-
{ unsigned max = MaxML;
|
2315
|
-
size_t const mostFrequent = HIST_countFast_wksp(
|
2316
|
-
count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
|
2317
|
-
DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
|
2318
|
-
nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
|
2319
|
-
MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
|
2320
|
-
count, max, mostFrequent, nbSeq,
|
2321
|
-
MLFSELog, prevEntropy->fse.matchlengthCTable,
|
2322
|
-
ML_defaultNorm, ML_defaultNormLog,
|
2323
|
-
ZSTD_defaultAllowed, strategy);
|
2324
|
-
assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
2325
|
-
{ size_t const countSize = ZSTD_buildCTable(
|
2326
|
-
op, (size_t)(oend - op),
|
2327
|
-
CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
|
2328
|
-
count, max, mlCodeTable, nbSeq,
|
2329
|
-
ML_defaultNorm, ML_defaultNormLog, MaxML,
|
2330
|
-
prevEntropy->fse.matchlengthCTable,
|
2331
|
-
sizeof(prevEntropy->fse.matchlengthCTable),
|
2332
|
-
entropyWorkspace, entropyWkspSize);
|
2333
|
-
FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
|
2334
|
-
if (MLtype == set_compressed)
|
2335
|
-
lastNCount = op;
|
2336
|
-
op += countSize;
|
2337
|
-
assert(op <= oend);
|
2338
|
-
} }
|
2339
|
-
|
2340
|
-
*seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
|
2617
|
+
{
|
2618
|
+
ZSTD_symbolEncodingTypeStats_t stats;
|
2619
|
+
BYTE* seqHead = op++;
|
2620
|
+
/* build stats for sequences */
|
2621
|
+
stats = ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq,
|
2622
|
+
&prevEntropy->fse, &nextEntropy->fse,
|
2623
|
+
op, oend,
|
2624
|
+
strategy, count,
|
2625
|
+
entropyWorkspace, entropyWkspSize);
|
2626
|
+
FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!");
|
2627
|
+
*seqHead = (BYTE)((stats.LLtype<<6) + (stats.Offtype<<4) + (stats.MLtype<<2));
|
2628
|
+
lastCountSize = stats.lastCountSize;
|
2629
|
+
op += stats.size;
|
2630
|
+
}
|
2341
2631
|
|
2342
2632
|
{ size_t const bitstreamSize = ZSTD_encodeSequences(
|
2343
2633
|
op, (size_t)(oend - op),
|
@@ -2357,9 +2647,9 @@ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
|
|
2357
2647
|
* In this exceedingly rare case, we will simply emit an uncompressed
|
2358
2648
|
* block, since it isn't worth optimizing.
|
2359
2649
|
*/
|
2360
|
-
if (
|
2361
|
-
/*
|
2362
|
-
assert(
|
2650
|
+
if (lastCountSize && (lastCountSize + bitstreamSize) < 4) {
|
2651
|
+
/* lastCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
|
2652
|
+
assert(lastCountSize + bitstreamSize == 3);
|
2363
2653
|
DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
|
2364
2654
|
"emitting an uncompressed block.");
|
2365
2655
|
return 0;
|
@@ -2371,7 +2661,7 @@ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
|
|
2371
2661
|
}
|
2372
2662
|
|
2373
2663
|
MEM_STATIC size_t
|
2374
|
-
|
2664
|
+
ZSTD_entropyCompressSeqStore(seqStore_t* seqStorePtr,
|
2375
2665
|
const ZSTD_entropyCTables_t* prevEntropy,
|
2376
2666
|
ZSTD_entropyCTables_t* nextEntropy,
|
2377
2667
|
const ZSTD_CCtx_params* cctxParams,
|
@@ -2380,7 +2670,7 @@ ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr,
|
|
2380
2670
|
void* entropyWorkspace, size_t entropyWkspSize,
|
2381
2671
|
int bmi2)
|
2382
2672
|
{
|
2383
|
-
size_t const cSize =
|
2673
|
+
size_t const cSize = ZSTD_entropyCompressSeqStore_internal(
|
2384
2674
|
seqStorePtr, prevEntropy, nextEntropy, cctxParams,
|
2385
2675
|
dst, dstCapacity,
|
2386
2676
|
entropyWorkspace, entropyWkspSize, bmi2);
|
@@ -2390,20 +2680,20 @@ ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr,
|
|
2390
2680
|
*/
|
2391
2681
|
if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
|
2392
2682
|
return 0; /* block not compressed */
|
2393
|
-
FORWARD_IF_ERROR(cSize, "
|
2683
|
+
FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSeqStore_internal failed");
|
2394
2684
|
|
2395
2685
|
/* Check compressibility */
|
2396
2686
|
{ size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
|
2397
2687
|
if (cSize >= maxCSize) return 0; /* block not compressed */
|
2398
2688
|
}
|
2399
|
-
DEBUGLOG(4, "
|
2689
|
+
DEBUGLOG(4, "ZSTD_entropyCompressSeqStore() cSize: %zu", cSize);
|
2400
2690
|
return cSize;
|
2401
2691
|
}
|
2402
2692
|
|
2403
2693
|
/* ZSTD_selectBlockCompressor() :
|
2404
2694
|
* Not static, but internal use only (used by long distance matcher)
|
2405
2695
|
* assumption : strat is a valid strategy */
|
2406
|
-
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
|
2696
|
+
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_useRowMatchFinderMode_e useRowMatchFinder, ZSTD_dictMode_e dictMode)
|
2407
2697
|
{
|
2408
2698
|
static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = {
|
2409
2699
|
{ ZSTD_compressBlock_fast /* default for 0 */,
|
@@ -2451,7 +2741,28 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo
|
|
2451
2741
|
ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
|
2452
2742
|
|
2453
2743
|
assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
|
2454
|
-
|
2744
|
+
DEBUGLOG(4, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder);
|
2745
|
+
if (ZSTD_rowMatchFinderUsed(strat, useRowMatchFinder)) {
|
2746
|
+
static const ZSTD_blockCompressor rowBasedBlockCompressors[4][3] = {
|
2747
|
+
{ ZSTD_compressBlock_greedy_row,
|
2748
|
+
ZSTD_compressBlock_lazy_row,
|
2749
|
+
ZSTD_compressBlock_lazy2_row },
|
2750
|
+
{ ZSTD_compressBlock_greedy_extDict_row,
|
2751
|
+
ZSTD_compressBlock_lazy_extDict_row,
|
2752
|
+
ZSTD_compressBlock_lazy2_extDict_row },
|
2753
|
+
{ ZSTD_compressBlock_greedy_dictMatchState_row,
|
2754
|
+
ZSTD_compressBlock_lazy_dictMatchState_row,
|
2755
|
+
ZSTD_compressBlock_lazy2_dictMatchState_row },
|
2756
|
+
{ ZSTD_compressBlock_greedy_dedicatedDictSearch_row,
|
2757
|
+
ZSTD_compressBlock_lazy_dedicatedDictSearch_row,
|
2758
|
+
ZSTD_compressBlock_lazy2_dedicatedDictSearch_row }
|
2759
|
+
};
|
2760
|
+
DEBUGLOG(4, "Selecting a row-based matchfinder");
|
2761
|
+
assert(useRowMatchFinder != ZSTD_urm_auto);
|
2762
|
+
selectedCompressor = rowBasedBlockCompressors[(int)dictMode][(int)strat - (int)ZSTD_greedy];
|
2763
|
+
} else {
|
2764
|
+
selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
|
2765
|
+
}
|
2455
2766
|
assert(selectedCompressor != NULL);
|
2456
2767
|
return selectedCompressor;
|
2457
2768
|
}
|
@@ -2467,7 +2778,7 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr)
|
|
2467
2778
|
{
|
2468
2779
|
ssPtr->lit = ssPtr->litStart;
|
2469
2780
|
ssPtr->sequences = ssPtr->sequencesStart;
|
2470
|
-
ssPtr->
|
2781
|
+
ssPtr->longLengthType = ZSTD_llt_none;
|
2471
2782
|
}
|
2472
2783
|
|
2473
2784
|
typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e;
|
@@ -2520,6 +2831,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
|
2520
2831
|
ZSTD_ldm_blockCompress(&zc->externSeqStore,
|
2521
2832
|
ms, &zc->seqStore,
|
2522
2833
|
zc->blockState.nextCBlock->rep,
|
2834
|
+
zc->appliedParams.useRowMatchFinder,
|
2523
2835
|
src, srcSize);
|
2524
2836
|
assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
|
2525
2837
|
} else if (zc->appliedParams.ldmParams.enableLdm) {
|
@@ -2536,10 +2848,13 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
|
2536
2848
|
ZSTD_ldm_blockCompress(&ldmSeqStore,
|
2537
2849
|
ms, &zc->seqStore,
|
2538
2850
|
zc->blockState.nextCBlock->rep,
|
2851
|
+
zc->appliedParams.useRowMatchFinder,
|
2539
2852
|
src, srcSize);
|
2540
2853
|
assert(ldmSeqStore.pos == ldmSeqStore.size);
|
2541
2854
|
} else { /* not long range mode */
|
2542
|
-
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy,
|
2855
|
+
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy,
|
2856
|
+
zc->appliedParams.useRowMatchFinder,
|
2857
|
+
dictMode);
|
2543
2858
|
ms->ldmSeqStore = NULL;
|
2544
2859
|
lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
|
2545
2860
|
}
|
@@ -2573,9 +2888,9 @@ static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
|
|
2573
2888
|
outSeqs[i].rep = 0;
|
2574
2889
|
|
2575
2890
|
if (i == seqStore->longLengthPos) {
|
2576
|
-
if (seqStore->
|
2891
|
+
if (seqStore->longLengthType == ZSTD_llt_literalLength) {
|
2577
2892
|
outSeqs[i].litLength += 0x10000;
|
2578
|
-
} else if (seqStore->
|
2893
|
+
} else if (seqStore->longLengthType == ZSTD_llt_matchLength) {
|
2579
2894
|
outSeqs[i].matchLength += 0x10000;
|
2580
2895
|
}
|
2581
2896
|
}
|
@@ -2686,11 +3001,713 @@ static int ZSTD_maybeRLE(seqStore_t const* seqStore)
|
|
2686
3001
|
return nbSeqs < 4 && nbLits < 10;
|
2687
3002
|
}
|
2688
3003
|
|
2689
|
-
static void
|
3004
|
+
static void ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs)
|
3005
|
+
{
|
3006
|
+
ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock;
|
3007
|
+
bs->prevCBlock = bs->nextCBlock;
|
3008
|
+
bs->nextCBlock = tmp;
|
3009
|
+
}
|
3010
|
+
|
3011
|
+
/* Writes the block header */
|
3012
|
+
static void writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock) {
|
3013
|
+
U32 const cBlockHeader = cSize == 1 ?
|
3014
|
+
lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) :
|
3015
|
+
lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
|
3016
|
+
MEM_writeLE24(op, cBlockHeader);
|
3017
|
+
DEBUGLOG(3, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock);
|
3018
|
+
}
|
3019
|
+
|
3020
|
+
/** ZSTD_buildBlockEntropyStats_literals() :
|
3021
|
+
* Builds entropy for the literals.
|
3022
|
+
* Stores literals block type (raw, rle, compressed, repeat) and
|
3023
|
+
* huffman description table to hufMetadata.
|
3024
|
+
* Requires ENTROPY_WORKSPACE_SIZE workspace
|
3025
|
+
* @return : size of huffman description table or error code */
|
3026
|
+
static size_t ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSize,
|
3027
|
+
const ZSTD_hufCTables_t* prevHuf,
|
3028
|
+
ZSTD_hufCTables_t* nextHuf,
|
3029
|
+
ZSTD_hufCTablesMetadata_t* hufMetadata,
|
3030
|
+
const int disableLiteralsCompression,
|
3031
|
+
void* workspace, size_t wkspSize)
|
3032
|
+
{
|
3033
|
+
BYTE* const wkspStart = (BYTE*)workspace;
|
3034
|
+
BYTE* const wkspEnd = wkspStart + wkspSize;
|
3035
|
+
BYTE* const countWkspStart = wkspStart;
|
3036
|
+
unsigned* const countWksp = (unsigned*)workspace;
|
3037
|
+
const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned);
|
3038
|
+
BYTE* const nodeWksp = countWkspStart + countWkspSize;
|
3039
|
+
const size_t nodeWkspSize = wkspEnd-nodeWksp;
|
3040
|
+
unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX;
|
3041
|
+
unsigned huffLog = HUF_TABLELOG_DEFAULT;
|
3042
|
+
HUF_repeat repeat = prevHuf->repeatMode;
|
3043
|
+
DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize);
|
3044
|
+
|
3045
|
+
/* Prepare nextEntropy assuming reusing the existing table */
|
3046
|
+
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
3047
|
+
|
3048
|
+
if (disableLiteralsCompression) {
|
3049
|
+
DEBUGLOG(5, "set_basic - disabled");
|
3050
|
+
hufMetadata->hType = set_basic;
|
3051
|
+
return 0;
|
3052
|
+
}
|
3053
|
+
|
3054
|
+
/* small ? don't even attempt compression (speed opt) */
|
3055
|
+
#ifndef COMPRESS_LITERALS_SIZE_MIN
|
3056
|
+
#define COMPRESS_LITERALS_SIZE_MIN 63
|
3057
|
+
#endif
|
3058
|
+
{ size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
|
3059
|
+
if (srcSize <= minLitSize) {
|
3060
|
+
DEBUGLOG(5, "set_basic - too small");
|
3061
|
+
hufMetadata->hType = set_basic;
|
3062
|
+
return 0;
|
3063
|
+
}
|
3064
|
+
}
|
3065
|
+
|
3066
|
+
/* Scan input and build symbol stats */
|
3067
|
+
{ size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize);
|
3068
|
+
FORWARD_IF_ERROR(largest, "HIST_count_wksp failed");
|
3069
|
+
if (largest == srcSize) {
|
3070
|
+
DEBUGLOG(5, "set_rle");
|
3071
|
+
hufMetadata->hType = set_rle;
|
3072
|
+
return 0;
|
3073
|
+
}
|
3074
|
+
if (largest <= (srcSize >> 7)+4) {
|
3075
|
+
DEBUGLOG(5, "set_basic - no gain");
|
3076
|
+
hufMetadata->hType = set_basic;
|
3077
|
+
return 0;
|
3078
|
+
}
|
3079
|
+
}
|
3080
|
+
|
3081
|
+
/* Validate the previous Huffman table */
|
3082
|
+
if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) {
|
3083
|
+
repeat = HUF_repeat_none;
|
3084
|
+
}
|
3085
|
+
|
3086
|
+
/* Build Huffman Tree */
|
3087
|
+
ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable));
|
3088
|
+
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
|
3089
|
+
{ size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp,
|
3090
|
+
maxSymbolValue, huffLog,
|
3091
|
+
nodeWksp, nodeWkspSize);
|
3092
|
+
FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp");
|
3093
|
+
huffLog = (U32)maxBits;
|
3094
|
+
{ /* Build and write the CTable */
|
3095
|
+
size_t const newCSize = HUF_estimateCompressedSize(
|
3096
|
+
(HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
|
3097
|
+
size_t const hSize = HUF_writeCTable_wksp(
|
3098
|
+
hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
|
3099
|
+
(HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog,
|
3100
|
+
nodeWksp, nodeWkspSize);
|
3101
|
+
/* Check against repeating the previous CTable */
|
3102
|
+
if (repeat != HUF_repeat_none) {
|
3103
|
+
size_t const oldCSize = HUF_estimateCompressedSize(
|
3104
|
+
(HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue);
|
3105
|
+
if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) {
|
3106
|
+
DEBUGLOG(5, "set_repeat - smaller");
|
3107
|
+
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
3108
|
+
hufMetadata->hType = set_repeat;
|
3109
|
+
return 0;
|
3110
|
+
}
|
3111
|
+
}
|
3112
|
+
if (newCSize + hSize >= srcSize) {
|
3113
|
+
DEBUGLOG(5, "set_basic - no gains");
|
3114
|
+
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
3115
|
+
hufMetadata->hType = set_basic;
|
3116
|
+
return 0;
|
3117
|
+
}
|
3118
|
+
DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize);
|
3119
|
+
hufMetadata->hType = set_compressed;
|
3120
|
+
nextHuf->repeatMode = HUF_repeat_check;
|
3121
|
+
return hSize;
|
3122
|
+
}
|
3123
|
+
}
|
3124
|
+
}
|
3125
|
+
|
3126
|
+
|
3127
|
+
/* ZSTD_buildDummySequencesStatistics():
|
3128
|
+
* Returns a ZSTD_symbolEncodingTypeStats_t with all encoding types as set_basic,
|
3129
|
+
* and updates nextEntropy to the appropriate repeatMode.
|
3130
|
+
*/
|
3131
|
+
static ZSTD_symbolEncodingTypeStats_t
|
3132
|
+
ZSTD_buildDummySequencesStatistics(ZSTD_fseCTables_t* nextEntropy) {
|
3133
|
+
ZSTD_symbolEncodingTypeStats_t stats = {set_basic, set_basic, set_basic, 0, 0};
|
3134
|
+
nextEntropy->litlength_repeatMode = FSE_repeat_none;
|
3135
|
+
nextEntropy->offcode_repeatMode = FSE_repeat_none;
|
3136
|
+
nextEntropy->matchlength_repeatMode = FSE_repeat_none;
|
3137
|
+
return stats;
|
3138
|
+
}
|
3139
|
+
|
3140
|
+
/** ZSTD_buildBlockEntropyStats_sequences() :
|
3141
|
+
* Builds entropy for the sequences.
|
3142
|
+
* Stores symbol compression modes and fse table to fseMetadata.
|
3143
|
+
* Requires ENTROPY_WORKSPACE_SIZE wksp.
|
3144
|
+
* @return : size of fse tables or error code */
|
3145
|
+
static size_t ZSTD_buildBlockEntropyStats_sequences(seqStore_t* seqStorePtr,
|
3146
|
+
const ZSTD_fseCTables_t* prevEntropy,
|
3147
|
+
ZSTD_fseCTables_t* nextEntropy,
|
3148
|
+
const ZSTD_CCtx_params* cctxParams,
|
3149
|
+
ZSTD_fseCTablesMetadata_t* fseMetadata,
|
3150
|
+
void* workspace, size_t wkspSize)
|
2690
3151
|
{
|
2691
|
-
|
2692
|
-
|
2693
|
-
|
3152
|
+
ZSTD_strategy const strategy = cctxParams->cParams.strategy;
|
3153
|
+
size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
|
3154
|
+
BYTE* const ostart = fseMetadata->fseTablesBuffer;
|
3155
|
+
BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer);
|
3156
|
+
BYTE* op = ostart;
|
3157
|
+
unsigned* countWorkspace = (unsigned*)workspace;
|
3158
|
+
unsigned* entropyWorkspace = countWorkspace + (MaxSeq + 1);
|
3159
|
+
size_t entropyWorkspaceSize = wkspSize - (MaxSeq + 1) * sizeof(*countWorkspace);
|
3160
|
+
ZSTD_symbolEncodingTypeStats_t stats;
|
3161
|
+
|
3162
|
+
DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_sequences (nbSeq=%zu)", nbSeq);
|
3163
|
+
stats = nbSeq != 0 ? ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq,
|
3164
|
+
prevEntropy, nextEntropy, op, oend,
|
3165
|
+
strategy, countWorkspace,
|
3166
|
+
entropyWorkspace, entropyWorkspaceSize)
|
3167
|
+
: ZSTD_buildDummySequencesStatistics(nextEntropy);
|
3168
|
+
FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!");
|
3169
|
+
fseMetadata->llType = (symbolEncodingType_e) stats.LLtype;
|
3170
|
+
fseMetadata->ofType = (symbolEncodingType_e) stats.Offtype;
|
3171
|
+
fseMetadata->mlType = (symbolEncodingType_e) stats.MLtype;
|
3172
|
+
fseMetadata->lastCountSize = stats.lastCountSize;
|
3173
|
+
return stats.size;
|
3174
|
+
}
|
3175
|
+
|
3176
|
+
|
3177
|
+
/** ZSTD_buildBlockEntropyStats() :
|
3178
|
+
* Builds entropy for the block.
|
3179
|
+
* Requires workspace size ENTROPY_WORKSPACE_SIZE
|
3180
|
+
*
|
3181
|
+
* @return : 0 on success or error code
|
3182
|
+
*/
|
3183
|
+
size_t ZSTD_buildBlockEntropyStats(seqStore_t* seqStorePtr,
|
3184
|
+
const ZSTD_entropyCTables_t* prevEntropy,
|
3185
|
+
ZSTD_entropyCTables_t* nextEntropy,
|
3186
|
+
const ZSTD_CCtx_params* cctxParams,
|
3187
|
+
ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
3188
|
+
void* workspace, size_t wkspSize)
|
3189
|
+
{
|
3190
|
+
size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart;
|
3191
|
+
entropyMetadata->hufMetadata.hufDesSize =
|
3192
|
+
ZSTD_buildBlockEntropyStats_literals(seqStorePtr->litStart, litSize,
|
3193
|
+
&prevEntropy->huf, &nextEntropy->huf,
|
3194
|
+
&entropyMetadata->hufMetadata,
|
3195
|
+
ZSTD_disableLiteralsCompression(cctxParams),
|
3196
|
+
workspace, wkspSize);
|
3197
|
+
FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildBlockEntropyStats_literals failed");
|
3198
|
+
entropyMetadata->fseMetadata.fseTablesSize =
|
3199
|
+
ZSTD_buildBlockEntropyStats_sequences(seqStorePtr,
|
3200
|
+
&prevEntropy->fse, &nextEntropy->fse,
|
3201
|
+
cctxParams,
|
3202
|
+
&entropyMetadata->fseMetadata,
|
3203
|
+
workspace, wkspSize);
|
3204
|
+
FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildBlockEntropyStats_sequences failed");
|
3205
|
+
return 0;
|
3206
|
+
}
|
3207
|
+
|
3208
|
+
/* Returns the size estimate for the literals section (header + content) of a block */
|
3209
|
+
static size_t ZSTD_estimateBlockSize_literal(const BYTE* literals, size_t litSize,
|
3210
|
+
const ZSTD_hufCTables_t* huf,
|
3211
|
+
const ZSTD_hufCTablesMetadata_t* hufMetadata,
|
3212
|
+
void* workspace, size_t wkspSize,
|
3213
|
+
int writeEntropy)
|
3214
|
+
{
|
3215
|
+
unsigned* const countWksp = (unsigned*)workspace;
|
3216
|
+
unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX;
|
3217
|
+
size_t literalSectionHeaderSize = 3 + (litSize >= 1 KB) + (litSize >= 16 KB);
|
3218
|
+
U32 singleStream = litSize < 256;
|
3219
|
+
|
3220
|
+
if (hufMetadata->hType == set_basic) return litSize;
|
3221
|
+
else if (hufMetadata->hType == set_rle) return 1;
|
3222
|
+
else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) {
|
3223
|
+
size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize);
|
3224
|
+
if (ZSTD_isError(largest)) return litSize;
|
3225
|
+
{ size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue);
|
3226
|
+
if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize;
|
3227
|
+
if (!singleStream) cLitSizeEstimate += 6; /* multi-stream huffman uses 6-byte jump table */
|
3228
|
+
return cLitSizeEstimate + literalSectionHeaderSize;
|
3229
|
+
} }
|
3230
|
+
assert(0); /* impossible */
|
3231
|
+
return 0;
|
3232
|
+
}
|
3233
|
+
|
3234
|
+
/* Returns the size estimate for the FSE-compressed symbols (of, ml, ll) of a block */
|
3235
|
+
static size_t ZSTD_estimateBlockSize_symbolType(symbolEncodingType_e type,
|
3236
|
+
const BYTE* codeTable, size_t nbSeq, unsigned maxCode,
|
3237
|
+
const FSE_CTable* fseCTable,
|
3238
|
+
const U32* additionalBits,
|
3239
|
+
short const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
3240
|
+
void* workspace, size_t wkspSize)
|
3241
|
+
{
|
3242
|
+
unsigned* const countWksp = (unsigned*)workspace;
|
3243
|
+
const BYTE* ctp = codeTable;
|
3244
|
+
const BYTE* const ctStart = ctp;
|
3245
|
+
const BYTE* const ctEnd = ctStart + nbSeq;
|
3246
|
+
size_t cSymbolTypeSizeEstimateInBits = 0;
|
3247
|
+
unsigned max = maxCode;
|
3248
|
+
|
3249
|
+
HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */
|
3250
|
+
if (type == set_basic) {
|
3251
|
+
/* We selected this encoding type, so it must be valid. */
|
3252
|
+
assert(max <= defaultMax);
|
3253
|
+
(void)defaultMax;
|
3254
|
+
cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max);
|
3255
|
+
} else if (type == set_rle) {
|
3256
|
+
cSymbolTypeSizeEstimateInBits = 0;
|
3257
|
+
} else if (type == set_compressed || type == set_repeat) {
|
3258
|
+
cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max);
|
3259
|
+
}
|
3260
|
+
if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) {
|
3261
|
+
return nbSeq * 10;
|
3262
|
+
}
|
3263
|
+
while (ctp < ctEnd) {
|
3264
|
+
if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp];
|
3265
|
+
else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */
|
3266
|
+
ctp++;
|
3267
|
+
}
|
3268
|
+
return cSymbolTypeSizeEstimateInBits >> 3;
|
3269
|
+
}
|
3270
|
+
|
3271
|
+
/* Returns the size estimate for the sequences section (header + content) of a block */
|
3272
|
+
static size_t ZSTD_estimateBlockSize_sequences(const BYTE* ofCodeTable,
|
3273
|
+
const BYTE* llCodeTable,
|
3274
|
+
const BYTE* mlCodeTable,
|
3275
|
+
size_t nbSeq,
|
3276
|
+
const ZSTD_fseCTables_t* fseTables,
|
3277
|
+
const ZSTD_fseCTablesMetadata_t* fseMetadata,
|
3278
|
+
void* workspace, size_t wkspSize,
|
3279
|
+
int writeEntropy)
|
3280
|
+
{
|
3281
|
+
size_t sequencesSectionHeaderSize = 1 /* seqHead */ + 1 /* min seqSize size */ + (nbSeq >= 128) + (nbSeq >= LONGNBSEQ);
|
3282
|
+
size_t cSeqSizeEstimate = 0;
|
3283
|
+
cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, nbSeq, MaxOff,
|
3284
|
+
fseTables->offcodeCTable, NULL,
|
3285
|
+
OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
3286
|
+
workspace, wkspSize);
|
3287
|
+
cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->llType, llCodeTable, nbSeq, MaxLL,
|
3288
|
+
fseTables->litlengthCTable, LL_bits,
|
3289
|
+
LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
3290
|
+
workspace, wkspSize);
|
3291
|
+
cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, nbSeq, MaxML,
|
3292
|
+
fseTables->matchlengthCTable, ML_bits,
|
3293
|
+
ML_defaultNorm, ML_defaultNormLog, MaxML,
|
3294
|
+
workspace, wkspSize);
|
3295
|
+
if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;
|
3296
|
+
return cSeqSizeEstimate + sequencesSectionHeaderSize;
|
3297
|
+
}
|
3298
|
+
|
3299
|
+
/* Returns the size estimate for a given stream of literals, of, ll, ml */
|
3300
|
+
static size_t ZSTD_estimateBlockSize(const BYTE* literals, size_t litSize,
|
3301
|
+
const BYTE* ofCodeTable,
|
3302
|
+
const BYTE* llCodeTable,
|
3303
|
+
const BYTE* mlCodeTable,
|
3304
|
+
size_t nbSeq,
|
3305
|
+
const ZSTD_entropyCTables_t* entropy,
|
3306
|
+
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
3307
|
+
void* workspace, size_t wkspSize,
|
3308
|
+
int writeLitEntropy, int writeSeqEntropy) {
|
3309
|
+
size_t const literalsSize = ZSTD_estimateBlockSize_literal(literals, litSize,
|
3310
|
+
&entropy->huf, &entropyMetadata->hufMetadata,
|
3311
|
+
workspace, wkspSize, writeLitEntropy);
|
3312
|
+
size_t const seqSize = ZSTD_estimateBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
|
3313
|
+
nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
|
3314
|
+
workspace, wkspSize, writeSeqEntropy);
|
3315
|
+
return seqSize + literalsSize + ZSTD_blockHeaderSize;
|
3316
|
+
}
|
3317
|
+
|
3318
|
+
/* Builds entropy statistics and uses them for blocksize estimation.
|
3319
|
+
*
|
3320
|
+
* Returns the estimated compressed size of the seqStore, or a zstd error.
|
3321
|
+
*/
|
3322
|
+
static size_t ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(seqStore_t* seqStore, const ZSTD_CCtx* zc) {
|
3323
|
+
ZSTD_entropyCTablesMetadata_t entropyMetadata;
|
3324
|
+
FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(seqStore,
|
3325
|
+
&zc->blockState.prevCBlock->entropy,
|
3326
|
+
&zc->blockState.nextCBlock->entropy,
|
3327
|
+
&zc->appliedParams,
|
3328
|
+
&entropyMetadata,
|
3329
|
+
zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");
|
3330
|
+
return ZSTD_estimateBlockSize(seqStore->litStart, (size_t)(seqStore->lit - seqStore->litStart),
|
3331
|
+
seqStore->ofCode, seqStore->llCode, seqStore->mlCode,
|
3332
|
+
(size_t)(seqStore->sequences - seqStore->sequencesStart),
|
3333
|
+
&zc->blockState.nextCBlock->entropy, &entropyMetadata, zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE,
|
3334
|
+
(int)(entropyMetadata.hufMetadata.hType == set_compressed), 1);
|
3335
|
+
}
|
3336
|
+
|
3337
|
+
/* Returns literals bytes represented in a seqStore */
|
3338
|
+
static size_t ZSTD_countSeqStoreLiteralsBytes(const seqStore_t* const seqStore) {
|
3339
|
+
size_t literalsBytes = 0;
|
3340
|
+
size_t const nbSeqs = seqStore->sequences - seqStore->sequencesStart;
|
3341
|
+
size_t i;
|
3342
|
+
for (i = 0; i < nbSeqs; ++i) {
|
3343
|
+
seqDef seq = seqStore->sequencesStart[i];
|
3344
|
+
literalsBytes += seq.litLength;
|
3345
|
+
if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_literalLength) {
|
3346
|
+
literalsBytes += 0x10000;
|
3347
|
+
}
|
3348
|
+
}
|
3349
|
+
return literalsBytes;
|
3350
|
+
}
|
3351
|
+
|
3352
|
+
/* Returns match bytes represented in a seqStore */
|
3353
|
+
static size_t ZSTD_countSeqStoreMatchBytes(const seqStore_t* const seqStore) {
|
3354
|
+
size_t matchBytes = 0;
|
3355
|
+
size_t const nbSeqs = seqStore->sequences - seqStore->sequencesStart;
|
3356
|
+
size_t i;
|
3357
|
+
for (i = 0; i < nbSeqs; ++i) {
|
3358
|
+
seqDef seq = seqStore->sequencesStart[i];
|
3359
|
+
matchBytes += seq.matchLength + MINMATCH;
|
3360
|
+
if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_matchLength) {
|
3361
|
+
matchBytes += 0x10000;
|
3362
|
+
}
|
3363
|
+
}
|
3364
|
+
return matchBytes;
|
3365
|
+
}
|
3366
|
+
|
3367
|
+
/* Derives the seqStore that is a chunk of the originalSeqStore from [startIdx, endIdx).
|
3368
|
+
* Stores the result in resultSeqStore.
|
3369
|
+
*/
|
3370
|
+
static void ZSTD_deriveSeqStoreChunk(seqStore_t* resultSeqStore,
|
3371
|
+
const seqStore_t* originalSeqStore,
|
3372
|
+
size_t startIdx, size_t endIdx) {
|
3373
|
+
BYTE* const litEnd = originalSeqStore->lit;
|
3374
|
+
size_t literalsBytes;
|
3375
|
+
size_t literalsBytesPreceding = 0;
|
3376
|
+
|
3377
|
+
*resultSeqStore = *originalSeqStore;
|
3378
|
+
if (startIdx > 0) {
|
3379
|
+
resultSeqStore->sequences = originalSeqStore->sequencesStart + startIdx;
|
3380
|
+
literalsBytesPreceding = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore);
|
3381
|
+
}
|
3382
|
+
|
3383
|
+
/* Move longLengthPos into the correct position if necessary */
|
3384
|
+
if (originalSeqStore->longLengthType != ZSTD_llt_none) {
|
3385
|
+
if (originalSeqStore->longLengthPos < startIdx || originalSeqStore->longLengthPos > endIdx) {
|
3386
|
+
resultSeqStore->longLengthType = ZSTD_llt_none;
|
3387
|
+
} else {
|
3388
|
+
resultSeqStore->longLengthPos -= (U32)startIdx;
|
3389
|
+
}
|
3390
|
+
}
|
3391
|
+
resultSeqStore->sequencesStart = originalSeqStore->sequencesStart + startIdx;
|
3392
|
+
resultSeqStore->sequences = originalSeqStore->sequencesStart + endIdx;
|
3393
|
+
literalsBytes = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore);
|
3394
|
+
resultSeqStore->litStart += literalsBytesPreceding;
|
3395
|
+
if (endIdx == (size_t)(originalSeqStore->sequences - originalSeqStore->sequencesStart)) {
|
3396
|
+
/* This accounts for possible last literals if the derived chunk reaches the end of the block */
|
3397
|
+
resultSeqStore->lit = litEnd;
|
3398
|
+
} else {
|
3399
|
+
resultSeqStore->lit = resultSeqStore->litStart+literalsBytes;
|
3400
|
+
}
|
3401
|
+
resultSeqStore->llCode += startIdx;
|
3402
|
+
resultSeqStore->mlCode += startIdx;
|
3403
|
+
resultSeqStore->ofCode += startIdx;
|
3404
|
+
}
|
3405
|
+
|
3406
|
+
/**
|
3407
|
+
* Returns the raw offset represented by the combination of offCode, ll0, and repcode history.
|
3408
|
+
* offCode must be an offCode representing a repcode, therefore in the range of [0, 2].
|
3409
|
+
*/
|
3410
|
+
static U32 ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offCode, const U32 ll0) {
|
3411
|
+
U32 const adjustedOffCode = offCode + ll0;
|
3412
|
+
assert(offCode < ZSTD_REP_NUM);
|
3413
|
+
if (adjustedOffCode == ZSTD_REP_NUM) {
|
3414
|
+
/* litlength == 0 and offCode == 2 implies selection of first repcode - 1 */
|
3415
|
+
assert(rep[0] > 0);
|
3416
|
+
return rep[0] - 1;
|
3417
|
+
}
|
3418
|
+
return rep[adjustedOffCode];
|
3419
|
+
}
|
3420
|
+
|
3421
|
+
/**
|
3422
|
+
* ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise
|
3423
|
+
* due to emission of RLE/raw blocks that disturb the offset history, and replaces any repcodes within
|
3424
|
+
* the seqStore that may be invalid.
|
3425
|
+
*
|
3426
|
+
* dRepcodes are updated as would be on the decompression side. cRepcodes are updated exactly in
|
3427
|
+
* accordance with the seqStore.
|
3428
|
+
*/
|
3429
|
+
static void ZSTD_seqStore_resolveOffCodes(repcodes_t* const dRepcodes, repcodes_t* const cRepcodes,
|
3430
|
+
seqStore_t* const seqStore, U32 const nbSeq) {
|
3431
|
+
U32 idx = 0;
|
3432
|
+
for (; idx < nbSeq; ++idx) {
|
3433
|
+
seqDef* const seq = seqStore->sequencesStart + idx;
|
3434
|
+
U32 const ll0 = (seq->litLength == 0);
|
3435
|
+
U32 offCode = seq->offset - 1;
|
3436
|
+
assert(seq->offset > 0);
|
3437
|
+
if (offCode <= ZSTD_REP_MOVE) {
|
3438
|
+
U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offCode, ll0);
|
3439
|
+
U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offCode, ll0);
|
3440
|
+
/* Adjust simulated decompression repcode history if we come across a mismatch. Replace
|
3441
|
+
* the repcode with the offset it actually references, determined by the compression
|
3442
|
+
* repcode history.
|
3443
|
+
*/
|
3444
|
+
if (dRawOffset != cRawOffset) {
|
3445
|
+
seq->offset = cRawOffset + ZSTD_REP_NUM;
|
3446
|
+
}
|
3447
|
+
}
|
3448
|
+
/* Compression repcode history is always updated with values directly from the unmodified seqStore.
|
3449
|
+
* Decompression repcode history may use modified seq->offset value taken from compression repcode history.
|
3450
|
+
*/
|
3451
|
+
*dRepcodes = ZSTD_updateRep(dRepcodes->rep, seq->offset - 1, ll0);
|
3452
|
+
*cRepcodes = ZSTD_updateRep(cRepcodes->rep, offCode, ll0);
|
3453
|
+
}
|
3454
|
+
}
|
3455
|
+
|
3456
|
+
/* ZSTD_compressSeqStore_singleBlock():
|
3457
|
+
* Compresses a seqStore into a block with a block header, into the buffer dst.
|
3458
|
+
*
|
3459
|
+
* Returns the total size of that block (including header) or a ZSTD error code.
|
3460
|
+
*/
|
3461
|
+
static size_t ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, seqStore_t* const seqStore,
|
3462
|
+
repcodes_t* const dRep, repcodes_t* const cRep,
|
3463
|
+
void* dst, size_t dstCapacity,
|
3464
|
+
const void* src, size_t srcSize,
|
3465
|
+
U32 lastBlock, U32 isPartition) {
|
3466
|
+
const U32 rleMaxLength = 25;
|
3467
|
+
BYTE* op = (BYTE*)dst;
|
3468
|
+
const BYTE* ip = (const BYTE*)src;
|
3469
|
+
size_t cSize;
|
3470
|
+
size_t cSeqsSize;
|
3471
|
+
|
3472
|
+
/* In case of an RLE or raw block, the simulated decompression repcode history must be reset */
|
3473
|
+
repcodes_t const dRepOriginal = *dRep;
|
3474
|
+
if (isPartition)
|
3475
|
+
ZSTD_seqStore_resolveOffCodes(dRep, cRep, seqStore, (U32)(seqStore->sequences - seqStore->sequencesStart));
|
3476
|
+
|
3477
|
+
cSeqsSize = ZSTD_entropyCompressSeqStore(seqStore,
|
3478
|
+
&zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
|
3479
|
+
&zc->appliedParams,
|
3480
|
+
op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize,
|
3481
|
+
srcSize,
|
3482
|
+
zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
|
3483
|
+
zc->bmi2);
|
3484
|
+
FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!");
|
3485
|
+
|
3486
|
+
if (!zc->isFirstBlock &&
|
3487
|
+
cSeqsSize < rleMaxLength &&
|
3488
|
+
ZSTD_isRLE((BYTE const*)src, srcSize)) {
|
3489
|
+
/* We don't want to emit our first block as a RLE even if it qualifies because
|
3490
|
+
* doing so will cause the decoder (cli only) to throw a "should consume all input error."
|
3491
|
+
* This is only an issue for zstd <= v1.4.3
|
3492
|
+
*/
|
3493
|
+
cSeqsSize = 1;
|
3494
|
+
}
|
3495
|
+
|
3496
|
+
if (zc->seqCollector.collectSequences) {
|
3497
|
+
ZSTD_copyBlockSequences(zc);
|
3498
|
+
ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
|
3499
|
+
return 0;
|
3500
|
+
}
|
3501
|
+
|
3502
|
+
if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
|
3503
|
+
zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
|
3504
|
+
|
3505
|
+
if (cSeqsSize == 0) {
|
3506
|
+
cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock);
|
3507
|
+
FORWARD_IF_ERROR(cSize, "Nocompress block failed");
|
3508
|
+
DEBUGLOG(4, "Writing out nocompress block, size: %zu", cSize);
|
3509
|
+
*dRep = dRepOriginal; /* reset simulated decompression repcode history */
|
3510
|
+
} else if (cSeqsSize == 1) {
|
3511
|
+
cSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, srcSize, lastBlock);
|
3512
|
+
FORWARD_IF_ERROR(cSize, "RLE compress block failed");
|
3513
|
+
DEBUGLOG(4, "Writing out RLE block, size: %zu", cSize);
|
3514
|
+
*dRep = dRepOriginal; /* reset simulated decompression repcode history */
|
3515
|
+
} else {
|
3516
|
+
ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
|
3517
|
+
writeBlockHeader(op, cSeqsSize, srcSize, lastBlock);
|
3518
|
+
cSize = ZSTD_blockHeaderSize + cSeqsSize;
|
3519
|
+
DEBUGLOG(4, "Writing out compressed block, size: %zu", cSize);
|
3520
|
+
}
|
3521
|
+
return cSize;
|
3522
|
+
}
|
3523
|
+
|
3524
|
+
/* Struct to keep track of where we are in our recursive calls. */
|
3525
|
+
typedef struct {
|
3526
|
+
U32* splitLocations; /* Array of split indices */
|
3527
|
+
size_t idx; /* The current index within splitLocations being worked on */
|
3528
|
+
} seqStoreSplits;
|
3529
|
+
|
3530
|
+
#define MIN_SEQUENCES_BLOCK_SPLITTING 300
|
3531
|
+
#define MAX_NB_SPLITS 196
|
3532
|
+
|
3533
|
+
/* Helper function to perform the recursive search for block splits.
|
3534
|
+
* Estimates the cost of seqStore prior to split, and estimates the cost of splitting the sequences in half.
|
3535
|
+
* If advantageous to split, then we recurse down the two sub-blocks. If not, or if an error occurred in estimation, then
|
3536
|
+
* we do not recurse.
|
3537
|
+
*
|
3538
|
+
* Note: The recursion depth is capped by a heuristic minimum number of sequences, defined by MIN_SEQUENCES_BLOCK_SPLITTING.
|
3539
|
+
* In theory, this means the absolute largest recursion depth is 10 == log2(maxNbSeqInBlock/MIN_SEQUENCES_BLOCK_SPLITTING).
|
3540
|
+
* In practice, recursion depth usually doesn't go beyond 4.
|
3541
|
+
*
|
3542
|
+
* Furthermore, the number of splits is capped by MAX_NB_SPLITS. At MAX_NB_SPLITS == 196 with the current existing blockSize
|
3543
|
+
* maximum of 128 KB, this value is actually impossible to reach.
|
3544
|
+
*/
|
3545
|
+
static void ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t endIdx,
|
3546
|
+
const ZSTD_CCtx* zc, const seqStore_t* origSeqStore) {
|
3547
|
+
seqStore_t fullSeqStoreChunk;
|
3548
|
+
seqStore_t firstHalfSeqStore;
|
3549
|
+
seqStore_t secondHalfSeqStore;
|
3550
|
+
size_t estimatedOriginalSize;
|
3551
|
+
size_t estimatedFirstHalfSize;
|
3552
|
+
size_t estimatedSecondHalfSize;
|
3553
|
+
size_t midIdx = (startIdx + endIdx)/2;
|
3554
|
+
|
3555
|
+
if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= MAX_NB_SPLITS) {
|
3556
|
+
return;
|
3557
|
+
}
|
3558
|
+
ZSTD_deriveSeqStoreChunk(&fullSeqStoreChunk, origSeqStore, startIdx, endIdx);
|
3559
|
+
ZSTD_deriveSeqStoreChunk(&firstHalfSeqStore, origSeqStore, startIdx, midIdx);
|
3560
|
+
ZSTD_deriveSeqStoreChunk(&secondHalfSeqStore, origSeqStore, midIdx, endIdx);
|
3561
|
+
estimatedOriginalSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&fullSeqStoreChunk, zc);
|
3562
|
+
estimatedFirstHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&firstHalfSeqStore, zc);
|
3563
|
+
estimatedSecondHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&secondHalfSeqStore, zc);
|
3564
|
+
DEBUGLOG(5, "Estimated original block size: %zu -- First half split: %zu -- Second half split: %zu",
|
3565
|
+
estimatedOriginalSize, estimatedFirstHalfSize, estimatedSecondHalfSize);
|
3566
|
+
if (ZSTD_isError(estimatedOriginalSize) || ZSTD_isError(estimatedFirstHalfSize) || ZSTD_isError(estimatedSecondHalfSize)) {
|
3567
|
+
return;
|
3568
|
+
}
|
3569
|
+
if (estimatedFirstHalfSize + estimatedSecondHalfSize < estimatedOriginalSize) {
|
3570
|
+
ZSTD_deriveBlockSplitsHelper(splits, startIdx, midIdx, zc, origSeqStore);
|
3571
|
+
splits->splitLocations[splits->idx] = (U32)midIdx;
|
3572
|
+
splits->idx++;
|
3573
|
+
ZSTD_deriveBlockSplitsHelper(splits, midIdx, endIdx, zc, origSeqStore);
|
3574
|
+
}
|
3575
|
+
}
|
3576
|
+
|
3577
|
+
/* Base recursive function. Populates a table with intra-block partition indices that can improve compression ratio.
|
3578
|
+
*
|
3579
|
+
* Returns the number of splits made (which equals the size of the partition table - 1).
|
3580
|
+
*/
|
3581
|
+
static size_t ZSTD_deriveBlockSplits(ZSTD_CCtx* zc, U32 partitions[], U32 nbSeq) {
|
3582
|
+
seqStoreSplits splits = {partitions, 0};
|
3583
|
+
if (nbSeq <= 4) {
|
3584
|
+
DEBUGLOG(4, "ZSTD_deriveBlockSplits: Too few sequences to split");
|
3585
|
+
/* Refuse to try and split anything with less than 4 sequences */
|
3586
|
+
return 0;
|
3587
|
+
}
|
3588
|
+
ZSTD_deriveBlockSplitsHelper(&splits, 0, nbSeq, zc, &zc->seqStore);
|
3589
|
+
splits.splitLocations[splits.idx] = nbSeq;
|
3590
|
+
DEBUGLOG(5, "ZSTD_deriveBlockSplits: final nb partitions: %zu", splits.idx+1);
|
3591
|
+
return splits.idx;
|
3592
|
+
}
|
3593
|
+
|
3594
|
+
/* ZSTD_compressBlock_splitBlock():
|
3595
|
+
* Attempts to split a given block into multiple blocks to improve compression ratio.
|
3596
|
+
*
|
3597
|
+
* Returns combined size of all blocks (which includes headers), or a ZSTD error code.
|
3598
|
+
*/
|
3599
|
+
static size_t ZSTD_compressBlock_splitBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity,
|
3600
|
+
const void* src, size_t blockSize, U32 lastBlock, U32 nbSeq) {
|
3601
|
+
size_t cSize = 0;
|
3602
|
+
const BYTE* ip = (const BYTE*)src;
|
3603
|
+
BYTE* op = (BYTE*)dst;
|
3604
|
+
U32 partitions[MAX_NB_SPLITS];
|
3605
|
+
size_t i = 0;
|
3606
|
+
size_t srcBytesTotal = 0;
|
3607
|
+
size_t numSplits = ZSTD_deriveBlockSplits(zc, partitions, nbSeq);
|
3608
|
+
seqStore_t nextSeqStore;
|
3609
|
+
seqStore_t currSeqStore;
|
3610
|
+
|
3611
|
+
/* If a block is split and some partitions are emitted as RLE/uncompressed, then repcode history
|
3612
|
+
* may become invalid. In order to reconcile potentially invalid repcodes, we keep track of two
|
3613
|
+
* separate repcode histories that simulate repcode history on compression and decompression side,
|
3614
|
+
* and use the histories to determine whether we must replace a particular repcode with its raw offset.
|
3615
|
+
*
|
3616
|
+
* 1) cRep gets updated for each partition, regardless of whether the block was emitted as uncompressed
|
3617
|
+
* or RLE. This allows us to retrieve the offset value that an invalid repcode references within
|
3618
|
+
* a nocompress/RLE block.
|
3619
|
+
* 2) dRep gets updated only for compressed partitions, and when a repcode gets replaced, will use
|
3620
|
+
* the replacement offset value rather than the original repcode to update the repcode history.
|
3621
|
+
* dRep also will be the final repcode history sent to the next block.
|
3622
|
+
*
|
3623
|
+
* See ZSTD_seqStore_resolveOffCodes() for more details.
|
3624
|
+
*/
|
3625
|
+
repcodes_t dRep;
|
3626
|
+
repcodes_t cRep;
|
3627
|
+
ZSTD_memcpy(dRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
|
3628
|
+
ZSTD_memcpy(cRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
|
3629
|
+
|
3630
|
+
DEBUGLOG(4, "ZSTD_compressBlock_splitBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
|
3631
|
+
(unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit,
|
3632
|
+
(unsigned)zc->blockState.matchState.nextToUpdate);
|
3633
|
+
|
3634
|
+
if (numSplits == 0) {
|
3635
|
+
size_t cSizeSingleBlock = ZSTD_compressSeqStore_singleBlock(zc, &zc->seqStore,
|
3636
|
+
&dRep, &cRep,
|
3637
|
+
op, dstCapacity,
|
3638
|
+
ip, blockSize,
|
3639
|
+
lastBlock, 0 /* isPartition */);
|
3640
|
+
FORWARD_IF_ERROR(cSizeSingleBlock, "Compressing single block from splitBlock_internal() failed!");
|
3641
|
+
DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal: No splits");
|
3642
|
+
assert(cSizeSingleBlock <= ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize);
|
3643
|
+
return cSizeSingleBlock;
|
3644
|
+
}
|
3645
|
+
|
3646
|
+
ZSTD_deriveSeqStoreChunk(&currSeqStore, &zc->seqStore, 0, partitions[0]);
|
3647
|
+
for (i = 0; i <= numSplits; ++i) {
|
3648
|
+
size_t srcBytes;
|
3649
|
+
size_t cSizeChunk;
|
3650
|
+
U32 const lastPartition = (i == numSplits);
|
3651
|
+
U32 lastBlockEntireSrc = 0;
|
3652
|
+
|
3653
|
+
srcBytes = ZSTD_countSeqStoreLiteralsBytes(&currSeqStore) + ZSTD_countSeqStoreMatchBytes(&currSeqStore);
|
3654
|
+
srcBytesTotal += srcBytes;
|
3655
|
+
if (lastPartition) {
|
3656
|
+
/* This is the final partition, need to account for possible last literals */
|
3657
|
+
srcBytes += blockSize - srcBytesTotal;
|
3658
|
+
lastBlockEntireSrc = lastBlock;
|
3659
|
+
} else {
|
3660
|
+
ZSTD_deriveSeqStoreChunk(&nextSeqStore, &zc->seqStore, partitions[i], partitions[i+1]);
|
3661
|
+
}
|
3662
|
+
|
3663
|
+
cSizeChunk = ZSTD_compressSeqStore_singleBlock(zc, &currSeqStore,
|
3664
|
+
&dRep, &cRep,
|
3665
|
+
op, dstCapacity,
|
3666
|
+
ip, srcBytes,
|
3667
|
+
lastBlockEntireSrc, 1 /* isPartition */);
|
3668
|
+
DEBUGLOG(5, "Estimated size: %zu actual size: %zu", ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&currSeqStore, zc), cSizeChunk);
|
3669
|
+
FORWARD_IF_ERROR(cSizeChunk, "Compressing chunk failed!");
|
3670
|
+
|
3671
|
+
ip += srcBytes;
|
3672
|
+
op += cSizeChunk;
|
3673
|
+
dstCapacity -= cSizeChunk;
|
3674
|
+
cSize += cSizeChunk;
|
3675
|
+
currSeqStore = nextSeqStore;
|
3676
|
+
assert(cSizeChunk <= ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize);
|
3677
|
+
}
|
3678
|
+
/* cRep and dRep may have diverged during the compression. If so, we use the dRep repcodes
|
3679
|
+
* for the next block.
|
3680
|
+
*/
|
3681
|
+
ZSTD_memcpy(zc->blockState.prevCBlock->rep, dRep.rep, sizeof(repcodes_t));
|
3682
|
+
return cSize;
|
3683
|
+
}
|
3684
|
+
|
3685
|
+
static size_t ZSTD_compressBlock_splitBlock(ZSTD_CCtx* zc,
|
3686
|
+
void* dst, size_t dstCapacity,
|
3687
|
+
const void* src, size_t srcSize, U32 lastBlock) {
|
3688
|
+
const BYTE* ip = (const BYTE*)src;
|
3689
|
+
BYTE* op = (BYTE*)dst;
|
3690
|
+
U32 nbSeq;
|
3691
|
+
size_t cSize;
|
3692
|
+
DEBUGLOG(4, "ZSTD_compressBlock_splitBlock");
|
3693
|
+
|
3694
|
+
{ const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
|
3695
|
+
FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
|
3696
|
+
if (bss == ZSTDbss_noCompress) {
|
3697
|
+
if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
|
3698
|
+
zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
|
3699
|
+
cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock);
|
3700
|
+
FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
|
3701
|
+
DEBUGLOG(4, "ZSTD_compressBlock_splitBlock: Nocompress block");
|
3702
|
+
return cSize;
|
3703
|
+
}
|
3704
|
+
nbSeq = (U32)(zc->seqStore.sequences - zc->seqStore.sequencesStart);
|
3705
|
+
}
|
3706
|
+
|
3707
|
+
assert(zc->appliedParams.splitBlocks == 1);
|
3708
|
+
cSize = ZSTD_compressBlock_splitBlock_internal(zc, dst, dstCapacity, src, srcSize, lastBlock, nbSeq);
|
3709
|
+
FORWARD_IF_ERROR(cSize, "Splitting blocks failed!");
|
3710
|
+
return cSize;
|
2694
3711
|
}
|
2695
3712
|
|
2696
3713
|
static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
|
@@ -2716,12 +3733,12 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
|
|
2716
3733
|
|
2717
3734
|
if (zc->seqCollector.collectSequences) {
|
2718
3735
|
ZSTD_copyBlockSequences(zc);
|
2719
|
-
|
3736
|
+
ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
|
2720
3737
|
return 0;
|
2721
3738
|
}
|
2722
3739
|
|
2723
3740
|
/* encode sequences and literals */
|
2724
|
-
cSize =
|
3741
|
+
cSize = ZSTD_entropyCompressSeqStore(&zc->seqStore,
|
2725
3742
|
&zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
|
2726
3743
|
&zc->appliedParams,
|
2727
3744
|
dst, dstCapacity,
|
@@ -2750,7 +3767,7 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
|
|
2750
3767
|
|
2751
3768
|
out:
|
2752
3769
|
if (!ZSTD_isError(cSize) && cSize > 1) {
|
2753
|
-
|
3770
|
+
ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
|
2754
3771
|
}
|
2755
3772
|
/* We check that dictionaries have offset codes available for the first
|
2756
3773
|
* block. After the first block, the offcode table might not have large
|
@@ -2803,7 +3820,7 @@ static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
|
|
2803
3820
|
size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy);
|
2804
3821
|
FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed");
|
2805
3822
|
if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) {
|
2806
|
-
|
3823
|
+
ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
|
2807
3824
|
return cSize;
|
2808
3825
|
}
|
2809
3826
|
}
|
@@ -2843,9 +3860,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
|
|
2843
3860
|
void const* ip,
|
2844
3861
|
void const* iend)
|
2845
3862
|
{
|
2846
|
-
|
2847
|
-
|
2848
|
-
|
3863
|
+
U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
|
3864
|
+
U32 const maxDist = (U32)1 << params->cParams.windowLog;
|
3865
|
+
if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) {
|
2849
3866
|
U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
|
2850
3867
|
ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
|
2851
3868
|
ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
|
@@ -2868,7 +3885,7 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
|
|
2868
3885
|
* Frame is supposed already started (header already produced)
|
2869
3886
|
* @return : compressed size, or an error code
|
2870
3887
|
*/
|
2871
|
-
static size_t ZSTD_compress_frameChunk
|
3888
|
+
static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx,
|
2872
3889
|
void* dst, size_t dstCapacity,
|
2873
3890
|
const void* src, size_t srcSize,
|
2874
3891
|
U32 lastFrameChunk)
|
@@ -2908,6 +3925,10 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
|
2908
3925
|
FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed");
|
2909
3926
|
assert(cSize > 0);
|
2910
3927
|
assert(cSize <= blockSize + ZSTD_blockHeaderSize);
|
3928
|
+
} else if (ZSTD_blockSplitterEnabled(&cctx->appliedParams)) {
|
3929
|
+
cSize = ZSTD_compressBlock_splitBlock(cctx, op, dstCapacity, ip, blockSize, lastBlock);
|
3930
|
+
FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_splitBlock failed");
|
3931
|
+
assert(cSize > 0 || cctx->seqCollector.collectSequences == 1);
|
2911
3932
|
} else {
|
2912
3933
|
cSize = ZSTD_compressBlock_internal(cctx,
|
2913
3934
|
op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
|
@@ -3063,11 +4084,12 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
|
3063
4084
|
|
3064
4085
|
if (!srcSize) return fhSize; /* do not generate an empty block if no input */
|
3065
4086
|
|
3066
|
-
if (!ZSTD_window_update(&ms->window, src, srcSize)) {
|
4087
|
+
if (!ZSTD_window_update(&ms->window, src, srcSize, ms->forceNonContiguous)) {
|
4088
|
+
ms->forceNonContiguous = 0;
|
3067
4089
|
ms->nextToUpdate = ms->window.dictLimit;
|
3068
4090
|
}
|
3069
4091
|
if (cctx->appliedParams.ldmParams.enableLdm) {
|
3070
|
-
ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
|
4092
|
+
ZSTD_window_update(&cctx->ldmState.window, src, srcSize, /* forceNonContiguous */ 0);
|
3071
4093
|
}
|
3072
4094
|
|
3073
4095
|
if (!frame) {
|
@@ -3135,63 +4157,86 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
|
|
3135
4157
|
{
|
3136
4158
|
const BYTE* ip = (const BYTE*) src;
|
3137
4159
|
const BYTE* const iend = ip + srcSize;
|
4160
|
+
int const loadLdmDict = params->ldmParams.enableLdm && ls != NULL;
|
4161
|
+
|
4162
|
+
/* Assert that we the ms params match the params we're being given */
|
4163
|
+
ZSTD_assertEqualCParams(params->cParams, ms->cParams);
|
3138
4164
|
|
3139
|
-
|
4165
|
+
if (srcSize > ZSTD_CHUNKSIZE_MAX) {
|
4166
|
+
/* Allow the dictionary to set indices up to exactly ZSTD_CURRENT_MAX.
|
4167
|
+
* Dictionaries right at the edge will immediately trigger overflow
|
4168
|
+
* correction, but I don't want to insert extra constraints here.
|
4169
|
+
*/
|
4170
|
+
U32 const maxDictSize = ZSTD_CURRENT_MAX - 1;
|
4171
|
+
/* We must have cleared our windows when our source is this large. */
|
4172
|
+
assert(ZSTD_window_isEmpty(ms->window));
|
4173
|
+
if (loadLdmDict)
|
4174
|
+
assert(ZSTD_window_isEmpty(ls->window));
|
4175
|
+
/* If the dictionary is too large, only load the suffix of the dictionary. */
|
4176
|
+
if (srcSize > maxDictSize) {
|
4177
|
+
ip = iend - maxDictSize;
|
4178
|
+
src = ip;
|
4179
|
+
srcSize = maxDictSize;
|
4180
|
+
}
|
4181
|
+
}
|
4182
|
+
|
4183
|
+
DEBUGLOG(4, "ZSTD_loadDictionaryContent(): useRowMatchFinder=%d", (int)params->useRowMatchFinder);
|
4184
|
+
ZSTD_window_update(&ms->window, src, srcSize, /* forceNonContiguous */ 0);
|
3140
4185
|
ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
|
4186
|
+
ms->forceNonContiguous = params->deterministicRefPrefix;
|
3141
4187
|
|
3142
|
-
if (
|
3143
|
-
ZSTD_window_update(&ls->window, src, srcSize);
|
4188
|
+
if (loadLdmDict) {
|
4189
|
+
ZSTD_window_update(&ls->window, src, srcSize, /* forceNonContiguous */ 0);
|
3144
4190
|
ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base);
|
3145
4191
|
}
|
3146
4192
|
|
3147
|
-
/* Assert that we the ms params match the params we're being given */
|
3148
|
-
ZSTD_assertEqualCParams(params->cParams, ms->cParams);
|
3149
|
-
|
3150
4193
|
if (srcSize <= HASH_READ_SIZE) return 0;
|
3151
4194
|
|
3152
|
-
|
3153
|
-
size_t const remaining = (size_t)(iend - ip);
|
3154
|
-
size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
|
3155
|
-
const BYTE* const ichunk = ip + chunk;
|
3156
|
-
|
3157
|
-
ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk);
|
4195
|
+
ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, iend);
|
3158
4196
|
|
3159
|
-
|
3160
|
-
|
4197
|
+
if (loadLdmDict)
|
4198
|
+
ZSTD_ldm_fillHashTable(ls, ip, iend, ¶ms->ldmParams);
|
3161
4199
|
|
3162
|
-
|
3163
|
-
|
3164
|
-
|
3165
|
-
|
3166
|
-
|
3167
|
-
|
3168
|
-
|
3169
|
-
|
4200
|
+
switch(params->cParams.strategy)
|
4201
|
+
{
|
4202
|
+
case ZSTD_fast:
|
4203
|
+
ZSTD_fillHashTable(ms, iend, dtlm);
|
4204
|
+
break;
|
4205
|
+
case ZSTD_dfast:
|
4206
|
+
ZSTD_fillDoubleHashTable(ms, iend, dtlm);
|
4207
|
+
break;
|
3170
4208
|
|
3171
|
-
|
3172
|
-
|
3173
|
-
|
3174
|
-
|
3175
|
-
|
3176
|
-
|
3177
|
-
|
3178
|
-
|
4209
|
+
case ZSTD_greedy:
|
4210
|
+
case ZSTD_lazy:
|
4211
|
+
case ZSTD_lazy2:
|
4212
|
+
assert(srcSize >= HASH_READ_SIZE);
|
4213
|
+
if (ms->dedicatedDictSearch) {
|
4214
|
+
assert(ms->chainTable != NULL);
|
4215
|
+
ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, iend-HASH_READ_SIZE);
|
4216
|
+
} else {
|
4217
|
+
assert(params->useRowMatchFinder != ZSTD_urm_auto);
|
4218
|
+
if (params->useRowMatchFinder == ZSTD_urm_enableRowMatchFinder) {
|
4219
|
+
size_t const tagTableSize = ((size_t)1 << params->cParams.hashLog) * sizeof(U16);
|
4220
|
+
ZSTD_memset(ms->tagTable, 0, tagTableSize);
|
4221
|
+
ZSTD_row_update(ms, iend-HASH_READ_SIZE);
|
4222
|
+
DEBUGLOG(4, "Using row-based hash table for lazy dict");
|
4223
|
+
} else {
|
4224
|
+
ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE);
|
4225
|
+
DEBUGLOG(4, "Using chain-based hash table for lazy dict");
|
3179
4226
|
}
|
3180
|
-
break;
|
3181
|
-
|
3182
|
-
case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
|
3183
|
-
case ZSTD_btopt:
|
3184
|
-
case ZSTD_btultra:
|
3185
|
-
case ZSTD_btultra2:
|
3186
|
-
if (chunk >= HASH_READ_SIZE)
|
3187
|
-
ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk);
|
3188
|
-
break;
|
3189
|
-
|
3190
|
-
default:
|
3191
|
-
assert(0); /* not possible : not a valid strategy id */
|
3192
4227
|
}
|
4228
|
+
break;
|
4229
|
+
|
4230
|
+
case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
|
4231
|
+
case ZSTD_btopt:
|
4232
|
+
case ZSTD_btultra:
|
4233
|
+
case ZSTD_btultra2:
|
4234
|
+
assert(srcSize >= HASH_READ_SIZE);
|
4235
|
+
ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend);
|
4236
|
+
break;
|
3193
4237
|
|
3194
|
-
|
4238
|
+
default:
|
4239
|
+
assert(0); /* not possible : not a valid strategy id */
|
3195
4240
|
}
|
3196
4241
|
|
3197
4242
|
ms->nextToUpdate = (U32)(iend - ms->window.base);
|
@@ -3330,7 +4375,6 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
|
|
3330
4375
|
const BYTE* const dictEnd = dictPtr + dictSize;
|
3331
4376
|
size_t dictID;
|
3332
4377
|
size_t eSize;
|
3333
|
-
|
3334
4378
|
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
3335
4379
|
assert(dictSize >= 8);
|
3336
4380
|
assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
|
@@ -3401,8 +4445,9 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
|
3401
4445
|
const ZSTD_CCtx_params* params, U64 pledgedSrcSize,
|
3402
4446
|
ZSTD_buffered_policy_e zbuff)
|
3403
4447
|
{
|
4448
|
+
size_t const dictContentSize = cdict ? cdict->dictContentSize : dictSize;
|
3404
4449
|
#if ZSTD_TRACE
|
3405
|
-
cctx->traceCtx = ZSTD_trace_compress_begin(cctx);
|
4450
|
+
cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0;
|
3406
4451
|
#endif
|
3407
4452
|
DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog);
|
3408
4453
|
/* params are supposed to be fully validated at this point */
|
@@ -3418,7 +4463,8 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
|
3418
4463
|
return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
|
3419
4464
|
}
|
3420
4465
|
|
3421
|
-
FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx,
|
4466
|
+
FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
|
4467
|
+
dictContentSize,
|
3422
4468
|
ZSTDcrp_makeClean, zbuff) , "");
|
3423
4469
|
{ size_t const dictID = cdict ?
|
3424
4470
|
ZSTD_compress_insertDictionary(
|
@@ -3433,7 +4479,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
|
3433
4479
|
FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
|
3434
4480
|
assert(dictID <= UINT_MAX);
|
3435
4481
|
cctx->dictID = (U32)dictID;
|
3436
|
-
cctx->dictContentSize =
|
4482
|
+
cctx->dictContentSize = dictContentSize;
|
3437
4483
|
}
|
3438
4484
|
return 0;
|
3439
4485
|
}
|
@@ -3533,7 +4579,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
|
|
3533
4579
|
void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)
|
3534
4580
|
{
|
3535
4581
|
#if ZSTD_TRACE
|
3536
|
-
if (cctx->traceCtx) {
|
4582
|
+
if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) {
|
3537
4583
|
int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0;
|
3538
4584
|
ZSTD_Trace trace;
|
3539
4585
|
ZSTD_memset(&trace, 0, sizeof(trace));
|
@@ -3586,15 +4632,14 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
|
|
3586
4632
|
const void* dict,size_t dictSize,
|
3587
4633
|
ZSTD_parameters params)
|
3588
4634
|
{
|
3589
|
-
ZSTD_CCtx_params cctxParams;
|
3590
4635
|
DEBUGLOG(4, "ZSTD_compress_advanced");
|
3591
4636
|
FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
|
3592
|
-
ZSTD_CCtxParams_init_internal(&
|
4637
|
+
ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, ZSTD_NO_CLEVEL);
|
3593
4638
|
return ZSTD_compress_advanced_internal(cctx,
|
3594
4639
|
dst, dstCapacity,
|
3595
4640
|
src, srcSize,
|
3596
4641
|
dict, dictSize,
|
3597
|
-
&
|
4642
|
+
&cctx->simpleApiParams);
|
3598
4643
|
}
|
3599
4644
|
|
3600
4645
|
/* Internal */
|
@@ -3618,14 +4663,13 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
|
|
3618
4663
|
const void* dict, size_t dictSize,
|
3619
4664
|
int compressionLevel)
|
3620
4665
|
{
|
3621
|
-
ZSTD_CCtx_params cctxParams;
|
3622
4666
|
{
|
3623
4667
|
ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict);
|
3624
4668
|
assert(params.fParams.contentSizeFlag == 1);
|
3625
|
-
ZSTD_CCtxParams_init_internal(&
|
4669
|
+
ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel);
|
3626
4670
|
}
|
3627
4671
|
DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
|
3628
|
-
return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &
|
4672
|
+
return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams);
|
3629
4673
|
}
|
3630
4674
|
|
3631
4675
|
size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
|
@@ -3669,7 +4713,10 @@ size_t ZSTD_estimateCDictSize_advanced(
|
|
3669
4713
|
DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
|
3670
4714
|
return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
|
3671
4715
|
+ ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
|
3672
|
-
|
4716
|
+
/* enableDedicatedDictSearch == 1 ensures that CDict estimation will not be too small
|
4717
|
+
* in case we are using DDS with row-hash. */
|
4718
|
+
+ ZSTD_sizeof_matchState(&cParams, ZSTD_resolveRowMatchFinderMode(ZSTD_urm_auto, &cParams),
|
4719
|
+
/* enableDedicatedDictSearch */ 1, /* forCCtx */ 0)
|
3673
4720
|
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0
|
3674
4721
|
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *))));
|
3675
4722
|
}
|
@@ -3700,9 +4747,6 @@ static size_t ZSTD_initCDict_internal(
|
|
3700
4747
|
assert(!ZSTD_checkCParams(params.cParams));
|
3701
4748
|
cdict->matchState.cParams = params.cParams;
|
3702
4749
|
cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch;
|
3703
|
-
if (cdict->matchState.dedicatedDictSearch && dictSize > ZSTD_CHUNKSIZE_MAX) {
|
3704
|
-
cdict->matchState.dedicatedDictSearch = 0;
|
3705
|
-
}
|
3706
4750
|
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
|
3707
4751
|
cdict->dictContent = dictBuffer;
|
3708
4752
|
} else {
|
@@ -3723,6 +4767,7 @@ static size_t ZSTD_initCDict_internal(
|
|
3723
4767
|
&cdict->matchState,
|
3724
4768
|
&cdict->workspace,
|
3725
4769
|
¶ms.cParams,
|
4770
|
+
params.useRowMatchFinder,
|
3726
4771
|
ZSTDcrp_makeClean,
|
3727
4772
|
ZSTDirp_reset,
|
3728
4773
|
ZSTD_resetTarget_CDict), "");
|
@@ -3746,14 +4791,17 @@ static size_t ZSTD_initCDict_internal(
|
|
3746
4791
|
|
3747
4792
|
static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize,
|
3748
4793
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
3749
|
-
ZSTD_compressionParameters cParams,
|
4794
|
+
ZSTD_compressionParameters cParams,
|
4795
|
+
ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
|
4796
|
+
U32 enableDedicatedDictSearch,
|
4797
|
+
ZSTD_customMem customMem)
|
3750
4798
|
{
|
3751
4799
|
if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
|
3752
4800
|
|
3753
4801
|
{ size_t const workspaceSize =
|
3754
4802
|
ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
|
3755
4803
|
ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) +
|
3756
|
-
ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
|
4804
|
+
ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, enableDedicatedDictSearch, /* forCCtx */ 0) +
|
3757
4805
|
(dictLoadMethod == ZSTD_dlm_byRef ? 0
|
3758
4806
|
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
|
3759
4807
|
void* const workspace = ZSTD_customMalloc(workspaceSize, customMem);
|
@@ -3772,7 +4820,7 @@ static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize,
|
|
3772
4820
|
ZSTD_cwksp_move(&cdict->workspace, &ws);
|
3773
4821
|
cdict->customMem = customMem;
|
3774
4822
|
cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */
|
3775
|
-
|
4823
|
+
cdict->useRowMatchFinder = useRowMatchFinder;
|
3776
4824
|
return cdict;
|
3777
4825
|
}
|
3778
4826
|
}
|
@@ -3824,10 +4872,13 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2(
|
|
3824
4872
|
&cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
|
3825
4873
|
}
|
3826
4874
|
|
4875
|
+
DEBUGLOG(3, "ZSTD_createCDict_advanced2: DDS: %u", cctxParams.enableDedicatedDictSearch);
|
3827
4876
|
cctxParams.cParams = cParams;
|
4877
|
+
cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams);
|
3828
4878
|
|
3829
4879
|
cdict = ZSTD_createCDict_advanced_internal(dictSize,
|
3830
4880
|
dictLoadMethod, cctxParams.cParams,
|
4881
|
+
cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch,
|
3831
4882
|
customMem);
|
3832
4883
|
|
3833
4884
|
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
@@ -3896,7 +4947,9 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
|
|
3896
4947
|
ZSTD_dictContentType_e dictContentType,
|
3897
4948
|
ZSTD_compressionParameters cParams)
|
3898
4949
|
{
|
3899
|
-
|
4950
|
+
ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(ZSTD_urm_auto, &cParams);
|
4951
|
+
/* enableDedicatedDictSearch == 1 ensures matchstate is not too small in case this CDict will be used for DDS + row hash */
|
4952
|
+
size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0);
|
3900
4953
|
size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
|
3901
4954
|
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0
|
3902
4955
|
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))))
|
@@ -3921,6 +4974,8 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
|
|
3921
4974
|
|
3922
4975
|
ZSTD_CCtxParams_init(¶ms, 0);
|
3923
4976
|
params.cParams = cParams;
|
4977
|
+
params.useRowMatchFinder = useRowMatchFinder;
|
4978
|
+
cdict->useRowMatchFinder = useRowMatchFinder;
|
3924
4979
|
|
3925
4980
|
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
3926
4981
|
dict, dictSize,
|
@@ -3947,15 +5002,15 @@ unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict)
|
|
3947
5002
|
return cdict->dictID;
|
3948
5003
|
}
|
3949
5004
|
|
3950
|
-
|
3951
|
-
|
3952
|
-
|
3953
|
-
size_t
|
5005
|
+
/* ZSTD_compressBegin_usingCDict_internal() :
|
5006
|
+
* Implementation of various ZSTD_compressBegin_usingCDict* functions.
|
5007
|
+
*/
|
5008
|
+
static size_t ZSTD_compressBegin_usingCDict_internal(
|
3954
5009
|
ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
|
3955
5010
|
ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
|
3956
5011
|
{
|
3957
5012
|
ZSTD_CCtx_params cctxParams;
|
3958
|
-
DEBUGLOG(4, "
|
5013
|
+
DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal");
|
3959
5014
|
RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!");
|
3960
5015
|
/* Initialize the cctxParams from the cdict */
|
3961
5016
|
{
|
@@ -3987,25 +5042,48 @@ size_t ZSTD_compressBegin_usingCDict_advanced(
|
|
3987
5042
|
ZSTDb_not_buffered);
|
3988
5043
|
}
|
3989
5044
|
|
5045
|
+
|
5046
|
+
/* ZSTD_compressBegin_usingCDict_advanced() :
|
5047
|
+
* This function is DEPRECATED.
|
5048
|
+
* cdict must be != NULL */
|
5049
|
+
size_t ZSTD_compressBegin_usingCDict_advanced(
|
5050
|
+
ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
|
5051
|
+
ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
|
5052
|
+
{
|
5053
|
+
return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, pledgedSrcSize);
|
5054
|
+
}
|
5055
|
+
|
3990
5056
|
/* ZSTD_compressBegin_usingCDict() :
|
3991
|
-
*
|
3992
|
-
* if pledgedSrcSize>0, it will enable contentSizeFlag */
|
5057
|
+
* cdict must be != NULL */
|
3993
5058
|
size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
|
3994
5059
|
{
|
3995
5060
|
ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
|
3996
|
-
|
3997
|
-
return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
|
5061
|
+
return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
|
3998
5062
|
}
|
3999
5063
|
|
4000
|
-
|
5064
|
+
/*! ZSTD_compress_usingCDict_internal():
|
5065
|
+
* Implementation of various ZSTD_compress_usingCDict* functions.
|
5066
|
+
*/
|
5067
|
+
static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx,
|
4001
5068
|
void* dst, size_t dstCapacity,
|
4002
5069
|
const void* src, size_t srcSize,
|
4003
5070
|
const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
|
4004
5071
|
{
|
4005
|
-
FORWARD_IF_ERROR(
|
5072
|
+
FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */
|
4006
5073
|
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
|
4007
5074
|
}
|
4008
5075
|
|
5076
|
+
/*! ZSTD_compress_usingCDict_advanced():
|
5077
|
+
* This function is DEPRECATED.
|
5078
|
+
*/
|
5079
|
+
size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
|
5080
|
+
void* dst, size_t dstCapacity,
|
5081
|
+
const void* src, size_t srcSize,
|
5082
|
+
const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
|
5083
|
+
{
|
5084
|
+
return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
|
5085
|
+
}
|
5086
|
+
|
4009
5087
|
/*! ZSTD_compress_usingCDict() :
|
4010
5088
|
* Compression using a digested Dictionary.
|
4011
5089
|
* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
|
@@ -4017,7 +5095,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
|
|
4017
5095
|
const ZSTD_CDict* cdict)
|
4018
5096
|
{
|
4019
5097
|
ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
|
4020
|
-
return
|
5098
|
+
return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
|
4021
5099
|
}
|
4022
5100
|
|
4023
5101
|
|
@@ -4427,8 +5505,13 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
|
|
4427
5505
|
FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
|
4428
5506
|
ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
|
4429
5507
|
assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
|
4430
|
-
if (cctx->cdict)
|
4431
|
-
|
5508
|
+
if (cctx->cdict && !cctx->localDict.cdict) {
|
5509
|
+
/* Let the cdict's compression level take priority over the requested params.
|
5510
|
+
* But do not take the cdict's compression level if the "cdict" is actually a localDict
|
5511
|
+
* generated from ZSTD_initLocalDict().
|
5512
|
+
*/
|
5513
|
+
params.compressionLevel = cctx->cdict->compressionLevel;
|
5514
|
+
}
|
4432
5515
|
DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
|
4433
5516
|
if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-fix pledgedSrcSize */
|
4434
5517
|
{
|
@@ -4447,13 +5530,20 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
|
|
4447
5530
|
params.ldmParams.enableLdm = 1;
|
4448
5531
|
}
|
4449
5532
|
|
5533
|
+
if (ZSTD_CParams_useBlockSplitter(¶ms.cParams)) {
|
5534
|
+
DEBUGLOG(4, "Block splitter enabled by default (window size >= 128K, strategy >= btopt)");
|
5535
|
+
params.splitBlocks = 1;
|
5536
|
+
}
|
5537
|
+
|
5538
|
+
params.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params.useRowMatchFinder, ¶ms.cParams);
|
5539
|
+
|
4450
5540
|
#ifdef ZSTD_MULTITHREAD
|
4451
5541
|
if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
|
4452
5542
|
params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
|
4453
5543
|
}
|
4454
5544
|
if (params.nbWorkers > 0) {
|
4455
5545
|
#if ZSTD_TRACE
|
4456
|
-
cctx->traceCtx = ZSTD_trace_compress_begin(cctx);
|
5546
|
+
cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0;
|
4457
5547
|
#endif
|
4458
5548
|
/* mt context creation */
|
4459
5549
|
if (cctx->mtctx == NULL) {
|
@@ -4921,7 +6011,7 @@ static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
|
|
4921
6011
|
continue;
|
4922
6012
|
}
|
4923
6013
|
|
4924
|
-
compressedSeqsSize =
|
6014
|
+
compressedSeqsSize = ZSTD_entropyCompressSeqStore(&cctx->seqStore,
|
4925
6015
|
&cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy,
|
4926
6016
|
&cctx->appliedParams,
|
4927
6017
|
op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize,
|
@@ -4953,7 +6043,7 @@ static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
|
|
4953
6043
|
} else {
|
4954
6044
|
U32 cBlockHeader;
|
4955
6045
|
/* Error checking and repcodes update */
|
4956
|
-
|
6046
|
+
ZSTD_blockState_confirmRepcodesAndEntropyTables(&cctx->blockState);
|
4957
6047
|
if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
|
4958
6048
|
cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
|
4959
6049
|
|
@@ -5054,6 +6144,7 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
|
|
5054
6144
|
#define ZSTD_MAX_CLEVEL 22
|
5055
6145
|
int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
|
5056
6146
|
int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
|
6147
|
+
int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; }
|
5057
6148
|
|
5058
6149
|
static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
|
5059
6150
|
{ /* "default" - for any srcSize > 256 KB */
|
@@ -5186,7 +6277,10 @@ static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const
|
|
5186
6277
|
static int ZSTD_dedicatedDictSearch_isSupported(
|
5187
6278
|
ZSTD_compressionParameters const* cParams)
|
5188
6279
|
{
|
5189
|
-
return (cParams->strategy >= ZSTD_greedy)
|
6280
|
+
return (cParams->strategy >= ZSTD_greedy)
|
6281
|
+
&& (cParams->strategy <= ZSTD_lazy2)
|
6282
|
+
&& (cParams->hashLog > cParams->chainLog)
|
6283
|
+
&& (cParams->chainLog <= 24);
|
5190
6284
|
}
|
5191
6285
|
|
5192
6286
|
/**
|
@@ -5204,6 +6298,9 @@ static void ZSTD_dedicatedDictSearch_revertCParams(
|
|
5204
6298
|
case ZSTD_lazy:
|
5205
6299
|
case ZSTD_lazy2:
|
5206
6300
|
cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG;
|
6301
|
+
if (cParams->hashLog < ZSTD_HASHLOG_MIN) {
|
6302
|
+
cParams->hashLog = ZSTD_HASHLOG_MIN;
|
6303
|
+
}
|
5207
6304
|
break;
|
5208
6305
|
case ZSTD_btlazy2:
|
5209
6306
|
case ZSTD_btopt:
|
@@ -5252,6 +6349,7 @@ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel,
|
|
5252
6349
|
else row = compressionLevel;
|
5253
6350
|
|
5254
6351
|
{ ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
|
6352
|
+
DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy);
|
5255
6353
|
/* acceleration factor */
|
5256
6354
|
if (compressionLevel < 0) {
|
5257
6355
|
int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel);
|