Show More
The requested changes are too big and content was truncated. Show full diff
@@ -0,0 +1,360 b'' | |||
|
1 | /** | |
|
2 | * Copyright (c) 2018-present, Gregory Szorc | |
|
3 | * All rights reserved. | |
|
4 | * | |
|
5 | * This software may be modified and distributed under the terms | |
|
6 | * of the BSD license. See the LICENSE file for details. | |
|
7 | */ | |
|
8 | ||
|
9 | #include "python-zstandard.h" | |
|
10 | ||
|
11 | extern PyObject* ZstdError; | |
|
12 | ||
|
13 | PyDoc_STRVAR(ZstdCompressionChunkerIterator__doc__, | |
|
14 | "Iterator of output chunks from ZstdCompressionChunker.\n" | |
|
15 | ); | |
|
16 | ||
|
17 | static void ZstdCompressionChunkerIterator_dealloc(ZstdCompressionChunkerIterator* self) { | |
|
18 | Py_XDECREF(self->chunker); | |
|
19 | ||
|
20 | PyObject_Del(self); | |
|
21 | } | |
|
22 | ||
|
23 | static PyObject* ZstdCompressionChunkerIterator_iter(PyObject* self) { | |
|
24 | Py_INCREF(self); | |
|
25 | return self; | |
|
26 | } | |
|
27 | ||
|
28 | static PyObject* ZstdCompressionChunkerIterator_iternext(ZstdCompressionChunkerIterator* self) { | |
|
29 | size_t zresult; | |
|
30 | PyObject* chunk; | |
|
31 | ZstdCompressionChunker* chunker = self->chunker; | |
|
32 | ZSTD_EndDirective zFlushMode; | |
|
33 | ||
|
34 | if (self->mode != compressionchunker_mode_normal && chunker->input.pos != chunker->input.size) { | |
|
35 | PyErr_SetString(ZstdError, "input should have been fully consumed before calling flush() or finish()"); | |
|
36 | return NULL; | |
|
37 | } | |
|
38 | ||
|
39 | if (chunker->finished) { | |
|
40 | return NULL; | |
|
41 | } | |
|
42 | ||
|
43 | /* If we have data left in the input, consume it. */ | |
|
44 | while (chunker->input.pos < chunker->input.size) { | |
|
45 | Py_BEGIN_ALLOW_THREADS | |
|
46 | zresult = ZSTD_compress_generic(chunker->compressor->cctx, &chunker->output, | |
|
47 | &chunker->input, ZSTD_e_continue); | |
|
48 | Py_END_ALLOW_THREADS | |
|
49 | ||
|
50 | /* Input is fully consumed. */ | |
|
51 | if (chunker->input.pos == chunker->input.size) { | |
|
52 | chunker->input.src = NULL; | |
|
53 | chunker->input.pos = 0; | |
|
54 | chunker->input.size = 0; | |
|
55 | PyBuffer_Release(&chunker->inBuffer); | |
|
56 | } | |
|
57 | ||
|
58 | if (ZSTD_isError(zresult)) { | |
|
59 | PyErr_Format(ZstdError, "zstd compress error: %s", ZSTD_getErrorName(zresult)); | |
|
60 | return NULL; | |
|
61 | } | |
|
62 | ||
|
63 | /* If it produced a full output chunk, emit it. */ | |
|
64 | if (chunker->output.pos == chunker->output.size) { | |
|
65 | chunk = PyBytes_FromStringAndSize(chunker->output.dst, chunker->output.pos); | |
|
66 | if (!chunk) { | |
|
67 | return NULL; | |
|
68 | } | |
|
69 | ||
|
70 | chunker->output.pos = 0; | |
|
71 | ||
|
72 | return chunk; | |
|
73 | } | |
|
74 | ||
|
75 | /* Else continue to compress available input data. */ | |
|
76 | } | |
|
77 | ||
|
78 | /* We also need this here for the special case of an empty input buffer. */ | |
|
79 | if (chunker->input.pos == chunker->input.size) { | |
|
80 | chunker->input.src = NULL; | |
|
81 | chunker->input.pos = 0; | |
|
82 | chunker->input.size = 0; | |
|
83 | PyBuffer_Release(&chunker->inBuffer); | |
|
84 | } | |
|
85 | ||
|
86 | /* No more input data. A partial chunk may be in chunker->output. | |
|
87 | * If we're in normal compression mode, we're done. Otherwise if we're in | |
|
88 | * flush or finish mode, we need to emit what data remains. | |
|
89 | */ | |
|
90 | if (self->mode == compressionchunker_mode_normal) { | |
|
91 | /* We don't need to set StopIteration. */ | |
|
92 | return NULL; | |
|
93 | } | |
|
94 | ||
|
95 | if (self->mode == compressionchunker_mode_flush) { | |
|
96 | zFlushMode = ZSTD_e_flush; | |
|
97 | } | |
|
98 | else if (self->mode == compressionchunker_mode_finish) { | |
|
99 | zFlushMode = ZSTD_e_end; | |
|
100 | } | |
|
101 | else { | |
|
102 | PyErr_SetString(ZstdError, "unhandled compression mode; this should never happen"); | |
|
103 | return NULL; | |
|
104 | } | |
|
105 | ||
|
106 | Py_BEGIN_ALLOW_THREADS | |
|
107 | zresult = ZSTD_compress_generic(chunker->compressor->cctx, &chunker->output, | |
|
108 | &chunker->input, zFlushMode); | |
|
109 | Py_END_ALLOW_THREADS | |
|
110 | ||
|
111 | if (ZSTD_isError(zresult)) { | |
|
112 | PyErr_Format(ZstdError, "zstd compress error: %s", | |
|
113 | ZSTD_getErrorName(zresult)); | |
|
114 | return NULL; | |
|
115 | } | |
|
116 | ||
|
117 | if (!zresult && chunker->output.pos == 0) { | |
|
118 | return NULL; | |
|
119 | } | |
|
120 | ||
|
121 | chunk = PyBytes_FromStringAndSize(chunker->output.dst, chunker->output.pos); | |
|
122 | if (!chunk) { | |
|
123 | return NULL; | |
|
124 | } | |
|
125 | ||
|
126 | chunker->output.pos = 0; | |
|
127 | ||
|
128 | if (!zresult && self->mode == compressionchunker_mode_finish) { | |
|
129 | chunker->finished = 1; | |
|
130 | } | |
|
131 | ||
|
132 | return chunk; | |
|
133 | } | |
|
134 | ||
|
135 | PyTypeObject ZstdCompressionChunkerIteratorType = { | |
|
136 | PyVarObject_HEAD_INIT(NULL, 0) | |
|
137 | "zstd.ZstdCompressionChunkerIterator", /* tp_name */ | |
|
138 | sizeof(ZstdCompressionChunkerIterator), /* tp_basicsize */ | |
|
139 | 0, /* tp_itemsize */ | |
|
140 | (destructor)ZstdCompressionChunkerIterator_dealloc, /* tp_dealloc */ | |
|
141 | 0, /* tp_print */ | |
|
142 | 0, /* tp_getattr */ | |
|
143 | 0, /* tp_setattr */ | |
|
144 | 0, /* tp_compare */ | |
|
145 | 0, /* tp_repr */ | |
|
146 | 0, /* tp_as_number */ | |
|
147 | 0, /* tp_as_sequence */ | |
|
148 | 0, /* tp_as_mapping */ | |
|
149 | 0, /* tp_hash */ | |
|
150 | 0, /* tp_call */ | |
|
151 | 0, /* tp_str */ | |
|
152 | 0, /* tp_getattro */ | |
|
153 | 0, /* tp_setattro */ | |
|
154 | 0, /* tp_as_buffer */ | |
|
155 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ | |
|
156 | ZstdCompressionChunkerIterator__doc__, /* tp_doc */ | |
|
157 | 0, /* tp_traverse */ | |
|
158 | 0, /* tp_clear */ | |
|
159 | 0, /* tp_richcompare */ | |
|
160 | 0, /* tp_weaklistoffset */ | |
|
161 | ZstdCompressionChunkerIterator_iter, /* tp_iter */ | |
|
162 | (iternextfunc)ZstdCompressionChunkerIterator_iternext, /* tp_iternext */ | |
|
163 | 0, /* tp_methods */ | |
|
164 | 0, /* tp_members */ | |
|
165 | 0, /* tp_getset */ | |
|
166 | 0, /* tp_base */ | |
|
167 | 0, /* tp_dict */ | |
|
168 | 0, /* tp_descr_get */ | |
|
169 | 0, /* tp_descr_set */ | |
|
170 | 0, /* tp_dictoffset */ | |
|
171 | 0, /* tp_init */ | |
|
172 | 0, /* tp_alloc */ | |
|
173 | PyType_GenericNew, /* tp_new */ | |
|
174 | }; | |
|
175 | ||
|
176 | PyDoc_STRVAR(ZstdCompressionChunker__doc__, | |
|
177 | "Compress chunks iteratively into exact chunk sizes.\n" | |
|
178 | ); | |
|
179 | ||
|
180 | static void ZstdCompressionChunker_dealloc(ZstdCompressionChunker* self) { | |
|
181 | PyBuffer_Release(&self->inBuffer); | |
|
182 | self->input.src = NULL; | |
|
183 | ||
|
184 | PyMem_Free(self->output.dst); | |
|
185 | self->output.dst = NULL; | |
|
186 | ||
|
187 | Py_XDECREF(self->compressor); | |
|
188 | ||
|
189 | PyObject_Del(self); | |
|
190 | } | |
|
191 | ||
|
192 | static ZstdCompressionChunkerIterator* ZstdCompressionChunker_compress(ZstdCompressionChunker* self, PyObject* args, PyObject* kwargs) { | |
|
193 | static char* kwlist[] = { | |
|
194 | "data", | |
|
195 | NULL | |
|
196 | }; | |
|
197 | ||
|
198 | ZstdCompressionChunkerIterator* result; | |
|
199 | ||
|
200 | if (self->finished) { | |
|
201 | PyErr_SetString(ZstdError, "cannot call compress() after compression finished"); | |
|
202 | return NULL; | |
|
203 | } | |
|
204 | ||
|
205 | if (self->inBuffer.obj) { | |
|
206 | PyErr_SetString(ZstdError, | |
|
207 | "cannot perform operation before consuming output from previous operation"); | |
|
208 | return NULL; | |
|
209 | } | |
|
210 | ||
|
211 | #if PY_MAJOR_VERSION >= 3 | |
|
212 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*:compress", | |
|
213 | #else | |
|
214 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s*:compress", | |
|
215 | #endif | |
|
216 | kwlist, &self->inBuffer)) { | |
|
217 | return NULL; | |
|
218 | } | |
|
219 | ||
|
220 | if (!PyBuffer_IsContiguous(&self->inBuffer, 'C') || self->inBuffer.ndim > 1) { | |
|
221 | PyErr_SetString(PyExc_ValueError, | |
|
222 | "data buffer should be contiguous and have at most one dimension"); | |
|
223 | PyBuffer_Release(&self->inBuffer); | |
|
224 | return NULL; | |
|
225 | } | |
|
226 | ||
|
227 | result = (ZstdCompressionChunkerIterator*)PyObject_CallObject((PyObject*)&ZstdCompressionChunkerIteratorType, NULL); | |
|
228 | if (!result) { | |
|
229 | PyBuffer_Release(&self->inBuffer); | |
|
230 | return NULL; | |
|
231 | } | |
|
232 | ||
|
233 | self->input.src = self->inBuffer.buf; | |
|
234 | self->input.size = self->inBuffer.len; | |
|
235 | self->input.pos = 0; | |
|
236 | ||
|
237 | result->chunker = self; | |
|
238 | Py_INCREF(result->chunker); | |
|
239 | ||
|
240 | result->mode = compressionchunker_mode_normal; | |
|
241 | ||
|
242 | return result; | |
|
243 | } | |
|
244 | ||
|
245 | static ZstdCompressionChunkerIterator* ZstdCompressionChunker_finish(ZstdCompressionChunker* self) { | |
|
246 | ZstdCompressionChunkerIterator* result; | |
|
247 | ||
|
248 | if (self->finished) { | |
|
249 | PyErr_SetString(ZstdError, "cannot call finish() after compression finished"); | |
|
250 | return NULL; | |
|
251 | } | |
|
252 | ||
|
253 | if (self->inBuffer.obj) { | |
|
254 | PyErr_SetString(ZstdError, | |
|
255 | "cannot call finish() before consuming output from previous operation"); | |
|
256 | return NULL; | |
|
257 | } | |
|
258 | ||
|
259 | result = (ZstdCompressionChunkerIterator*)PyObject_CallObject((PyObject*)&ZstdCompressionChunkerIteratorType, NULL); | |
|
260 | if (!result) { | |
|
261 | return NULL; | |
|
262 | } | |
|
263 | ||
|
264 | result->chunker = self; | |
|
265 | Py_INCREF(result->chunker); | |
|
266 | ||
|
267 | result->mode = compressionchunker_mode_finish; | |
|
268 | ||
|
269 | return result; | |
|
270 | } | |
|
271 | ||
|
272 | static ZstdCompressionChunkerIterator* ZstdCompressionChunker_flush(ZstdCompressionChunker* self, PyObject* args, PyObject* kwargs) { | |
|
273 | ZstdCompressionChunkerIterator* result; | |
|
274 | ||
|
275 | if (self->finished) { | |
|
276 | PyErr_SetString(ZstdError, "cannot call flush() after compression finished"); | |
|
277 | return NULL; | |
|
278 | } | |
|
279 | ||
|
280 | if (self->inBuffer.obj) { | |
|
281 | PyErr_SetString(ZstdError, | |
|
282 | "cannot call flush() before consuming output from previous operation"); | |
|
283 | return NULL; | |
|
284 | } | |
|
285 | ||
|
286 | result = (ZstdCompressionChunkerIterator*)PyObject_CallObject((PyObject*)&ZstdCompressionChunkerIteratorType, NULL); | |
|
287 | if (!result) { | |
|
288 | return NULL; | |
|
289 | } | |
|
290 | ||
|
291 | result->chunker = self; | |
|
292 | Py_INCREF(result->chunker); | |
|
293 | ||
|
294 | result->mode = compressionchunker_mode_flush; | |
|
295 | ||
|
296 | return result; | |
|
297 | } | |
|
298 | ||
|
299 | static PyMethodDef ZstdCompressionChunker_methods[] = { | |
|
300 | { "compress", (PyCFunction)ZstdCompressionChunker_compress, METH_VARARGS | METH_KEYWORDS, | |
|
301 | PyDoc_STR("compress data") }, | |
|
302 | { "finish", (PyCFunction)ZstdCompressionChunker_finish, METH_NOARGS, | |
|
303 | PyDoc_STR("finish compression operation") }, | |
|
304 | { "flush", (PyCFunction)ZstdCompressionChunker_flush, METH_VARARGS | METH_KEYWORDS, | |
|
305 | PyDoc_STR("finish compression operation") }, | |
|
306 | { NULL, NULL } | |
|
307 | }; | |
|
308 | ||
|
309 | PyTypeObject ZstdCompressionChunkerType = { | |
|
310 | PyVarObject_HEAD_INIT(NULL, 0) | |
|
311 | "zstd.ZstdCompressionChunkerType", /* tp_name */ | |
|
312 | sizeof(ZstdCompressionChunker), /* tp_basicsize */ | |
|
313 | 0, /* tp_itemsize */ | |
|
314 | (destructor)ZstdCompressionChunker_dealloc, /* tp_dealloc */ | |
|
315 | 0, /* tp_print */ | |
|
316 | 0, /* tp_getattr */ | |
|
317 | 0, /* tp_setattr */ | |
|
318 | 0, /* tp_compare */ | |
|
319 | 0, /* tp_repr */ | |
|
320 | 0, /* tp_as_number */ | |
|
321 | 0, /* tp_as_sequence */ | |
|
322 | 0, /* tp_as_mapping */ | |
|
323 | 0, /* tp_hash */ | |
|
324 | 0, /* tp_call */ | |
|
325 | 0, /* tp_str */ | |
|
326 | 0, /* tp_getattro */ | |
|
327 | 0, /* tp_setattro */ | |
|
328 | 0, /* tp_as_buffer */ | |
|
329 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ | |
|
330 | ZstdCompressionChunker__doc__, /* tp_doc */ | |
|
331 | 0, /* tp_traverse */ | |
|
332 | 0, /* tp_clear */ | |
|
333 | 0, /* tp_richcompare */ | |
|
334 | 0, /* tp_weaklistoffset */ | |
|
335 | 0, /* tp_iter */ | |
|
336 | 0, /* tp_iternext */ | |
|
337 | ZstdCompressionChunker_methods, /* tp_methods */ | |
|
338 | 0, /* tp_members */ | |
|
339 | 0, /* tp_getset */ | |
|
340 | 0, /* tp_base */ | |
|
341 | 0, /* tp_dict */ | |
|
342 | 0, /* tp_descr_get */ | |
|
343 | 0, /* tp_descr_set */ | |
|
344 | 0, /* tp_dictoffset */ | |
|
345 | 0, /* tp_init */ | |
|
346 | 0, /* tp_alloc */ | |
|
347 | PyType_GenericNew, /* tp_new */ | |
|
348 | }; | |
|
349 | ||
|
350 | void compressionchunker_module_init(PyObject* module) { | |
|
351 | Py_TYPE(&ZstdCompressionChunkerIteratorType) = &PyType_Type; | |
|
352 | if (PyType_Ready(&ZstdCompressionChunkerIteratorType) < 0) { | |
|
353 | return; | |
|
354 | } | |
|
355 | ||
|
356 | Py_TYPE(&ZstdCompressionChunkerType) = &PyType_Type; | |
|
357 | if (PyType_Ready(&ZstdCompressionChunkerType) < 0) { | |
|
358 | return; | |
|
359 | } | |
|
360 | } |
@@ -0,0 +1,44 b'' | |||
|
1 | /* ****************************************************************** | |
|
2 | debug | |
|
3 | Part of FSE library | |
|
4 | Copyright (C) 2013-present, Yann Collet. | |
|
5 | ||
|
6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | |
|
7 | ||
|
8 | Redistribution and use in source and binary forms, with or without | |
|
9 | modification, are permitted provided that the following conditions are | |
|
10 | met: | |
|
11 | ||
|
12 | * Redistributions of source code must retain the above copyright | |
|
13 | notice, this list of conditions and the following disclaimer. | |
|
14 | * Redistributions in binary form must reproduce the above | |
|
15 | copyright notice, this list of conditions and the following disclaimer | |
|
16 | in the documentation and/or other materials provided with the | |
|
17 | distribution. | |
|
18 | ||
|
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
|
20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
|
21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
|
22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
|
23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
|
24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
|
25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
|
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
|
27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
|
28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
|
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
|
30 | ||
|
31 | You can contact the author at : | |
|
32 | - Source repository : https://github.com/Cyan4973/FiniteStateEntropy | |
|
33 | ****************************************************************** */ | |
|
34 | ||
|
35 | ||
|
36 | /* | |
|
37 | * This module only hosts one global variable | |
|
38 | * which can be used to dynamically influence the verbosity of traces, | |
|
39 | * such as DEBUGLOG and RAWLOG | |
|
40 | */ | |
|
41 | ||
|
42 | #include "debug.h" | |
|
43 | ||
|
44 | int g_debuglevel = DEBUGLEVEL; |
@@ -0,0 +1,123 b'' | |||
|
1 | /* ****************************************************************** | |
|
2 | debug | |
|
3 | Part of FSE library | |
|
4 | Copyright (C) 2013-present, Yann Collet. | |
|
5 | ||
|
6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | |
|
7 | ||
|
8 | Redistribution and use in source and binary forms, with or without | |
|
9 | modification, are permitted provided that the following conditions are | |
|
10 | met: | |
|
11 | ||
|
12 | * Redistributions of source code must retain the above copyright | |
|
13 | notice, this list of conditions and the following disclaimer. | |
|
14 | * Redistributions in binary form must reproduce the above | |
|
15 | copyright notice, this list of conditions and the following disclaimer | |
|
16 | in the documentation and/or other materials provided with the | |
|
17 | distribution. | |
|
18 | ||
|
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
|
20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
|
21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
|
22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
|
23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
|
24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
|
25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
|
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
|
27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
|
28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
|
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
|
30 | ||
|
31 | You can contact the author at : | |
|
32 | - Source repository : https://github.com/Cyan4973/FiniteStateEntropy | |
|
33 | ****************************************************************** */ | |
|
34 | ||
|
35 | ||
|
36 | /* | |
|
37 | * The purpose of this header is to enable debug functions. | |
|
38 | * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time, | |
|
39 | * and DEBUG_STATIC_ASSERT() for compile-time. | |
|
40 | * | |
|
41 | * By default, DEBUGLEVEL==0, which means run-time debug is disabled. | |
|
42 | * | |
|
43 | * Level 1 enables assert() only. | |
|
44 | * Starting level 2, traces can be generated and pushed to stderr. | |
|
45 | * The higher the level, the more verbose the traces. | |
|
46 | * | |
|
47 | * It's possible to dynamically adjust level using variable g_debug_level, | |
|
48 | * which is only declared if DEBUGLEVEL>=2, | |
|
49 | * and is a global variable, not multi-thread protected (use with care) | |
|
50 | */ | |
|
51 | ||
|
52 | #ifndef DEBUG_H_12987983217 | |
|
53 | #define DEBUG_H_12987983217 | |
|
54 | ||
|
55 | #if defined (__cplusplus) | |
|
56 | extern "C" { | |
|
57 | #endif | |
|
58 | ||
|
59 | ||
|
60 | /* static assert is triggered at compile time, leaving no runtime artefact, | |
|
61 | * but can only work with compile-time constants. | |
|
62 | * This variant can only be used inside a function. */ | |
|
63 | #define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1]) | |
|
64 | ||
|
65 | ||
|
66 | /* DEBUGLEVEL is expected to be defined externally, | |
|
67 | * typically through compiler command line. | |
|
68 | * Value must be a number. */ | |
|
69 | #ifndef DEBUGLEVEL | |
|
70 | # define DEBUGLEVEL 0 | |
|
71 | #endif | |
|
72 | ||
|
73 | /* recommended values for DEBUGLEVEL : | |
|
74 | * 0 : no debug, all run-time functions disabled | |
|
75 | * 1 : no display, enables assert() only | |
|
76 | * 2 : reserved, for currently active debug path | |
|
77 | * 3 : events once per object lifetime (CCtx, CDict, etc.) | |
|
78 | * 4 : events once per frame | |
|
79 | * 5 : events once per block | |
|
80 | * 6 : events once per sequence (verbose) | |
|
81 | * 7+: events at every position (*very* verbose) | |
|
82 | * | |
|
83 | * It's generally inconvenient to output traces > 5. | |
|
84 | * In which case, it's possible to selectively enable higher verbosity levels | |
|
85 | * by modifying g_debug_level. | |
|
86 | */ | |
|
87 | ||
|
88 | #if (DEBUGLEVEL>=1) | |
|
89 | # include <assert.h> | |
|
90 | #else | |
|
91 | # ifndef assert /* assert may be already defined, due to prior #include <assert.h> */ | |
|
92 | # define assert(condition) ((void)0) /* disable assert (default) */ | |
|
93 | # endif | |
|
94 | #endif | |
|
95 | ||
|
96 | #if (DEBUGLEVEL>=2) | |
|
97 | # include <stdio.h> | |
|
98 | extern int g_debuglevel; /* here, this variable is only declared, | |
|
99 | it actually lives in debug.c, | |
|
100 | and is shared by the whole process. | |
|
101 | It's typically used to enable very verbose levels | |
|
102 | on selective conditions (such as position in src) */ | |
|
103 | ||
|
104 | # define RAWLOG(l, ...) { \ | |
|
105 | if (l<=g_debuglevel) { \ | |
|
106 | fprintf(stderr, __VA_ARGS__); \ | |
|
107 | } } | |
|
108 | # define DEBUGLOG(l, ...) { \ | |
|
109 | if (l<=g_debuglevel) { \ | |
|
110 | fprintf(stderr, __FILE__ ": " __VA_ARGS__); \ | |
|
111 | fprintf(stderr, " \n"); \ | |
|
112 | } } | |
|
113 | #else | |
|
114 | # define RAWLOG(l, ...) {} /* disabled */ | |
|
115 | # define DEBUGLOG(l, ...) {} /* disabled */ | |
|
116 | #endif | |
|
117 | ||
|
118 | ||
|
119 | #if defined (__cplusplus) | |
|
120 | } | |
|
121 | #endif | |
|
122 | ||
|
123 | #endif /* DEBUG_H_12987983217 */ |
@@ -0,0 +1,195 b'' | |||
|
1 | /* ****************************************************************** | |
|
2 | hist : Histogram functions | |
|
3 | part of Finite State Entropy project | |
|
4 | Copyright (C) 2013-present, Yann Collet. | |
|
5 | ||
|
6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | |
|
7 | ||
|
8 | Redistribution and use in source and binary forms, with or without | |
|
9 | modification, are permitted provided that the following conditions are | |
|
10 | met: | |
|
11 | ||
|
12 | * Redistributions of source code must retain the above copyright | |
|
13 | notice, this list of conditions and the following disclaimer. | |
|
14 | * Redistributions in binary form must reproduce the above | |
|
15 | copyright notice, this list of conditions and the following disclaimer | |
|
16 | in the documentation and/or other materials provided with the | |
|
17 | distribution. | |
|
18 | ||
|
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
|
20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
|
21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
|
22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
|
23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
|
24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
|
25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
|
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
|
27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
|
28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
|
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
|
30 | ||
|
31 | You can contact the author at : | |
|
32 | - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy | |
|
33 | - Public forum : https://groups.google.com/forum/#!forum/lz4c | |
|
34 | ****************************************************************** */ | |
|
35 | ||
|
36 | /* --- dependencies --- */ | |
|
37 | #include "mem.h" /* U32, BYTE, etc. */ | |
|
38 | #include "debug.h" /* assert, DEBUGLOG */ | |
|
39 | #include "error_private.h" /* ERROR */ | |
|
40 | #include "hist.h" | |
|
41 | ||
|
42 | ||
|
43 | /* --- Error management --- */ | |
|
44 | unsigned HIST_isError(size_t code) { return ERR_isError(code); } | |
|
45 | ||
|
46 | /*-************************************************************** | |
|
47 | * Histogram functions | |
|
48 | ****************************************************************/ | |
|
49 | unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
50 | const void* src, size_t srcSize) | |
|
51 | { | |
|
52 | const BYTE* ip = (const BYTE*)src; | |
|
53 | const BYTE* const end = ip + srcSize; | |
|
54 | unsigned maxSymbolValue = *maxSymbolValuePtr; | |
|
55 | unsigned largestCount=0; | |
|
56 | ||
|
57 | memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); | |
|
58 | if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; } | |
|
59 | ||
|
60 | while (ip<end) { | |
|
61 | assert(*ip <= maxSymbolValue); | |
|
62 | count[*ip++]++; | |
|
63 | } | |
|
64 | ||
|
65 | while (!count[maxSymbolValue]) maxSymbolValue--; | |
|
66 | *maxSymbolValuePtr = maxSymbolValue; | |
|
67 | ||
|
68 | { U32 s; | |
|
69 | for (s=0; s<=maxSymbolValue; s++) | |
|
70 | if (count[s] > largestCount) largestCount = count[s]; | |
|
71 | } | |
|
72 | ||
|
73 | return largestCount; | |
|
74 | } | |
|
75 | ||
|
76 | ||
|
77 | /* HIST_count_parallel_wksp() : | |
|
78 | * store histogram into 4 intermediate tables, recombined at the end. | |
|
79 | * this design makes better use of OoO cpus, | |
|
80 | * and is noticeably faster when some values are heavily repeated. | |
|
81 | * But it needs some additional workspace for intermediate tables. | |
|
82 | * `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32. | |
|
83 | * @return : largest histogram frequency, | |
|
84 | * or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */ | |
|
85 | static size_t HIST_count_parallel_wksp( | |
|
86 | unsigned* count, unsigned* maxSymbolValuePtr, | |
|
87 | const void* source, size_t sourceSize, | |
|
88 | unsigned checkMax, | |
|
89 | unsigned* const workSpace) | |
|
90 | { | |
|
91 | const BYTE* ip = (const BYTE*)source; | |
|
92 | const BYTE* const iend = ip+sourceSize; | |
|
93 | unsigned maxSymbolValue = *maxSymbolValuePtr; | |
|
94 | unsigned max=0; | |
|
95 | U32* const Counting1 = workSpace; | |
|
96 | U32* const Counting2 = Counting1 + 256; | |
|
97 | U32* const Counting3 = Counting2 + 256; | |
|
98 | U32* const Counting4 = Counting3 + 256; | |
|
99 | ||
|
100 | memset(workSpace, 0, 4*256*sizeof(unsigned)); | |
|
101 | ||
|
102 | /* safety checks */ | |
|
103 | if (!sourceSize) { | |
|
104 | memset(count, 0, maxSymbolValue + 1); | |
|
105 | *maxSymbolValuePtr = 0; | |
|
106 | return 0; | |
|
107 | } | |
|
108 | if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */ | |
|
109 | ||
|
110 | /* by stripes of 16 bytes */ | |
|
111 | { U32 cached = MEM_read32(ip); ip += 4; | |
|
112 | while (ip < iend-15) { | |
|
113 | U32 c = cached; cached = MEM_read32(ip); ip += 4; | |
|
114 | Counting1[(BYTE) c ]++; | |
|
115 | Counting2[(BYTE)(c>>8) ]++; | |
|
116 | Counting3[(BYTE)(c>>16)]++; | |
|
117 | Counting4[ c>>24 ]++; | |
|
118 | c = cached; cached = MEM_read32(ip); ip += 4; | |
|
119 | Counting1[(BYTE) c ]++; | |
|
120 | Counting2[(BYTE)(c>>8) ]++; | |
|
121 | Counting3[(BYTE)(c>>16)]++; | |
|
122 | Counting4[ c>>24 ]++; | |
|
123 | c = cached; cached = MEM_read32(ip); ip += 4; | |
|
124 | Counting1[(BYTE) c ]++; | |
|
125 | Counting2[(BYTE)(c>>8) ]++; | |
|
126 | Counting3[(BYTE)(c>>16)]++; | |
|
127 | Counting4[ c>>24 ]++; | |
|
128 | c = cached; cached = MEM_read32(ip); ip += 4; | |
|
129 | Counting1[(BYTE) c ]++; | |
|
130 | Counting2[(BYTE)(c>>8) ]++; | |
|
131 | Counting3[(BYTE)(c>>16)]++; | |
|
132 | Counting4[ c>>24 ]++; | |
|
133 | } | |
|
134 | ip-=4; | |
|
135 | } | |
|
136 | ||
|
137 | /* finish last symbols */ | |
|
138 | while (ip<iend) Counting1[*ip++]++; | |
|
139 | ||
|
140 | if (checkMax) { /* verify stats will fit into destination table */ | |
|
141 | U32 s; for (s=255; s>maxSymbolValue; s--) { | |
|
142 | Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; | |
|
143 | if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); | |
|
144 | } } | |
|
145 | ||
|
146 | { U32 s; | |
|
147 | if (maxSymbolValue > 255) maxSymbolValue = 255; | |
|
148 | for (s=0; s<=maxSymbolValue; s++) { | |
|
149 | count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; | |
|
150 | if (count[s] > max) max = count[s]; | |
|
151 | } } | |
|
152 | ||
|
153 | while (!count[maxSymbolValue]) maxSymbolValue--; | |
|
154 | *maxSymbolValuePtr = maxSymbolValue; | |
|
155 | return (size_t)max; | |
|
156 | } | |
|
157 | ||
|
158 | /* HIST_countFast_wksp() : | |
|
159 | * Same as HIST_countFast(), but using an externally provided scratch buffer. | |
|
160 | * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */ | |
|
161 | size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
162 | const void* source, size_t sourceSize, | |
|
163 | unsigned* workSpace) | |
|
164 | { | |
|
165 | if (sourceSize < 1500) /* heuristic threshold */ | |
|
166 | return HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize); | |
|
167 | return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace); | |
|
168 | } | |
|
169 | ||
|
170 | /* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ | |
|
171 | size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
172 | const void* source, size_t sourceSize) | |
|
173 | { | |
|
174 | unsigned tmpCounters[HIST_WKSP_SIZE_U32]; | |
|
175 | return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters); | |
|
176 | } | |
|
177 | ||
|
178 | /* HIST_count_wksp() : | |
|
179 | * Same as HIST_count(), but using an externally provided scratch buffer. | |
|
180 | * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */ | |
|
181 | size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
182 | const void* source, size_t sourceSize, unsigned* workSpace) | |
|
183 | { | |
|
184 | if (*maxSymbolValuePtr < 255) | |
|
185 | return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace); | |
|
186 | *maxSymbolValuePtr = 255; | |
|
187 | return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace); | |
|
188 | } | |
|
189 | ||
|
190 | size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
191 | const void* src, size_t srcSize) | |
|
192 | { | |
|
193 | unsigned tmpCounters[HIST_WKSP_SIZE_U32]; | |
|
194 | return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters); | |
|
195 | } |
@@ -0,0 +1,92 b'' | |||
|
1 | /* ****************************************************************** | |
|
2 | hist : Histogram functions | |
|
3 | part of Finite State Entropy project | |
|
4 | Copyright (C) 2013-present, Yann Collet. | |
|
5 | ||
|
6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | |
|
7 | ||
|
8 | Redistribution and use in source and binary forms, with or without | |
|
9 | modification, are permitted provided that the following conditions are | |
|
10 | met: | |
|
11 | ||
|
12 | * Redistributions of source code must retain the above copyright | |
|
13 | notice, this list of conditions and the following disclaimer. | |
|
14 | * Redistributions in binary form must reproduce the above | |
|
15 | copyright notice, this list of conditions and the following disclaimer | |
|
16 | in the documentation and/or other materials provided with the | |
|
17 | distribution. | |
|
18 | ||
|
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
|
20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
|
21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
|
22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
|
23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
|
24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
|
25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
|
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
|
27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
|
28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
|
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
|
30 | ||
|
31 | You can contact the author at : | |
|
32 | - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy | |
|
33 | - Public forum : https://groups.google.com/forum/#!forum/lz4c | |
|
34 | ****************************************************************** */ | |
|
35 | ||
|
36 | /* --- dependencies --- */ | |
|
37 | #include <stddef.h> /* size_t */ | |
|
38 | ||
|
39 | ||
|
40 | /* --- simple histogram functions --- */ | |
|
41 | ||
|
42 | /*! HIST_count(): | |
|
43 | * Provides the precise count of each byte within a table 'count'. | |
|
44 | * 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1). | |
|
45 | * Updates *maxSymbolValuePtr with actual largest symbol value detected. | |
|
46 | * @return : count of the most frequent symbol (which isn't identified). | |
|
47 | * or an error code, which can be tested using HIST_isError(). | |
|
48 | * note : if return == srcSize, there is only one symbol. | |
|
49 | */ | |
|
50 | size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
51 | const void* src, size_t srcSize); | |
|
52 | ||
|
53 | unsigned HIST_isError(size_t code); /**< tells if a return value is an error code */ | |
|
54 | ||
|
55 | ||
|
56 | /* --- advanced histogram functions --- */ | |
|
57 | ||
|
58 | #define HIST_WKSP_SIZE_U32 1024 | |
|
59 | /** HIST_count_wksp() : | |
|
60 | * Same as HIST_count(), but using an externally provided scratch buffer. | |
|
61 | * Benefit is this function will use very little stack space. | |
|
62 | * `workSpace` must be a table of unsigned of size >= HIST_WKSP_SIZE_U32 | |
|
63 | */ | |
|
64 | size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
65 | const void* src, size_t srcSize, | |
|
66 | unsigned* workSpace); | |
|
67 | ||
|
68 | /** HIST_countFast() : | |
|
69 | * same as HIST_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr. | |
|
70 | * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` | |
|
71 | */ | |
|
72 | size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
73 | const void* src, size_t srcSize); | |
|
74 | ||
|
75 | /** HIST_countFast_wksp() : | |
|
76 | * Same as HIST_countFast(), but using an externally provided scratch buffer. | |
|
77 | * `workSpace` must be a table of unsigned of size >= HIST_WKSP_SIZE_U32 | |
|
78 | */ | |
|
79 | size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
80 | const void* src, size_t srcSize, | |
|
81 | unsigned* workSpace); | |
|
82 | ||
|
83 | /*! HIST_count_simple() : | |
|
84 | * Same as HIST_countFast(), this function is unsafe, | |
|
85 | * and will segfault if any value within `src` is `> *maxSymbolValuePtr`. | |
|
86 | * It is also a bit slower for large inputs. | |
|
87 | * However, it does not need any additional memory (not even on stack). | |
|
88 | * @return : count of the most frequent symbol. | |
|
89 | * Note this function doesn't produce any error (i.e. it must succeed). | |
|
90 | */ | |
|
91 | unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
92 | const void* src, size_t srcSize); |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
@@ -6,6 +6,7 b' mercurial/cext/osutil.c' | |||
|
6 | 6 | mercurial/cext/revlog.c |
|
7 | 7 | # Vendored code that we should never format: |
|
8 | 8 | contrib/python-zstandard/c-ext/bufferutil.c |
|
9 | contrib/python-zstandard/c-ext/compressionchunker.c | |
|
9 | 10 | contrib/python-zstandard/c-ext/compressiondict.c |
|
10 | 11 | contrib/python-zstandard/c-ext/compressionparams.c |
|
11 | 12 | contrib/python-zstandard/c-ext/compressionreader.c |
@@ -25,6 +26,8 b' contrib/python-zstandard/zstd.c' | |||
|
25 | 26 | contrib/python-zstandard/zstd/common/bitstream.h |
|
26 | 27 | contrib/python-zstandard/zstd/common/compiler.h |
|
27 | 28 | contrib/python-zstandard/zstd/common/cpu.h |
|
29 | contrib/python-zstandard/zstd/common/debug.c | |
|
30 | contrib/python-zstandard/zstd/common/debug.h | |
|
28 | 31 | contrib/python-zstandard/zstd/common/entropy_common.c |
|
29 | 32 | contrib/python-zstandard/zstd/common/error_private.c |
|
30 | 33 | contrib/python-zstandard/zstd/common/error_private.h |
@@ -42,6 +45,8 b' contrib/python-zstandard/zstd/common/zst' | |||
|
42 | 45 | contrib/python-zstandard/zstd/common/zstd_errors.h |
|
43 | 46 | contrib/python-zstandard/zstd/common/zstd_internal.h |
|
44 | 47 | contrib/python-zstandard/zstd/compress/fse_compress.c |
|
48 | contrib/python-zstandard/zstd/compress/hist.c | |
|
49 | contrib/python-zstandard/zstd/compress/hist.h | |
|
45 | 50 | contrib/python-zstandard/zstd/compress/huf_compress.c |
|
46 | 51 | contrib/python-zstandard/zstd/compress/zstd_compress.c |
|
47 | 52 | contrib/python-zstandard/zstd/compress/zstd_compress_internal.h |
@@ -64,8 +69,10 b' contrib/python-zstandard/zstd/deprecated' | |||
|
64 | 69 | contrib/python-zstandard/zstd/deprecated/zbuff_decompress.c |
|
65 | 70 | contrib/python-zstandard/zstd/deprecated/zbuff.h |
|
66 | 71 | contrib/python-zstandard/zstd/dictBuilder/cover.c |
|
72 | contrib/python-zstandard/zstd/dictBuilder/cover.h | |
|
67 | 73 | contrib/python-zstandard/zstd/dictBuilder/divsufsort.c |
|
68 | 74 | contrib/python-zstandard/zstd/dictBuilder/divsufsort.h |
|
75 | contrib/python-zstandard/zstd/dictBuilder/fastcover.c | |
|
69 | 76 | contrib/python-zstandard/zstd/dictBuilder/zdict.c |
|
70 | 77 | contrib/python-zstandard/zstd/dictBuilder/zdict.h |
|
71 | 78 | contrib/python-zstandard/zstd/zstd.h |
@@ -1,7 +1,10 b'' | |||
|
1 | 1 | graft c-ext |
|
2 | graft debian | |
|
2 | 3 | graft zstd |
|
3 | 4 | graft tests |
|
4 | 5 | include make_cffi.py |
|
5 | 6 | include setup_zstd.py |
|
6 | 7 | include zstd.c |
|
8 | include zstd_cffi.py | |
|
7 | 9 | include LICENSE |
|
10 | include NEWS.rst |
@@ -30,6 +30,19 b' Actions Blocking Release' | |||
|
30 | 30 | * Remove low-level compression parameters from ``ZstdCompressor.__init__`` and |
|
31 | 31 | require use of ``CompressionParameters``. |
|
32 | 32 | * Expose ``ZSTD_getFrameProgression()`` from more compressor types. |
|
33 | * Support modifying compression parameters mid operation when supported by | |
|
34 | zstd API. | |
|
35 | * Expose ``ZSTD_CLEVEL_DEFAULT`` constant. | |
|
36 | * Support ``ZSTD_p_forceAttachDict`` compression parameter. | |
|
37 | * Use ``ZSTD_CCtx_getParameter()``/``ZSTD_CCtxParam_getParameter()`` for retrieving | |
|
38 | compression parameters. | |
|
39 | * Consider exposing ``ZSTDMT_toFlushNow()``. | |
|
40 | * Expose ``ZDICT_trainFromBuffer_fastCover()``, | |
|
41 | ``ZDICT_optimizeTrainFromBuffer_fastCover``. | |
|
42 | * Expose and enforce ``ZSTD_minCLevel()`` for minimum compression level. | |
|
43 | * Consider a ``chunker()`` API for decompression. | |
|
44 | * Consider stats for ``chunker()`` API, including finding the last consumed | |
|
45 | offset of input data. | |
|
33 | 46 | |
|
34 | 47 | Other Actions Not Blocking Release |
|
35 | 48 | --------------------------------------- |
@@ -38,6 +51,111 b' Other Actions Not Blocking Release' | |||
|
38 | 51 | * API for ensuring max memory ceiling isn't exceeded. |
|
39 | 52 | * Move off nose for testing. |
|
40 | 53 | |
|
54 | 0.10.1 (released 2018-10-08) | |
|
55 | ============================ | |
|
56 | ||
|
57 | Backwards Compatibility Notes | |
|
58 | ----------------------------- | |
|
59 | ||
|
60 | * ``ZstdCompressor.stream_reader().closed`` is now a property instead of a | |
|
61 | method (#58). | |
|
62 | * ``ZstdDecompressor.stream_reader().closed`` is now a property instead of a | |
|
63 | method (#58). | |
|
64 | ||
|
65 | Changes | |
|
66 | ------- | |
|
67 | ||
|
68 | * Stop attempting to package Python 3.6 for Miniconda. The latest version of | |
|
69 | Miniconda is using Python 3.7. The Python 3.6 Miniconda packages were a lie | |
|
70 | since this were built against Python 3.7. | |
|
71 | * ``ZstdCompressor.stream_reader()``'s and ``ZstdDecompressor.stream_reader()``'s | |
|
72 | ``closed`` attribute is now a read-only property instead of a method. This now | |
|
73 | properly matches the ``IOBase`` API and allows instances to be used in more | |
|
74 | places that accept ``IOBase`` instances. | |
|
75 | ||
|
76 | 0.10.0 (released 2018-10-08) | |
|
77 | ============================ | |
|
78 | ||
|
79 | Backwards Compatibility Notes | |
|
80 | ----------------------------- | |
|
81 | ||
|
82 | * ``ZstdDecompressor.stream_reader().read()`` now consistently requires an | |
|
83 | argument in both the C and CFFI backends. Before, the CFFI implementation | |
|
84 | would assume a default value of ``-1``, which was later rejected. | |
|
85 | * The ``compress_literals`` argument and attribute has been removed from | |
|
86 | ``zstd.ZstdCompressionParameters`` because it was removed by the zstd 1.3.5 | |
|
87 | API. | |
|
88 | * ``ZSTD_CCtx_setParametersUsingCCtxParams()`` is no longer called on every | |
|
89 | operation performed against ``ZstdCompressor`` instances. The reason for this | |
|
90 | change is that the zstd 1.3.5 API no longer allows this without calling | |
|
91 | ``ZSTD_CCtx_resetParameters()`` first. But if we called | |
|
92 | ``ZSTD_CCtx_resetParameters()`` on every operation, we'd have to redo | |
|
93 | potentially expensive setup when using dictionaries. We now call | |
|
94 | ``ZSTD_CCtx_reset()`` on every operation and don't attempt to change | |
|
95 | compression parameters. | |
|
96 | * Objects returned by ``ZstdCompressor.stream_reader()`` no longer need to be | |
|
97 | used as a context manager. The context manager interface still exists and its | |
|
98 | behavior is unchanged. | |
|
99 | * Objects returned by ``ZstdDecompressor.stream_reader()`` no longer need to be | |
|
100 | used as a context manager. The context manager interface still exists and its | |
|
101 | behavior is unchanged. | |
|
102 | ||
|
103 | Bug Fixes | |
|
104 | --------- | |
|
105 | ||
|
106 | * ``ZstdDecompressor.decompressobj().decompress()`` should now return all data | |
|
107 | from internal buffers in more scenarios. Before, it was possible for data to | |
|
108 | remain in internal buffers. This data would be emitted on a subsequent call | |
|
109 | to ``decompress()``. The overall output stream would still be valid. But if | |
|
110 | callers were expecting input data to exactly map to output data (say the | |
|
111 | producer had used ``flush(COMPRESSOBJ_FLUSH_BLOCK)`` and was attempting to | |
|
112 | map input chunks to output chunks), then the previous behavior would be | |
|
113 | wrong. The new behavior is such that output from | |
|
114 | ``flush(COMPRESSOBJ_FLUSH_BLOCK)`` fed into ``decompressobj().decompress()`` | |
|
115 | should produce all available compressed input. | |
|
116 | * ``ZstdDecompressor.stream_reader().read()`` should no longer segfault after | |
|
117 | a previous context manager resulted in error (#56). | |
|
118 | * ``ZstdCompressor.compressobj().flush(COMPRESSOBJ_FLUSH_BLOCK)`` now returns | |
|
119 | all data necessary to flush a block. Before, it was possible for the | |
|
120 | ``flush()`` to not emit all data necessary to fully represent a block. This | |
|
121 | would mean decompressors wouldn't be able to decompress all data that had been | |
|
122 | fed into the compressor and ``flush()``ed. (#55). | |
|
123 | ||
|
124 | New Features | |
|
125 | ------------ | |
|
126 | ||
|
127 | * New module constants ``BLOCKSIZELOG_MAX``, ``BLOCKSIZE_MAX``, | |
|
128 | ``TARGETLENGTH_MAX`` that expose constants from libzstd. | |
|
129 | * New ``ZstdCompressor.chunker()`` API for manually feeding data into a | |
|
130 | compressor and emitting chunks of a fixed size. Like ``compressobj()``, the | |
|
131 | API doesn't impose restrictions on the input or output types for the | |
|
132 | data streams. Unlike ``compressobj()``, it ensures output chunks are of a | |
|
133 | fixed size. This makes this API useful when the compressed output is being | |
|
134 | fed into an I/O layer, where uniform write sizes are useful. | |
|
135 | * ``ZstdCompressor.stream_reader()`` no longer needs to be used as a context | |
|
136 | manager (#34). | |
|
137 | * ``ZstdDecompressor.stream_reader()`` no longer needs to be used as a context | |
|
138 | manager (#34). | |
|
139 | * Bundled zstandard library upgraded from 1.3.4 to 1.3.6. | |
|
140 | ||
|
141 | Changes | |
|
142 | ------- | |
|
143 | ||
|
144 | * Added ``zstd_cffi.py`` and ``NEWS.rst`` to ``MANIFEST.in``. | |
|
145 | * ``zstandard.__version__`` is now defined (#50). | |
|
146 | * Upgrade pip, setuptools, wheel, and cibuildwheel packages to latest versions. | |
|
147 | * Upgrade various packages used in CI to latest versions. Notably tox (in | |
|
148 | order to support Python 3.7). | |
|
149 | * Use relative paths in setup.py to appease Python 3.7 (#51). | |
|
150 | * Added CI for Python 3.7. | |
|
151 | ||
|
152 | 0.9.1 (released 2018-06-04) | |
|
153 | =========================== | |
|
154 | ||
|
155 | * Debian packaging support. | |
|
156 | * Fix typo in setup.py (#44). | |
|
157 | * Support building with mingw compiler (#46). | |
|
158 | ||
|
41 | 159 | 0.9.0 (released 2018-04-08) |
|
42 | 160 | =========================== |
|
43 | 161 | |
@@ -90,7 +208,7 b' Bug Fixes' | |||
|
90 | 208 | New Features |
|
91 | 209 | ------------ |
|
92 | 210 | |
|
93 |
* Bundl |
|
|
211 | * Bundled zstandard library upgraded from 1.1.3 to 1.3.4. This delivers various | |
|
94 | 212 | bug fixes and performance improvements. It also gives us access to newer |
|
95 | 213 | features. |
|
96 | 214 | * Support for negative compression levels. |
@@ -196,6 +196,17 b' Stream Reader API' | |||
|
196 | 196 | |
|
197 | 197 | with open(path, 'rb') as fh: |
|
198 | 198 | cctx = zstd.ZstdCompressor() |
|
199 | reader = cctx.stream_reader(fh) | |
|
200 | while True: | |
|
201 | chunk = reader.read(16384) | |
|
202 | if not chunk: | |
|
203 | break | |
|
204 | ||
|
205 | # Do something with compressed chunk. | |
|
206 | ||
|
207 | Instances can also be used as context managers:: | |
|
208 | ||
|
209 | with open(path, 'rb') as fh: | |
|
199 | 210 | with cctx.stream_reader(fh) as reader: |
|
200 | 211 | while True: |
|
201 | 212 | chunk = reader.read(16384) |
@@ -204,9 +215,9 b' Stream Reader API' | |||
|
204 | 215 | |
|
205 | 216 | # Do something with compressed chunk. |
|
206 | 217 | |
|
207 | The stream can only be read within a context manager. When the context | |
|
208 | manager exits, the stream is closed and the underlying resource is | |
|
209 | released and future operations against the compression stream stream will fail. | |
|
218 | When the context manager exists or ``close()`` is called, the stream is closed, | |
|
219 | underlying resources are released, and future operations against the compression | |
|
220 | stream will fail. | |
|
210 | 221 | |
|
211 | 222 | The ``source`` argument to ``stream_reader()`` can be any object with a |
|
212 | 223 | ``read(size)`` method or any object implementing the *buffer protocol*. |
@@ -419,6 +430,64 b' the compressor::' | |||
|
419 | 430 | data = cobj.compress(b'foobar') |
|
420 | 431 | data = cobj.flush() |
|
421 | 432 | |
|
433 | Chunker API | |
|
434 | ^^^^^^^^^^^ | |
|
435 | ||
|
436 | ``chunker(size=None, chunk_size=COMPRESSION_RECOMMENDED_OUTPUT_SIZE)`` returns | |
|
437 | an object that can be used to iteratively feed chunks of data into a compressor | |
|
438 | and produce output chunks of a uniform size. | |
|
439 | ||
|
440 | The object returned by ``chunker()`` exposes the following methods: | |
|
441 | ||
|
442 | ``compress(data)`` | |
|
443 | Feeds new input data into the compressor. | |
|
444 | ||
|
445 | ``flush()`` | |
|
446 | Flushes all data currently in the compressor. | |
|
447 | ||
|
448 | ``finish()`` | |
|
449 | Signals the end of input data. No new data can be compressed after this | |
|
450 | method is called. | |
|
451 | ||
|
452 | ``compress()``, ``flush()``, and ``finish()`` all return an iterator of | |
|
453 | ``bytes`` instances holding compressed data. The iterator may be empty. Callers | |
|
454 | MUST iterate through all elements of the returned iterator before performing | |
|
455 | another operation on the object. | |
|
456 | ||
|
457 | All chunks emitted by ``compress()`` will have a length of ``chunk_size``. | |
|
458 | ||
|
459 | ``flush()`` and ``finish()`` may return a final chunk smaller than | |
|
460 | ``chunk_size``. | |
|
461 | ||
|
462 | Here is how the API should be used:: | |
|
463 | ||
|
464 | cctx = zstd.ZstdCompressor() | |
|
465 | chunker = cctx.chunker(chunk_size=32768) | |
|
466 | ||
|
467 | with open(path, 'rb') as fh: | |
|
468 | while True: | |
|
469 | in_chunk = fh.read(32768) | |
|
470 | if not in_chunk: | |
|
471 | break | |
|
472 | ||
|
473 | for out_chunk in chunker.compress(in_chunk): | |
|
474 | # Do something with output chunk of size 32768. | |
|
475 | ||
|
476 | for out_chunk in chunker.finish(): | |
|
477 | # Do something with output chunks that finalize the zstd frame. | |
|
478 | ||
|
479 | The ``chunker()`` API is often a better alternative to ``compressobj()``. | |
|
480 | ||
|
481 | ``compressobj()`` will emit output data as it is available. This results in a | |
|
482 | *stream* of output chunks of varying sizes. The consistency of the output chunk | |
|
483 | size with ``chunker()`` is more appropriate for many usages, such as sending | |
|
484 | compressed data to a socket. | |
|
485 | ||
|
486 | ``compressobj()`` may also perform extra memory reallocations in order to | |
|
487 | dynamically adjust the sizes of the output chunks. Since ``chunker()`` output | |
|
488 | chunks are all the same size (except for flushed or final chunks), there is | |
|
489 | less memory allocation overhead. | |
|
490 | ||
|
422 | 491 | Batch Compression API |
|
423 | 492 | ^^^^^^^^^^^^^^^^^^^^^ |
|
424 | 493 | |
@@ -542,17 +611,24 b' Stream Reader API' | |||
|
542 | 611 | |
|
543 | 612 | with open(path, 'rb') as fh: |
|
544 | 613 | dctx = zstd.ZstdDecompressor() |
|
545 |
|
|
|
546 |
|
|
|
547 |
|
|
|
548 |
|
|
|
549 |
|
|
|
614 | reader = dctx.stream_reader(fh) | |
|
615 | while True: | |
|
616 | chunk = reader.read(16384) | |
|
617 | if not chunk: | |
|
618 | break | |
|
619 | ||
|
620 | # Do something with decompressed chunk. | |
|
550 | 621 | |
|
551 | # Do something with decompressed chunk. | |
|
622 | The stream can also be used as a context manager:: | |
|
552 | 623 | |
|
553 | The stream can only be read within a context manager. When the context | |
|
554 | manager exits, the stream is closed and the underlying resource is | |
|
555 | released and future operations against the stream will fail. | |
|
624 | with open(path, 'rb') as fh: | |
|
625 | dctx = zstd.ZstdDecompressor() | |
|
626 | with dctx.stream_reader(fh) as reader: | |
|
627 | ... | |
|
628 | ||
|
629 | When used as a context manager, the stream is closed and the underlying | |
|
630 | resources are released when the context manager exits. Future operations against | |
|
631 | the stream will fail. | |
|
556 | 632 | |
|
557 | 633 | The ``source`` argument to ``stream_reader()`` can be any object with a |
|
558 | 634 | ``read(size)`` method or any object implementing the *buffer protocol*. |
@@ -1077,7 +1153,6 b' follows:' | |||
|
1077 | 1153 | * write_dict_id |
|
1078 | 1154 | * job_size |
|
1079 | 1155 | * overlap_size_log |
|
1080 | * compress_literals | |
|
1081 | 1156 | * force_max_window |
|
1082 | 1157 | * enable_ldm |
|
1083 | 1158 | * ldm_hash_log |
@@ -39,7 +39,6 b' int set_parameters(ZSTD_CCtx_params* par' | |||
|
39 | 39 | TRY_SET_PARAMETER(params, ZSTD_p_nbWorkers, obj->threads); |
|
40 | 40 | TRY_SET_PARAMETER(params, ZSTD_p_jobSize, obj->jobSize); |
|
41 | 41 | TRY_SET_PARAMETER(params, ZSTD_p_overlapSizeLog, obj->overlapSizeLog); |
|
42 | TRY_SET_PARAMETER(params, ZSTD_p_compressLiterals, obj->compressLiterals); | |
|
43 | 42 | TRY_SET_PARAMETER(params, ZSTD_p_forceMaxWindow, obj->forceMaxWindow); |
|
44 | 43 | TRY_SET_PARAMETER(params, ZSTD_p_enableLongDistanceMatching, obj->enableLongDistanceMatching); |
|
45 | 44 | TRY_SET_PARAMETER(params, ZSTD_p_ldmHashLog, obj->ldmHashLog); |
@@ -88,7 +87,6 b' static int ZstdCompressionParameters_ini' | |||
|
88 | 87 | "ldm_bucket_size_log", |
|
89 | 88 | "ldm_hash_every_log", |
|
90 | 89 | "threads", |
|
91 | "compress_literals", | |
|
92 | 90 | NULL |
|
93 | 91 | }; |
|
94 | 92 | |
@@ -114,18 +112,13 b' static int ZstdCompressionParameters_ini' | |||
|
114 | 112 | unsigned ldmHashEveryLog = 0; |
|
115 | 113 | int threads = 0; |
|
116 | 114 | |
|
117 | /* Setting value 0 has the effect of disabling. So we use -1 as a default | |
|
118 | * to detect whether to set. Then we automatically derive the expected value | |
|
119 | * based on the level, just like zstandard does itself. */ | |
|
120 | int compressLiterals = -1; | |
|
121 | ||
|
122 | 115 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, |
|
123 |
"|IiIIIIIIIIIIIIIIIIIIi |
|
|
116 | "|IiIIIIIIIIIIIIIIIIIIi:CompressionParameters", | |
|
124 | 117 | kwlist, &format, &compressionLevel, &windowLog, &hashLog, &chainLog, |
|
125 | 118 | &searchLog, &minMatch, &targetLength, &compressionStrategy, |
|
126 | 119 | &contentSizeFlag, &checksumFlag, &dictIDFlag, &jobSize, &overlapSizeLog, |
|
127 | 120 | &forceMaxWindow, &enableLDM, &ldmHashLog, &ldmMinMatch, &ldmBucketSizeLog, |
|
128 |
&ldmHashEveryLog, &threads |
|
|
121 | &ldmHashEveryLog, &threads)) { | |
|
129 | 122 | return -1; |
|
130 | 123 | } |
|
131 | 124 | |
@@ -133,10 +126,6 b' static int ZstdCompressionParameters_ini' | |||
|
133 | 126 | threads = cpu_count(); |
|
134 | 127 | } |
|
135 | 128 | |
|
136 | if (compressLiterals < 0) { | |
|
137 | compressLiterals = compressionLevel >= 0; | |
|
138 | } | |
|
139 | ||
|
140 | 129 | self->format = format; |
|
141 | 130 | self->compressionLevel = compressionLevel; |
|
142 | 131 | self->windowLog = windowLog; |
@@ -152,7 +141,6 b' static int ZstdCompressionParameters_ini' | |||
|
152 | 141 | self->threads = threads; |
|
153 | 142 | self->jobSize = jobSize; |
|
154 | 143 | self->overlapSizeLog = overlapSizeLog; |
|
155 | self->compressLiterals = compressLiterals; | |
|
156 | 144 | self->forceMaxWindow = forceMaxWindow; |
|
157 | 145 | self->enableLongDistanceMatching = enableLDM; |
|
158 | 146 | self->ldmHashLog = ldmHashLog; |
@@ -299,16 +287,6 b' ZstdCompressionParametersObject* Compres' | |||
|
299 | 287 | Py_DECREF(val); |
|
300 | 288 | } |
|
301 | 289 | |
|
302 | val = PyDict_GetItemString(kwargs, "compress_literals"); | |
|
303 | if (!val) { | |
|
304 | val = PyLong_FromLong(level >= 0 ? 1 : 0); | |
|
305 | if (!val) { | |
|
306 | goto cleanup; | |
|
307 | } | |
|
308 | PyDict_SetItemString(kwargs, "compress_literals", val); | |
|
309 | Py_DECREF(val); | |
|
310 | } | |
|
311 | ||
|
312 | 290 | result = PyObject_New(ZstdCompressionParametersObject, &ZstdCompressionParametersType); |
|
313 | 291 | if (!result) { |
|
314 | 292 | goto cleanup; |
@@ -420,9 +398,6 b' static PyMemberDef ZstdCompressionParame' | |||
|
420 | 398 | { "overlap_size_log", T_UINT, |
|
421 | 399 | offsetof(ZstdCompressionParametersObject, overlapSizeLog), READONLY, |
|
422 | 400 | "Size of previous input reloaded at the beginning of each job" }, |
|
423 | { "compress_literals", T_UINT, | |
|
424 | offsetof(ZstdCompressionParametersObject, compressLiterals), READONLY, | |
|
425 | "whether Huffman compression of literals is in use" }, | |
|
426 | 401 | { "force_max_window", T_UINT, |
|
427 | 402 | offsetof(ZstdCompressionParametersObject, forceMaxWindow), READONLY, |
|
428 | 403 | "force back references to remain smaller than window size" }, |
@@ -43,20 +43,11 b' static void reader_dealloc(ZstdCompressi' | |||
|
43 | 43 | } |
|
44 | 44 | |
|
45 | 45 | static ZstdCompressionReader* reader_enter(ZstdCompressionReader* self) { |
|
46 | size_t zresult; | |
|
47 | ||
|
48 | 46 | if (self->entered) { |
|
49 | 47 | PyErr_SetString(PyExc_ValueError, "cannot __enter__ multiple times"); |
|
50 | 48 | return NULL; |
|
51 | 49 | } |
|
52 | 50 | |
|
53 | zresult = ZSTD_CCtx_setPledgedSrcSize(self->compressor->cctx, self->sourceSize); | |
|
54 | if (ZSTD_isError(zresult)) { | |
|
55 | PyErr_Format(ZstdError, "error setting source size: %s", | |
|
56 | ZSTD_getErrorName(zresult)); | |
|
57 | return NULL; | |
|
58 | } | |
|
59 | ||
|
60 | 51 | self->entered = 1; |
|
61 | 52 | |
|
62 | 53 | Py_INCREF(self); |
@@ -132,15 +123,6 b' static PyObject* reader_close(ZstdCompre' | |||
|
132 | 123 | Py_RETURN_NONE; |
|
133 | 124 | } |
|
134 | 125 | |
|
135 | static PyObject* reader_closed(ZstdCompressionReader* self) { | |
|
136 | if (self->closed) { | |
|
137 | Py_RETURN_TRUE; | |
|
138 | } | |
|
139 | else { | |
|
140 | Py_RETURN_FALSE; | |
|
141 | } | |
|
142 | } | |
|
143 | ||
|
144 | 126 | static PyObject* reader_tell(ZstdCompressionReader* self) { |
|
145 | 127 | /* TODO should this raise OSError since stream isn't seekable? */ |
|
146 | 128 | return PyLong_FromUnsignedLongLong(self->bytesCompressed); |
@@ -159,11 +141,6 b' static PyObject* reader_read(ZstdCompres' | |||
|
159 | 141 | size_t zresult; |
|
160 | 142 | size_t oldPos; |
|
161 | 143 | |
|
162 | if (!self->entered) { | |
|
163 | PyErr_SetString(ZstdError, "read() must be called from an active context manager"); | |
|
164 | return NULL; | |
|
165 | } | |
|
166 | ||
|
167 | 144 | if (self->closed) { |
|
168 | 145 | PyErr_SetString(PyExc_ValueError, "stream is closed"); |
|
169 | 146 | return NULL; |
@@ -333,8 +310,6 b' static PyMethodDef reader_methods[] = {' | |||
|
333 | 310 | PyDoc_STR("Exit a compression context") }, |
|
334 | 311 | { "close", (PyCFunction)reader_close, METH_NOARGS, |
|
335 | 312 | PyDoc_STR("Close the stream so it cannot perform any more operations") }, |
|
336 | { "closed", (PyCFunction)reader_closed, METH_NOARGS, | |
|
337 | PyDoc_STR("Whether stream is closed") }, | |
|
338 | 313 | { "flush", (PyCFunction)reader_flush, METH_NOARGS, PyDoc_STR("no-ops") }, |
|
339 | 314 | { "isatty", (PyCFunction)reader_isatty, METH_NOARGS, PyDoc_STR("Returns False") }, |
|
340 | 315 | { "readable", (PyCFunction)reader_readable, METH_NOARGS, |
@@ -354,6 +329,12 b' static PyMethodDef reader_methods[] = {' | |||
|
354 | 329 | { NULL, NULL } |
|
355 | 330 | }; |
|
356 | 331 | |
|
332 | static PyMemberDef reader_members[] = { | |
|
333 | { "closed", T_BOOL, offsetof(ZstdCompressionReader, closed), | |
|
334 | READONLY, "whether stream is closed" }, | |
|
335 | { NULL } | |
|
336 | }; | |
|
337 | ||
|
357 | 338 | PyTypeObject ZstdCompressionReaderType = { |
|
358 | 339 | PyVarObject_HEAD_INIT(NULL, 0) |
|
359 | 340 | "zstd.ZstdCompressionReader", /* tp_name */ |
@@ -383,7 +364,7 b' PyTypeObject ZstdCompressionReaderType =' | |||
|
383 | 364 | reader_iter, /* tp_iter */ |
|
384 | 365 | reader_iternext, /* tp_iternext */ |
|
385 | 366 | reader_methods, /* tp_methods */ |
|
386 |
|
|
|
367 | reader_members, /* tp_members */ | |
|
387 | 368 | 0, /* tp_getset */ |
|
388 | 369 | 0, /* tp_base */ |
|
389 | 370 | 0, /* tp_dict */ |
@@ -222,10 +222,6 b' static PyObject* ZstdCompressionWriter_f' | |||
|
222 | 222 | return NULL; |
|
223 | 223 | } |
|
224 | 224 | |
|
225 | if (!output.pos) { | |
|
226 | break; | |
|
227 | } | |
|
228 | ||
|
229 | 225 | /* Copy data from output buffer to writer. */ |
|
230 | 226 | if (output.pos) { |
|
231 | 227 | #if PY_MAJOR_VERSION >= 3 |
@@ -238,7 +234,12 b' static PyObject* ZstdCompressionWriter_f' | |||
|
238 | 234 | totalWrite += output.pos; |
|
239 | 235 | self->bytesCompressed += output.pos; |
|
240 | 236 | } |
|
237 | ||
|
241 | 238 | output.pos = 0; |
|
239 | ||
|
240 | if (!zresult) { | |
|
241 | break; | |
|
242 | } | |
|
242 | 243 | } |
|
243 | 244 | |
|
244 | 245 | PyMem_Free(output.dst); |
@@ -115,6 +115,7 b' static PyObject* ZstdCompressionObj_flus' | |||
|
115 | 115 | PyObject* result = NULL; |
|
116 | 116 | Py_ssize_t resultSize = 0; |
|
117 | 117 | ZSTD_inBuffer input; |
|
118 | ZSTD_EndDirective zFlushMode; | |
|
118 | 119 | |
|
119 | 120 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:flush", kwlist, &flushMode)) { |
|
120 | 121 | return NULL; |
@@ -130,52 +131,34 b' static PyObject* ZstdCompressionObj_flus' | |||
|
130 | 131 | return NULL; |
|
131 | 132 | } |
|
132 | 133 | |
|
134 | switch (flushMode) { | |
|
135 | case compressorobj_flush_block: | |
|
136 | zFlushMode = ZSTD_e_flush; | |
|
137 | break; | |
|
138 | ||
|
139 | case compressorobj_flush_finish: | |
|
140 | zFlushMode = ZSTD_e_end; | |
|
141 | self->finished = 1; | |
|
142 | break; | |
|
143 | ||
|
144 | default: | |
|
145 | PyErr_SetString(ZstdError, "unhandled flush mode"); | |
|
146 | return NULL; | |
|
147 | } | |
|
148 | ||
|
133 | 149 | assert(self->output.pos == 0); |
|
134 | 150 | |
|
135 | 151 | input.src = NULL; |
|
136 | 152 | input.size = 0; |
|
137 | 153 | input.pos = 0; |
|
138 | 154 | |
|
139 | if (flushMode == compressorobj_flush_block) { | |
|
140 | /* The output buffer is of size ZSTD_CStreamOutSize(), which is | |
|
141 | guaranteed to hold a full block. */ | |
|
155 | while (1) { | |
|
142 | 156 | Py_BEGIN_ALLOW_THREADS |
|
143 |
|
|
|
144 |
|
|
|
157 | zresult = ZSTD_compress_generic(self->compressor->cctx, &self->output, | |
|
158 | &input, zFlushMode); | |
|
145 | 159 | Py_END_ALLOW_THREADS |
|
146 | 160 | |
|
147 | 161 | if (ZSTD_isError(zresult)) { |
|
148 | PyErr_Format(ZstdError, "zstd compress error: %s", ZSTD_getErrorName(zresult)); | |
|
149 | return NULL; | |
|
150 | } | |
|
151 | ||
|
152 | /* Output buffer is guaranteed to hold full block. */ | |
|
153 | assert(zresult == 0); | |
|
154 | ||
|
155 | if (self->output.pos) { | |
|
156 | result = PyBytes_FromStringAndSize(self->output.dst, self->output.pos); | |
|
157 | if (!result) { | |
|
158 | return NULL; | |
|
159 | } | |
|
160 | } | |
|
161 | ||
|
162 | self->output.pos = 0; | |
|
163 | ||
|
164 | if (result) { | |
|
165 | return result; | |
|
166 | } | |
|
167 | else { | |
|
168 | return PyBytes_FromString(""); | |
|
169 | } | |
|
170 | } | |
|
171 | ||
|
172 | assert(flushMode == compressorobj_flush_finish); | |
|
173 | self->finished = 1; | |
|
174 | ||
|
175 | while (1) { | |
|
176 | zresult = ZSTD_compress_generic(self->compressor->cctx, &self->output, | |
|
177 | &input, ZSTD_e_end); | |
|
178 | if (ZSTD_isError(zresult)) { | |
|
179 | 162 | PyErr_Format(ZstdError, "error ending compression stream: %s", |
|
180 | 163 | ZSTD_getErrorName(zresult)); |
|
181 | 164 | return NULL; |
@@ -11,15 +11,13 b'' | |||
|
11 | 11 | |
|
12 | 12 | extern PyObject* ZstdError; |
|
13 | 13 | |
|
14 |
int |
|
|
14 | int setup_cctx(ZstdCompressor* compressor) { | |
|
15 | 15 | size_t zresult; |
|
16 | 16 | |
|
17 | 17 | assert(compressor); |
|
18 | 18 | assert(compressor->cctx); |
|
19 | 19 | assert(compressor->params); |
|
20 | 20 | |
|
21 | ZSTD_CCtx_reset(compressor->cctx); | |
|
22 | ||
|
23 | 21 | zresult = ZSTD_CCtx_setParametersUsingCCtxParams(compressor->cctx, compressor->params); |
|
24 | 22 | if (ZSTD_isError(zresult)) { |
|
25 | 23 | PyErr_Format(ZstdError, "could not set compression parameters: %s", |
@@ -237,9 +235,9 b' static int ZstdCompressor_init(ZstdCompr' | |||
|
237 | 235 | Py_INCREF(dict); |
|
238 | 236 | } |
|
239 | 237 | |
|
240 |
|
|
|
241 |
|
|
|
242 | } | |
|
238 | if (setup_cctx(self)) { | |
|
239 | return -1; | |
|
240 | } | |
|
243 | 241 | |
|
244 | 242 | return 0; |
|
245 | 243 | } |
@@ -346,9 +344,7 b' static PyObject* ZstdCompressor_copy_str' | |||
|
346 | 344 | return NULL; |
|
347 | 345 | } |
|
348 | 346 | |
|
349 | if (ensure_cctx(self)) { | |
|
350 | return NULL; | |
|
351 | } | |
|
347 | ZSTD_CCtx_reset(self->cctx); | |
|
352 | 348 | |
|
353 | 349 | zresult = ZSTD_CCtx_setPledgedSrcSize(self->cctx, sourceSize); |
|
354 | 350 | if (ZSTD_isError(zresult)) { |
@@ -489,6 +485,7 b' static ZstdCompressionReader* ZstdCompre' | |||
|
489 | 485 | unsigned long long sourceSize = ZSTD_CONTENTSIZE_UNKNOWN; |
|
490 | 486 | size_t readSize = ZSTD_CStreamInSize(); |
|
491 | 487 | ZstdCompressionReader* result = NULL; |
|
488 | size_t zresult; | |
|
492 | 489 | |
|
493 | 490 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Kk:stream_reader", kwlist, |
|
494 | 491 | &source, &sourceSize, &readSize)) { |
@@ -520,13 +517,17 b' static ZstdCompressionReader* ZstdCompre' | |||
|
520 | 517 | goto except; |
|
521 | 518 | } |
|
522 | 519 | |
|
523 | if (ensure_cctx(self)) { | |
|
520 | ZSTD_CCtx_reset(self->cctx); | |
|
521 | ||
|
522 | zresult = ZSTD_CCtx_setPledgedSrcSize(self->cctx, sourceSize); | |
|
523 | if (ZSTD_isError(zresult)) { | |
|
524 | PyErr_Format(ZstdError, "error setting source source: %s", | |
|
525 | ZSTD_getErrorName(zresult)); | |
|
524 | 526 | goto except; |
|
525 | 527 | } |
|
526 | 528 | |
|
527 | 529 | result->compressor = self; |
|
528 | 530 | Py_INCREF(self); |
|
529 | result->sourceSize = sourceSize; | |
|
530 | 531 | |
|
531 | 532 | return result; |
|
532 | 533 | |
@@ -576,9 +577,7 b' static PyObject* ZstdCompressor_compress' | |||
|
576 | 577 | goto finally; |
|
577 | 578 | } |
|
578 | 579 | |
|
579 | if (ensure_cctx(self)) { | |
|
580 | goto finally; | |
|
581 | } | |
|
580 | ZSTD_CCtx_reset(self->cctx); | |
|
582 | 581 | |
|
583 | 582 | destSize = ZSTD_compressBound(source.len); |
|
584 | 583 | output = PyBytes_FromStringAndSize(NULL, destSize); |
@@ -652,9 +651,7 b' static ZstdCompressionObj* ZstdCompresso' | |||
|
652 | 651 | return NULL; |
|
653 | 652 | } |
|
654 | 653 | |
|
655 | if (ensure_cctx(self)) { | |
|
656 | return NULL; | |
|
657 | } | |
|
654 | ZSTD_CCtx_reset(self->cctx); | |
|
658 | 655 | |
|
659 | 656 | zresult = ZSTD_CCtx_setPledgedSrcSize(self->cctx, inSize); |
|
660 | 657 | if (ZSTD_isError(zresult)) { |
@@ -743,9 +740,7 b' static ZstdCompressorIterator* ZstdCompr' | |||
|
743 | 740 | goto except; |
|
744 | 741 | } |
|
745 | 742 | |
|
746 | if (ensure_cctx(self)) { | |
|
747 | return NULL; | |
|
748 | } | |
|
743 | ZSTD_CCtx_reset(self->cctx); | |
|
749 | 744 | |
|
750 | 745 | zresult = ZSTD_CCtx_setPledgedSrcSize(self->cctx, sourceSize); |
|
751 | 746 | if (ZSTD_isError(zresult)) { |
@@ -817,9 +812,7 b' static ZstdCompressionWriter* ZstdCompre' | |||
|
817 | 812 | return NULL; |
|
818 | 813 | } |
|
819 | 814 | |
|
820 | if (ensure_cctx(self)) { | |
|
821 | return NULL; | |
|
822 | } | |
|
815 | ZSTD_CCtx_reset(self->cctx); | |
|
823 | 816 | |
|
824 | 817 | result = (ZstdCompressionWriter*)PyObject_CallObject((PyObject*)&ZstdCompressionWriterType, NULL); |
|
825 | 818 | if (!result) { |
@@ -839,6 +832,58 b' static ZstdCompressionWriter* ZstdCompre' | |||
|
839 | 832 | return result; |
|
840 | 833 | } |
|
841 | 834 | |
|
835 | PyDoc_STRVAR(ZstdCompressor_chunker__doc__, | |
|
836 | "Create an object for iterative compressing to same-sized chunks.\n" | |
|
837 | ); | |
|
838 | ||
|
839 | static ZstdCompressionChunker* ZstdCompressor_chunker(ZstdCompressor* self, PyObject* args, PyObject* kwargs) { | |
|
840 | static char* kwlist[] = { | |
|
841 | "size", | |
|
842 | "chunk_size", | |
|
843 | NULL | |
|
844 | }; | |
|
845 | ||
|
846 | unsigned long long sourceSize = ZSTD_CONTENTSIZE_UNKNOWN; | |
|
847 | size_t chunkSize = ZSTD_CStreamOutSize(); | |
|
848 | ZstdCompressionChunker* chunker; | |
|
849 | size_t zresult; | |
|
850 | ||
|
851 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Kk:chunker", kwlist, | |
|
852 | &sourceSize, &chunkSize)) { | |
|
853 | return NULL; | |
|
854 | } | |
|
855 | ||
|
856 | ZSTD_CCtx_reset(self->cctx); | |
|
857 | ||
|
858 | zresult = ZSTD_CCtx_setPledgedSrcSize(self->cctx, sourceSize); | |
|
859 | if (ZSTD_isError(zresult)) { | |
|
860 | PyErr_Format(ZstdError, "error setting source size: %s", | |
|
861 | ZSTD_getErrorName(zresult)); | |
|
862 | return NULL; | |
|
863 | } | |
|
864 | ||
|
865 | chunker = (ZstdCompressionChunker*)PyObject_CallObject((PyObject*)&ZstdCompressionChunkerType, NULL); | |
|
866 | if (!chunker) { | |
|
867 | return NULL; | |
|
868 | } | |
|
869 | ||
|
870 | chunker->output.dst = PyMem_Malloc(chunkSize); | |
|
871 | if (!chunker->output.dst) { | |
|
872 | PyErr_NoMemory(); | |
|
873 | Py_DECREF(chunker); | |
|
874 | return NULL; | |
|
875 | } | |
|
876 | chunker->output.size = chunkSize; | |
|
877 | chunker->output.pos = 0; | |
|
878 | ||
|
879 | chunker->compressor = self; | |
|
880 | Py_INCREF(chunker->compressor); | |
|
881 | ||
|
882 | chunker->chunkSize = chunkSize; | |
|
883 | ||
|
884 | return chunker; | |
|
885 | } | |
|
886 | ||
|
842 | 887 | typedef struct { |
|
843 | 888 | void* sourceData; |
|
844 | 889 | size_t sourceSize; |
@@ -1524,6 +1569,8 b' finally:' | |||
|
1524 | 1569 | } |
|
1525 | 1570 | |
|
1526 | 1571 | static PyMethodDef ZstdCompressor_methods[] = { |
|
1572 | { "chunker", (PyCFunction)ZstdCompressor_chunker, | |
|
1573 | METH_VARARGS | METH_KEYWORDS, ZstdCompressor_chunker__doc__ }, | |
|
1527 | 1574 | { "compress", (PyCFunction)ZstdCompressor_compress, |
|
1528 | 1575 | METH_VARARGS | METH_KEYWORDS, ZstdCompressor_compress__doc__ }, |
|
1529 | 1576 | { "compressobj", (PyCFunction)ZstdCompressor_compressobj, |
@@ -27,7 +27,6 b' void constants_module_init(PyObject* mod' | |||
|
27 | 27 | #else |
|
28 | 28 | version = PyString_FromString(PYTHON_ZSTANDARD_VERSION); |
|
29 | 29 | #endif |
|
30 | Py_INCREF(version); | |
|
31 | 30 | PyModule_AddObject(mod, "__version__", version); |
|
32 | 31 | |
|
33 | 32 | ZstdError = PyErr_NewException("zstd.ZstdError", NULL, NULL); |
@@ -41,7 +40,6 b' void constants_module_init(PyObject* mod' | |||
|
41 | 40 | PyTuple_SetItem(zstdVersion, 0, PyLong_FromLong(ZSTD_VERSION_MAJOR)); |
|
42 | 41 | PyTuple_SetItem(zstdVersion, 1, PyLong_FromLong(ZSTD_VERSION_MINOR)); |
|
43 | 42 | PyTuple_SetItem(zstdVersion, 2, PyLong_FromLong(ZSTD_VERSION_RELEASE)); |
|
44 | Py_INCREF(zstdVersion); | |
|
45 | 43 | PyModule_AddObject(mod, "ZSTD_VERSION", zstdVersion); |
|
46 | 44 | |
|
47 | 45 | frameHeader = PyBytes_FromStringAndSize(frame_header, sizeof(frame_header)); |
@@ -68,6 +66,8 b' void constants_module_init(PyObject* mod' | |||
|
68 | 66 | (long)ZSTD_DStreamOutSize()); |
|
69 | 67 | |
|
70 | 68 | PyModule_AddIntConstant(mod, "MAGIC_NUMBER", ZSTD_MAGICNUMBER); |
|
69 | PyModule_AddIntConstant(mod, "BLOCKSIZELOG_MAX", ZSTD_BLOCKSIZELOG_MAX); | |
|
70 | PyModule_AddIntConstant(mod, "BLOCKSIZE_MAX", ZSTD_BLOCKSIZE_MAX); | |
|
71 | 71 | PyModule_AddIntConstant(mod, "WINDOWLOG_MIN", ZSTD_WINDOWLOG_MIN); |
|
72 | 72 | PyModule_AddIntConstant(mod, "WINDOWLOG_MAX", ZSTD_WINDOWLOG_MAX); |
|
73 | 73 | PyModule_AddIntConstant(mod, "CHAINLOG_MIN", ZSTD_CHAINLOG_MIN); |
@@ -80,6 +80,7 b' void constants_module_init(PyObject* mod' | |||
|
80 | 80 | PyModule_AddIntConstant(mod, "SEARCHLENGTH_MIN", ZSTD_SEARCHLENGTH_MIN); |
|
81 | 81 | PyModule_AddIntConstant(mod, "SEARCHLENGTH_MAX", ZSTD_SEARCHLENGTH_MAX); |
|
82 | 82 | PyModule_AddIntConstant(mod, "TARGETLENGTH_MIN", ZSTD_TARGETLENGTH_MIN); |
|
83 | PyModule_AddIntConstant(mod, "TARGETLENGTH_MAX", ZSTD_TARGETLENGTH_MAX); | |
|
83 | 84 | PyModule_AddIntConstant(mod, "LDM_MINMATCH_MIN", ZSTD_LDM_MINMATCH_MIN); |
|
84 | 85 | PyModule_AddIntConstant(mod, "LDM_MINMATCH_MAX", ZSTD_LDM_MINMATCH_MAX); |
|
85 | 86 | PyModule_AddIntConstant(mod, "LDM_BUCKETSIZELOG_MAX", ZSTD_LDM_BUCKETSIZELOG_MAX); |
@@ -47,10 +47,6 b' static ZstdDecompressionReader* reader_e' | |||
|
47 | 47 | return NULL; |
|
48 | 48 | } |
|
49 | 49 | |
|
50 | if (ensure_dctx(self->decompressor, 1)) { | |
|
51 | return NULL; | |
|
52 | } | |
|
53 | ||
|
54 | 50 | self->entered = 1; |
|
55 | 51 | |
|
56 | 52 | Py_INCREF(self); |
@@ -98,15 +94,6 b' static PyObject* reader_close(ZstdDecomp' | |||
|
98 | 94 | Py_RETURN_NONE; |
|
99 | 95 | } |
|
100 | 96 | |
|
101 | static PyObject* reader_closed(ZstdDecompressionReader* self) { | |
|
102 | if (self->closed) { | |
|
103 | Py_RETURN_TRUE; | |
|
104 | } | |
|
105 | else { | |
|
106 | Py_RETURN_FALSE; | |
|
107 | } | |
|
108 | } | |
|
109 | ||
|
110 | 97 | static PyObject* reader_flush(PyObject* self) { |
|
111 | 98 | Py_RETURN_NONE; |
|
112 | 99 | } |
@@ -128,11 +115,6 b' static PyObject* reader_read(ZstdDecompr' | |||
|
128 | 115 | ZSTD_outBuffer output; |
|
129 | 116 | size_t zresult; |
|
130 | 117 | |
|
131 | if (!self->entered) { | |
|
132 | PyErr_SetString(ZstdError, "read() must be called from an active context manager"); | |
|
133 | return NULL; | |
|
134 | } | |
|
135 | ||
|
136 | 118 | if (self->closed) { |
|
137 | 119 | PyErr_SetString(PyExc_ValueError, "stream is closed"); |
|
138 | 120 | return NULL; |
@@ -281,11 +263,6 b' static PyObject* reader_seek(ZstdDecompr' | |||
|
281 | 263 | unsigned long long readAmount = 0; |
|
282 | 264 | size_t defaultOutSize = ZSTD_DStreamOutSize(); |
|
283 | 265 | |
|
284 | if (!self->entered) { | |
|
285 | PyErr_SetString(ZstdError, "seek() must be called from an active context manager"); | |
|
286 | return NULL; | |
|
287 | } | |
|
288 | ||
|
289 | 266 | if (self->closed) { |
|
290 | 267 | PyErr_SetString(PyExc_ValueError, "stream is closed"); |
|
291 | 268 | return NULL; |
@@ -384,8 +361,6 b' static PyMethodDef reader_methods[] = {' | |||
|
384 | 361 | PyDoc_STR("Exit a compression context") }, |
|
385 | 362 | { "close", (PyCFunction)reader_close, METH_NOARGS, |
|
386 | 363 | PyDoc_STR("Close the stream so it cannot perform any more operations") }, |
|
387 | { "closed", (PyCFunction)reader_closed, METH_NOARGS, | |
|
388 | PyDoc_STR("Whether stream is closed") }, | |
|
389 | 364 | { "flush", (PyCFunction)reader_flush, METH_NOARGS, PyDoc_STR("no-ops") }, |
|
390 | 365 | { "isatty", (PyCFunction)reader_isatty, METH_NOARGS, PyDoc_STR("Returns False") }, |
|
391 | 366 | { "readable", (PyCFunction)reader_readable, METH_NOARGS, |
@@ -407,6 +382,12 b' static PyMethodDef reader_methods[] = {' | |||
|
407 | 382 | { NULL, NULL } |
|
408 | 383 | }; |
|
409 | 384 | |
|
385 | static PyMemberDef reader_members[] = { | |
|
386 | { "closed", T_BOOL, offsetof(ZstdDecompressionReader, closed), | |
|
387 | READONLY, "whether stream is closed" }, | |
|
388 | { NULL } | |
|
389 | }; | |
|
390 | ||
|
410 | 391 | PyTypeObject ZstdDecompressionReaderType = { |
|
411 | 392 | PyVarObject_HEAD_INIT(NULL, 0) |
|
412 | 393 | "zstd.ZstdDecompressionReader", /* tp_name */ |
@@ -436,7 +417,7 b' PyTypeObject ZstdDecompressionReaderType' | |||
|
436 | 417 | reader_iter, /* tp_iter */ |
|
437 | 418 | reader_iternext, /* tp_iternext */ |
|
438 | 419 | reader_methods, /* tp_methods */ |
|
439 |
|
|
|
420 | reader_members, /* tp_members */ | |
|
440 | 421 | 0, /* tp_getset */ |
|
441 | 422 | 0, /* tp_base */ |
|
442 | 423 | 0, /* tp_dict */ |
@@ -33,6 +33,8 b' static PyObject* DecompressionObj_decomp' | |||
|
33 | 33 | PyObject* result = NULL; |
|
34 | 34 | Py_ssize_t resultSize = 0; |
|
35 | 35 | |
|
36 | output.dst = NULL; | |
|
37 | ||
|
36 | 38 | if (self->finished) { |
|
37 | 39 | PyErr_SetString(ZstdError, "cannot use a decompressobj multiple times"); |
|
38 | 40 | return NULL; |
@@ -53,6 +55,12 b' static PyObject* DecompressionObj_decomp' | |||
|
53 | 55 | goto finally; |
|
54 | 56 | } |
|
55 | 57 | |
|
58 | /* Special case of empty input. Output will always be empty. */ | |
|
59 | if (source.len == 0) { | |
|
60 | result = PyBytes_FromString(""); | |
|
61 | goto finally; | |
|
62 | } | |
|
63 | ||
|
56 | 64 | input.src = source.buf; |
|
57 | 65 | input.size = source.len; |
|
58 | 66 | input.pos = 0; |
@@ -65,8 +73,7 b' static PyObject* DecompressionObj_decomp' | |||
|
65 | 73 | output.size = self->outSize; |
|
66 | 74 | output.pos = 0; |
|
67 | 75 | |
|
68 | /* Read input until exhausted. */ | |
|
69 | while (input.pos < input.size) { | |
|
76 | while (1) { | |
|
70 | 77 | Py_BEGIN_ALLOW_THREADS |
|
71 | 78 | zresult = ZSTD_decompress_generic(self->decompressor->dctx, &output, &input); |
|
72 | 79 | Py_END_ALLOW_THREADS |
@@ -98,9 +105,13 b' static PyObject* DecompressionObj_decomp' | |||
|
98 | 105 | goto except; |
|
99 | 106 | } |
|
100 | 107 | } |
|
108 | } | |
|
101 | 109 | |
|
102 | output.pos = 0; | |
|
110 | if (zresult == 0 || (input.pos == input.size && output.pos == 0)) { | |
|
111 | break; | |
|
103 | 112 | } |
|
113 | ||
|
114 | output.pos = 0; | |
|
104 | 115 | } |
|
105 | 116 | |
|
106 | 117 | if (!result) { |
@@ -575,6 +575,10 b' static ZstdDecompressionReader* Decompre' | |||
|
575 | 575 | return NULL; |
|
576 | 576 | } |
|
577 | 577 | |
|
578 | if (ensure_dctx(self, 1)) { | |
|
579 | return NULL; | |
|
580 | } | |
|
581 | ||
|
578 | 582 | result = (ZstdDecompressionReader*)PyObject_CallObject((PyObject*)&ZstdDecompressionReaderType, NULL); |
|
579 | 583 | if (NULL == result) { |
|
580 | 584 | return NULL; |
@@ -15,7 +15,8 b'' | |||
|
15 | 15 | #include <zstd.h> |
|
16 | 16 | #include <zdict.h> |
|
17 | 17 | |
|
18 | #define PYTHON_ZSTANDARD_VERSION "0.9.0" | |
|
18 | /* Remember to change the string in zstandard/__init__ as well */ | |
|
19 | #define PYTHON_ZSTANDARD_VERSION "0.10.1" | |
|
19 | 20 | |
|
20 | 21 | typedef enum { |
|
21 | 22 | compressorobj_flush_finish, |
@@ -45,7 +46,6 b' typedef struct {' | |||
|
45 | 46 | unsigned threads; |
|
46 | 47 | unsigned jobSize; |
|
47 | 48 | unsigned overlapSizeLog; |
|
48 | unsigned compressLiterals; | |
|
49 | 49 | unsigned forceMaxWindow; |
|
50 | 50 | unsigned enableLongDistanceMatching; |
|
51 | 51 | unsigned ldmHashLog; |
@@ -162,7 +162,6 b' typedef struct {' | |||
|
162 | 162 | ZstdCompressor* compressor; |
|
163 | 163 | PyObject* reader; |
|
164 | 164 | Py_buffer buffer; |
|
165 | unsigned long long sourceSize; | |
|
166 | 165 | size_t readSize; |
|
167 | 166 | |
|
168 | 167 | int entered; |
@@ -181,6 +180,34 b' extern PyTypeObject ZstdCompressionReade' | |||
|
181 | 180 | typedef struct { |
|
182 | 181 | PyObject_HEAD |
|
183 | 182 | |
|
183 | ZstdCompressor* compressor; | |
|
184 | ZSTD_inBuffer input; | |
|
185 | ZSTD_outBuffer output; | |
|
186 | Py_buffer inBuffer; | |
|
187 | int finished; | |
|
188 | size_t chunkSize; | |
|
189 | } ZstdCompressionChunker; | |
|
190 | ||
|
191 | extern PyTypeObject ZstdCompressionChunkerType; | |
|
192 | ||
|
193 | typedef enum { | |
|
194 | compressionchunker_mode_normal, | |
|
195 | compressionchunker_mode_flush, | |
|
196 | compressionchunker_mode_finish, | |
|
197 | } CompressionChunkerMode; | |
|
198 | ||
|
199 | typedef struct { | |
|
200 | PyObject_HEAD | |
|
201 | ||
|
202 | ZstdCompressionChunker* chunker; | |
|
203 | CompressionChunkerMode mode; | |
|
204 | } ZstdCompressionChunkerIterator; | |
|
205 | ||
|
206 | extern PyTypeObject ZstdCompressionChunkerIteratorType; | |
|
207 | ||
|
208 | typedef struct { | |
|
209 | PyObject_HEAD | |
|
210 | ||
|
184 | 211 | ZSTD_DCtx* dctx; |
|
185 | 212 | ZstdCompressionDict* dict; |
|
186 | 213 | size_t maxWindowSize; |
@@ -17,6 +17,7 b' import tempfile' | |||
|
17 | 17 | HERE = os.path.abspath(os.path.dirname(__file__)) |
|
18 | 18 | |
|
19 | 19 | SOURCES = ['zstd/%s' % p for p in ( |
|
20 | 'common/debug.c', | |
|
20 | 21 | 'common/entropy_common.c', |
|
21 | 22 | 'common/error_private.c', |
|
22 | 23 | 'common/fse_decompress.c', |
@@ -25,6 +26,7 b" SOURCES = ['zstd/%s' % p for p in (" | |||
|
25 | 26 | 'common/xxhash.c', |
|
26 | 27 | 'common/zstd_common.c', |
|
27 | 28 | 'compress/fse_compress.c', |
|
29 | 'compress/hist.c', | |
|
28 | 30 | 'compress/huf_compress.c', |
|
29 | 31 | 'compress/zstd_compress.c', |
|
30 | 32 | 'compress/zstd_double_fast.c', |
@@ -36,6 +38,7 b" SOURCES = ['zstd/%s' % p for p in (" | |||
|
36 | 38 | 'decompress/huf_decompress.c', |
|
37 | 39 | 'decompress/zstd_decompress.c', |
|
38 | 40 | 'dictBuilder/cover.c', |
|
41 | 'dictBuilder/fastcover.c', | |
|
39 | 42 | 'dictBuilder/divsufsort.c', |
|
40 | 43 | 'dictBuilder/zdict.c', |
|
41 | 44 | )] |
@@ -6,12 +6,12 b'' | |||
|
6 | 6 | |
|
7 | 7 | import distutils.ccompiler |
|
8 | 8 | import os |
|
9 | import sys | |
|
10 | 9 | |
|
11 | 10 | from distutils.extension import Extension |
|
12 | 11 | |
|
13 | 12 | |
|
14 | 13 | zstd_sources = ['zstd/%s' % p for p in ( |
|
14 | 'common/debug.c', | |
|
15 | 15 | 'common/entropy_common.c', |
|
16 | 16 | 'common/error_private.c', |
|
17 | 17 | 'common/fse_decompress.c', |
@@ -20,6 +20,7 b" zstd_sources = ['zstd/%s' % p for p in (" | |||
|
20 | 20 | 'common/xxhash.c', |
|
21 | 21 | 'common/zstd_common.c', |
|
22 | 22 | 'compress/fse_compress.c', |
|
23 | 'compress/hist.c', | |
|
23 | 24 | 'compress/huf_compress.c', |
|
24 | 25 | 'compress/zstd_compress.c', |
|
25 | 26 | 'compress/zstd_double_fast.c', |
@@ -32,6 +33,7 b" zstd_sources = ['zstd/%s' % p for p in (" | |||
|
32 | 33 | 'decompress/zstd_decompress.c', |
|
33 | 34 | 'dictBuilder/cover.c', |
|
34 | 35 | 'dictBuilder/divsufsort.c', |
|
36 | 'dictBuilder/fastcover.c', | |
|
35 | 37 | 'dictBuilder/zdict.c', |
|
36 | 38 | )] |
|
37 | 39 | |
@@ -75,6 +77,7 b' ext_sources = [' | |||
|
75 | 77 | 'c-ext/compressobj.c', |
|
76 | 78 | 'c-ext/compressor.c', |
|
77 | 79 | 'c-ext/compressoriterator.c', |
|
80 | 'c-ext/compressionchunker.c', | |
|
78 | 81 | 'c-ext/compressionparams.c', |
|
79 | 82 | 'c-ext/compressionreader.c', |
|
80 | 83 | 'c-ext/compressionwriter.c', |
@@ -93,25 +96,45 b' zstd_depends = [' | |||
|
93 | 96 | |
|
94 | 97 | |
|
95 | 98 | def get_c_extension(support_legacy=False, system_zstd=False, name='zstd', |
|
96 | warnings_as_errors=False): | |
|
97 |
"""Obtain a distutils.extension.Extension for the C extension. |
|
|
98 | root = os.path.abspath(os.path.dirname(__file__)) | |
|
99 | warnings_as_errors=False, root=None): | |
|
100 | """Obtain a distutils.extension.Extension for the C extension. | |
|
101 | ||
|
102 | ``support_legacy`` controls whether to compile in legacy zstd format support. | |
|
103 | ||
|
104 | ``system_zstd`` controls whether to compile against the system zstd library. | |
|
105 | For this to work, the system zstd library and headers must match what | |
|
106 | python-zstandard is coded against exactly. | |
|
107 | ||
|
108 | ``name`` is the module name of the C extension to produce. | |
|
109 | ||
|
110 | ``warnings_as_errors`` controls whether compiler warnings are turned into | |
|
111 | compiler errors. | |
|
99 | 112 |
|
|
100 | sources = set([os.path.join(root, p) for p in ext_sources]) | |
|
113 | ``root`` defines a root path that source should be computed as relative | |
|
114 | to. This should be the directory with the main ``setup.py`` that is | |
|
115 | being invoked. If not defined, paths will be relative to this file. | |
|
116 | """ | |
|
117 | actual_root = os.path.abspath(os.path.dirname(__file__)) | |
|
118 | root = root or actual_root | |
|
119 | ||
|
120 | sources = set([os.path.join(actual_root, p) for p in ext_sources]) | |
|
101 | 121 | if not system_zstd: |
|
102 | sources.update([os.path.join(root, p) for p in zstd_sources]) | |
|
122 | sources.update([os.path.join(actual_root, p) for p in zstd_sources]) | |
|
103 | 123 | if support_legacy: |
|
104 |
sources.update([os.path.join(root, p) |
|
|
124 | sources.update([os.path.join(actual_root, p) | |
|
125 | for p in zstd_sources_legacy]) | |
|
105 | 126 | sources = list(sources) |
|
106 | 127 | |
|
107 | include_dirs = set([os.path.join(root, d) for d in ext_includes]) | |
|
128 | include_dirs = set([os.path.join(actual_root, d) for d in ext_includes]) | |
|
108 | 129 | if not system_zstd: |
|
109 |
include_dirs.update([os.path.join(root, d) |
|
|
130 | include_dirs.update([os.path.join(actual_root, d) | |
|
131 | for d in zstd_includes]) | |
|
110 | 132 | if support_legacy: |
|
111 |
include_dirs.update([os.path.join(root, d) |
|
|
133 | include_dirs.update([os.path.join(actual_root, d) | |
|
134 | for d in zstd_includes_legacy]) | |
|
112 | 135 | include_dirs = list(include_dirs) |
|
113 | 136 | |
|
114 | depends = [os.path.join(root, p) for p in zstd_depends] | |
|
137 | depends = [os.path.join(actual_root, p) for p in zstd_depends] | |
|
115 | 138 | |
|
116 | 139 | compiler = distutils.ccompiler.new_compiler() |
|
117 | 140 | |
@@ -152,6 +175,11 b' def get_c_extension(support_legacy=False' | |||
|
152 | 175 | |
|
153 | 176 | libraries = ['zstd'] if system_zstd else [] |
|
154 | 177 | |
|
178 | # Python 3.7 doesn't like absolute paths. So normalize to relative. | |
|
179 | sources = [os.path.relpath(p, root) for p in sources] | |
|
180 | include_dirs = [os.path.relpath(p, root) for p in include_dirs] | |
|
181 | depends = [os.path.relpath(p, root) for p in depends] | |
|
182 | ||
|
155 | 183 | # TODO compile with optimizations. |
|
156 | 184 | return Extension(name, sources, |
|
157 | 185 | include_dirs=include_dirs, |
@@ -153,7 +153,7 b' class TestCompressor_compress(unittest.T' | |||
|
153 | 153 | no_params = zstd.get_frame_parameters(no_dict_id) |
|
154 | 154 | with_params = zstd.get_frame_parameters(with_dict_id) |
|
155 | 155 | self.assertEqual(no_params.dict_id, 0) |
|
156 |
self.assertEqual(with_params.dict_id, 1 |
|
|
156 | self.assertEqual(with_params.dict_id, 1880053135) | |
|
157 | 157 | |
|
158 | 158 | def test_compress_dict_multiple(self): |
|
159 | 159 | samples = [] |
@@ -216,7 +216,7 b' class TestCompressor_compress(unittest.T' | |||
|
216 | 216 | self.assertEqual(params.dict_id, d.dict_id()) |
|
217 | 217 | |
|
218 | 218 | self.assertEqual(result, |
|
219 |
b'\x28\xb5\x2f\xfd\x23\x |
|
|
219 | b'\x28\xb5\x2f\xfd\x23\x8f\x55\x0f\x70\x03\x19\x00\x00' | |
|
220 | 220 | b'\x66\x6f\x6f') |
|
221 | 221 | |
|
222 | 222 | def test_multithreaded_compression_params(self): |
@@ -336,7 +336,9 b' class TestCompressor_compressobj(unittes' | |||
|
336 | 336 | b'\x28\xb5\x2f\xfd\x00\x48\x18\x00\x00foo') |
|
337 | 337 | self.assertEqual(cobj.compress(b'bar'), b'') |
|
338 | 338 | # 3 byte header plus content. |
|
339 |
self.assertEqual(cobj.flush(), |
|
|
339 | self.assertEqual(cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK), | |
|
340 | b'\x18\x00\x00bar') | |
|
341 | self.assertEqual(cobj.flush(), b'\x01\x00\x00') | |
|
340 | 342 | |
|
341 | 343 | def test_flush_empty_block(self): |
|
342 | 344 | cctx = zstd.ZstdCompressor(write_checksum=True) |
@@ -576,15 +578,23 b' class TestCompressor_stream_reader(unitt' | |||
|
576 | 578 | def test_context_manager(self): |
|
577 | 579 | cctx = zstd.ZstdCompressor() |
|
578 | 580 | |
|
579 | reader = cctx.stream_reader(b'foo' * 60) | |
|
580 | with self.assertRaisesRegexp(zstd.ZstdError, 'read\(\) must be called from an active'): | |
|
581 | reader.read(10) | |
|
582 | ||
|
583 | 581 | with cctx.stream_reader(b'foo') as reader: |
|
584 | 582 | with self.assertRaisesRegexp(ValueError, 'cannot __enter__ multiple times'): |
|
585 | 583 | with reader as reader2: |
|
586 | 584 | pass |
|
587 | 585 | |
|
586 | def test_no_context_manager(self): | |
|
587 | cctx = zstd.ZstdCompressor() | |
|
588 | ||
|
589 | reader = cctx.stream_reader(b'foo') | |
|
590 | reader.read(4) | |
|
591 | self.assertFalse(reader.closed) | |
|
592 | ||
|
593 | reader.close() | |
|
594 | self.assertTrue(reader.closed) | |
|
595 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): | |
|
596 | reader.read(1) | |
|
597 | ||
|
588 | 598 | def test_not_implemented(self): |
|
589 | 599 | cctx = zstd.ZstdCompressor() |
|
590 | 600 | |
@@ -619,13 +629,18 b' class TestCompressor_stream_reader(unitt' | |||
|
619 | 629 | self.assertFalse(reader.writable()) |
|
620 | 630 | self.assertFalse(reader.seekable()) |
|
621 | 631 | self.assertFalse(reader.isatty()) |
|
632 | self.assertFalse(reader.closed) | |
|
622 | 633 | self.assertIsNone(reader.flush()) |
|
634 | self.assertFalse(reader.closed) | |
|
635 | ||
|
636 | self.assertTrue(reader.closed) | |
|
623 | 637 | |
|
624 | 638 | def test_read_closed(self): |
|
625 | 639 | cctx = zstd.ZstdCompressor() |
|
626 | 640 | |
|
627 | 641 | with cctx.stream_reader(b'foo' * 60) as reader: |
|
628 | 642 | reader.close() |
|
643 | self.assertTrue(reader.closed) | |
|
629 | 644 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): |
|
630 | 645 | reader.read(10) |
|
631 | 646 | |
@@ -715,7 +730,7 b' class TestCompressor_stream_reader(unitt' | |||
|
715 | 730 | while reader.read(8192): |
|
716 | 731 | pass |
|
717 | 732 | |
|
718 |
with self.assertRaisesRegexp( |
|
|
733 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): | |
|
719 | 734 | reader.read(10) |
|
720 | 735 | |
|
721 | 736 | def test_bad_size(self): |
@@ -792,7 +807,7 b' class TestCompressor_stream_writer(unitt' | |||
|
792 | 807 | d = zstd.train_dictionary(8192, samples) |
|
793 | 808 | |
|
794 | 809 | h = hashlib.sha1(d.as_bytes()).hexdigest() |
|
795 | self.assertEqual(h, '3040faa0ddc37d50e71a4dd28052cb8db5d9d027') | |
|
810 | self.assertEqual(h, '2b3b6428da5bf2c9cc9d4bb58ba0bc5990dd0e79') | |
|
796 | 811 | |
|
797 | 812 | buffer = io.BytesIO() |
|
798 | 813 | cctx = zstd.ZstdCompressor(level=9, dict_data=d) |
@@ -808,9 +823,16 b' class TestCompressor_stream_writer(unitt' | |||
|
808 | 823 | self.assertEqual(params.window_size, 2097152) |
|
809 | 824 | self.assertEqual(params.dict_id, d.dict_id()) |
|
810 | 825 | self.assertFalse(params.has_checksum) |
|
811 | self.assertEqual(compressed, | |
|
812 | b'\x28\xb5\x2f\xfd\x03\x58\x06\x59\xb5\x52\x5d\x00' | |
|
813 | b'\x00\x00\x02\xfc\x3d\x3f\xd9\xb0\x51\x03\x45\x89') | |
|
826 | ||
|
827 | h = hashlib.sha1(compressed).hexdigest() | |
|
828 | self.assertEqual(h, '23f88344263678478f5f82298e0a5d1833125786') | |
|
829 | ||
|
830 | source = b'foo' + b'bar' + (b'foo' * 16384) | |
|
831 | ||
|
832 | dctx = zstd.ZstdDecompressor(dict_data=d) | |
|
833 | ||
|
834 | self.assertEqual(dctx.decompress(compressed, max_output_size=len(source)), | |
|
835 | source) | |
|
814 | 836 | |
|
815 | 837 | def test_compression_params(self): |
|
816 | 838 | params = zstd.ZstdCompressionParameters( |
@@ -1157,6 +1179,181 b' class TestCompressor_read_to_iter(unitte' | |||
|
1157 | 1179 | b''.join(cctx.read_to_iter(source)) |
|
1158 | 1180 | |
|
1159 | 1181 | |
|
1182 | @make_cffi | |
|
1183 | class TestCompressor_chunker(unittest.TestCase): | |
|
1184 | def test_empty(self): | |
|
1185 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
|
1186 | chunker = cctx.chunker() | |
|
1187 | ||
|
1188 | it = chunker.compress(b'') | |
|
1189 | ||
|
1190 | with self.assertRaises(StopIteration): | |
|
1191 | next(it) | |
|
1192 | ||
|
1193 | it = chunker.finish() | |
|
1194 | ||
|
1195 | self.assertEqual(next(it), b'\x28\xb5\x2f\xfd\x00\x50\x01\x00\x00') | |
|
1196 | ||
|
1197 | with self.assertRaises(StopIteration): | |
|
1198 | next(it) | |
|
1199 | ||
|
1200 | def test_simple_input(self): | |
|
1201 | cctx = zstd.ZstdCompressor() | |
|
1202 | chunker = cctx.chunker() | |
|
1203 | ||
|
1204 | it = chunker.compress(b'foobar') | |
|
1205 | ||
|
1206 | with self.assertRaises(StopIteration): | |
|
1207 | next(it) | |
|
1208 | ||
|
1209 | it = chunker.compress(b'baz' * 30) | |
|
1210 | ||
|
1211 | with self.assertRaises(StopIteration): | |
|
1212 | next(it) | |
|
1213 | ||
|
1214 | it = chunker.finish() | |
|
1215 | ||
|
1216 | self.assertEqual(next(it), | |
|
1217 | b'\x28\xb5\x2f\xfd\x00\x50\x7d\x00\x00\x48\x66\x6f' | |
|
1218 | b'\x6f\x62\x61\x72\x62\x61\x7a\x01\x00\xe4\xe4\x8e') | |
|
1219 | ||
|
1220 | with self.assertRaises(StopIteration): | |
|
1221 | next(it) | |
|
1222 | ||
|
1223 | def test_input_size(self): | |
|
1224 | cctx = zstd.ZstdCompressor() | |
|
1225 | chunker = cctx.chunker(size=1024) | |
|
1226 | ||
|
1227 | it = chunker.compress(b'x' * 1000) | |
|
1228 | ||
|
1229 | with self.assertRaises(StopIteration): | |
|
1230 | next(it) | |
|
1231 | ||
|
1232 | it = chunker.compress(b'y' * 24) | |
|
1233 | ||
|
1234 | with self.assertRaises(StopIteration): | |
|
1235 | next(it) | |
|
1236 | ||
|
1237 | chunks = list(chunker.finish()) | |
|
1238 | ||
|
1239 | self.assertEqual(chunks, [ | |
|
1240 | b'\x28\xb5\x2f\xfd\x60\x00\x03\x65\x00\x00\x18\x78\x78\x79\x02\x00' | |
|
1241 | b'\xa0\x16\xe3\x2b\x80\x05' | |
|
1242 | ]) | |
|
1243 | ||
|
1244 | dctx = zstd.ZstdDecompressor() | |
|
1245 | ||
|
1246 | self.assertEqual(dctx.decompress(b''.join(chunks)), | |
|
1247 | (b'x' * 1000) + (b'y' * 24)) | |
|
1248 | ||
|
1249 | def test_small_chunk_size(self): | |
|
1250 | cctx = zstd.ZstdCompressor() | |
|
1251 | chunker = cctx.chunker(chunk_size=1) | |
|
1252 | ||
|
1253 | chunks = list(chunker.compress(b'foo' * 1024)) | |
|
1254 | self.assertEqual(chunks, []) | |
|
1255 | ||
|
1256 | chunks = list(chunker.finish()) | |
|
1257 | self.assertTrue(all(len(chunk) == 1 for chunk in chunks)) | |
|
1258 | ||
|
1259 | self.assertEqual( | |
|
1260 | b''.join(chunks), | |
|
1261 | b'\x28\xb5\x2f\xfd\x00\x50\x55\x00\x00\x18\x66\x6f\x6f\x01\x00' | |
|
1262 | b'\xfa\xd3\x77\x43') | |
|
1263 | ||
|
1264 | dctx = zstd.ZstdDecompressor() | |
|
1265 | self.assertEqual(dctx.decompress(b''.join(chunks), | |
|
1266 | max_output_size=10000), | |
|
1267 | b'foo' * 1024) | |
|
1268 | ||
|
1269 | def test_input_types(self): | |
|
1270 | cctx = zstd.ZstdCompressor() | |
|
1271 | ||
|
1272 | mutable_array = bytearray(3) | |
|
1273 | mutable_array[:] = b'foo' | |
|
1274 | ||
|
1275 | sources = [ | |
|
1276 | memoryview(b'foo'), | |
|
1277 | bytearray(b'foo'), | |
|
1278 | mutable_array, | |
|
1279 | ] | |
|
1280 | ||
|
1281 | for source in sources: | |
|
1282 | chunker = cctx.chunker() | |
|
1283 | ||
|
1284 | self.assertEqual(list(chunker.compress(source)), []) | |
|
1285 | self.assertEqual(list(chunker.finish()), [ | |
|
1286 | b'\x28\xb5\x2f\xfd\x00\x50\x19\x00\x00\x66\x6f\x6f' | |
|
1287 | ]) | |
|
1288 | ||
|
1289 | def test_flush(self): | |
|
1290 | cctx = zstd.ZstdCompressor() | |
|
1291 | chunker = cctx.chunker() | |
|
1292 | ||
|
1293 | self.assertEqual(list(chunker.compress(b'foo' * 1024)), []) | |
|
1294 | self.assertEqual(list(chunker.compress(b'bar' * 1024)), []) | |
|
1295 | ||
|
1296 | chunks1 = list(chunker.flush()) | |
|
1297 | ||
|
1298 | self.assertEqual(chunks1, [ | |
|
1299 | b'\x28\xb5\x2f\xfd\x00\x50\x8c\x00\x00\x30\x66\x6f\x6f\x62\x61\x72' | |
|
1300 | b'\x02\x00\xfa\x03\xfe\xd0\x9f\xbe\x1b\x02' | |
|
1301 | ]) | |
|
1302 | ||
|
1303 | self.assertEqual(list(chunker.flush()), []) | |
|
1304 | self.assertEqual(list(chunker.flush()), []) | |
|
1305 | ||
|
1306 | self.assertEqual(list(chunker.compress(b'baz' * 1024)), []) | |
|
1307 | ||
|
1308 | chunks2 = list(chunker.flush()) | |
|
1309 | self.assertEqual(len(chunks2), 1) | |
|
1310 | ||
|
1311 | chunks3 = list(chunker.finish()) | |
|
1312 | self.assertEqual(len(chunks2), 1) | |
|
1313 | ||
|
1314 | dctx = zstd.ZstdDecompressor() | |
|
1315 | ||
|
1316 | self.assertEqual(dctx.decompress(b''.join(chunks1 + chunks2 + chunks3), | |
|
1317 | max_output_size=10000), | |
|
1318 | (b'foo' * 1024) + (b'bar' * 1024) + (b'baz' * 1024)) | |
|
1319 | ||
|
1320 | def test_compress_after_finish(self): | |
|
1321 | cctx = zstd.ZstdCompressor() | |
|
1322 | chunker = cctx.chunker() | |
|
1323 | ||
|
1324 | list(chunker.compress(b'foo')) | |
|
1325 | list(chunker.finish()) | |
|
1326 | ||
|
1327 | with self.assertRaisesRegexp( | |
|
1328 | zstd.ZstdError, | |
|
1329 | 'cannot call compress\(\) after compression finished'): | |
|
1330 | list(chunker.compress(b'foo')) | |
|
1331 | ||
|
1332 | def test_flush_after_finish(self): | |
|
1333 | cctx = zstd.ZstdCompressor() | |
|
1334 | chunker = cctx.chunker() | |
|
1335 | ||
|
1336 | list(chunker.compress(b'foo')) | |
|
1337 | list(chunker.finish()) | |
|
1338 | ||
|
1339 | with self.assertRaisesRegexp( | |
|
1340 | zstd.ZstdError, | |
|
1341 | 'cannot call flush\(\) after compression finished'): | |
|
1342 | list(chunker.flush()) | |
|
1343 | ||
|
1344 | def test_finish_after_finish(self): | |
|
1345 | cctx = zstd.ZstdCompressor() | |
|
1346 | chunker = cctx.chunker() | |
|
1347 | ||
|
1348 | list(chunker.compress(b'foo')) | |
|
1349 | list(chunker.finish()) | |
|
1350 | ||
|
1351 | with self.assertRaisesRegexp( | |
|
1352 | zstd.ZstdError, | |
|
1353 | 'cannot call finish\(\) after compression finished'): | |
|
1354 | list(chunker.finish()) | |
|
1355 | ||
|
1356 | ||
|
1160 | 1357 | class TestCompressor_multi_compress_to_buffer(unittest.TestCase): |
|
1161 | 1358 | def test_invalid_inputs(self): |
|
1162 | 1359 | cctx = zstd.ZstdCompressor() |
@@ -135,6 +135,51 b' class TestCompressor_compressobj_fuzzing' | |||
|
135 | 135 | |
|
136 | 136 | self.assertEqual(b''.join(chunks), ref_frame) |
|
137 | 137 | |
|
138 | @hypothesis.settings( | |
|
139 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) | |
|
140 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), | |
|
141 | level=strategies.integers(min_value=1, max_value=5), | |
|
142 | chunk_sizes=strategies.data(), | |
|
143 | flushes=strategies.data()) | |
|
144 | def test_flush_block(self, original, level, chunk_sizes, flushes): | |
|
145 | cctx = zstd.ZstdCompressor(level=level) | |
|
146 | cobj = cctx.compressobj() | |
|
147 | ||
|
148 | dctx = zstd.ZstdDecompressor() | |
|
149 | dobj = dctx.decompressobj() | |
|
150 | ||
|
151 | compressed_chunks = [] | |
|
152 | decompressed_chunks = [] | |
|
153 | i = 0 | |
|
154 | while True: | |
|
155 | input_size = chunk_sizes.draw(strategies.integers(1, 4096)) | |
|
156 | source = original[i:i + input_size] | |
|
157 | if not source: | |
|
158 | break | |
|
159 | ||
|
160 | i += input_size | |
|
161 | ||
|
162 | chunk = cobj.compress(source) | |
|
163 | compressed_chunks.append(chunk) | |
|
164 | decompressed_chunks.append(dobj.decompress(chunk)) | |
|
165 | ||
|
166 | if not flushes.draw(strategies.booleans()): | |
|
167 | continue | |
|
168 | ||
|
169 | chunk = cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK) | |
|
170 | compressed_chunks.append(chunk) | |
|
171 | decompressed_chunks.append(dobj.decompress(chunk)) | |
|
172 | ||
|
173 | self.assertEqual(b''.join(decompressed_chunks), original[0:i]) | |
|
174 | ||
|
175 | chunk = cobj.flush(zstd.COMPRESSOBJ_FLUSH_FINISH) | |
|
176 | compressed_chunks.append(chunk) | |
|
177 | decompressed_chunks.append(dobj.decompress(chunk)) | |
|
178 | ||
|
179 | self.assertEqual(dctx.decompress(b''.join(compressed_chunks), | |
|
180 | max_output_size=len(original)), | |
|
181 | original) | |
|
182 | self.assertEqual(b''.join(decompressed_chunks), original) | |
|
138 | 183 | |
|
139 | 184 | @unittest.skipUnless('ZSTD_SLOW_TESTS' in os.environ, 'ZSTD_SLOW_TESTS not set') |
|
140 | 185 | @make_cffi |
@@ -186,3 +231,90 b' class TestCompressor_multi_compress_to_b' | |||
|
186 | 231 | |
|
187 | 232 | for i, frame in enumerate(result): |
|
188 | 233 | self.assertEqual(dctx.decompress(frame), original[i]) |
|
234 | ||
|
235 | ||
|
236 | @unittest.skipUnless('ZSTD_SLOW_TESTS' in os.environ, 'ZSTD_SLOW_TESTS not set') | |
|
237 | @make_cffi | |
|
238 | class TestCompressor_chunker_fuzzing(unittest.TestCase): | |
|
239 | @hypothesis.settings( | |
|
240 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) | |
|
241 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), | |
|
242 | level=strategies.integers(min_value=1, max_value=5), | |
|
243 | chunk_size=strategies.integers( | |
|
244 | min_value=1, | |
|
245 | max_value=32 * 1048576), | |
|
246 | input_sizes=strategies.data()) | |
|
247 | def test_random_input_sizes(self, original, level, chunk_size, input_sizes): | |
|
248 | cctx = zstd.ZstdCompressor(level=level) | |
|
249 | chunker = cctx.chunker(chunk_size=chunk_size) | |
|
250 | ||
|
251 | chunks = [] | |
|
252 | i = 0 | |
|
253 | while True: | |
|
254 | input_size = input_sizes.draw(strategies.integers(1, 4096)) | |
|
255 | source = original[i:i + input_size] | |
|
256 | if not source: | |
|
257 | break | |
|
258 | ||
|
259 | chunks.extend(chunker.compress(source)) | |
|
260 | i += input_size | |
|
261 | ||
|
262 | chunks.extend(chunker.finish()) | |
|
263 | ||
|
264 | dctx = zstd.ZstdDecompressor() | |
|
265 | ||
|
266 | self.assertEqual(dctx.decompress(b''.join(chunks), | |
|
267 | max_output_size=len(original)), | |
|
268 | original) | |
|
269 | ||
|
270 | self.assertTrue(all(len(chunk) == chunk_size for chunk in chunks[:-1])) | |
|
271 | ||
|
272 | @hypothesis.settings( | |
|
273 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) | |
|
274 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), | |
|
275 | level=strategies.integers(min_value=1, max_value=5), | |
|
276 | chunk_size=strategies.integers( | |
|
277 | min_value=1, | |
|
278 | max_value=32 * 1048576), | |
|
279 | input_sizes=strategies.data(), | |
|
280 | flushes=strategies.data()) | |
|
281 | def test_flush_block(self, original, level, chunk_size, input_sizes, | |
|
282 | flushes): | |
|
283 | cctx = zstd.ZstdCompressor(level=level) | |
|
284 | chunker = cctx.chunker(chunk_size=chunk_size) | |
|
285 | ||
|
286 | dctx = zstd.ZstdDecompressor() | |
|
287 | dobj = dctx.decompressobj() | |
|
288 | ||
|
289 | compressed_chunks = [] | |
|
290 | decompressed_chunks = [] | |
|
291 | i = 0 | |
|
292 | while True: | |
|
293 | input_size = input_sizes.draw(strategies.integers(1, 4096)) | |
|
294 | source = original[i:i + input_size] | |
|
295 | if not source: | |
|
296 | break | |
|
297 | ||
|
298 | i += input_size | |
|
299 | ||
|
300 | chunks = list(chunker.compress(source)) | |
|
301 | compressed_chunks.extend(chunks) | |
|
302 | decompressed_chunks.append(dobj.decompress(b''.join(chunks))) | |
|
303 | ||
|
304 | if not flushes.draw(strategies.booleans()): | |
|
305 | continue | |
|
306 | ||
|
307 | chunks = list(chunker.flush()) | |
|
308 | compressed_chunks.extend(chunks) | |
|
309 | decompressed_chunks.append(dobj.decompress(b''.join(chunks))) | |
|
310 | ||
|
311 | self.assertEqual(b''.join(decompressed_chunks), original[0:i]) | |
|
312 | ||
|
313 | chunks = list(chunker.finish()) | |
|
314 | compressed_chunks.extend(chunks) | |
|
315 | decompressed_chunks.append(dobj.decompress(b''.join(chunks))) | |
|
316 | ||
|
317 | self.assertEqual(dctx.decompress(b''.join(compressed_chunks), | |
|
318 | max_output_size=len(original)), | |
|
319 | original) | |
|
320 | self.assertEqual(b''.join(decompressed_chunks), original) No newline at end of file |
@@ -24,6 +24,7 b' class TestCompressionParameters(unittest' | |||
|
24 | 24 | hash_log=zstd.HASHLOG_MAX, |
|
25 | 25 | search_log=zstd.SEARCHLOG_MAX, |
|
26 | 26 | min_match=zstd.SEARCHLENGTH_MAX - 1, |
|
27 | target_length=zstd.TARGETLENGTH_MAX, | |
|
27 | 28 | compression_strategy=zstd.STRATEGY_BTULTRA) |
|
28 | 29 | |
|
29 | 30 | def test_from_level(self): |
@@ -34,7 +35,6 b' class TestCompressionParameters(unittest' | |||
|
34 | 35 | |
|
35 | 36 | p = zstd.ZstdCompressionParameters.from_level(-4) |
|
36 | 37 | self.assertEqual(p.window_log, 19) |
|
37 | self.assertEqual(p.compress_literals, 0) | |
|
38 | 38 | |
|
39 | 39 | def test_members(self): |
|
40 | 40 | p = zstd.ZstdCompressionParameters(window_log=10, |
@@ -64,19 +64,11 b' class TestCompressionParameters(unittest' | |||
|
64 | 64 | self.assertEqual(p.job_size, 1048576) |
|
65 | 65 | self.assertEqual(p.overlap_size_log, 6) |
|
66 | 66 | |
|
67 | p = zstd.ZstdCompressionParameters(compression_level=2) | |
|
68 | self.assertEqual(p.compress_literals, 1) | |
|
69 | ||
|
70 | p = zstd.ZstdCompressionParameters(compress_literals=False) | |
|
71 | self.assertEqual(p.compress_literals, 0) | |
|
72 | ||
|
73 | 67 | p = zstd.ZstdCompressionParameters(compression_level=-1) |
|
74 | 68 | self.assertEqual(p.compression_level, -1) |
|
75 | self.assertEqual(p.compress_literals, 0) | |
|
76 | 69 | |
|
77 |
p = zstd.ZstdCompressionParameters(compression_level=-2 |
|
|
70 | p = zstd.ZstdCompressionParameters(compression_level=-2) | |
|
78 | 71 | self.assertEqual(p.compression_level, -2) |
|
79 | self.assertEqual(p.compress_literals, 1) | |
|
80 | 72 | |
|
81 | 73 | p = zstd.ZstdCompressionParameters(force_max_window=True) |
|
82 | 74 | self.assertEqual(p.force_max_window, 1) |
@@ -27,7 +27,7 b' s_searchlog = strategies.integers(min_va' | |||
|
27 | 27 | s_searchlength = strategies.integers(min_value=zstd.SEARCHLENGTH_MIN, |
|
28 | 28 | max_value=zstd.SEARCHLENGTH_MAX) |
|
29 | 29 | s_targetlength = strategies.integers(min_value=zstd.TARGETLENGTH_MIN, |
|
30 |
max_value= |
|
|
30 | max_value=zstd.TARGETLENGTH_MAX) | |
|
31 | 31 | s_strategy = strategies.sampled_from((zstd.STRATEGY_FAST, |
|
32 | 32 | zstd.STRATEGY_DFAST, |
|
33 | 33 | zstd.STRATEGY_GREEDY, |
@@ -293,10 +293,6 b' class TestDecompressor_stream_reader(uni' | |||
|
293 | 293 | def test_context_manager(self): |
|
294 | 294 | dctx = zstd.ZstdDecompressor() |
|
295 | 295 | |
|
296 | reader = dctx.stream_reader(b'foo') | |
|
297 | with self.assertRaisesRegexp(zstd.ZstdError, 'read\(\) must be called from an active'): | |
|
298 | reader.read(1) | |
|
299 | ||
|
300 | 296 | with dctx.stream_reader(b'foo') as reader: |
|
301 | 297 | with self.assertRaisesRegexp(ValueError, 'cannot __enter__ multiple times'): |
|
302 | 298 | with reader as reader2: |
@@ -331,17 +327,23 b' class TestDecompressor_stream_reader(uni' | |||
|
331 | 327 | dctx = zstd.ZstdDecompressor() |
|
332 | 328 | |
|
333 | 329 | with dctx.stream_reader(b'foo') as reader: |
|
330 | self.assertFalse(reader.closed) | |
|
334 | 331 | self.assertTrue(reader.readable()) |
|
335 | 332 | self.assertFalse(reader.writable()) |
|
336 | 333 | self.assertTrue(reader.seekable()) |
|
337 | 334 | self.assertFalse(reader.isatty()) |
|
335 | self.assertFalse(reader.closed) | |
|
338 | 336 | self.assertIsNone(reader.flush()) |
|
337 | self.assertFalse(reader.closed) | |
|
338 | ||
|
339 | self.assertTrue(reader.closed) | |
|
339 | 340 | |
|
340 | 341 | def test_read_closed(self): |
|
341 | 342 | dctx = zstd.ZstdDecompressor() |
|
342 | 343 | |
|
343 | 344 | with dctx.stream_reader(b'foo') as reader: |
|
344 | 345 | reader.close() |
|
346 | self.assertTrue(reader.closed) | |
|
345 | 347 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): |
|
346 | 348 | reader.read(1) |
|
347 | 349 | |
@@ -372,10 +374,10 b' class TestDecompressor_stream_reader(uni' | |||
|
372 | 374 | self.assertEqual(reader.tell(), len(source)) |
|
373 | 375 | |
|
374 | 376 | # Read after EOF should return empty bytes. |
|
375 | self.assertEqual(reader.read(), b'') | |
|
377 | self.assertEqual(reader.read(1), b'') | |
|
376 | 378 | self.assertEqual(reader.tell(), len(result)) |
|
377 | 379 | |
|
378 |
self.assertTrue(reader.closed |
|
|
380 | self.assertTrue(reader.closed) | |
|
379 | 381 | |
|
380 | 382 | def test_read_buffer_small_chunks(self): |
|
381 | 383 | cctx = zstd.ZstdCompressor() |
@@ -408,8 +410,11 b' class TestDecompressor_stream_reader(uni' | |||
|
408 | 410 | chunk = reader.read(8192) |
|
409 | 411 | self.assertEqual(chunk, source) |
|
410 | 412 | self.assertEqual(reader.tell(), len(source)) |
|
411 | self.assertEqual(reader.read(), b'') | |
|
413 | self.assertEqual(reader.read(1), b'') | |
|
412 | 414 | self.assertEqual(reader.tell(), len(source)) |
|
415 | self.assertFalse(reader.closed) | |
|
416 | ||
|
417 | self.assertTrue(reader.closed) | |
|
413 | 418 | |
|
414 | 419 | def test_read_stream_small_chunks(self): |
|
415 | 420 | cctx = zstd.ZstdCompressor() |
@@ -440,7 +445,9 b' class TestDecompressor_stream_reader(uni' | |||
|
440 | 445 | while reader.read(16): |
|
441 | 446 | pass |
|
442 | 447 | |
|
443 | with self.assertRaisesRegexp(zstd.ZstdError, 'read\(\) must be called from an active'): | |
|
448 | self.assertTrue(reader.closed) | |
|
449 | ||
|
450 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): | |
|
444 | 451 | reader.read(10) |
|
445 | 452 | |
|
446 | 453 | def test_illegal_seeks(self): |
@@ -474,8 +481,7 b' class TestDecompressor_stream_reader(uni' | |||
|
474 | 481 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): |
|
475 | 482 | reader.seek(4, os.SEEK_SET) |
|
476 | 483 | |
|
477 | with self.assertRaisesRegexp( | |
|
478 | zstd.ZstdError, 'seek\(\) must be called from an active context'): | |
|
484 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): | |
|
479 | 485 | reader.seek(0) |
|
480 | 486 | |
|
481 | 487 | def test_seek(self): |
@@ -492,6 +498,39 b' class TestDecompressor_stream_reader(uni' | |||
|
492 | 498 | reader.seek(4, os.SEEK_CUR) |
|
493 | 499 | self.assertEqual(reader.read(2), b'ar') |
|
494 | 500 | |
|
501 | def test_no_context_manager(self): | |
|
502 | source = b'foobar' * 60 | |
|
503 | cctx = zstd.ZstdCompressor() | |
|
504 | frame = cctx.compress(source) | |
|
505 | ||
|
506 | dctx = zstd.ZstdDecompressor() | |
|
507 | reader = dctx.stream_reader(frame) | |
|
508 | ||
|
509 | self.assertEqual(reader.read(6), b'foobar') | |
|
510 | self.assertEqual(reader.read(18), b'foobar' * 3) | |
|
511 | self.assertFalse(reader.closed) | |
|
512 | ||
|
513 | # Calling close prevents subsequent use. | |
|
514 | reader.close() | |
|
515 | self.assertTrue(reader.closed) | |
|
516 | ||
|
517 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): | |
|
518 | reader.read(6) | |
|
519 | ||
|
520 | def test_read_after_error(self): | |
|
521 | source = io.BytesIO(b'') | |
|
522 | dctx = zstd.ZstdDecompressor() | |
|
523 | ||
|
524 | reader = dctx.stream_reader(source) | |
|
525 | ||
|
526 | with reader: | |
|
527 | with self.assertRaises(TypeError): | |
|
528 | reader.read() | |
|
529 | ||
|
530 | with reader: | |
|
531 | with self.assertRaisesRegexp(ValueError, 'stream is closed'): | |
|
532 | reader.read(100) | |
|
533 | ||
|
495 | 534 | |
|
496 | 535 | @make_cffi |
|
497 | 536 | class TestDecompressor_decompressobj(unittest.TestCase): |
@@ -12,7 +12,9 b' from . common import (' | |||
|
12 | 12 | @make_cffi |
|
13 | 13 | class TestModuleAttributes(unittest.TestCase): |
|
14 | 14 | def test_version(self): |
|
15 |
self.assertEqual(zstd.ZSTD_VERSION, (1, 3, |
|
|
15 | self.assertEqual(zstd.ZSTD_VERSION, (1, 3, 6)) | |
|
16 | ||
|
17 | self.assertEqual(zstd.__version__, '0.10.1') | |
|
16 | 18 | |
|
17 | 19 | def test_constants(self): |
|
18 | 20 | self.assertEqual(zstd.MAX_COMPRESSION_LEVEL, 22) |
@@ -27,6 +29,8 b' class TestModuleAttributes(unittest.Test' | |||
|
27 | 29 | 'DECOMPRESSION_RECOMMENDED_INPUT_SIZE', |
|
28 | 30 | 'DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE', |
|
29 | 31 | 'MAGIC_NUMBER', |
|
32 | 'BLOCKSIZELOG_MAX', | |
|
33 | 'BLOCKSIZE_MAX', | |
|
30 | 34 | 'WINDOWLOG_MIN', |
|
31 | 35 | 'WINDOWLOG_MAX', |
|
32 | 36 | 'CHAINLOG_MIN', |
@@ -39,6 +43,7 b' class TestModuleAttributes(unittest.Test' | |||
|
39 | 43 | 'SEARCHLENGTH_MIN', |
|
40 | 44 | 'SEARCHLENGTH_MAX', |
|
41 | 45 | 'TARGETLENGTH_MIN', |
|
46 | 'TARGETLENGTH_MAX', | |
|
42 | 47 | 'LDM_MINMATCH_MIN', |
|
43 | 48 | 'LDM_MINMATCH_MAX', |
|
44 | 49 | 'LDM_BUCKETSIZELOG_MAX', |
@@ -57,7 +57,8 b' class TestTrainDictionary(unittest.TestC' | |||
|
57 | 57 | d = zstd.train_dictionary(8192, generate_samples(), threads=-1, steps=1, |
|
58 | 58 | d=16) |
|
59 | 59 | |
|
60 | self.assertEqual(d.k, 50) | |
|
60 | # This varies by platform. | |
|
61 | self.assertIn(d.k, (50, 2000)) | |
|
61 | 62 | self.assertEqual(d.d, 16) |
|
62 | 63 | |
|
63 | 64 | @make_cffi |
@@ -60,3 +60,6 b" elif _module_policy == 'cffi':" | |||
|
60 | 60 | else: |
|
61 | 61 | raise ImportError('unknown module import policy: %s; use default, cffi_fallback, ' |
|
62 | 62 | 'cext, or cffi' % _module_policy) |
|
63 | ||
|
64 | # Keep this in sync with python-zstandard.h. | |
|
65 | __version__ = '0.10.1' |
@@ -182,6 +182,7 b' void compressobj_module_init(PyObject* m' | |||
|
182 | 182 | void compressor_module_init(PyObject* mod); |
|
183 | 183 | void compressionparams_module_init(PyObject* mod); |
|
184 | 184 | void constants_module_init(PyObject* mod); |
|
185 | void compressionchunker_module_init(PyObject* mod); | |
|
185 | 186 | void compressiondict_module_init(PyObject* mod); |
|
186 | 187 | void compressionreader_module_init(PyObject* mod); |
|
187 | 188 | void compressionwriter_module_init(PyObject* mod); |
@@ -209,7 +210,7 b' void zstd_module_init(PyObject* m) {' | |||
|
209 | 210 | We detect this mismatch here and refuse to load the module if this |
|
210 | 211 | scenario is detected. |
|
211 | 212 | */ |
|
212 |
if (ZSTD_VERSION_NUMBER != 1030 |
|
|
213 | if (ZSTD_VERSION_NUMBER != 10306 || ZSTD_versionNumber() != 10306) { | |
|
213 | 214 | PyErr_SetString(PyExc_ImportError, "zstd C API mismatch; Python bindings not compiled against expected zstd version"); |
|
214 | 215 | return; |
|
215 | 216 | } |
@@ -219,6 +220,7 b' void zstd_module_init(PyObject* m) {' | |||
|
219 | 220 | compressiondict_module_init(m); |
|
220 | 221 | compressobj_module_init(m); |
|
221 | 222 | compressor_module_init(m); |
|
223 | compressionchunker_module_init(m); | |
|
222 | 224 | compressionreader_module_init(m); |
|
223 | 225 | compressionwriter_module_init(m); |
|
224 | 226 | compressoriterator_module_init(m); |
@@ -1,8 +1,7 b'' | |||
|
1 | 1 | /* ****************************************************************** |
|
2 | 2 | bitstream |
|
3 | 3 | Part of FSE library |
|
4 | header file (to include) | |
|
5 | Copyright (C) 2013-2017, Yann Collet. | |
|
4 | Copyright (C) 2013-present, Yann Collet. | |
|
6 | 5 | |
|
7 | 6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) |
|
8 | 7 | |
@@ -49,21 +48,10 b' extern "C" {' | |||
|
49 | 48 | * Dependencies |
|
50 | 49 | ******************************************/ |
|
51 | 50 | #include "mem.h" /* unaligned access routines */ |
|
51 | #include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ | |
|
52 | 52 | #include "error_private.h" /* error codes and messages */ |
|
53 | 53 | |
|
54 | 54 | |
|
55 | /*-************************************* | |
|
56 | * Debug | |
|
57 | ***************************************/ | |
|
58 | #if defined(BIT_DEBUG) && (BIT_DEBUG>=1) | |
|
59 | # include <assert.h> | |
|
60 | #else | |
|
61 | # ifndef assert | |
|
62 | # define assert(condition) ((void)0) | |
|
63 | # endif | |
|
64 | #endif | |
|
65 | ||
|
66 | ||
|
67 | 55 | /*========================================= |
|
68 | 56 | * Target specific |
|
69 | 57 | =========================================*/ |
@@ -83,8 +71,7 b' extern "C" {' | |||
|
83 | 71 | * A critical property of these streams is that they encode and decode in **reverse** direction. |
|
84 | 72 | * So the first bit sequence you add will be the last to be read, like a LIFO stack. |
|
85 | 73 | */ |
|
86 | typedef struct | |
|
87 | { | |
|
74 | typedef struct { | |
|
88 | 75 | size_t bitContainer; |
|
89 | 76 | unsigned bitPos; |
|
90 | 77 | char* startPtr; |
@@ -118,8 +105,7 b' MEM_STATIC size_t BIT_closeCStream(BIT_C' | |||
|
118 | 105 | /*-******************************************** |
|
119 | 106 | * bitStream decoding API (read backward) |
|
120 | 107 | **********************************************/ |
|
121 | typedef struct | |
|
122 | { | |
|
108 | typedef struct { | |
|
123 | 109 | size_t bitContainer; |
|
124 | 110 | unsigned bitsConsumed; |
|
125 | 111 | const char* ptr; |
@@ -236,7 +222,8 b' MEM_STATIC void BIT_addBits(BIT_CStream_' | |||
|
236 | 222 | } |
|
237 | 223 | |
|
238 | 224 | /*! BIT_addBitsFast() : |
|
239 |
* works only if `value` is _clean_, |
|
|
225 | * works only if `value` is _clean_, | |
|
226 | * meaning all high bits above nbBits are 0 */ | |
|
240 | 227 | MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, |
|
241 | 228 | size_t value, unsigned nbBits) |
|
242 | 229 | { |
@@ -77,9 +77,9 b'' | |||
|
77 | 77 | * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. |
|
78 | 78 | */ |
|
79 | 79 | #ifndef DYNAMIC_BMI2 |
|
80 | #if (defined(__clang__) && __has_attribute(__target__)) \ | |
|
80 | #if ((defined(__clang__) && __has_attribute(__target__)) \ | |
|
81 | 81 | || (defined(__GNUC__) \ |
|
82 | && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \ | |
|
82 | && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ | |
|
83 | 83 | && (defined(__x86_64__) || defined(_M_X86)) \ |
|
84 | 84 | && !defined(__BMI2__) |
|
85 | 85 | # define DYNAMIC_BMI2 1 |
@@ -88,15 +88,37 b'' | |||
|
88 | 88 | #endif |
|
89 | 89 | #endif |
|
90 | 90 | |
|
91 |
/* prefetch |
|
|
92 | #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ | |
|
93 | # include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ | |
|
94 | # define PREFETCH(ptr) _mm_prefetch((const char*)ptr, _MM_HINT_T0) | |
|
95 | #elif defined(__GNUC__) | |
|
96 | # define PREFETCH(ptr) __builtin_prefetch(ptr, 0, 0) | |
|
91 | /* prefetch | |
|
92 | * can be disabled, by declaring NO_PREFETCH macro | |
|
93 | * All prefetch invocations use a single default locality 2, | |
|
94 | * generating instruction prefetcht1, | |
|
95 | * which, according to Intel, means "load data into L2 cache". | |
|
96 | * This is a good enough "middle ground" for the time being, | |
|
97 | * though in theory, it would be better to specialize locality depending on data being prefetched. | |
|
98 | * Tests could not determine any sensible difference based on locality value. */ | |
|
99 | #if defined(NO_PREFETCH) | |
|
100 | # define PREFETCH(ptr) (void)(ptr) /* disabled */ | |
|
97 | 101 | #else |
|
98 | # define PREFETCH(ptr) /* disabled */ | |
|
99 | #endif | |
|
102 | # if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ | |
|
103 | # include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ | |
|
104 | # define PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) | |
|
105 | # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) | |
|
106 | # define PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) | |
|
107 | # else | |
|
108 | # define PREFETCH(ptr) (void)(ptr) /* disabled */ | |
|
109 | # endif | |
|
110 | #endif /* NO_PREFETCH */ | |
|
111 | ||
|
112 | #define CACHELINE_SIZE 64 | |
|
113 | ||
|
114 | #define PREFETCH_AREA(p, s) { \ | |
|
115 | const char* const _ptr = (const char*)(p); \ | |
|
116 | size_t const _size = (size_t)(s); \ | |
|
117 | size_t _pos; \ | |
|
118 | for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ | |
|
119 | PREFETCH(_ptr + _pos); \ | |
|
120 | } \ | |
|
121 | } | |
|
100 | 122 | |
|
101 | 123 | /* disable warnings */ |
|
102 | 124 | #ifdef _MSC_VER /* Visual Studio */ |
@@ -36,7 +36,7 b' MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void)' | |||
|
36 | 36 | U32 f1d = 0; |
|
37 | 37 | U32 f7b = 0; |
|
38 | 38 | U32 f7c = 0; |
|
39 | #ifdef _MSC_VER | |
|
39 | #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) | |
|
40 | 40 | int reg[4]; |
|
41 | 41 | __cpuid((int*)reg, 0); |
|
42 | 42 | { |
@@ -72,8 +72,7 b' MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void)' | |||
|
72 | 72 | "cpuid\n\t" |
|
73 | 73 | "popl %%ebx\n\t" |
|
74 | 74 | : "=a"(f1a), "=c"(f1c), "=d"(f1d) |
|
75 | : "a"(1) | |
|
76 | :); | |
|
75 | : "a"(1)); | |
|
77 | 76 | } |
|
78 | 77 | if (n >= 7) { |
|
79 | 78 | __asm__( |
@@ -72,7 +72,21 b' size_t FSE_readNCount (short* normalized' | |||
|
72 | 72 | unsigned charnum = 0; |
|
73 | 73 | int previous0 = 0; |
|
74 | 74 | |
|
75 | if (hbSize < 4) return ERROR(srcSize_wrong); | |
|
75 | if (hbSize < 4) { | |
|
76 | /* This function only works when hbSize >= 4 */ | |
|
77 | char buffer[4]; | |
|
78 | memset(buffer, 0, sizeof(buffer)); | |
|
79 | memcpy(buffer, headerBuffer, hbSize); | |
|
80 | { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, | |
|
81 | buffer, sizeof(buffer)); | |
|
82 | if (FSE_isError(countSize)) return countSize; | |
|
83 | if (countSize > hbSize) return ERROR(corruption_detected); | |
|
84 | return countSize; | |
|
85 | } } | |
|
86 | assert(hbSize >= 4); | |
|
87 | ||
|
88 | /* init */ | |
|
89 | memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ | |
|
76 | 90 | bitStream = MEM_readLE32(ip); |
|
77 | 91 | nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ |
|
78 | 92 | if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); |
@@ -105,6 +119,7 b' size_t FSE_readNCount (short* normalized' | |||
|
105 | 119 | if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); |
|
106 | 120 | while (charnum < n0) normalizedCounter[charnum++] = 0; |
|
107 | 121 | if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { |
|
122 | assert((bitCount >> 3) <= 3); /* For first condition to work */ | |
|
108 | 123 | ip += bitCount>>3; |
|
109 | 124 | bitCount &= 7; |
|
110 | 125 | bitStream = MEM_readLE32(ip) >> bitCount; |
@@ -72,6 +72,7 b' extern "C" {' | |||
|
72 | 72 | #define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE) |
|
73 | 73 | FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */ |
|
74 | 74 | |
|
75 | ||
|
75 | 76 | /*-**************************************** |
|
76 | 77 | * FSE simple functions |
|
77 | 78 | ******************************************/ |
@@ -129,7 +130,7 b' FSE_PUBLIC_API size_t FSE_compress2 (voi' | |||
|
129 | 130 | ******************************************/ |
|
130 | 131 | /*! |
|
131 | 132 | FSE_compress() does the following: |
|
132 | 1. count symbol occurrence from source[] into table count[] | |
|
133 | 1. count symbol occurrence from source[] into table count[] (see hist.h) | |
|
133 | 134 | 2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog) |
|
134 | 135 | 3. save normalized counters to memory buffer using writeNCount() |
|
135 | 136 | 4. build encoding table 'CTable' from normalized counters |
@@ -147,15 +148,6 b' or to save and provide normalized distri' | |||
|
147 | 148 | |
|
148 | 149 | /* *** COMPRESSION *** */ |
|
149 | 150 | |
|
150 | /*! FSE_count(): | |
|
151 | Provides the precise count of each byte within a table 'count'. | |
|
152 | 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1). | |
|
153 | *maxSymbolValuePtr will be updated if detected smaller than initial value. | |
|
154 | @return : the count of the most frequent symbol (which is not identified). | |
|
155 | if return == srcSize, there is only one symbol. | |
|
156 | Can also return an error code, which can be tested with FSE_isError(). */ | |
|
157 | FSE_PUBLIC_API size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); | |
|
158 | ||
|
159 | 151 | /*! FSE_optimalTableLog(): |
|
160 | 152 | dynamically downsize 'tableLog' when conditions are met. |
|
161 | 153 | It saves CPU time, by using smaller tables, while preserving or even improving compression ratio. |
@@ -167,7 +159,8 b' FSE_PUBLIC_API unsigned FSE_optimalTable' | |||
|
167 | 159 | 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). |
|
168 | 160 | @return : tableLog, |
|
169 | 161 | or an errorCode, which can be tested using FSE_isError() */ |
|
170 |
FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, |
|
|
162 | FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, | |
|
163 | const unsigned* count, size_t srcSize, unsigned maxSymbolValue); | |
|
171 | 164 | |
|
172 | 165 | /*! FSE_NCountWriteBound(): |
|
173 | 166 | Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. |
@@ -178,8 +171,9 b' FSE_PUBLIC_API size_t FSE_NCountWriteBou' | |||
|
178 | 171 | Compactly save 'normalizedCounter' into 'buffer'. |
|
179 | 172 | @return : size of the compressed table, |
|
180 | 173 | or an errorCode, which can be tested using FSE_isError(). */ |
|
181 |
FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, |
|
|
182 | ||
|
174 | FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, | |
|
175 | const short* normalizedCounter, | |
|
176 | unsigned maxSymbolValue, unsigned tableLog); | |
|
183 | 177 | |
|
184 | 178 | /*! Constructor and Destructor of FSE_CTable. |
|
185 | 179 | Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ |
@@ -250,7 +244,9 b' If there is an error, the function will ' | |||
|
250 | 244 | @return : size read from 'rBuffer', |
|
251 | 245 | or an errorCode, which can be tested using FSE_isError(). |
|
252 | 246 | maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */ |
|
253 | FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize); | |
|
247 | FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, | |
|
248 | unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, | |
|
249 | const void* rBuffer, size_t rBuffSize); | |
|
254 | 250 | |
|
255 | 251 | /*! Constructor and Destructor of FSE_DTable. |
|
256 | 252 | Note that its size depends on 'tableLog' */ |
@@ -325,33 +321,8 b' If there is an error, the function will ' | |||
|
325 | 321 | |
|
326 | 322 | |
|
327 | 323 | /* ***************************************** |
|
328 | * FSE advanced API | |
|
329 |
***************************************** |
|
|
330 | /* FSE_count_wksp() : | |
|
331 | * Same as FSE_count(), but using an externally provided scratch buffer. | |
|
332 | * `workSpace` size must be table of >= `1024` unsigned | |
|
333 | */ | |
|
334 | size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
335 | const void* source, size_t sourceSize, unsigned* workSpace); | |
|
336 | ||
|
337 | /** FSE_countFast() : | |
|
338 | * same as FSE_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr | |
|
339 | */ | |
|
340 | size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); | |
|
341 | ||
|
342 | /* FSE_countFast_wksp() : | |
|
343 | * Same as FSE_countFast(), but using an externally provided scratch buffer. | |
|
344 | * `workSpace` must be a table of minimum `1024` unsigned | |
|
345 | */ | |
|
346 | size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* workSpace); | |
|
347 | ||
|
348 | /*! FSE_count_simple() : | |
|
349 | * Same as FSE_countFast(), but does not use any additional memory (not even on stack). | |
|
350 | * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`). | |
|
351 | */ | |
|
352 | size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); | |
|
353 | ||
|
354 | ||
|
324 | * FSE advanced API | |
|
325 | ***************************************** */ | |
|
355 | 326 | |
|
356 | 327 | unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus); |
|
357 | 328 | /**< same as FSE_optimalTableLog(), which used `minus==2` */ |
@@ -576,6 +547,39 b' MEM_STATIC void FSE_flushCState(BIT_CStr' | |||
|
576 | 547 | } |
|
577 | 548 | |
|
578 | 549 | |
|
550 | /* FSE_getMaxNbBits() : | |
|
551 | * Approximate maximum cost of a symbol, in bits. | |
|
552 | * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) | |
|
553 | * note 1 : assume symbolValue is valid (<= maxSymbolValue) | |
|
554 | * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ | |
|
555 | MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) | |
|
556 | { | |
|
557 | const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; | |
|
558 | return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16; | |
|
559 | } | |
|
560 | ||
|
561 | /* FSE_bitCost() : | |
|
562 | * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) | |
|
563 | * note 1 : assume symbolValue is valid (<= maxSymbolValue) | |
|
564 | * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ | |
|
565 | MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog) | |
|
566 | { | |
|
567 | const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; | |
|
568 | U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16; | |
|
569 | U32 const threshold = (minNbBits+1) << 16; | |
|
570 | assert(tableLog < 16); | |
|
571 | assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */ | |
|
572 | { U32 const tableSize = 1 << tableLog; | |
|
573 | U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize); | |
|
574 | U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */ | |
|
575 | U32 const bitMultiplier = 1 << accuracyLog; | |
|
576 | assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold); | |
|
577 | assert(normalizedDeltaFromThreshold <= bitMultiplier); | |
|
578 | return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold; | |
|
579 | } | |
|
580 | } | |
|
581 | ||
|
582 | ||
|
579 | 583 | /* ====== Decompression ====== */ |
|
580 | 584 | |
|
581 | 585 | typedef struct { |
@@ -49,7 +49,7 b'' | |||
|
49 | 49 | * Error Management |
|
50 | 50 | ****************************************************************/ |
|
51 | 51 | #define FSE_isError ERR_isError |
|
52 |
#define FSE_STATIC_ASSERT(c) |
|
|
52 | #define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ | |
|
53 | 53 | |
|
54 | 54 | /* check and forward error code */ |
|
55 | 55 | #define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; } |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | /* ****************************************************************** |
|
2 | Huffman coder, part of New Generation Entropy library | |
|
3 | header file | |
|
4 |
Copyright (C) 2013- |
|
|
2 | huff0 huffman codec, | |
|
3 | part of Finite State Entropy library | |
|
4 | Copyright (C) 2013-present, Yann Collet. | |
|
5 | 5 | |
|
6 | 6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) |
|
7 | 7 | |
@@ -163,25 +163,25 b' HUF_PUBLIC_API size_t HUF_compress4X_wks' | |||
|
163 | 163 | /* static allocation of HUF's DTable */ |
|
164 | 164 | typedef U32 HUF_DTable; |
|
165 | 165 | #define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog))) |
|
166 |
#define HUF_CREATE_STATIC_DTABLEX |
|
|
166 | #define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \ | |
|
167 | 167 | HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) } |
|
168 |
#define HUF_CREATE_STATIC_DTABLEX |
|
|
168 | #define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \ | |
|
169 | 169 | HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) } |
|
170 | 170 | |
|
171 | 171 | |
|
172 | 172 | /* **************************************** |
|
173 | 173 | * Advanced decompression functions |
|
174 | 174 | ******************************************/ |
|
175 |
size_t HUF_decompress4X |
|
|
176 |
size_t HUF_decompress4X |
|
|
175 | size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ | |
|
176 | size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ | |
|
177 | 177 | |
|
178 | 178 | size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */ |
|
179 | 179 | size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */ |
|
180 | 180 | size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */ |
|
181 |
size_t HUF_decompress4X |
|
|
182 |
size_t HUF_decompress4X |
|
|
183 |
size_t HUF_decompress4X |
|
|
184 |
size_t HUF_decompress4X |
|
|
181 | size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ | |
|
182 | size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ | |
|
183 | size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ | |
|
184 | size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ | |
|
185 | 185 | |
|
186 | 186 | |
|
187 | 187 | /* **************************************** |
@@ -208,7 +208,7 b' size_t HUF_compress4X_usingCTable(void* ' | |||
|
208 | 208 | typedef enum { |
|
209 | 209 | HUF_repeat_none, /**< Cannot use the previous table */ |
|
210 | 210 | HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ |
|
211 | HUF_repeat_valid /**< Can use the previous table and it is asumed to be valid */ | |
|
211 | HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ | |
|
212 | 212 | } HUF_repeat; |
|
213 | 213 | /** HUF_compress4X_repeat() : |
|
214 | 214 | * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. |
@@ -227,7 +227,9 b' size_t HUF_compress4X_repeat(void* dst, ' | |||
|
227 | 227 | */ |
|
228 | 228 | #define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1) |
|
229 | 229 | #define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) |
|
230 | size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize); | |
|
230 | size_t HUF_buildCTable_wksp (HUF_CElt* tree, | |
|
231 | const U32* count, U32 maxSymbolValue, U32 maxNbBits, | |
|
232 | void* workSpace, size_t wkspSize); | |
|
231 | 233 | |
|
232 | 234 | /*! HUF_readStats() : |
|
233 | 235 | * Read compact Huffman tree, saved by HUF_writeCTable(). |
@@ -242,10 +244,15 b' size_t HUF_readStats(BYTE* huffWeight, s' | |||
|
242 | 244 | * Loading a CTable saved with HUF_writeCTable() */ |
|
243 | 245 | size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); |
|
244 | 246 | |
|
247 | /** HUF_getNbBits() : | |
|
248 | * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX | |
|
249 | * Note 1 : is not inlined, as HUF_CElt definition is private | |
|
250 | * Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */ | |
|
251 | U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue); | |
|
245 | 252 | |
|
246 | 253 | /* |
|
247 | 254 | * HUF_decompress() does the following: |
|
248 |
* 1. select the decompression algorithm (X |
|
|
255 | * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics | |
|
249 | 256 | * 2. build Huffman table from save, using HUF_readDTableX?() |
|
250 | 257 | * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable() |
|
251 | 258 | */ |
@@ -253,13 +260,13 b' size_t HUF_readCTable (HUF_CElt* CTable,' | |||
|
253 | 260 | /** HUF_selectDecoder() : |
|
254 | 261 | * Tells which decoder is likely to decode faster, |
|
255 | 262 | * based on a set of pre-computed metrics. |
|
256 |
* @return : 0==HUF_decompress4X |
|
|
263 | * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . | |
|
257 | 264 | * Assumption : 0 < dstSize <= 128 KB */ |
|
258 | 265 | U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); |
|
259 | 266 | |
|
260 | 267 | /** |
|
261 | 268 | * The minimum workspace size for the `workSpace` used in |
|
262 |
* HUF_readDTableX |
|
|
269 | * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp(). | |
|
263 | 270 | * |
|
264 | 271 | * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when |
|
265 | 272 | * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. |
@@ -270,14 +277,14 b' U32 HUF_selectDecoder (size_t dstSize, s' | |||
|
270 | 277 | #define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10) |
|
271 | 278 | #define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) |
|
272 | 279 | |
|
280 | size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize); | |
|
281 | size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); | |
|
273 | 282 | size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize); |
|
274 | 283 | size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); |
|
275 | size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize); | |
|
276 | size_t HUF_readDTableX4_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); | |
|
277 | 284 | |
|
278 | 285 | size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); |
|
286 | size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); | |
|
279 | 287 | size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); |
|
280 | size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); | |
|
281 | 288 | |
|
282 | 289 | |
|
283 | 290 | /* ====================== */ |
@@ -298,25 +305,25 b' size_t HUF_compress1X_repeat(void* dst, ' | |||
|
298 | 305 | void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ |
|
299 | 306 | HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); |
|
300 | 307 | |
|
301 |
size_t HUF_decompress1X |
|
|
302 |
size_t HUF_decompress1X |
|
|
308 | size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ | |
|
309 | size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ | |
|
303 | 310 | |
|
304 | 311 | size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); |
|
305 | 312 | size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); |
|
306 |
size_t HUF_decompress1X |
|
|
307 |
size_t HUF_decompress1X |
|
|
308 |
size_t HUF_decompress1X |
|
|
309 |
size_t HUF_decompress1X |
|
|
313 | size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ | |
|
314 | size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ | |
|
315 | size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ | |
|
316 | size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ | |
|
310 | 317 | |
|
311 | 318 | size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */ |
|
319 | size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); | |
|
312 | 320 | size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); |
|
313 | size_t HUF_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); | |
|
314 | 321 | |
|
315 | 322 | /* BMI2 variants. |
|
316 | 323 | * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. |
|
317 | 324 | */ |
|
318 | 325 | size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); |
|
319 |
size_t HUF_decompress1X |
|
|
326 | size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); | |
|
320 | 327 | size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); |
|
321 | 328 | size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); |
|
322 | 329 |
@@ -57,11 +57,23 b' MEM_STATIC void MEM_check(void) { MEM_ST' | |||
|
57 | 57 | typedef uint64_t U64; |
|
58 | 58 | typedef int64_t S64; |
|
59 | 59 | #else |
|
60 | # include <limits.h> | |
|
61 | #if CHAR_BIT != 8 | |
|
62 | # error "this implementation requires char to be exactly 8-bit type" | |
|
63 | #endif | |
|
60 | 64 | typedef unsigned char BYTE; |
|
65 | #if USHRT_MAX != 65535 | |
|
66 | # error "this implementation requires short to be exactly 16-bit type" | |
|
67 | #endif | |
|
61 | 68 | typedef unsigned short U16; |
|
62 | 69 | typedef signed short S16; |
|
70 | #if UINT_MAX != 4294967295 | |
|
71 | # error "this implementation requires int to be exactly 32-bit type" | |
|
72 | #endif | |
|
63 | 73 | typedef unsigned int U32; |
|
64 | 74 | typedef signed int S32; |
|
75 | /* note : there are no limits defined for long long type in C90. | |
|
76 | * limits exist in C99, however, in such case, <stdint.h> is preferred */ | |
|
65 | 77 | typedef unsigned long long U64; |
|
66 | 78 | typedef signed long long S64; |
|
67 | 79 | #endif |
@@ -10,9 +10,10 b'' | |||
|
10 | 10 | |
|
11 | 11 | |
|
12 | 12 | /* ====== Dependencies ======= */ |
|
13 | #include <stddef.h> /* size_t */ | |
|
13 | #include <stddef.h> /* size_t */ | |
|
14 | #include "debug.h" /* assert */ | |
|
15 | #include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */ | |
|
14 | 16 | #include "pool.h" |
|
15 | #include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */ | |
|
16 | 17 | |
|
17 | 18 | /* ====== Compiler specifics ====== */ |
|
18 | 19 | #if defined(_MSC_VER) |
@@ -33,8 +34,9 b' typedef struct POOL_job_s {' | |||
|
33 | 34 | struct POOL_ctx_s { |
|
34 | 35 | ZSTD_customMem customMem; |
|
35 | 36 | /* Keep track of the threads */ |
|
36 |
ZSTD_pthread_t |
|
|
37 |
size_t |
|
|
37 | ZSTD_pthread_t* threads; | |
|
38 | size_t threadCapacity; | |
|
39 | size_t threadLimit; | |
|
38 | 40 | |
|
39 | 41 | /* The queue is a circular buffer */ |
|
40 | 42 | POOL_job *queue; |
@@ -58,10 +60,10 b' struct POOL_ctx_s {' | |||
|
58 | 60 | }; |
|
59 | 61 | |
|
60 | 62 | /* POOL_thread() : |
|
61 |
|
|
|
62 |
|
|
|
63 |
|
|
|
64 | */ | |
|
63 | * Work thread for the thread pool. | |
|
64 | * Waits for jobs and executes them. | |
|
65 | * @returns : NULL on failure else non-null. | |
|
66 | */ | |
|
65 | 67 | static void* POOL_thread(void* opaque) { |
|
66 | 68 | POOL_ctx* const ctx = (POOL_ctx*)opaque; |
|
67 | 69 | if (!ctx) { return NULL; } |
@@ -69,14 +71,17 b' static void* POOL_thread(void* opaque) {' | |||
|
69 | 71 | /* Lock the mutex and wait for a non-empty queue or until shutdown */ |
|
70 | 72 | ZSTD_pthread_mutex_lock(&ctx->queueMutex); |
|
71 | 73 | |
|
72 |
while (ctx->queueEmpty |
|
|
74 | while ( ctx->queueEmpty | |
|
75 | || (ctx->numThreadsBusy >= ctx->threadLimit) ) { | |
|
76 | if (ctx->shutdown) { | |
|
77 | /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit), | |
|
78 | * a few threads will be shutdown while !queueEmpty, | |
|
79 | * but enough threads will remain active to finish the queue */ | |
|
80 | ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | |
|
81 | return opaque; | |
|
82 | } | |
|
73 | 83 | ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); |
|
74 | 84 | } |
|
75 | /* empty => shutting down: so stop */ | |
|
76 | if (ctx->queueEmpty) { | |
|
77 | ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | |
|
78 | return opaque; | |
|
79 | } | |
|
80 | 85 | /* Pop a job off the queue */ |
|
81 | 86 | { POOL_job const job = ctx->queue[ctx->queueHead]; |
|
82 | 87 | ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; |
@@ -89,30 +94,32 b' static void* POOL_thread(void* opaque) {' | |||
|
89 | 94 | job.function(job.opaque); |
|
90 | 95 | |
|
91 | 96 | /* If the intended queue size was 0, signal after finishing job */ |
|
97 | ZSTD_pthread_mutex_lock(&ctx->queueMutex); | |
|
98 | ctx->numThreadsBusy--; | |
|
92 | 99 | if (ctx->queueSize == 1) { |
|
93 | ZSTD_pthread_mutex_lock(&ctx->queueMutex); | |
|
94 | ctx->numThreadsBusy--; | |
|
95 | ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | |
|
96 | 100 | ZSTD_pthread_cond_signal(&ctx->queuePushCond); |
|
97 |
|
|
|
101 | } | |
|
102 | ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | |
|
103 | } | |
|
98 | 104 | } /* for (;;) */ |
|
99 | /* Unreachable */ | |
|
105 | assert(0); /* Unreachable */ | |
|
100 | 106 | } |
|
101 | 107 | |
|
102 | 108 | POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { |
|
103 | 109 | return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); |
|
104 | 110 | } |
|
105 | 111 | |
|
106 |
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, |
|
|
112 | POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, | |
|
113 | ZSTD_customMem customMem) { | |
|
107 | 114 | POOL_ctx* ctx; |
|
108 |
/* Check |
|
|
115 | /* Check parameters */ | |
|
109 | 116 | if (!numThreads) { return NULL; } |
|
110 | 117 | /* Allocate the context and zero initialize */ |
|
111 | 118 | ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem); |
|
112 | 119 | if (!ctx) { return NULL; } |
|
113 | 120 | /* Initialize the job queue. |
|
114 |
* It needs one extra space since one space is wasted to differentiate |
|
|
115 | * and full queues. | |
|
121 | * It needs one extra space since one space is wasted to differentiate | |
|
122 | * empty and full queues. | |
|
116 | 123 | */ |
|
117 | 124 | ctx->queueSize = queueSize + 1; |
|
118 | 125 | ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem); |
@@ -126,7 +133,7 b' POOL_ctx* POOL_create_advanced(size_t nu' | |||
|
126 | 133 | ctx->shutdown = 0; |
|
127 | 134 | /* Allocate space for the thread handles */ |
|
128 | 135 | ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem); |
|
129 |
ctx-> |
|
|
136 | ctx->threadCapacity = 0; | |
|
130 | 137 | ctx->customMem = customMem; |
|
131 | 138 | /* Check for errors */ |
|
132 | 139 | if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } |
@@ -134,11 +141,12 b' POOL_ctx* POOL_create_advanced(size_t nu' | |||
|
134 | 141 | { size_t i; |
|
135 | 142 | for (i = 0; i < numThreads; ++i) { |
|
136 | 143 | if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { |
|
137 |
ctx-> |
|
|
144 | ctx->threadCapacity = i; | |
|
138 | 145 | POOL_free(ctx); |
|
139 | 146 | return NULL; |
|
140 | 147 | } } |
|
141 |
ctx-> |
|
|
148 | ctx->threadCapacity = numThreads; | |
|
149 | ctx->threadLimit = numThreads; | |
|
142 | 150 | } |
|
143 | 151 | return ctx; |
|
144 | 152 | } |
@@ -156,8 +164,8 b' static void POOL_join(POOL_ctx* ctx) {' | |||
|
156 | 164 | ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); |
|
157 | 165 | /* Join all of the threads */ |
|
158 | 166 | { size_t i; |
|
159 |
for (i = 0; i < ctx-> |
|
|
160 | ZSTD_pthread_join(ctx->threads[i], NULL); | |
|
167 | for (i = 0; i < ctx->threadCapacity; ++i) { | |
|
168 | ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */ | |
|
161 | 169 | } } |
|
162 | 170 | } |
|
163 | 171 | |
@@ -172,24 +180,68 b' void POOL_free(POOL_ctx *ctx) {' | |||
|
172 | 180 | ZSTD_free(ctx, ctx->customMem); |
|
173 | 181 | } |
|
174 | 182 | |
|
183 | ||
|
184 | ||
|
175 | 185 | size_t POOL_sizeof(POOL_ctx *ctx) { |
|
176 | 186 | if (ctx==NULL) return 0; /* supports sizeof NULL */ |
|
177 | 187 | return sizeof(*ctx) |
|
178 | 188 | + ctx->queueSize * sizeof(POOL_job) |
|
179 |
+ ctx-> |
|
|
189 | + ctx->threadCapacity * sizeof(ZSTD_pthread_t); | |
|
190 | } | |
|
191 | ||
|
192 | ||
|
193 | /* @return : 0 on success, 1 on error */ | |
|
194 | static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) | |
|
195 | { | |
|
196 | if (numThreads <= ctx->threadCapacity) { | |
|
197 | if (!numThreads) return 1; | |
|
198 | ctx->threadLimit = numThreads; | |
|
199 | return 0; | |
|
200 | } | |
|
201 | /* numThreads > threadCapacity */ | |
|
202 | { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); | |
|
203 | if (!threadPool) return 1; | |
|
204 | /* replace existing thread pool */ | |
|
205 | memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); | |
|
206 | ZSTD_free(ctx->threads, ctx->customMem); | |
|
207 | ctx->threads = threadPool; | |
|
208 | /* Initialize additional threads */ | |
|
209 | { size_t threadId; | |
|
210 | for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) { | |
|
211 | if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) { | |
|
212 | ctx->threadCapacity = threadId; | |
|
213 | return 1; | |
|
214 | } } | |
|
215 | } } | |
|
216 | /* successfully expanded */ | |
|
217 | ctx->threadCapacity = numThreads; | |
|
218 | ctx->threadLimit = numThreads; | |
|
219 | return 0; | |
|
220 | } | |
|
221 | ||
|
222 | /* @return : 0 on success, 1 on error */ | |
|
223 | int POOL_resize(POOL_ctx* ctx, size_t numThreads) | |
|
224 | { | |
|
225 | int result; | |
|
226 | if (ctx==NULL) return 1; | |
|
227 | ZSTD_pthread_mutex_lock(&ctx->queueMutex); | |
|
228 | result = POOL_resize_internal(ctx, numThreads); | |
|
229 | ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); | |
|
230 | ZSTD_pthread_mutex_unlock(&ctx->queueMutex); | |
|
231 | return result; | |
|
180 | 232 | } |
|
181 | 233 | |
|
182 | 234 | /** |
|
183 | 235 | * Returns 1 if the queue is full and 0 otherwise. |
|
184 | 236 | * |
|
185 |
* |
|
|
186 | * then a queue is empty if there is a thread free and no job is waiting. | |
|
237 | * When queueSize is 1 (pool was created with an intended queueSize of 0), | |
|
238 | * then a queue is empty if there is a thread free _and_ no job is waiting. | |
|
187 | 239 | */ |
|
188 | 240 | static int isQueueFull(POOL_ctx const* ctx) { |
|
189 | 241 | if (ctx->queueSize > 1) { |
|
190 | 242 | return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize); |
|
191 | 243 | } else { |
|
192 |
return ctx->numThreadsBusy == ctx-> |
|
|
244 | return (ctx->numThreadsBusy == ctx->threadLimit) || | |
|
193 | 245 | !ctx->queueEmpty; |
|
194 | 246 | } |
|
195 | 247 | } |
@@ -263,6 +315,11 b' void POOL_free(POOL_ctx* ctx) {' | |||
|
263 | 315 | (void)ctx; |
|
264 | 316 | } |
|
265 | 317 | |
|
318 | int POOL_resize(POOL_ctx* ctx, size_t numThreads) { | |
|
319 | (void)ctx; (void)numThreads; | |
|
320 | return 0; | |
|
321 | } | |
|
322 | ||
|
266 | 323 | void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) { |
|
267 | 324 | (void)ctx; |
|
268 | 325 | function(opaque); |
@@ -30,40 +30,50 b' typedef struct POOL_ctx_s POOL_ctx;' | |||
|
30 | 30 | */ |
|
31 | 31 | POOL_ctx* POOL_create(size_t numThreads, size_t queueSize); |
|
32 | 32 | |
|
33 |
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, |
|
|
33 | POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, | |
|
34 | ZSTD_customMem customMem); | |
|
34 | 35 | |
|
35 | 36 | /*! POOL_free() : |
|
36 |
|
|
|
37 | */ | |
|
37 | * Free a thread pool returned by POOL_create(). | |
|
38 | */ | |
|
38 | 39 | void POOL_free(POOL_ctx* ctx); |
|
39 | 40 | |
|
41 | /*! POOL_resize() : | |
|
42 | * Expands or shrinks pool's number of threads. | |
|
43 | * This is more efficient than releasing + creating a new context, | |
|
44 | * since it tries to preserve and re-use existing threads. | |
|
45 | * `numThreads` must be at least 1. | |
|
46 | * @return : 0 when resize was successful, | |
|
47 | * !0 (typically 1) if there is an error. | |
|
48 | * note : only numThreads can be resized, queueSize remains unchanged. | |
|
49 | */ | |
|
50 | int POOL_resize(POOL_ctx* ctx, size_t numThreads); | |
|
51 | ||
|
40 | 52 | /*! POOL_sizeof() : |
|
41 | return memory usage of pool returned by POOL_create(). | |
|
42 | */ | |
|
53 | * @return threadpool memory usage | |
|
54 | * note : compatible with NULL (returns 0 in this case) | |
|
55 | */ | |
|
43 | 56 | size_t POOL_sizeof(POOL_ctx* ctx); |
|
44 | 57 | |
|
45 | 58 | /*! POOL_function : |
|
46 |
|
|
|
47 | */ | |
|
59 | * The function type that can be added to a thread pool. | |
|
60 | */ | |
|
48 | 61 | typedef void (*POOL_function)(void*); |
|
49 | /*! POOL_add_function : | |
|
50 | The function type for a generic thread pool add function. | |
|
51 | */ | |
|
52 | typedef void (*POOL_add_function)(void*, POOL_function, void*); | |
|
53 | 62 | |
|
54 | 63 | /*! POOL_add() : |
|
55 |
|
|
|
56 |
|
|
|
57 |
|
|
|
58 | */ | |
|
64 | * Add the job `function(opaque)` to the thread pool. `ctx` must be valid. | |
|
65 | * Possibly blocks until there is room in the queue. | |
|
66 | * Note : The function may be executed asynchronously, | |
|
67 | * therefore, `opaque` must live until function has been completed. | |
|
68 | */ | |
|
59 | 69 | void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); |
|
60 | 70 | |
|
61 | 71 | |
|
62 | 72 | /*! POOL_tryAdd() : |
|
63 |
|
|
|
64 | return immediately otherwise. | |
|
65 |
|
|
|
66 | */ | |
|
73 | * Add the job `function(opaque)` to thread pool _if_ a worker is available. | |
|
74 | * Returns immediately even if not (does not block). | |
|
75 | * @return : 1 if successful, 0 if not. | |
|
76 | */ | |
|
67 | 77 | int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); |
|
68 | 78 | |
|
69 | 79 |
@@ -98,6 +98,7 b'' | |||
|
98 | 98 | /* Modify the local functions below should you wish to use some other memory routines */ |
|
99 | 99 | /* for malloc(), free() */ |
|
100 | 100 | #include <stdlib.h> |
|
101 | #include <stddef.h> /* size_t */ | |
|
101 | 102 | static void* XXH_malloc(size_t s) { return malloc(s); } |
|
102 | 103 | static void XXH_free (void* p) { free(p); } |
|
103 | 104 | /* for memcpy() */ |
@@ -46,11 +46,6 b' ZSTD_ErrorCode ZSTD_getErrorCode(size_t ' | |||
|
46 | 46 | * provides error code string from enum */ |
|
47 | 47 | const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } |
|
48 | 48 | |
|
49 | /*! g_debuglog_enable : | |
|
50 | * turn on/off debug traces (global switch) */ | |
|
51 | #if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 2) | |
|
52 | int g_debuglog_enable = 1; | |
|
53 | #endif | |
|
54 | 49 | |
|
55 | 50 | |
|
56 | 51 | /*=************************************************************** |
@@ -21,6 +21,7 b'' | |||
|
21 | 21 | ***************************************/ |
|
22 | 22 | #include "compiler.h" |
|
23 | 23 | #include "mem.h" |
|
24 | #include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ | |
|
24 | 25 | #include "error_private.h" |
|
25 | 26 | #define ZSTD_STATIC_LINKING_ONLY |
|
26 | 27 | #include "zstd.h" |
@@ -38,43 +39,8 b'' | |||
|
38 | 39 | extern "C" { |
|
39 | 40 | #endif |
|
40 | 41 | |
|
41 | ||
|
42 | /*-************************************* | |
|
43 | * Debug | |
|
44 | ***************************************/ | |
|
45 | #if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1) | |
|
46 | # include <assert.h> | |
|
47 | #else | |
|
48 | # ifndef assert | |
|
49 | # define assert(condition) ((void)0) | |
|
50 | # endif | |
|
51 | #endif | |
|
52 | ||
|
53 | #define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; } | |
|
54 | ||
|
55 | #if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2) | |
|
56 | # include <stdio.h> | |
|
57 | extern int g_debuglog_enable; | |
|
58 | /* recommended values for ZSTD_DEBUG display levels : | |
|
59 | * 1 : no display, enables assert() only | |
|
60 | * 2 : reserved for currently active debug path | |
|
61 | * 3 : events once per object lifetime (CCtx, CDict, etc.) | |
|
62 | * 4 : events once per frame | |
|
63 | * 5 : events once per block | |
|
64 | * 6 : events once per sequence (*very* verbose) */ | |
|
65 | # define RAWLOG(l, ...) { \ | |
|
66 | if ((g_debuglog_enable) & (l<=ZSTD_DEBUG)) { \ | |
|
67 | fprintf(stderr, __VA_ARGS__); \ | |
|
68 | } } | |
|
69 | # define DEBUGLOG(l, ...) { \ | |
|
70 | if ((g_debuglog_enable) & (l<=ZSTD_DEBUG)) { \ | |
|
71 | fprintf(stderr, __FILE__ ": " __VA_ARGS__); \ | |
|
72 | fprintf(stderr, " \n"); \ | |
|
73 | } } | |
|
74 | #else | |
|
75 | # define RAWLOG(l, ...) {} /* disabled */ | |
|
76 | # define DEBUGLOG(l, ...) {} /* disabled */ | |
|
77 | #endif | |
|
42 | /* ---- static assert (debug) --- */ | |
|
43 | #define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) | |
|
78 | 44 | |
|
79 | 45 | |
|
80 | 46 | /*-************************************* |
@@ -113,8 +79,7 b' static const U32 repStartValue[ZSTD_REP_' | |||
|
113 | 79 | static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; |
|
114 | 80 | static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; |
|
115 | 81 | |
|
116 | #define ZSTD_FRAMEIDSIZE 4 | |
|
117 | static const size_t ZSTD_frameIdSize = ZSTD_FRAMEIDSIZE; /* magic number size */ | |
|
82 | #define ZSTD_FRAMEIDSIZE 4 /* magic number size */ | |
|
118 | 83 | |
|
119 | 84 | #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ |
|
120 | 85 | static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; |
@@ -227,6 +192,8 b' typedef struct {' | |||
|
227 | 192 | BYTE* llCode; |
|
228 | 193 | BYTE* mlCode; |
|
229 | 194 | BYTE* ofCode; |
|
195 | size_t maxNbSeq; | |
|
196 | size_t maxNbLit; | |
|
230 | 197 | U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */ |
|
231 | 198 | U32 longLengthPos; |
|
232 | 199 | } seqStore_t; |
@@ -1,6 +1,6 b'' | |||
|
1 | 1 | /* ****************************************************************** |
|
2 | 2 | FSE : Finite State Entropy encoder |
|
3 |
Copyright (C) 2013- |
|
|
3 | Copyright (C) 2013-present, Yann Collet. | |
|
4 | 4 | |
|
5 | 5 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) |
|
6 | 6 | |
@@ -37,9 +37,11 b'' | |||
|
37 | 37 | ****************************************************************/ |
|
38 | 38 | #include <stdlib.h> /* malloc, free, qsort */ |
|
39 | 39 | #include <string.h> /* memcpy, memset */ |
|
40 | #include <stdio.h> /* printf (debug) */ | |
|
40 | #include "compiler.h" | |
|
41 | #include "mem.h" /* U32, U16, etc. */ | |
|
42 | #include "debug.h" /* assert, DEBUGLOG */ | |
|
43 | #include "hist.h" /* HIST_count_wksp */ | |
|
41 | 44 | #include "bitstream.h" |
|
42 | #include "compiler.h" | |
|
43 | 45 | #define FSE_STATIC_LINKING_ONLY |
|
44 | 46 | #include "fse.h" |
|
45 | 47 | #include "error_private.h" |
@@ -49,7 +51,6 b'' | |||
|
49 | 51 | * Error Management |
|
50 | 52 | ****************************************************************/ |
|
51 | 53 | #define FSE_isError ERR_isError |
|
52 | #define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ | |
|
53 | 54 | |
|
54 | 55 | |
|
55 | 56 | /* ************************************************************** |
@@ -82,7 +83,9 b'' | |||
|
82 | 83 | * wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)` |
|
83 | 84 | * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements |
|
84 | 85 | */ |
|
85 | size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) | |
|
86 | size_t FSE_buildCTable_wksp(FSE_CTable* ct, | |
|
87 | const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, | |
|
88 | void* workSpace, size_t wkspSize) | |
|
86 | 89 | { |
|
87 | 90 | U32 const tableSize = 1 << tableLog; |
|
88 | 91 | U32 const tableMask = tableSize - 1; |
@@ -100,9 +103,14 b' size_t FSE_buildCTable_wksp(FSE_CTable* ' | |||
|
100 | 103 | if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge); |
|
101 | 104 | tableU16[-2] = (U16) tableLog; |
|
102 | 105 | tableU16[-1] = (U16) maxSymbolValue; |
|
106 | assert(tableLog < 16); /* required for threshold strategy to work */ | |
|
103 | 107 | |
|
104 | 108 | /* For explanations on how to distribute symbol values over the table : |
|
105 |
|
|
|
109 | * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ | |
|
110 | ||
|
111 | #ifdef __clang_analyzer__ | |
|
112 | memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ | |
|
113 | #endif | |
|
106 | 114 | |
|
107 | 115 | /* symbol start positions */ |
|
108 | 116 | { U32 u; |
@@ -122,13 +130,15 b' size_t FSE_buildCTable_wksp(FSE_CTable* ' | |||
|
122 | 130 | U32 symbol; |
|
123 | 131 | for (symbol=0; symbol<=maxSymbolValue; symbol++) { |
|
124 | 132 | int nbOccurences; |
|
125 | for (nbOccurences=0; nbOccurences<normalizedCounter[symbol]; nbOccurences++) { | |
|
133 | int const freq = normalizedCounter[symbol]; | |
|
134 | for (nbOccurences=0; nbOccurences<freq; nbOccurences++) { | |
|
126 | 135 | tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol; |
|
127 | 136 | position = (position + step) & tableMask; |
|
128 | while (position > highThreshold) position = (position + step) & tableMask; /* Low proba area */ | |
|
137 | while (position > highThreshold) | |
|
138 | position = (position + step) & tableMask; /* Low proba area */ | |
|
129 | 139 | } } |
|
130 | 140 | |
|
131 |
|
|
|
141 | assert(position==0); /* Must have initialized all positions */ | |
|
132 | 142 | } |
|
133 | 143 | |
|
134 | 144 | /* Build table */ |
@@ -143,7 +153,10 b' size_t FSE_buildCTable_wksp(FSE_CTable* ' | |||
|
143 | 153 | for (s=0; s<=maxSymbolValue; s++) { |
|
144 | 154 | switch (normalizedCounter[s]) |
|
145 | 155 | { |
|
146 |
case 0: |
|
|
156 | case 0: | |
|
157 | /* filling nonetheless, for compatibility with FSE_getMaxNbBits() */ | |
|
158 | symbolTT[s].deltaNbBits = ((tableLog+1) << 16) - (1<<tableLog); | |
|
159 | break; | |
|
147 | 160 | |
|
148 | 161 | case -1: |
|
149 | 162 | case 1: |
@@ -160,6 +173,18 b' size_t FSE_buildCTable_wksp(FSE_CTable* ' | |||
|
160 | 173 | total += normalizedCounter[s]; |
|
161 | 174 | } } } } |
|
162 | 175 | |
|
176 | #if 0 /* debug : symbol costs */ | |
|
177 | DEBUGLOG(5, "\n --- table statistics : "); | |
|
178 | { U32 symbol; | |
|
179 | for (symbol=0; symbol<=maxSymbolValue; symbol++) { | |
|
180 | DEBUGLOG(5, "%3u: w=%3i, maxBits=%u, fracBits=%.2f", | |
|
181 | symbol, normalizedCounter[symbol], | |
|
182 | FSE_getMaxNbBits(symbolTT, symbol), | |
|
183 | (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256); | |
|
184 | } | |
|
185 | } | |
|
186 | #endif | |
|
187 | ||
|
163 | 188 | return 0; |
|
164 | 189 | } |
|
165 | 190 | |
@@ -174,8 +199,9 b' size_t FSE_buildCTable(FSE_CTable* ct, c' | |||
|
174 | 199 | |
|
175 | 200 | #ifndef FSE_COMMONDEFS_ONLY |
|
176 | 201 | |
|
202 | ||
|
177 | 203 | /*-************************************************************** |
|
178 |
* FSE NCount encoding |
|
|
204 | * FSE NCount encoding | |
|
179 | 205 | ****************************************************************/ |
|
180 | 206 | size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog) |
|
181 | 207 | { |
@@ -183,9 +209,10 b' size_t FSE_NCountWriteBound(unsigned max' | |||
|
183 | 209 | return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */ |
|
184 | 210 | } |
|
185 | 211 | |
|
186 | static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize, | |
|
187 | const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, | |
|
188 | unsigned writeIsSafe) | |
|
212 | static size_t | |
|
213 | FSE_writeNCount_generic (void* header, size_t headerBufferSize, | |
|
214 | const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, | |
|
215 | unsigned writeIsSafe) | |
|
189 | 216 | { |
|
190 | 217 | BYTE* const ostart = (BYTE*) header; |
|
191 | 218 | BYTE* out = ostart; |
@@ -194,13 +221,12 b' static size_t FSE_writeNCount_generic (v' | |||
|
194 | 221 | const int tableSize = 1 << tableLog; |
|
195 | 222 | int remaining; |
|
196 | 223 | int threshold; |
|
197 | U32 bitStream; | |
|
198 | int bitCount; | |
|
199 |
unsigned |
|
|
200 | int previous0 = 0; | |
|
224 | U32 bitStream = 0; | |
|
225 | int bitCount = 0; | |
|
226 | unsigned symbol = 0; | |
|
227 | unsigned const alphabetSize = maxSymbolValue + 1; | |
|
228 | int previousIs0 = 0; | |
|
201 | 229 | |
|
202 | bitStream = 0; | |
|
203 | bitCount = 0; | |
|
204 | 230 | /* Table Size */ |
|
205 | 231 | bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount; |
|
206 | 232 | bitCount += 4; |
@@ -210,48 +236,53 b' static size_t FSE_writeNCount_generic (v' | |||
|
210 | 236 | threshold = tableSize; |
|
211 | 237 | nbBits = tableLog+1; |
|
212 | 238 | |
|
213 | while (remaining>1) { /* stops at 1 */ | |
|
214 | if (previous0) { | |
|
215 |
unsigned start = |
|
|
216 |
while (!normalizedCounter[ |
|
|
217 | while (charnum >= start+24) { | |
|
239 | while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */ | |
|
240 | if (previousIs0) { | |
|
241 | unsigned start = symbol; | |
|
242 | while ((symbol < alphabetSize) && !normalizedCounter[symbol]) symbol++; | |
|
243 | if (symbol == alphabetSize) break; /* incorrect distribution */ | |
|
244 | while (symbol >= start+24) { | |
|
218 | 245 | start+=24; |
|
219 | 246 | bitStream += 0xFFFFU << bitCount; |
|
220 |
if ((!writeIsSafe) && (out > oend-2)) |
|
|
247 | if ((!writeIsSafe) && (out > oend-2)) | |
|
248 | return ERROR(dstSize_tooSmall); /* Buffer overflow */ | |
|
221 | 249 | out[0] = (BYTE) bitStream; |
|
222 | 250 | out[1] = (BYTE)(bitStream>>8); |
|
223 | 251 | out+=2; |
|
224 | 252 | bitStream>>=16; |
|
225 | 253 | } |
|
226 |
while ( |
|
|
254 | while (symbol >= start+3) { | |
|
227 | 255 | start+=3; |
|
228 | 256 | bitStream += 3 << bitCount; |
|
229 | 257 | bitCount += 2; |
|
230 | 258 | } |
|
231 |
bitStream += ( |
|
|
259 | bitStream += (symbol-start) << bitCount; | |
|
232 | 260 | bitCount += 2; |
|
233 | 261 | if (bitCount>16) { |
|
234 |
if ((!writeIsSafe) && (out > oend - 2)) |
|
|
262 | if ((!writeIsSafe) && (out > oend - 2)) | |
|
263 | return ERROR(dstSize_tooSmall); /* Buffer overflow */ | |
|
235 | 264 | out[0] = (BYTE)bitStream; |
|
236 | 265 | out[1] = (BYTE)(bitStream>>8); |
|
237 | 266 | out += 2; |
|
238 | 267 | bitStream >>= 16; |
|
239 | 268 | bitCount -= 16; |
|
240 | 269 | } } |
|
241 |
{ int count = normalizedCounter[ |
|
|
242 | int const max = (2*threshold-1)-remaining; | |
|
270 | { int count = normalizedCounter[symbol++]; | |
|
271 | int const max = (2*threshold-1) - remaining; | |
|
243 | 272 | remaining -= count < 0 ? -count : count; |
|
244 | 273 | count++; /* +1 for extra accuracy */ |
|
245 | if (count>=threshold) count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */ | |
|
274 | if (count>=threshold) | |
|
275 | count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */ | |
|
246 | 276 | bitStream += count << bitCount; |
|
247 | 277 | bitCount += nbBits; |
|
248 | 278 | bitCount -= (count<max); |
|
249 | previous0 = (count==1); | |
|
279 | previousIs0 = (count==1); | |
|
250 | 280 | if (remaining<1) return ERROR(GENERIC); |
|
251 | 281 | while (remaining<threshold) { nbBits--; threshold>>=1; } |
|
252 | 282 | } |
|
253 | 283 | if (bitCount>16) { |
|
254 |
if ((!writeIsSafe) && (out > oend - 2)) |
|
|
284 | if ((!writeIsSafe) && (out > oend - 2)) | |
|
285 | return ERROR(dstSize_tooSmall); /* Buffer overflow */ | |
|
255 | 286 | out[0] = (BYTE)bitStream; |
|
256 | 287 | out[1] = (BYTE)(bitStream>>8); |
|
257 | 288 | out += 2; |
@@ -259,19 +290,23 b' static size_t FSE_writeNCount_generic (v' | |||
|
259 | 290 | bitCount -= 16; |
|
260 | 291 | } } |
|
261 | 292 | |
|
293 | if (remaining != 1) | |
|
294 | return ERROR(GENERIC); /* incorrect normalized distribution */ | |
|
295 | assert(symbol <= alphabetSize); | |
|
296 | ||
|
262 | 297 | /* flush remaining bitStream */ |
|
263 |
if ((!writeIsSafe) && (out > oend - 2)) |
|
|
298 | if ((!writeIsSafe) && (out > oend - 2)) | |
|
299 | return ERROR(dstSize_tooSmall); /* Buffer overflow */ | |
|
264 | 300 | out[0] = (BYTE)bitStream; |
|
265 | 301 | out[1] = (BYTE)(bitStream>>8); |
|
266 | 302 | out+= (bitCount+7) /8; |
|
267 | 303 | |
|
268 | if (charnum > maxSymbolValue + 1) return ERROR(GENERIC); | |
|
269 | ||
|
270 | 304 | return (out-ostart); |
|
271 | 305 | } |
|
272 | 306 | |
|
273 | 307 | |
|
274 | size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) | |
|
308 | size_t FSE_writeNCount (void* buffer, size_t bufferSize, | |
|
309 | const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) | |
|
275 | 310 | { |
|
276 | 311 | if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported */ |
|
277 | 312 | if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported */ |
@@ -279,179 +314,13 b' size_t FSE_writeNCount (void* buffer, si' | |||
|
279 | 314 | if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog)) |
|
280 | 315 | return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0); |
|
281 | 316 | |
|
282 | return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1); | |
|
283 | } | |
|
284 | ||
|
285 | ||
|
286 | ||
|
287 | /*-************************************************************** | |
|
288 | * Counting histogram | |
|
289 | ****************************************************************/ | |
|
290 | /*! FSE_count_simple | |
|
291 | This function counts byte values within `src`, and store the histogram into table `count`. | |
|
292 | It doesn't use any additional memory. | |
|
293 | But this function is unsafe : it doesn't check that all values within `src` can fit into `count`. | |
|
294 | For this reason, prefer using a table `count` with 256 elements. | |
|
295 | @return : count of most numerous element. | |
|
296 | */ | |
|
297 | size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
298 | const void* src, size_t srcSize) | |
|
299 | { | |
|
300 | const BYTE* ip = (const BYTE*)src; | |
|
301 | const BYTE* const end = ip + srcSize; | |
|
302 | unsigned maxSymbolValue = *maxSymbolValuePtr; | |
|
303 | unsigned max=0; | |
|
304 | ||
|
305 | memset(count, 0, (maxSymbolValue+1)*sizeof(*count)); | |
|
306 | if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; } | |
|
307 | ||
|
308 | while (ip<end) { | |
|
309 | assert(*ip <= maxSymbolValue); | |
|
310 | count[*ip++]++; | |
|
311 | } | |
|
312 | ||
|
313 | while (!count[maxSymbolValue]) maxSymbolValue--; | |
|
314 | *maxSymbolValuePtr = maxSymbolValue; | |
|
315 | ||
|
316 | { U32 s; for (s=0; s<=maxSymbolValue; s++) if (count[s] > max) max = count[s]; } | |
|
317 | ||
|
318 | return (size_t)max; | |
|
317 | return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1 /* write in buffer is safe */); | |
|
319 | 318 | } |
|
320 | 319 | |
|
321 | 320 | |
|
322 | /* FSE_count_parallel_wksp() : | |
|
323 | * Same as FSE_count_parallel(), but using an externally provided scratch buffer. | |
|
324 | * `workSpace` size must be a minimum of `1024 * sizeof(unsigned)`. | |
|
325 | * @return : largest histogram frequency, or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */ | |
|
326 | static size_t FSE_count_parallel_wksp( | |
|
327 | unsigned* count, unsigned* maxSymbolValuePtr, | |
|
328 | const void* source, size_t sourceSize, | |
|
329 | unsigned checkMax, unsigned* const workSpace) | |
|
330 | { | |
|
331 | const BYTE* ip = (const BYTE*)source; | |
|
332 | const BYTE* const iend = ip+sourceSize; | |
|
333 | unsigned maxSymbolValue = *maxSymbolValuePtr; | |
|
334 | unsigned max=0; | |
|
335 | U32* const Counting1 = workSpace; | |
|
336 | U32* const Counting2 = Counting1 + 256; | |
|
337 | U32* const Counting3 = Counting2 + 256; | |
|
338 | U32* const Counting4 = Counting3 + 256; | |
|
339 | ||
|
340 | memset(workSpace, 0, 4*256*sizeof(unsigned)); | |
|
341 | ||
|
342 | /* safety checks */ | |
|
343 | if (!sourceSize) { | |
|
344 | memset(count, 0, maxSymbolValue + 1); | |
|
345 | *maxSymbolValuePtr = 0; | |
|
346 | return 0; | |
|
347 | } | |
|
348 | if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */ | |
|
349 | ||
|
350 | /* by stripes of 16 bytes */ | |
|
351 | { U32 cached = MEM_read32(ip); ip += 4; | |
|
352 | while (ip < iend-15) { | |
|
353 | U32 c = cached; cached = MEM_read32(ip); ip += 4; | |
|
354 | Counting1[(BYTE) c ]++; | |
|
355 | Counting2[(BYTE)(c>>8) ]++; | |
|
356 | Counting3[(BYTE)(c>>16)]++; | |
|
357 | Counting4[ c>>24 ]++; | |
|
358 | c = cached; cached = MEM_read32(ip); ip += 4; | |
|
359 | Counting1[(BYTE) c ]++; | |
|
360 | Counting2[(BYTE)(c>>8) ]++; | |
|
361 | Counting3[(BYTE)(c>>16)]++; | |
|
362 | Counting4[ c>>24 ]++; | |
|
363 | c = cached; cached = MEM_read32(ip); ip += 4; | |
|
364 | Counting1[(BYTE) c ]++; | |
|
365 | Counting2[(BYTE)(c>>8) ]++; | |
|
366 | Counting3[(BYTE)(c>>16)]++; | |
|
367 | Counting4[ c>>24 ]++; | |
|
368 | c = cached; cached = MEM_read32(ip); ip += 4; | |
|
369 | Counting1[(BYTE) c ]++; | |
|
370 | Counting2[(BYTE)(c>>8) ]++; | |
|
371 | Counting3[(BYTE)(c>>16)]++; | |
|
372 | Counting4[ c>>24 ]++; | |
|
373 | } | |
|
374 | ip-=4; | |
|
375 | } | |
|
376 | ||
|
377 | /* finish last symbols */ | |
|
378 | while (ip<iend) Counting1[*ip++]++; | |
|
379 | ||
|
380 | if (checkMax) { /* verify stats will fit into destination table */ | |
|
381 | U32 s; for (s=255; s>maxSymbolValue; s--) { | |
|
382 | Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; | |
|
383 | if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); | |
|
384 | } } | |
|
385 | ||
|
386 | { U32 s; | |
|
387 | if (maxSymbolValue > 255) maxSymbolValue = 255; | |
|
388 | for (s=0; s<=maxSymbolValue; s++) { | |
|
389 | count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; | |
|
390 | if (count[s] > max) max = count[s]; | |
|
391 | } } | |
|
392 | ||
|
393 | while (!count[maxSymbolValue]) maxSymbolValue--; | |
|
394 | *maxSymbolValuePtr = maxSymbolValue; | |
|
395 | return (size_t)max; | |
|
396 | } | |
|
397 | ||
|
398 | /* FSE_countFast_wksp() : | |
|
399 | * Same as FSE_countFast(), but using an externally provided scratch buffer. | |
|
400 | * `workSpace` size must be table of >= `1024` unsigned */ | |
|
401 | size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
402 | const void* source, size_t sourceSize, | |
|
403 | unsigned* workSpace) | |
|
404 | { | |
|
405 | if (sourceSize < 1500) /* heuristic threshold */ | |
|
406 | return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize); | |
|
407 | return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace); | |
|
408 | } | |
|
409 | ||
|
410 | /* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ | |
|
411 | size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
412 | const void* source, size_t sourceSize) | |
|
413 | { | |
|
414 | unsigned tmpCounters[1024]; | |
|
415 | return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters); | |
|
416 | } | |
|
417 | ||
|
418 | /* FSE_count_wksp() : | |
|
419 | * Same as FSE_count(), but using an externally provided scratch buffer. | |
|
420 | * `workSpace` size must be table of >= `1024` unsigned */ | |
|
421 | size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
422 | const void* source, size_t sourceSize, unsigned* workSpace) | |
|
423 | { | |
|
424 | if (*maxSymbolValuePtr < 255) | |
|
425 | return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace); | |
|
426 | *maxSymbolValuePtr = 255; | |
|
427 | return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace); | |
|
428 | } | |
|
429 | ||
|
430 | size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, | |
|
431 | const void* src, size_t srcSize) | |
|
432 | { | |
|
433 | unsigned tmpCounters[1024]; | |
|
434 | return FSE_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters); | |
|
435 | } | |
|
436 | ||
|
437 | ||
|
438 | ||
|
439 | 321 | /*-************************************************************** |
|
440 | 322 | * FSE Compression Code |
|
441 | 323 | ****************************************************************/ |
|
442 | /*! FSE_sizeof_CTable() : | |
|
443 | FSE_CTable is a variable size structure which contains : | |
|
444 | `U16 tableLog;` | |
|
445 | `U16 maxSymbolValue;` | |
|
446 | `U16 nextStateNumber[1 << tableLog];` // This size is variable | |
|
447 | `FSE_symbolCompressionTransform symbolTT[maxSymbolValue+1];` // This size is variable | |
|
448 | Allocation is manual (C standard does not support variable-size structures). | |
|
449 | */ | |
|
450 | size_t FSE_sizeof_CTable (unsigned maxSymbolValue, unsigned tableLog) | |
|
451 | { | |
|
452 | if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); | |
|
453 | return FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32); | |
|
454 | } | |
|
455 | 324 | |
|
456 | 325 | FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog) |
|
457 | 326 | { |
@@ -466,7 +335,7 b' void FSE_freeCTable (FSE_CTable* ct) { f' | |||
|
466 | 335 | /* provides the minimum logSize to safely represent a distribution */ |
|
467 | 336 | static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) |
|
468 | 337 | { |
|
469 |
U32 minBitsSrc = BIT_highbit32((U32)(srcSize |
|
|
338 | U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1; | |
|
470 | 339 | U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2; |
|
471 | 340 | U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols; |
|
472 | 341 | assert(srcSize > 1); /* Not supported, RLE should be used instead */ |
@@ -529,6 +398,9 b' static size_t FSE_normalizeM2(short* nor' | |||
|
529 | 398 | } |
|
530 | 399 | ToDistribute = (1 << tableLog) - distributed; |
|
531 | 400 | |
|
401 | if (ToDistribute == 0) | |
|
402 | return 0; | |
|
403 | ||
|
532 | 404 | if ((total / ToDistribute) > lowOne) { |
|
533 | 405 | /* risk of rounding to zero */ |
|
534 | 406 | lowOne = (U32)((total * 3) / (ToDistribute * 2)); |
@@ -629,11 +501,11 b' size_t FSE_normalizeCount (short* normal' | |||
|
629 | 501 | U32 s; |
|
630 | 502 | U32 nTotal = 0; |
|
631 | 503 | for (s=0; s<=maxSymbolValue; s++) |
|
632 |
|
|
|
504 | RAWLOG(2, "%3i: %4i \n", s, normalizedCounter[s]); | |
|
633 | 505 | for (s=0; s<=maxSymbolValue; s++) |
|
634 | 506 | nTotal += abs(normalizedCounter[s]); |
|
635 | 507 | if (nTotal != (1U<<tableLog)) |
|
636 |
|
|
|
508 | RAWLOG(2, "Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog); | |
|
637 | 509 | getchar(); |
|
638 | 510 | } |
|
639 | 511 | #endif |
@@ -800,7 +672,7 b' size_t FSE_compress_wksp (void* dst, siz' | |||
|
800 | 672 | if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG; |
|
801 | 673 | |
|
802 | 674 | /* Scan input and build symbol stats */ |
|
803 |
{ CHECK_V_F(maxCount, |
|
|
675 | { CHECK_V_F(maxCount, HIST_count_wksp(count, &maxSymbolValue, src, srcSize, (unsigned*)scratchBuffer) ); | |
|
804 | 676 | if (maxCount == srcSize) return 1; /* only a single symbol in src : rle */ |
|
805 | 677 | if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */ |
|
806 | 678 | if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */ |
@@ -835,7 +707,7 b' typedef struct {' | |||
|
835 | 707 | size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog) |
|
836 | 708 | { |
|
837 | 709 | fseWkspMax_t scratchBuffer; |
|
838 |
|
|
|
710 | DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */ | |
|
839 | 711 | if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); |
|
840 | 712 | return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer)); |
|
841 | 713 | } |
@@ -45,8 +45,9 b'' | |||
|
45 | 45 | ****************************************************************/ |
|
46 | 46 | #include <string.h> /* memcpy, memset */ |
|
47 | 47 | #include <stdio.h> /* printf (debug) */ |
|
48 | #include "compiler.h" | |
|
48 | 49 | #include "bitstream.h" |
|
49 |
#include " |
|
|
50 | #include "hist.h" | |
|
50 | 51 | #define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */ |
|
51 | 52 | #include "fse.h" /* header compression */ |
|
52 | 53 | #define HUF_STATIC_LINKING_ONLY |
@@ -58,7 +59,7 b'' | |||
|
58 | 59 | * Error Management |
|
59 | 60 | ****************************************************************/ |
|
60 | 61 | #define HUF_isError ERR_isError |
|
61 |
#define HUF_STATIC_ASSERT(c) |
|
|
62 | #define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ | |
|
62 | 63 | #define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e |
|
63 | 64 | #define CHECK_F(f) { CHECK_V_F(_var_err__, f); } |
|
64 | 65 | |
@@ -81,7 +82,7 b' unsigned HUF_optimalTableLog(unsigned ma' | |||
|
81 | 82 | * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX. |
|
82 | 83 | */ |
|
83 | 84 | #define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6 |
|
84 | size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize) | |
|
85 | static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize) | |
|
85 | 86 | { |
|
86 | 87 | BYTE* const ostart = (BYTE*) dst; |
|
87 | 88 | BYTE* op = ostart; |
@@ -100,9 +101,9 b' size_t HUF_compressWeights (void* dst, s' | |||
|
100 | 101 | if (wtSize <= 1) return 0; /* Not compressible */ |
|
101 | 102 | |
|
102 | 103 | /* Scan input and build symbol stats */ |
|
103 |
{ |
|
|
104 | { unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */ | |
|
104 | 105 | if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */ |
|
105 |
if (maxCount == 1) return 0; |
|
|
106 | if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */ | |
|
106 | 107 | } |
|
107 | 108 | |
|
108 | 109 | tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue); |
@@ -216,6 +217,13 b' size_t HUF_readCTable (HUF_CElt* CTable,' | |||
|
216 | 217 | return readSize; |
|
217 | 218 | } |
|
218 | 219 | |
|
220 | U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue) | |
|
221 | { | |
|
222 | const HUF_CElt* table = (const HUF_CElt*)symbolTable; | |
|
223 | assert(symbolValue <= HUF_SYMBOLVALUE_MAX); | |
|
224 | return table[symbolValue].nbBits; | |
|
225 | } | |
|
226 | ||
|
219 | 227 | |
|
220 | 228 | typedef struct nodeElt_s { |
|
221 | 229 | U32 count; |
@@ -660,9 +668,9 b' static size_t HUF_compress_internal (' | |||
|
660 | 668 | } |
|
661 | 669 | |
|
662 | 670 | /* Scan input and build symbol stats */ |
|
663 |
{ CHECK_V_F(largest, |
|
|
671 | { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, table->count) ); | |
|
664 | 672 | if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */ |
|
665 |
if (largest <= (srcSize >> 7)+ |
|
|
673 | if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */ | |
|
666 | 674 | } |
|
667 | 675 | |
|
668 | 676 | /* Check validity of previous table */ |
This diff has been collapsed as it changes many lines, (1413 lines changed) Show them Hide them | |||
@@ -8,21 +8,13 b'' | |||
|
8 | 8 | * You may select, at your option, one of the above-listed licenses. |
|
9 | 9 | */ |
|
10 | 10 | |
|
11 | ||
|
12 | /*-************************************* | |
|
13 | * Tuning parameters | |
|
14 | ***************************************/ | |
|
15 | #ifndef ZSTD_CLEVEL_DEFAULT | |
|
16 | # define ZSTD_CLEVEL_DEFAULT 3 | |
|
17 | #endif | |
|
18 | ||
|
19 | ||
|
20 | 11 | /*-************************************* |
|
21 | 12 | * Dependencies |
|
22 | 13 | ***************************************/ |
|
23 | 14 | #include <string.h> /* memset */ |
|
24 | 15 | #include "cpu.h" |
|
25 | 16 | #include "mem.h" |
|
17 | #include "hist.h" /* HIST_countFast_wksp */ | |
|
26 | 18 | #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ |
|
27 | 19 | #include "fse.h" |
|
28 | 20 | #define HUF_STATIC_LINKING_ONLY |
@@ -54,7 +46,6 b' struct ZSTD_CDict_s {' | |||
|
54 | 46 | size_t workspaceSize; |
|
55 | 47 | ZSTD_matchState_t matchState; |
|
56 | 48 | ZSTD_compressedBlockState_t cBlockState; |
|
57 | ZSTD_compressionParameters cParams; | |
|
58 | 49 | ZSTD_customMem customMem; |
|
59 | 50 | U32 dictID; |
|
60 | 51 | }; /* typedef'd to ZSTD_CDict within "zstd.h" */ |
@@ -64,17 +55,26 b' ZSTD_CCtx* ZSTD_createCCtx(void)' | |||
|
64 | 55 | return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); |
|
65 | 56 | } |
|
66 | 57 | |
|
58 | static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) | |
|
59 | { | |
|
60 | assert(cctx != NULL); | |
|
61 | memset(cctx, 0, sizeof(*cctx)); | |
|
62 | cctx->customMem = memManager; | |
|
63 | cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); | |
|
64 | { size_t const err = ZSTD_CCtx_resetParameters(cctx); | |
|
65 | assert(!ZSTD_isError(err)); | |
|
66 | (void)err; | |
|
67 | } | |
|
68 | } | |
|
69 | ||
|
67 | 70 | ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) |
|
68 | 71 | { |
|
69 | 72 | ZSTD_STATIC_ASSERT(zcss_init==0); |
|
70 | 73 | ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); |
|
71 | 74 | if (!customMem.customAlloc ^ !customMem.customFree) return NULL; |
|
72 |
{ ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_ |
|
|
75 | { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); | |
|
73 | 76 | if (!cctx) return NULL; |
|
74 |
cctx |
|
|
75 | cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; | |
|
76 | cctx->requestedParams.fParams.contentSizeFlag = 1; | |
|
77 | cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); | |
|
77 | ZSTD_initCCtx(cctx, customMem); | |
|
78 | 78 | return cctx; |
|
79 | 79 | } |
|
80 | 80 | } |
@@ -102,17 +102,24 b' ZSTD_CCtx* ZSTD_initStaticCCtx(void *wor' | |||
|
102 | 102 | return cctx; |
|
103 | 103 | } |
|
104 | 104 | |
|
105 |
s |
|
|
105 | static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) | |
|
106 | 106 | { |
|
107 | if (cctx==NULL) return 0; /* support free on NULL */ | |
|
108 | if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */ | |
|
107 | assert(cctx != NULL); | |
|
108 | assert(cctx->staticSize == 0); | |
|
109 | 109 | ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL; |
|
110 | 110 | ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL; |
|
111 | 111 | #ifdef ZSTD_MULTITHREAD |
|
112 | 112 | ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL; |
|
113 | 113 | #endif |
|
114 | } | |
|
115 | ||
|
116 | size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) | |
|
117 | { | |
|
118 | if (cctx==NULL) return 0; /* support free on NULL */ | |
|
119 | if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */ | |
|
120 | ZSTD_freeCCtxContent(cctx); | |
|
114 | 121 | ZSTD_free(cctx, cctx->customMem); |
|
115 | return 0; /* reserved as a potential error code in the future */ | |
|
122 | return 0; | |
|
116 | 123 | } |
|
117 | 124 | |
|
118 | 125 | |
@@ -143,21 +150,6 b' size_t ZSTD_sizeof_CStream(const ZSTD_CS' | |||
|
143 | 150 | /* private API call, for dictBuilder only */ |
|
144 | 151 | const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } |
|
145 | 152 | |
|
146 | ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( | |
|
147 | const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) | |
|
148 | { | |
|
149 | ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); | |
|
150 | if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; | |
|
151 | if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; | |
|
152 | if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; | |
|
153 | if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; | |
|
154 | if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; | |
|
155 | if (CCtxParams->cParams.searchLength) cParams.searchLength = CCtxParams->cParams.searchLength; | |
|
156 | if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; | |
|
157 | if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; | |
|
158 | return cParams; | |
|
159 | } | |
|
160 | ||
|
161 | 153 | static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( |
|
162 | 154 | ZSTD_compressionParameters cParams) |
|
163 | 155 | { |
@@ -251,7 +243,6 b' static int ZSTD_isUpdateAuthorized(ZSTD_' | |||
|
251 | 243 | case ZSTD_p_minMatch: |
|
252 | 244 | case ZSTD_p_targetLength: |
|
253 | 245 | case ZSTD_p_compressionStrategy: |
|
254 | case ZSTD_p_compressLiterals: | |
|
255 | 246 | return 1; |
|
256 | 247 | |
|
257 | 248 | case ZSTD_p_format: |
@@ -268,6 +259,7 b' static int ZSTD_isUpdateAuthorized(ZSTD_' | |||
|
268 | 259 | case ZSTD_p_ldmMinMatch: |
|
269 | 260 | case ZSTD_p_ldmBucketSizeLog: |
|
270 | 261 | case ZSTD_p_ldmHashEveryLog: |
|
262 | case ZSTD_p_forceAttachDict: | |
|
271 | 263 | default: |
|
272 | 264 | return 0; |
|
273 | 265 | } |
@@ -302,7 +294,6 b' size_t ZSTD_CCtx_setParameter(ZSTD_CCtx*' | |||
|
302 | 294 | if (cctx->cdict) return ERROR(stage_wrong); |
|
303 | 295 | return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); |
|
304 | 296 | |
|
305 | case ZSTD_p_compressLiterals: | |
|
306 | 297 | case ZSTD_p_contentSizeFlag: |
|
307 | 298 | case ZSTD_p_checksumFlag: |
|
308 | 299 | case ZSTD_p_dictIDFlag: |
@@ -313,6 +304,9 b' size_t ZSTD_CCtx_setParameter(ZSTD_CCtx*' | |||
|
313 | 304 | * default : 0 when using a CDict, 1 when using a Prefix */ |
|
314 | 305 | return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); |
|
315 | 306 | |
|
307 | case ZSTD_p_forceAttachDict: | |
|
308 | return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); | |
|
309 | ||
|
316 | 310 | case ZSTD_p_nbWorkers: |
|
317 | 311 | if ((value>0) && cctx->staticSize) { |
|
318 | 312 | return ERROR(parameter_unsupported); /* MT not compatible with static alloc */ |
@@ -351,7 +345,6 b' size_t ZSTD_CCtxParam_setParameter(' | |||
|
351 | 345 | int cLevel = (int)value; /* cast expected to restore negative sign */ |
|
352 | 346 | if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel(); |
|
353 | 347 | if (cLevel) { /* 0 : does not change current level */ |
|
354 | CCtxParams->disableLiteralCompression = (cLevel<0); /* negative levels disable huffman */ | |
|
355 | 348 | CCtxParams->compressionLevel = cLevel; |
|
356 | 349 | } |
|
357 | 350 | if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel; |
@@ -399,10 +392,6 b' size_t ZSTD_CCtxParam_setParameter(' | |||
|
399 | 392 | CCtxParams->cParams.strategy = (ZSTD_strategy)value; |
|
400 | 393 | return (size_t)CCtxParams->cParams.strategy; |
|
401 | 394 | |
|
402 | case ZSTD_p_compressLiterals: | |
|
403 | CCtxParams->disableLiteralCompression = !value; | |
|
404 | return !CCtxParams->disableLiteralCompression; | |
|
405 | ||
|
406 | 395 | case ZSTD_p_contentSizeFlag : |
|
407 | 396 | /* Content size written in frame header _when known_ (default:1) */ |
|
408 | 397 | DEBUGLOG(4, "set content size flag = %u", (value>0)); |
@@ -423,6 +412,12 b' size_t ZSTD_CCtxParam_setParameter(' | |||
|
423 | 412 | CCtxParams->forceWindow = (value > 0); |
|
424 | 413 | return CCtxParams->forceWindow; |
|
425 | 414 | |
|
415 | case ZSTD_p_forceAttachDict : | |
|
416 | CCtxParams->attachDictPref = value ? | |
|
417 | (value > 0 ? ZSTD_dictForceAttach : ZSTD_dictForceCopy) : | |
|
418 | ZSTD_dictDefaultAttach; | |
|
419 | return CCtxParams->attachDictPref; | |
|
420 | ||
|
426 | 421 | case ZSTD_p_nbWorkers : |
|
427 | 422 | #ifndef ZSTD_MULTITHREAD |
|
428 | 423 | if (value>0) return ERROR(parameter_unsupported); |
@@ -477,6 +472,98 b' size_t ZSTD_CCtxParam_setParameter(' | |||
|
477 | 472 | } |
|
478 | 473 | } |
|
479 | 474 | |
|
475 | size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned* value) | |
|
476 | { | |
|
477 | return ZSTD_CCtxParam_getParameter(&cctx->requestedParams, param, value); | |
|
478 | } | |
|
479 | ||
|
480 | size_t ZSTD_CCtxParam_getParameter( | |
|
481 | ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, unsigned* value) | |
|
482 | { | |
|
483 | switch(param) | |
|
484 | { | |
|
485 | case ZSTD_p_format : | |
|
486 | *value = CCtxParams->format; | |
|
487 | break; | |
|
488 | case ZSTD_p_compressionLevel : | |
|
489 | *value = CCtxParams->compressionLevel; | |
|
490 | break; | |
|
491 | case ZSTD_p_windowLog : | |
|
492 | *value = CCtxParams->cParams.windowLog; | |
|
493 | break; | |
|
494 | case ZSTD_p_hashLog : | |
|
495 | *value = CCtxParams->cParams.hashLog; | |
|
496 | break; | |
|
497 | case ZSTD_p_chainLog : | |
|
498 | *value = CCtxParams->cParams.chainLog; | |
|
499 | break; | |
|
500 | case ZSTD_p_searchLog : | |
|
501 | *value = CCtxParams->cParams.searchLog; | |
|
502 | break; | |
|
503 | case ZSTD_p_minMatch : | |
|
504 | *value = CCtxParams->cParams.searchLength; | |
|
505 | break; | |
|
506 | case ZSTD_p_targetLength : | |
|
507 | *value = CCtxParams->cParams.targetLength; | |
|
508 | break; | |
|
509 | case ZSTD_p_compressionStrategy : | |
|
510 | *value = (unsigned)CCtxParams->cParams.strategy; | |
|
511 | break; | |
|
512 | case ZSTD_p_contentSizeFlag : | |
|
513 | *value = CCtxParams->fParams.contentSizeFlag; | |
|
514 | break; | |
|
515 | case ZSTD_p_checksumFlag : | |
|
516 | *value = CCtxParams->fParams.checksumFlag; | |
|
517 | break; | |
|
518 | case ZSTD_p_dictIDFlag : | |
|
519 | *value = !CCtxParams->fParams.noDictIDFlag; | |
|
520 | break; | |
|
521 | case ZSTD_p_forceMaxWindow : | |
|
522 | *value = CCtxParams->forceWindow; | |
|
523 | break; | |
|
524 | case ZSTD_p_forceAttachDict : | |
|
525 | *value = CCtxParams->attachDictPref; | |
|
526 | break; | |
|
527 | case ZSTD_p_nbWorkers : | |
|
528 | #ifndef ZSTD_MULTITHREAD | |
|
529 | assert(CCtxParams->nbWorkers == 0); | |
|
530 | #endif | |
|
531 | *value = CCtxParams->nbWorkers; | |
|
532 | break; | |
|
533 | case ZSTD_p_jobSize : | |
|
534 | #ifndef ZSTD_MULTITHREAD | |
|
535 | return ERROR(parameter_unsupported); | |
|
536 | #else | |
|
537 | *value = CCtxParams->jobSize; | |
|
538 | break; | |
|
539 | #endif | |
|
540 | case ZSTD_p_overlapSizeLog : | |
|
541 | #ifndef ZSTD_MULTITHREAD | |
|
542 | return ERROR(parameter_unsupported); | |
|
543 | #else | |
|
544 | *value = CCtxParams->overlapSizeLog; | |
|
545 | break; | |
|
546 | #endif | |
|
547 | case ZSTD_p_enableLongDistanceMatching : | |
|
548 | *value = CCtxParams->ldmParams.enableLdm; | |
|
549 | break; | |
|
550 | case ZSTD_p_ldmHashLog : | |
|
551 | *value = CCtxParams->ldmParams.hashLog; | |
|
552 | break; | |
|
553 | case ZSTD_p_ldmMinMatch : | |
|
554 | *value = CCtxParams->ldmParams.minMatchLength; | |
|
555 | break; | |
|
556 | case ZSTD_p_ldmBucketSizeLog : | |
|
557 | *value = CCtxParams->ldmParams.bucketSizeLog; | |
|
558 | break; | |
|
559 | case ZSTD_p_ldmHashEveryLog : | |
|
560 | *value = CCtxParams->ldmParams.hashEveryLog; | |
|
561 | break; | |
|
562 | default: return ERROR(parameter_unsupported); | |
|
563 | } | |
|
564 | return 0; | |
|
565 | } | |
|
566 | ||
|
480 | 567 | /** ZSTD_CCtx_setParametersUsingCCtxParams() : |
|
481 | 568 | * just applies `params` into `cctx` |
|
482 | 569 | * no action is performed, parameters are merely stored. |
@@ -487,6 +574,7 b' size_t ZSTD_CCtxParam_setParameter(' | |||
|
487 | 574 | size_t ZSTD_CCtx_setParametersUsingCCtxParams( |
|
488 | 575 | ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) |
|
489 | 576 | { |
|
577 | DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); | |
|
490 | 578 | if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); |
|
491 | 579 | if (cctx->cdict) return ERROR(stage_wrong); |
|
492 | 580 | |
@@ -565,18 +653,19 b' size_t ZSTD_CCtx_refPrefix_advanced(' | |||
|
565 | 653 | return 0; |
|
566 | 654 | } |
|
567 | 655 | |
|
568 | static void ZSTD_startNewCompression(ZSTD_CCtx* cctx) | |
|
656 | /*! ZSTD_CCtx_reset() : | |
|
657 | * Also dumps dictionary */ | |
|
658 | void ZSTD_CCtx_reset(ZSTD_CCtx* cctx) | |
|
569 | 659 | { |
|
570 | 660 | cctx->streamStage = zcss_init; |
|
571 | 661 | cctx->pledgedSrcSizePlusOne = 0; |
|
572 | 662 | } |
|
573 | 663 | |
|
574 | /*! ZSTD_CCtx_reset() : | |
|
575 | * Also dumps dictionary */ | |
|
576 | void ZSTD_CCtx_reset(ZSTD_CCtx* cctx) | |
|
664 | size_t ZSTD_CCtx_resetParameters(ZSTD_CCtx* cctx) | |
|
577 | 665 | { |
|
578 | ZSTD_startNewCompression(cctx); | |
|
666 | if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); | |
|
579 | 667 | cctx->cdict = NULL; |
|
668 | return ZSTD_CCtxParams_reset(&cctx->requestedParams); | |
|
580 | 669 | } |
|
581 | 670 | |
|
582 | 671 | /** ZSTD_checkCParams() : |
@@ -589,8 +678,9 b' size_t ZSTD_checkCParams(ZSTD_compressio' | |||
|
589 | 678 | CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); |
|
590 | 679 | CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); |
|
591 | 680 | CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); |
|
592 | if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN) | |
|
593 | return ERROR(parameter_unsupported); | |
|
681 | ZSTD_STATIC_ASSERT(ZSTD_TARGETLENGTH_MIN == 0); | |
|
682 | if (cParams.targetLength > ZSTD_TARGETLENGTH_MAX) | |
|
683 | return ERROR(parameter_outOfBound); | |
|
594 | 684 | if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) |
|
595 | 685 | return ERROR(parameter_unsupported); |
|
596 | 686 | return 0; |
@@ -599,7 +689,8 b' size_t ZSTD_checkCParams(ZSTD_compressio' | |||
|
599 | 689 | /** ZSTD_clampCParams() : |
|
600 | 690 | * make CParam values within valid range. |
|
601 | 691 | * @return : valid CParams */ |
|
602 | static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams) | |
|
692 | static ZSTD_compressionParameters | |
|
693 | ZSTD_clampCParams(ZSTD_compressionParameters cParams) | |
|
603 | 694 | { |
|
604 | 695 | # define CLAMP(val,min,max) { \ |
|
605 | 696 | if (val<min) val=min; \ |
@@ -610,8 +701,10 b' static ZSTD_compressionParameters ZSTD_c' | |||
|
610 | 701 | CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); |
|
611 | 702 | CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); |
|
612 | 703 | CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); |
|
613 | if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN) cParams.targetLength = ZSTD_TARGETLENGTH_MIN; | |
|
614 | if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra; | |
|
704 | ZSTD_STATIC_ASSERT(ZSTD_TARGETLENGTH_MIN == 0); | |
|
705 | if (cParams.targetLength > ZSTD_TARGETLENGTH_MAX) | |
|
706 | cParams.targetLength = ZSTD_TARGETLENGTH_MAX; | |
|
707 | CLAMP(cParams.strategy, ZSTD_fast, ZSTD_btultra); | |
|
615 | 708 | return cParams; |
|
616 | 709 | } |
|
617 | 710 | |
@@ -627,8 +720,11 b' static U32 ZSTD_cycleLog(U32 hashLog, ZS' | |||
|
627 | 720 | optimize `cPar` for a given input (`srcSize` and `dictSize`). |
|
628 | 721 | mostly downsizing to reduce memory consumption and initialization latency. |
|
629 | 722 | Both `srcSize` and `dictSize` are optional (use 0 if unknown). |
|
630 |
Note : cPar is |
|
|
631 | ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) | |
|
723 | Note : cPar is assumed validated. Use ZSTD_checkCParams() to ensure this condition. */ | |
|
724 | static ZSTD_compressionParameters | |
|
725 | ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, | |
|
726 | unsigned long long srcSize, | |
|
727 | size_t dictSize) | |
|
632 | 728 | { |
|
633 | 729 | static const U64 minSrcSize = 513; /* (1<<9) + 1 */ |
|
634 | 730 | static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); |
@@ -648,7 +744,7 b' ZSTD_compressionParameters ZSTD_adjustCP' | |||
|
648 | 744 | ZSTD_highbit32(tSize-1) + 1; |
|
649 | 745 | if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; |
|
650 | 746 | } |
|
651 | if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; | |
|
747 | if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; | |
|
652 | 748 | { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); |
|
653 | 749 | if (cycleLog > cPar.windowLog) |
|
654 | 750 | cPar.chainLog -= (cycleLog - cPar.windowLog); |
@@ -660,13 +756,34 b' ZSTD_compressionParameters ZSTD_adjustCP' | |||
|
660 | 756 | return cPar; |
|
661 | 757 | } |
|
662 | 758 | |
|
663 | ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) | |
|
759 | ZSTD_compressionParameters | |
|
760 | ZSTD_adjustCParams(ZSTD_compressionParameters cPar, | |
|
761 | unsigned long long srcSize, | |
|
762 | size_t dictSize) | |
|
664 | 763 | { |
|
665 | 764 | cPar = ZSTD_clampCParams(cPar); |
|
666 | 765 | return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); |
|
667 | 766 | } |
|
668 | 767 | |
|
669 | static size_t ZSTD_sizeof_matchState(ZSTD_compressionParameters const* cParams, const U32 forCCtx) | |
|
768 | ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( | |
|
769 | const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) | |
|
770 | { | |
|
771 | ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); | |
|
772 | if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; | |
|
773 | if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; | |
|
774 | if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; | |
|
775 | if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; | |
|
776 | if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; | |
|
777 | if (CCtxParams->cParams.searchLength) cParams.searchLength = CCtxParams->cParams.searchLength; | |
|
778 | if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; | |
|
779 | if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; | |
|
780 | assert(!ZSTD_checkCParams(cParams)); | |
|
781 | return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); | |
|
782 | } | |
|
783 | ||
|
784 | static size_t | |
|
785 | ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, | |
|
786 | const U32 forCCtx) | |
|
670 | 787 | { |
|
671 | 788 | size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); |
|
672 | 789 | size_t const hSize = ((size_t)1) << cParams->hashLog; |
@@ -693,7 +810,7 b' size_t ZSTD_estimateCCtxSize_usingCCtxPa' | |||
|
693 | 810 | size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); |
|
694 | 811 | U32 const divider = (cParams.searchLength==3) ? 3 : 4; |
|
695 | 812 | size_t const maxNbSeq = blockSize / divider; |
|
696 | size_t const tokenSpace = blockSize + 11*maxNbSeq; | |
|
813 | size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq; | |
|
697 | 814 | size_t const entropySpace = HUF_WORKSPACE_SIZE; |
|
698 | 815 | size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); |
|
699 | 816 | size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); |
@@ -752,12 +869,14 b' size_t ZSTD_estimateCStreamSize_usingCPa' | |||
|
752 | 869 | return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); |
|
753 | 870 | } |
|
754 | 871 | |
|
755 |
static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) |
|
|
872 | static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) | |
|
873 | { | |
|
756 | 874 | ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); |
|
757 | 875 | return ZSTD_estimateCStreamSize_usingCParams(cParams); |
|
758 | 876 | } |
|
759 | 877 | |
|
760 |
size_t ZSTD_estimateCStreamSize(int compressionLevel) |
|
|
878 | size_t ZSTD_estimateCStreamSize(int compressionLevel) | |
|
879 | { | |
|
761 | 880 | int level; |
|
762 | 881 | size_t memBudget = 0; |
|
763 | 882 | for (level=1; level<=compressionLevel; level++) { |
@@ -786,9 +905,27 b' ZSTD_frameProgression ZSTD_getFrameProgr' | |||
|
786 | 905 | fp.ingested = cctx->consumedSrcSize + buffered; |
|
787 | 906 | fp.consumed = cctx->consumedSrcSize; |
|
788 | 907 | fp.produced = cctx->producedCSize; |
|
908 | fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */ | |
|
909 | fp.currentJobID = 0; | |
|
910 | fp.nbActiveWorkers = 0; | |
|
789 | 911 | return fp; |
|
790 | 912 | } } |
|
791 | 913 | |
|
914 | /*! ZSTD_toFlushNow() | |
|
915 | * Only useful for multithreading scenarios currently (nbWorkers >= 1). | |
|
916 | */ | |
|
917 | size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx) | |
|
918 | { | |
|
919 | #ifdef ZSTD_MULTITHREAD | |
|
920 | if (cctx->appliedParams.nbWorkers > 0) { | |
|
921 | return ZSTDMT_toFlushNow(cctx->mtctx); | |
|
922 | } | |
|
923 | #endif | |
|
924 | (void)cctx; | |
|
925 | return 0; /* over-simplification; could also check if context is currently running in streaming mode, and in which case, report how many bytes are left to be flushed within output buffer */ | |
|
926 | } | |
|
927 | ||
|
928 | ||
|
792 | 929 | |
|
793 | 930 | static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1, |
|
794 | 931 | ZSTD_compressionParameters cParams2) |
@@ -799,6 +936,20 b' static U32 ZSTD_equivalentCParams(ZSTD_c' | |||
|
799 | 936 | & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */ |
|
800 | 937 | } |
|
801 | 938 | |
|
939 | static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, | |
|
940 | ZSTD_compressionParameters cParams2) | |
|
941 | { | |
|
942 | (void)cParams1; | |
|
943 | (void)cParams2; | |
|
944 | assert(cParams1.windowLog == cParams2.windowLog); | |
|
945 | assert(cParams1.chainLog == cParams2.chainLog); | |
|
946 | assert(cParams1.hashLog == cParams2.hashLog); | |
|
947 | assert(cParams1.searchLog == cParams2.searchLog); | |
|
948 | assert(cParams1.searchLength == cParams2.searchLength); | |
|
949 | assert(cParams1.targetLength == cParams2.targetLength); | |
|
950 | assert(cParams1.strategy == cParams2.strategy); | |
|
951 | } | |
|
952 | ||
|
802 | 953 | /** The parameters are equivalent if ldm is not enabled in both sets or |
|
803 | 954 | * all the parameters are equivalent. */ |
|
804 | 955 | static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1, |
@@ -817,33 +968,51 b' typedef enum { ZSTDb_not_buffered, ZSTDb' | |||
|
817 | 968 | /* ZSTD_sufficientBuff() : |
|
818 | 969 | * check internal buffers exist for streaming if buffPol == ZSTDb_buffered . |
|
819 | 970 | * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */ |
|
820 |
static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t b |
|
|
971 | static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t maxNbSeq1, | |
|
972 | size_t maxNbLit1, | |
|
821 | 973 | ZSTD_buffered_policy_e buffPol2, |
|
822 | 974 | ZSTD_compressionParameters cParams2, |
|
823 | 975 | U64 pledgedSrcSize) |
|
824 | 976 | { |
|
825 | 977 | size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize)); |
|
826 | 978 | size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2); |
|
979 | size_t const maxNbSeq2 = blockSize2 / ((cParams2.searchLength == 3) ? 3 : 4); | |
|
980 | size_t const maxNbLit2 = blockSize2; | |
|
827 | 981 | size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0; |
|
828 |
DEBUGLOG(4, "ZSTD_sufficientBuff: is |
|
|
829 |
(U32) |
|
|
830 |
DEBUGLOG(4, "ZSTD_sufficientBuff: is b |
|
|
831 |
(U32)b |
|
|
832 | return (blockSize2 <= blockSize1) /* seqStore space depends on blockSize */ | |
|
982 | DEBUGLOG(4, "ZSTD_sufficientBuff: is neededBufferSize2=%u <= bufferSize1=%u", | |
|
983 | (U32)neededBufferSize2, (U32)bufferSize1); | |
|
984 | DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbSeq2=%u <= maxNbSeq1=%u", | |
|
985 | (U32)maxNbSeq2, (U32)maxNbSeq1); | |
|
986 | DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbLit2=%u <= maxNbLit1=%u", | |
|
987 | (U32)maxNbLit2, (U32)maxNbLit1); | |
|
988 | return (maxNbLit2 <= maxNbLit1) | |
|
989 | & (maxNbSeq2 <= maxNbSeq1) | |
|
833 | 990 | & (neededBufferSize2 <= bufferSize1); |
|
834 | 991 | } |
|
835 | 992 | |
|
836 | 993 | /** Equivalence for resetCCtx purposes */ |
|
837 | 994 | static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1, |
|
838 | 995 | ZSTD_CCtx_params params2, |
|
839 |
size_t buffSize1, |
|
|
996 | size_t buffSize1, | |
|
997 | size_t maxNbSeq1, size_t maxNbLit1, | |
|
840 | 998 | ZSTD_buffered_policy_e buffPol2, |
|
841 | 999 | U64 pledgedSrcSize) |
|
842 | 1000 | { |
|
843 | 1001 | DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize); |
|
844 |
|
|
|
845 | ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams) && | |
|
846 | ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize); | |
|
1002 | if (!ZSTD_equivalentCParams(params1.cParams, params2.cParams)) { | |
|
1003 | DEBUGLOG(4, "ZSTD_equivalentCParams() == 0"); | |
|
1004 | return 0; | |
|
1005 | } | |
|
1006 | if (!ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams)) { | |
|
1007 | DEBUGLOG(4, "ZSTD_equivalentLdmParams() == 0"); | |
|
1008 | return 0; | |
|
1009 | } | |
|
1010 | if (!ZSTD_sufficientBuff(buffSize1, maxNbSeq1, maxNbLit1, buffPol2, | |
|
1011 | params2.cParams, pledgedSrcSize)) { | |
|
1012 | DEBUGLOG(4, "ZSTD_sufficientBuff() == 0"); | |
|
1013 | return 0; | |
|
1014 | } | |
|
1015 | return 1; | |
|
847 | 1016 | } |
|
848 | 1017 | |
|
849 | 1018 | static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) |
@@ -851,10 +1020,10 b' static void ZSTD_reset_compressedBlockSt' | |||
|
851 | 1020 | int i; |
|
852 | 1021 | for (i = 0; i < ZSTD_REP_NUM; ++i) |
|
853 | 1022 | bs->rep[i] = repStartValue[i]; |
|
854 |
bs->entropy.huf |
|
|
855 | bs->entropy.offcode_repeatMode = FSE_repeat_none; | |
|
856 | bs->entropy.matchlength_repeatMode = FSE_repeat_none; | |
|
857 | bs->entropy.litlength_repeatMode = FSE_repeat_none; | |
|
1023 | bs->entropy.huf.repeatMode = HUF_repeat_none; | |
|
1024 | bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; | |
|
1025 | bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; | |
|
1026 | bs->entropy.fse.litlength_repeatMode = FSE_repeat_none; | |
|
858 | 1027 | } |
|
859 | 1028 | |
|
860 | 1029 | /*! ZSTD_invalidateMatchState() |
@@ -866,8 +1035,10 b' static void ZSTD_invalidateMatchState(ZS' | |||
|
866 | 1035 | ZSTD_window_clear(&ms->window); |
|
867 | 1036 | |
|
868 | 1037 | ms->nextToUpdate = ms->window.dictLimit + 1; |
|
1038 | ms->nextToUpdate3 = ms->window.dictLimit + 1; | |
|
869 | 1039 | ms->loadedDictEnd = 0; |
|
870 | 1040 | ms->opt.litLengthSum = 0; /* force reset of btopt stats */ |
|
1041 | ms->dictMatchState = NULL; | |
|
871 | 1042 | } |
|
872 | 1043 | |
|
873 | 1044 | /*! ZSTD_continueCCtx() : |
@@ -880,6 +1051,7 b' static size_t ZSTD_continueCCtx(ZSTD_CCt' | |||
|
880 | 1051 | |
|
881 | 1052 | cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */ |
|
882 | 1053 | cctx->appliedParams = params; |
|
1054 | cctx->blockState.matchState.cParams = params.cParams; | |
|
883 | 1055 | cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; |
|
884 | 1056 | cctx->consumedSrcSize = 0; |
|
885 | 1057 | cctx->producedCSize = 0; |
@@ -900,7 +1072,11 b' static size_t ZSTD_continueCCtx(ZSTD_CCt' | |||
|
900 | 1072 | |
|
901 | 1073 | typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; |
|
902 | 1074 | |
|
903 | static void* ZSTD_reset_matchState(ZSTD_matchState_t* ms, void* ptr, ZSTD_compressionParameters const* cParams, ZSTD_compResetPolicy_e const crp, U32 const forCCtx) | |
|
1075 | static void* | |
|
1076 | ZSTD_reset_matchState(ZSTD_matchState_t* ms, | |
|
1077 | void* ptr, | |
|
1078 | const ZSTD_compressionParameters* cParams, | |
|
1079 | ZSTD_compResetPolicy_e const crp, U32 const forCCtx) | |
|
904 | 1080 | { |
|
905 | 1081 | size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); |
|
906 | 1082 | size_t const hSize = ((size_t)1) << cParams->hashLog; |
@@ -912,6 +1088,9 b' static void* ZSTD_reset_matchState(ZSTD_' | |||
|
912 | 1088 | |
|
913 | 1089 | ms->hashLog3 = hashLog3; |
|
914 | 1090 | memset(&ms->window, 0, sizeof(ms->window)); |
|
1091 | ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */ | |
|
1092 | ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ | |
|
1093 | ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */ | |
|
915 | 1094 | ZSTD_invalidateMatchState(ms); |
|
916 | 1095 | |
|
917 | 1096 | /* opt parser space */ |
@@ -937,14 +1116,24 b' static void* ZSTD_reset_matchState(ZSTD_' | |||
|
937 | 1116 | ms->hashTable3 = ms->chainTable + chainSize; |
|
938 | 1117 | ptr = ms->hashTable3 + h3Size; |
|
939 | 1118 | |
|
1119 | ms->cParams = *cParams; | |
|
1120 | ||
|
940 | 1121 | assert(((size_t)ptr & 3) == 0); |
|
941 | 1122 | return ptr; |
|
942 | 1123 | } |
|
943 | 1124 | |
|
1125 | #define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */ | |
|
1126 | #define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 /* when workspace is continuously too large | |
|
1127 | * during at least this number of times, | |
|
1128 | * context's memory usage is considered wasteful, | |
|
1129 | * because it's sized to handle a worst case scenario which rarely happens. | |
|
1130 | * In which case, resize it down to free some memory */ | |
|
1131 | ||
|
944 | 1132 | /*! ZSTD_resetCCtx_internal() : |
|
945 | 1133 | note : `params` are assumed fully validated at this stage */ |
|
946 | 1134 | static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, |
|
947 |
ZSTD_CCtx_params params, |
|
|
1135 | ZSTD_CCtx_params params, | |
|
1136 | U64 pledgedSrcSize, | |
|
948 | 1137 | ZSTD_compResetPolicy_e const crp, |
|
949 | 1138 | ZSTD_buffered_policy_e const zbuff) |
|
950 | 1139 | { |
@@ -954,34 +1143,35 b' static size_t ZSTD_resetCCtx_internal(ZS' | |||
|
954 | 1143 | |
|
955 | 1144 | if (crp == ZSTDcrp_continue) { |
|
956 | 1145 | if (ZSTD_equivalentParams(zc->appliedParams, params, |
|
957 |
zc->inBuffSize, |
|
|
958 | zbuff, pledgedSrcSize)) { | |
|
959 | DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%u)", | |
|
960 | zc->appliedParams.cParams.windowLog, (U32)zc->blockSize); | |
|
961 | return ZSTD_continueCCtx(zc, params, pledgedSrcSize); | |
|
1146 | zc->inBuffSize, | |
|
1147 | zc->seqStore.maxNbSeq, zc->seqStore.maxNbLit, | |
|
1148 | zbuff, pledgedSrcSize)) { | |
|
1149 | DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%zu)", | |
|
1150 | zc->appliedParams.cParams.windowLog, zc->blockSize); | |
|
1151 | zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0); /* if it was too large, it still is */ | |
|
1152 | if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION) | |
|
1153 | return ZSTD_continueCCtx(zc, params, pledgedSrcSize); | |
|
962 | 1154 | } } |
|
963 | 1155 | DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx"); |
|
964 | 1156 | |
|
965 | 1157 | if (params.ldmParams.enableLdm) { |
|
966 | 1158 | /* Adjust long distance matching parameters */ |
|
967 | params.ldmParams.windowLog = params.cParams.windowLog; | |
|
968 | 1159 | ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); |
|
969 | 1160 | assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); |
|
970 | 1161 | assert(params.ldmParams.hashEveryLog < 32); |
|
971 | zc->ldmState.hashPower = | |
|
972 | ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength); | |
|
1162 | zc->ldmState.hashPower = ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength); | |
|
973 | 1163 | } |
|
974 | 1164 | |
|
975 | 1165 | { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); |
|
976 | 1166 | size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); |
|
977 | 1167 | U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; |
|
978 | 1168 | size_t const maxNbSeq = blockSize / divider; |
|
979 | size_t const tokenSpace = blockSize + 11*maxNbSeq; | |
|
1169 | size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq; | |
|
980 | 1170 | size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; |
|
981 | 1171 | size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; |
|
982 | 1172 | size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); |
|
983 | 1173 | size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); |
|
984 | void* ptr; | |
|
1174 | void* ptr; /* used to partition workSpace */ | |
|
985 | 1175 | |
|
986 | 1176 | /* Check if workSpace is large enough, alloc a new one if needed */ |
|
987 | 1177 | { size_t const entropySpace = HUF_WORKSPACE_SIZE; |
@@ -993,14 +1183,20 b' static size_t ZSTD_resetCCtx_internal(ZS' | |||
|
993 | 1183 | size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace + |
|
994 | 1184 | ldmSeqSpace + matchStateSize + tokenSpace + |
|
995 | 1185 | bufferSpace; |
|
996 | DEBUGLOG(4, "Need %uKB workspace, including %uKB for match state, and %uKB for buffers", | |
|
997 | (U32)(neededSpace>>10), (U32)(matchStateSize>>10), (U32)(bufferSpace>>10)); | |
|
998 | DEBUGLOG(4, "windowSize: %u - blockSize: %u", (U32)windowSize, (U32)blockSize); | |
|
999 | ||
|
1000 | if (zc->workSpaceSize < neededSpace) { /* too small : resize */ | |
|
1001 | DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK", | |
|
1002 | (unsigned)(zc->workSpaceSize>>10), | |
|
1003 |
|
|
|
1186 | ||
|
1187 | int const workSpaceTooSmall = zc->workSpaceSize < neededSpace; | |
|
1188 | int const workSpaceTooLarge = zc->workSpaceSize > ZSTD_WORKSPACETOOLARGE_FACTOR * neededSpace; | |
|
1189 | int const workSpaceWasteful = workSpaceTooLarge && (zc->workSpaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION); | |
|
1190 | zc->workSpaceOversizedDuration = workSpaceTooLarge ? zc->workSpaceOversizedDuration+1 : 0; | |
|
1191 | ||
|
1192 | DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", | |
|
1193 | neededSpace>>10, matchStateSize>>10, bufferSpace>>10); | |
|
1194 | DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); | |
|
1195 | ||
|
1196 | if (workSpaceTooSmall || workSpaceWasteful) { | |
|
1197 | DEBUGLOG(4, "Need to resize workSpaceSize from %zuKB to %zuKB", | |
|
1198 | zc->workSpaceSize >> 10, | |
|
1199 | neededSpace >> 10); | |
|
1004 | 1200 | /* static cctx : no resize, error out */ |
|
1005 | 1201 | if (zc->staticSize) return ERROR(memory_allocation); |
|
1006 | 1202 | |
@@ -1009,9 +1205,11 b' static size_t ZSTD_resetCCtx_internal(ZS' | |||
|
1009 | 1205 | zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); |
|
1010 | 1206 | if (zc->workSpace == NULL) return ERROR(memory_allocation); |
|
1011 | 1207 | zc->workSpaceSize = neededSpace; |
|
1012 |
|
|
|
1013 | ||
|
1014 | /* Statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ | |
|
1208 | zc->workSpaceOversizedDuration = 0; | |
|
1209 | ||
|
1210 | /* Statically sized space. | |
|
1211 | * entropyWorkspace never moves, | |
|
1212 | * though prev/next block swap places */ | |
|
1015 | 1213 | assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */ |
|
1016 | 1214 | assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t)); |
|
1017 | 1215 | zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace; |
@@ -1022,6 +1220,7 b' static size_t ZSTD_resetCCtx_internal(ZS' | |||
|
1022 | 1220 | |
|
1023 | 1221 | /* init params */ |
|
1024 | 1222 | zc->appliedParams = params; |
|
1223 | zc->blockState.matchState.cParams = params.cParams; | |
|
1025 | 1224 | zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; |
|
1026 | 1225 | zc->consumedSrcSize = 0; |
|
1027 | 1226 | zc->producedCSize = 0; |
@@ -1058,13 +1257,18 b' static size_t ZSTD_resetCCtx_internal(ZS' | |||
|
1058 | 1257 | ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, ¶ms.cParams, crp, /* forCCtx */ 1); |
|
1059 | 1258 | |
|
1060 | 1259 | /* sequences storage */ |
|
1260 | zc->seqStore.maxNbSeq = maxNbSeq; | |
|
1061 | 1261 | zc->seqStore.sequencesStart = (seqDef*)ptr; |
|
1062 | 1262 | ptr = zc->seqStore.sequencesStart + maxNbSeq; |
|
1063 | 1263 | zc->seqStore.llCode = (BYTE*) ptr; |
|
1064 | 1264 | zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; |
|
1065 | 1265 | zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; |
|
1066 | 1266 | zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; |
|
1067 | ptr = zc->seqStore.litStart + blockSize; | |
|
1267 | /* ZSTD_wildcopy() is used to copy into the literals buffer, | |
|
1268 | * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. | |
|
1269 | */ | |
|
1270 | zc->seqStore.maxNbLit = blockSize; | |
|
1271 | ptr = zc->seqStore.litStart + blockSize + WILDCOPY_OVERLENGTH; | |
|
1068 | 1272 | |
|
1069 | 1273 | /* ldm bucketOffsets table */ |
|
1070 | 1274 | if (params.ldmParams.enableLdm) { |
@@ -1098,28 +1302,110 b' void ZSTD_invalidateRepCodes(ZSTD_CCtx* ' | |||
|
1098 | 1302 | assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); |
|
1099 | 1303 | } |
|
1100 | 1304 | |
|
1101 | static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, | |
|
1305 | /* These are the approximate sizes for each strategy past which copying the | |
|
1306 | * dictionary tables into the working context is faster than using them | |
|
1307 | * in-place. | |
|
1308 | */ | |
|
1309 | static const size_t attachDictSizeCutoffs[(unsigned)ZSTD_btultra+1] = { | |
|
1310 | 8 KB, /* unused */ | |
|
1311 | 8 KB, /* ZSTD_fast */ | |
|
1312 | 16 KB, /* ZSTD_dfast */ | |
|
1313 | 32 KB, /* ZSTD_greedy */ | |
|
1314 | 32 KB, /* ZSTD_lazy */ | |
|
1315 | 32 KB, /* ZSTD_lazy2 */ | |
|
1316 | 32 KB, /* ZSTD_btlazy2 */ | |
|
1317 | 32 KB, /* ZSTD_btopt */ | |
|
1318 | 8 KB /* ZSTD_btultra */ | |
|
1319 | }; | |
|
1320 | ||
|
1321 | static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, | |
|
1322 | ZSTD_CCtx_params params, | |
|
1323 | U64 pledgedSrcSize) | |
|
1324 | { | |
|
1325 | size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; | |
|
1326 | return ( pledgedSrcSize <= cutoff | |
|
1327 | || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN | |
|
1328 | || params.attachDictPref == ZSTD_dictForceAttach ) | |
|
1329 | && params.attachDictPref != ZSTD_dictForceCopy | |
|
1330 | && !params.forceWindow; /* dictMatchState isn't correctly | |
|
1331 | * handled in _enforceMaxDist */ | |
|
1332 | } | |
|
1333 | ||
|
1334 | static size_t ZSTD_resetCCtx_byAttachingCDict( | |
|
1335 | ZSTD_CCtx* cctx, | |
|
1336 | const ZSTD_CDict* cdict, | |
|
1337 | ZSTD_CCtx_params params, | |
|
1338 | U64 pledgedSrcSize, | |
|
1339 | ZSTD_buffered_policy_e zbuff) | |
|
1340 | { | |
|
1341 | { | |
|
1342 | const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; | |
|
1343 | unsigned const windowLog = params.cParams.windowLog; | |
|
1344 | assert(windowLog != 0); | |
|
1345 | /* Resize working context table params for input only, since the dict | |
|
1346 | * has its own tables. */ | |
|
1347 | params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); | |
|
1348 | params.cParams.windowLog = windowLog; | |
|
1349 | ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, | |
|
1350 | ZSTDcrp_continue, zbuff); | |
|
1351 | assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); | |
|
1352 | } | |
|
1353 | ||
|
1354 | { | |
|
1355 | const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc | |
|
1356 | - cdict->matchState.window.base); | |
|
1357 | const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit; | |
|
1358 | if (cdictLen == 0) { | |
|
1359 | /* don't even attach dictionaries with no contents */ | |
|
1360 | DEBUGLOG(4, "skipping attaching empty dictionary"); | |
|
1361 | } else { | |
|
1362 | DEBUGLOG(4, "attaching dictionary into context"); | |
|
1363 | cctx->blockState.matchState.dictMatchState = &cdict->matchState; | |
|
1364 | ||
|
1365 | /* prep working match state so dict matches never have negative indices | |
|
1366 | * when they are translated to the working context's index space. */ | |
|
1367 | if (cctx->blockState.matchState.window.dictLimit < cdictEnd) { | |
|
1368 | cctx->blockState.matchState.window.nextSrc = | |
|
1369 | cctx->blockState.matchState.window.base + cdictEnd; | |
|
1370 | ZSTD_window_clear(&cctx->blockState.matchState.window); | |
|
1371 | } | |
|
1372 | cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit; | |
|
1373 | } | |
|
1374 | } | |
|
1375 | ||
|
1376 | cctx->dictID = cdict->dictID; | |
|
1377 | ||
|
1378 | /* copy block state */ | |
|
1379 | memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); | |
|
1380 | ||
|
1381 | return 0; | |
|
1382 | } | |
|
1383 | ||
|
1384 | static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, | |
|
1102 | 1385 | const ZSTD_CDict* cdict, |
|
1103 |
|
|
|
1104 | ZSTD_frameParameters fParams, | |
|
1386 | ZSTD_CCtx_params params, | |
|
1105 | 1387 | U64 pledgedSrcSize, |
|
1106 | 1388 | ZSTD_buffered_policy_e zbuff) |
|
1107 | 1389 | { |
|
1108 | { ZSTD_CCtx_params params = cctx->requestedParams; | |
|
1390 | const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; | |
|
1391 | ||
|
1392 | DEBUGLOG(4, "copying dictionary into context"); | |
|
1393 | ||
|
1394 | { unsigned const windowLog = params.cParams.windowLog; | |
|
1395 | assert(windowLog != 0); | |
|
1109 | 1396 | /* Copy only compression parameters related to tables. */ |
|
1110 |
params.cParams = |
|
|
1111 |
|
|
|
1112 | params.fParams = fParams; | |
|
1397 | params.cParams = *cdict_cParams; | |
|
1398 | params.cParams.windowLog = windowLog; | |
|
1113 | 1399 | ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, |
|
1114 | 1400 | ZSTDcrp_noMemset, zbuff); |
|
1115 |
assert(cctx->appliedParams.cParams.strategy == cdict-> |
|
|
1116 |
assert(cctx->appliedParams.cParams.hashLog == cdict-> |
|
|
1117 |
assert(cctx->appliedParams.cParams.chainLog == cdict-> |
|
|
1401 | assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); | |
|
1402 | assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); | |
|
1403 | assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); | |
|
1118 | 1404 | } |
|
1119 | 1405 | |
|
1120 | 1406 | /* copy tables */ |
|
1121 |
{ size_t const chainSize = (cdict-> |
|
|
1122 |
size_t const hSize = (size_t)1 << cdict-> |
|
|
1407 | { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); | |
|
1408 | size_t const hSize = (size_t)1 << cdict_cParams->hashLog; | |
|
1123 | 1409 | size_t const tableSpace = (chainSize + hSize) * sizeof(U32); |
|
1124 | 1410 | assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ |
|
1125 | 1411 | assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize); |
@@ -1127,6 +1413,7 b' static size_t ZSTD_resetCCtx_usingCDict(' | |||
|
1127 | 1413 | assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize); |
|
1128 | 1414 | memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */ |
|
1129 | 1415 | } |
|
1416 | ||
|
1130 | 1417 | /* Zero the hashTable3, since the cdict never fills it */ |
|
1131 | 1418 | { size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3; |
|
1132 | 1419 | assert(cdict->matchState.hashLog3 == 0); |
@@ -1134,14 +1421,14 b' static size_t ZSTD_resetCCtx_usingCDict(' | |||
|
1134 | 1421 | } |
|
1135 | 1422 | |
|
1136 | 1423 | /* copy dictionary offsets */ |
|
1137 | { | |
|
1138 | ZSTD_matchState_t const* srcMatchState = &cdict->matchState; | |
|
1424 | { ZSTD_matchState_t const* srcMatchState = &cdict->matchState; | |
|
1139 | 1425 | ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; |
|
1140 | 1426 | dstMatchState->window = srcMatchState->window; |
|
1141 | 1427 | dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; |
|
1142 | 1428 | dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; |
|
1143 | 1429 | dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; |
|
1144 | 1430 | } |
|
1431 | ||
|
1145 | 1432 | cctx->dictID = cdict->dictID; |
|
1146 | 1433 | |
|
1147 | 1434 | /* copy block state */ |
@@ -1150,6 +1437,27 b' static size_t ZSTD_resetCCtx_usingCDict(' | |||
|
1150 | 1437 | return 0; |
|
1151 | 1438 | } |
|
1152 | 1439 | |
|
1440 | /* We have a choice between copying the dictionary context into the working | |
|
1441 | * context, or referencing the dictionary context from the working context | |
|
1442 | * in-place. We decide here which strategy to use. */ | |
|
1443 | static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, | |
|
1444 | const ZSTD_CDict* cdict, | |
|
1445 | ZSTD_CCtx_params params, | |
|
1446 | U64 pledgedSrcSize, | |
|
1447 | ZSTD_buffered_policy_e zbuff) | |
|
1448 | { | |
|
1449 | ||
|
1450 | DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)", (U32)pledgedSrcSize); | |
|
1451 | ||
|
1452 | if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) { | |
|
1453 | return ZSTD_resetCCtx_byAttachingCDict( | |
|
1454 | cctx, cdict, params, pledgedSrcSize, zbuff); | |
|
1455 | } else { | |
|
1456 | return ZSTD_resetCCtx_byCopyingCDict( | |
|
1457 | cctx, cdict, params, pledgedSrcSize, zbuff); | |
|
1458 | } | |
|
1459 | } | |
|
1460 | ||
|
1153 | 1461 | /*! ZSTD_copyCCtx_internal() : |
|
1154 | 1462 | * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. |
|
1155 | 1463 | * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). |
@@ -1192,7 +1500,7 b' static size_t ZSTD_copyCCtx_internal(ZST' | |||
|
1192 | 1500 | |
|
1193 | 1501 | /* copy dictionary offsets */ |
|
1194 | 1502 | { |
|
1195 |
ZSTD_matchState_t |
|
|
1503 | const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState; | |
|
1196 | 1504 | ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; |
|
1197 | 1505 | dstMatchState->window = srcMatchState->window; |
|
1198 | 1506 | dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; |
@@ -1294,15 +1602,15 b' static void ZSTD_reduceIndex (ZSTD_CCtx*' | |||
|
1294 | 1602 | |
|
1295 | 1603 | /* See doc/zstd_compression_format.md for detailed format description */ |
|
1296 | 1604 | |
|
1297 | size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) | |
|
1605 | static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) | |
|
1298 | 1606 | { |
|
1607 | U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); | |
|
1299 | 1608 | if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall); |
|
1609 | MEM_writeLE24(dst, cBlockHeader24); | |
|
1300 | 1610 | memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); |
|
1301 | MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw); | |
|
1302 | return ZSTD_blockHeaderSize+srcSize; | |
|
1611 | return ZSTD_blockHeaderSize + srcSize; | |
|
1303 | 1612 | } |
|
1304 | 1613 | |
|
1305 | ||
|
1306 | 1614 | static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize) |
|
1307 | 1615 | { |
|
1308 | 1616 | BYTE* const ostart = (BYTE* const)dst; |
@@ -1356,16 +1664,24 b' static size_t ZSTD_compressRleLiteralsBl' | |||
|
1356 | 1664 | } |
|
1357 | 1665 | |
|
1358 | 1666 | |
|
1359 | static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } | |
|
1360 | ||
|
1361 | static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t const* prevEntropy, | |
|
1362 | ZSTD_entropyCTables_t* nextEntropy, | |
|
1667 | /* ZSTD_minGain() : | |
|
1668 | * minimum compression required | |
|
1669 | * to generate a compress block or a compressed literals section. | |
|
1670 | * note : use same formula for both situations */ | |
|
1671 | static size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) | |
|
1672 | { | |
|
1673 | U32 const minlog = (strat==ZSTD_btultra) ? 7 : 6; | |
|
1674 | return (srcSize >> minlog) + 2; | |
|
1675 | } | |
|
1676 | ||
|
1677 | static size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, | |
|
1678 | ZSTD_hufCTables_t* nextHuf, | |
|
1363 | 1679 | ZSTD_strategy strategy, int disableLiteralCompression, |
|
1364 | 1680 | void* dst, size_t dstCapacity, |
|
1365 | 1681 | const void* src, size_t srcSize, |
|
1366 | 1682 | U32* workspace, const int bmi2) |
|
1367 | 1683 | { |
|
1368 | size_t const minGain = ZSTD_minGain(srcSize); | |
|
1684 | size_t const minGain = ZSTD_minGain(srcSize, strategy); | |
|
1369 | 1685 | size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); |
|
1370 | 1686 | BYTE* const ostart = (BYTE*)dst; |
|
1371 | 1687 | U32 singleStream = srcSize < 256; |
@@ -1376,27 +1692,25 b' static size_t ZSTD_compressLiterals (ZST' | |||
|
1376 | 1692 | disableLiteralCompression); |
|
1377 | 1693 | |
|
1378 | 1694 | /* Prepare nextEntropy assuming reusing the existing table */ |
|
1379 | nextEntropy->hufCTable_repeatMode = prevEntropy->hufCTable_repeatMode; | |
|
1380 | memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, | |
|
1381 | sizeof(prevEntropy->hufCTable)); | |
|
1695 | memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); | |
|
1382 | 1696 | |
|
1383 | 1697 | if (disableLiteralCompression) |
|
1384 | 1698 | return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); |
|
1385 | 1699 | |
|
1386 | 1700 | /* small ? don't even attempt compression (speed opt) */ |
|
1387 | 1701 | # define COMPRESS_LITERALS_SIZE_MIN 63 |
|
1388 |
{ size_t const minLitSize = (prev |
|
|
1702 | { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; | |
|
1389 | 1703 | if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); |
|
1390 | 1704 | } |
|
1391 | 1705 | |
|
1392 | 1706 | if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ |
|
1393 |
{ HUF_repeat repeat = prev |
|
|
1707 | { HUF_repeat repeat = prevHuf->repeatMode; | |
|
1394 | 1708 | int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; |
|
1395 | 1709 | if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; |
|
1396 | 1710 | cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, |
|
1397 |
workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)next |
|
|
1711 | workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) | |
|
1398 | 1712 | : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, |
|
1399 |
workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)next |
|
|
1713 | workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2); | |
|
1400 | 1714 | if (repeat != HUF_repeat_none) { |
|
1401 | 1715 | /* reused the existing table */ |
|
1402 | 1716 | hType = set_repeat; |
@@ -1404,17 +1718,17 b' static size_t ZSTD_compressLiterals (ZST' | |||
|
1404 | 1718 | } |
|
1405 | 1719 | |
|
1406 | 1720 | if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) { |
|
1407 |
memcpy(next |
|
|
1721 | memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); | |
|
1408 | 1722 | return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); |
|
1409 | 1723 | } |
|
1410 | 1724 | if (cLitSize==1) { |
|
1411 |
memcpy(next |
|
|
1725 | memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); | |
|
1412 | 1726 | return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); |
|
1413 | 1727 | } |
|
1414 | 1728 | |
|
1415 | 1729 | if (hType == set_compressed) { |
|
1416 | 1730 | /* using a newly constructed table */ |
|
1417 |
next |
|
|
1731 | nextHuf->repeatMode = HUF_repeat_check; | |
|
1418 | 1732 | } |
|
1419 | 1733 | |
|
1420 | 1734 | /* Build header */ |
@@ -1451,6 +1765,7 b' void ZSTD_seqToCodes(const seqStore_t* s' | |||
|
1451 | 1765 | BYTE* const mlCodeTable = seqStorePtr->mlCode; |
|
1452 | 1766 | U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); |
|
1453 | 1767 | U32 u; |
|
1768 | assert(nbSeq <= seqStorePtr->maxNbSeq); | |
|
1454 | 1769 | for (u=0; u<nbSeq; u++) { |
|
1455 | 1770 | U32 const llv = sequences[u].litLength; |
|
1456 | 1771 | U32 const mlv = sequences[u].matchLength; |
@@ -1464,61 +1779,234 b' void ZSTD_seqToCodes(const seqStore_t* s' | |||
|
1464 | 1779 | mlCodeTable[seqStorePtr->longLengthPos] = MaxML; |
|
1465 | 1780 | } |
|
1466 | 1781 | |
|
1782 | ||
|
1783 | /** | |
|
1784 | * -log2(x / 256) lookup table for x in [0, 256). | |
|
1785 | * If x == 0: Return 0 | |
|
1786 | * Else: Return floor(-log2(x / 256) * 256) | |
|
1787 | */ | |
|
1788 | static unsigned const kInverseProbabiltyLog256[256] = { | |
|
1789 | 0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162, | |
|
1790 | 1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889, | |
|
1791 | 874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734, | |
|
1792 | 724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626, | |
|
1793 | 618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542, | |
|
1794 | 535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473, | |
|
1795 | 468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415, | |
|
1796 | 411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366, | |
|
1797 | 362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322, | |
|
1798 | 318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282, | |
|
1799 | 279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247, | |
|
1800 | 244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215, | |
|
1801 | 212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185, | |
|
1802 | 182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157, | |
|
1803 | 155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132, | |
|
1804 | 130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108, | |
|
1805 | 106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85, | |
|
1806 | 83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64, | |
|
1807 | 62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44, | |
|
1808 | 42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25, | |
|
1809 | 23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7, | |
|
1810 | 5, 4, 2, 1, | |
|
1811 | }; | |
|
1812 | ||
|
1813 | ||
|
1814 | /** | |
|
1815 | * Returns the cost in bits of encoding the distribution described by count | |
|
1816 | * using the entropy bound. | |
|
1817 | */ | |
|
1818 | static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total) | |
|
1819 | { | |
|
1820 | unsigned cost = 0; | |
|
1821 | unsigned s; | |
|
1822 | for (s = 0; s <= max; ++s) { | |
|
1823 | unsigned norm = (unsigned)((256 * count[s]) / total); | |
|
1824 | if (count[s] != 0 && norm == 0) | |
|
1825 | norm = 1; | |
|
1826 | assert(count[s] < total); | |
|
1827 | cost += count[s] * kInverseProbabiltyLog256[norm]; | |
|
1828 | } | |
|
1829 | return cost >> 8; | |
|
1830 | } | |
|
1831 | ||
|
1832 | ||
|
1833 | /** | |
|
1834 | * Returns the cost in bits of encoding the distribution in count using the | |
|
1835 | * table described by norm. The max symbol support by norm is assumed >= max. | |
|
1836 | * norm must be valid for every symbol with non-zero probability in count. | |
|
1837 | */ | |
|
1838 | static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, | |
|
1839 | unsigned const* count, unsigned const max) | |
|
1840 | { | |
|
1841 | unsigned const shift = 8 - accuracyLog; | |
|
1842 | size_t cost = 0; | |
|
1843 | unsigned s; | |
|
1844 | assert(accuracyLog <= 8); | |
|
1845 | for (s = 0; s <= max; ++s) { | |
|
1846 | unsigned const normAcc = norm[s] != -1 ? norm[s] : 1; | |
|
1847 | unsigned const norm256 = normAcc << shift; | |
|
1848 | assert(norm256 > 0); | |
|
1849 | assert(norm256 < 256); | |
|
1850 | cost += count[s] * kInverseProbabiltyLog256[norm256]; | |
|
1851 | } | |
|
1852 | return cost >> 8; | |
|
1853 | } | |
|
1854 | ||
|
1855 | ||
|
1856 | static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) { | |
|
1857 | void const* ptr = ctable; | |
|
1858 | U16 const* u16ptr = (U16 const*)ptr; | |
|
1859 | U32 const maxSymbolValue = MEM_read16(u16ptr + 1); | |
|
1860 | return maxSymbolValue; | |
|
1861 | } | |
|
1862 | ||
|
1863 | ||
|
1864 | /** | |
|
1865 | * Returns the cost in bits of encoding the distribution in count using ctable. | |
|
1866 | * Returns an error if ctable cannot represent all the symbols in count. | |
|
1867 | */ | |
|
1868 | static size_t ZSTD_fseBitCost( | |
|
1869 | FSE_CTable const* ctable, | |
|
1870 | unsigned const* count, | |
|
1871 | unsigned const max) | |
|
1872 | { | |
|
1873 | unsigned const kAccuracyLog = 8; | |
|
1874 | size_t cost = 0; | |
|
1875 | unsigned s; | |
|
1876 | FSE_CState_t cstate; | |
|
1877 | FSE_initCState(&cstate, ctable); | |
|
1878 | if (ZSTD_getFSEMaxSymbolValue(ctable) < max) { | |
|
1879 | DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u", | |
|
1880 | ZSTD_getFSEMaxSymbolValue(ctable), max); | |
|
1881 | return ERROR(GENERIC); | |
|
1882 | } | |
|
1883 | for (s = 0; s <= max; ++s) { | |
|
1884 | unsigned const tableLog = cstate.stateLog; | |
|
1885 | unsigned const badCost = (tableLog + 1) << kAccuracyLog; | |
|
1886 | unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog); | |
|
1887 | if (count[s] == 0) | |
|
1888 | continue; | |
|
1889 | if (bitCost >= badCost) { | |
|
1890 | DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s); | |
|
1891 | return ERROR(GENERIC); | |
|
1892 | } | |
|
1893 | cost += count[s] * bitCost; | |
|
1894 | } | |
|
1895 | return cost >> kAccuracyLog; | |
|
1896 | } | |
|
1897 | ||
|
1898 | /** | |
|
1899 | * Returns the cost in bytes of encoding the normalized count header. | |
|
1900 | * Returns an error if any of the helper functions return an error. | |
|
1901 | */ | |
|
1902 | static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max, | |
|
1903 | size_t const nbSeq, unsigned const FSELog) | |
|
1904 | { | |
|
1905 | BYTE wksp[FSE_NCOUNTBOUND]; | |
|
1906 | S16 norm[MaxSeq + 1]; | |
|
1907 | const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); | |
|
1908 | CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq, max)); | |
|
1909 | return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog); | |
|
1910 | } | |
|
1911 | ||
|
1912 | ||
|
1467 | 1913 | typedef enum { |
|
1468 | 1914 | ZSTD_defaultDisallowed = 0, |
|
1469 | 1915 | ZSTD_defaultAllowed = 1 |
|
1470 | 1916 | } ZSTD_defaultPolicy_e; |
|
1471 | 1917 | |
|
1472 | MEM_STATIC | |
|
1473 |
|
|
|
1474 |
FSE_repeat* repeatMode, |
|
|
1475 | U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed) | |
|
1918 | MEM_STATIC symbolEncodingType_e | |
|
1919 | ZSTD_selectEncodingType( | |
|
1920 | FSE_repeat* repeatMode, unsigned const* count, unsigned const max, | |
|
1921 | size_t const mostFrequent, size_t nbSeq, unsigned const FSELog, | |
|
1922 | FSE_CTable const* prevCTable, | |
|
1923 | short const* defaultNorm, U32 defaultNormLog, | |
|
1924 | ZSTD_defaultPolicy_e const isDefaultAllowed, | |
|
1925 | ZSTD_strategy const strategy) | |
|
1476 | 1926 | { |
|
1477 | #define MIN_SEQ_FOR_DYNAMIC_FSE 64 | |
|
1478 | #define MAX_SEQ_FOR_STATIC_FSE 1000 | |
|
1479 | 1927 | ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0); |
|
1480 |
if |
|
|
1928 | if (mostFrequent == nbSeq) { | |
|
1929 | *repeatMode = FSE_repeat_none; | |
|
1930 | if (isDefaultAllowed && nbSeq <= 2) { | |
|
1931 | /* Prefer set_basic over set_rle when there are 2 or less symbols, | |
|
1932 | * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. | |
|
1933 | * If basic encoding isn't possible, always choose RLE. | |
|
1934 | */ | |
|
1935 | DEBUGLOG(5, "Selected set_basic"); | |
|
1936 | return set_basic; | |
|
1937 | } | |
|
1481 | 1938 | DEBUGLOG(5, "Selected set_rle"); |
|
1482 | /* Prefer set_basic over set_rle when there are 2 or less symbols, | |
|
1483 | * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. | |
|
1484 | * If basic encoding isn't possible, always choose RLE. | |
|
1485 | */ | |
|
1486 | *repeatMode = FSE_repeat_check; | |
|
1487 | 1939 | return set_rle; |
|
1488 | 1940 | } |
|
1489 | if ( isDefaultAllowed | |
|
1490 | && (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { | |
|
1491 | DEBUGLOG(5, "Selected set_repeat"); | |
|
1492 | return set_repeat; | |
|
1493 | } | |
|
1494 | if ( isDefaultAllowed | |
|
1495 | && ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) ) { | |
|
1496 | DEBUGLOG(5, "Selected set_basic"); | |
|
1497 | /* The format allows default tables to be repeated, but it isn't useful. | |
|
1498 | * When using simple heuristics to select encoding type, we don't want | |
|
1499 | * to confuse these tables with dictionaries. When running more careful | |
|
1500 | * analysis, we don't need to waste time checking both repeating tables | |
|
1501 | * and default tables. | |
|
1502 | */ | |
|
1503 | *repeatMode = FSE_repeat_none; | |
|
1504 | return set_basic; | |
|
1941 | if (strategy < ZSTD_lazy) { | |
|
1942 | if (isDefaultAllowed) { | |
|
1943 | size_t const staticFse_nbSeq_max = 1000; | |
|
1944 | size_t const mult = 10 - strategy; | |
|
1945 | size_t const baseLog = 3; | |
|
1946 | size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */ | |
|
1947 | assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */ | |
|
1948 | assert(mult <= 9 && mult >= 7); | |
|
1949 | if ( (*repeatMode == FSE_repeat_valid) | |
|
1950 | && (nbSeq < staticFse_nbSeq_max) ) { | |
|
1951 | DEBUGLOG(5, "Selected set_repeat"); | |
|
1952 | return set_repeat; | |
|
1953 | } | |
|
1954 | if ( (nbSeq < dynamicFse_nbSeq_min) | |
|
1955 | || (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) { | |
|
1956 | DEBUGLOG(5, "Selected set_basic"); | |
|
1957 | /* The format allows default tables to be repeated, but it isn't useful. | |
|
1958 | * When using simple heuristics to select encoding type, we don't want | |
|
1959 | * to confuse these tables with dictionaries. When running more careful | |
|
1960 | * analysis, we don't need to waste time checking both repeating tables | |
|
1961 | * and default tables. | |
|
1962 | */ | |
|
1963 | *repeatMode = FSE_repeat_none; | |
|
1964 | return set_basic; | |
|
1965 | } | |
|
1966 | } | |
|
1967 | } else { | |
|
1968 | size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC); | |
|
1969 | size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC); | |
|
1970 | size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog); | |
|
1971 | size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq); | |
|
1972 | ||
|
1973 | if (isDefaultAllowed) { | |
|
1974 | assert(!ZSTD_isError(basicCost)); | |
|
1975 | assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost))); | |
|
1976 | } | |
|
1977 | assert(!ZSTD_isError(NCountCost)); | |
|
1978 | assert(compressedCost < ERROR(maxCode)); | |
|
1979 | DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u", | |
|
1980 | (U32)basicCost, (U32)repeatCost, (U32)compressedCost); | |
|
1981 | if (basicCost <= repeatCost && basicCost <= compressedCost) { | |
|
1982 | DEBUGLOG(5, "Selected set_basic"); | |
|
1983 | assert(isDefaultAllowed); | |
|
1984 | *repeatMode = FSE_repeat_none; | |
|
1985 | return set_basic; | |
|
1986 | } | |
|
1987 | if (repeatCost <= compressedCost) { | |
|
1988 | DEBUGLOG(5, "Selected set_repeat"); | |
|
1989 | assert(!ZSTD_isError(repeatCost)); | |
|
1990 | return set_repeat; | |
|
1991 | } | |
|
1992 | assert(compressedCost < basicCost && compressedCost < repeatCost); | |
|
1505 | 1993 | } |
|
1506 | 1994 | DEBUGLOG(5, "Selected set_compressed"); |
|
1507 | 1995 | *repeatMode = FSE_repeat_check; |
|
1508 | 1996 | return set_compressed; |
|
1509 | 1997 | } |
|
1510 | 1998 | |
|
1511 | MEM_STATIC | |
|
1512 |
|
|
|
1513 | FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, | |
|
1514 | U32* count, U32 max, | |
|
1515 |
BYTE |
|
|
1516 |
S16 |
|
|
1517 |
FSE_CTable |
|
|
1518 | void* workspace, size_t workspaceSize) | |
|
1999 | MEM_STATIC size_t | |
|
2000 | ZSTD_buildCTable(void* dst, size_t dstCapacity, | |
|
2001 | FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, | |
|
2002 | U32* count, U32 max, | |
|
2003 | const BYTE* codeTable, size_t nbSeq, | |
|
2004 | const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax, | |
|
2005 | const FSE_CTable* prevCTable, size_t prevCTableSize, | |
|
2006 | void* workspace, size_t workspaceSize) | |
|
1519 | 2007 | { |
|
1520 | 2008 | BYTE* op = (BYTE*)dst; |
|
1521 |
BYTE |
|
|
2009 | const BYTE* const oend = op + dstCapacity; | |
|
1522 | 2010 | |
|
1523 | 2011 | switch (type) { |
|
1524 | 2012 | case set_rle: |
@@ -1674,7 +2162,7 b' ZSTD_encodeSequences_bmi2(' | |||
|
1674 | 2162 | |
|
1675 | 2163 | #endif |
|
1676 | 2164 | |
|
1677 | size_t ZSTD_encodeSequences( | |
|
2165 | static size_t ZSTD_encodeSequences( | |
|
1678 | 2166 | void* dst, size_t dstCapacity, |
|
1679 | 2167 | FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, |
|
1680 | 2168 | FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, |
@@ -1706,10 +2194,11 b' MEM_STATIC size_t ZSTD_compressSequences' | |||
|
1706 | 2194 | const int bmi2) |
|
1707 | 2195 | { |
|
1708 | 2196 | const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; |
|
2197 | ZSTD_strategy const strategy = cctxParams->cParams.strategy; | |
|
1709 | 2198 | U32 count[MaxSeq+1]; |
|
1710 | FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; | |
|
1711 | FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; | |
|
1712 | FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; | |
|
2199 | FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; | |
|
2200 | FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; | |
|
2201 | FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; | |
|
1713 | 2202 | U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ |
|
1714 | 2203 | const seqDef* const sequences = seqStorePtr->sequencesStart; |
|
1715 | 2204 | const BYTE* const ofCodeTable = seqStorePtr->ofCode; |
@@ -1720,15 +2209,17 b' MEM_STATIC size_t ZSTD_compressSequences' | |||
|
1720 | 2209 | BYTE* op = ostart; |
|
1721 | 2210 | size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; |
|
1722 | 2211 | BYTE* seqHead; |
|
2212 | BYTE* lastNCount = NULL; | |
|
1723 | 2213 | |
|
1724 | 2214 | ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); |
|
1725 | 2215 | |
|
1726 | 2216 | /* Compress literals */ |
|
1727 | 2217 | { const BYTE* const literals = seqStorePtr->litStart; |
|
1728 | 2218 | size_t const litSize = seqStorePtr->lit - literals; |
|
2219 | int const disableLiteralCompression = (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); | |
|
1729 | 2220 | size_t const cSize = ZSTD_compressLiterals( |
|
1730 | prevEntropy, nextEntropy, | |
|
1731 |
cctxParams->cParams.strategy, |
|
|
2221 | &prevEntropy->huf, &nextEntropy->huf, | |
|
2222 | cctxParams->cParams.strategy, disableLiteralCompression, | |
|
1732 | 2223 | op, dstCapacity, |
|
1733 | 2224 | literals, litSize, |
|
1734 | 2225 | workspace, bmi2); |
@@ -1747,13 +2238,9 b' MEM_STATIC size_t ZSTD_compressSequences' | |||
|
1747 | 2238 | else |
|
1748 | 2239 | op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; |
|
1749 | 2240 | if (nbSeq==0) { |
|
1750 | memcpy(nextEntropy->litlengthCTable, prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable)); | |
|
1751 | nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; | |
|
1752 | memcpy(nextEntropy->offcodeCTable, prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable)); | |
|
1753 | nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; | |
|
1754 | memcpy(nextEntropy->matchlengthCTable, prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable)); | |
|
1755 | nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; | |
|
1756 | return op - ostart; | |
|
2241 | /* Copy the old tables over as if we repeated them */ | |
|
2242 | memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); | |
|
2243 | return op - ostart; | |
|
1757 | 2244 | } |
|
1758 | 2245 | |
|
1759 | 2246 | /* seqHead : flags for FSE encoding type */ |
@@ -1763,43 +2250,53 b' MEM_STATIC size_t ZSTD_compressSequences' | |||
|
1763 | 2250 | ZSTD_seqToCodes(seqStorePtr); |
|
1764 | 2251 | /* build CTable for Literal Lengths */ |
|
1765 | 2252 | { U32 max = MaxLL; |
|
1766 |
size_t const mostFrequent = |
|
|
2253 | size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace); /* can't fail */ | |
|
1767 | 2254 | DEBUGLOG(5, "Building LL table"); |
|
1768 | nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; | |
|
1769 | LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed); | |
|
2255 | nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; | |
|
2256 | LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, count, max, mostFrequent, nbSeq, LLFSELog, prevEntropy->fse.litlengthCTable, LL_defaultNorm, LL_defaultNormLog, ZSTD_defaultAllowed, strategy); | |
|
2257 | assert(set_basic < set_compressed && set_rle < set_compressed); | |
|
2258 | assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ | |
|
1770 | 2259 | { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, |
|
1771 | count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, | |
|
1772 | prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable), | |
|
1773 | workspace, HUF_WORKSPACE_SIZE); | |
|
2260 | count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, | |
|
2261 | prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable), | |
|
2262 | workspace, HUF_WORKSPACE_SIZE); | |
|
1774 | 2263 | if (ZSTD_isError(countSize)) return countSize; |
|
2264 | if (LLtype == set_compressed) | |
|
2265 | lastNCount = op; | |
|
1775 | 2266 | op += countSize; |
|
1776 | 2267 | } } |
|
1777 | 2268 | /* build CTable for Offsets */ |
|
1778 | 2269 | { U32 max = MaxOff; |
|
1779 |
size_t const mostFrequent = |
|
|
2270 | size_t const mostFrequent = HIST_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace); /* can't fail */ | |
|
1780 | 2271 | /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ |
|
1781 | 2272 | ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; |
|
1782 | 2273 | DEBUGLOG(5, "Building OF table"); |
|
1783 | nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; | |
|
1784 | Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy); | |
|
2274 | nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; | |
|
2275 | Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, count, max, mostFrequent, nbSeq, OffFSELog, prevEntropy->fse.offcodeCTable, OF_defaultNorm, OF_defaultNormLog, defaultPolicy, strategy); | |
|
2276 | assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ | |
|
1785 | 2277 | { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, |
|
1786 | count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, | |
|
1787 | prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable), | |
|
1788 | workspace, HUF_WORKSPACE_SIZE); | |
|
2278 | count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, | |
|
2279 | prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable), | |
|
2280 | workspace, HUF_WORKSPACE_SIZE); | |
|
1789 | 2281 | if (ZSTD_isError(countSize)) return countSize; |
|
2282 | if (Offtype == set_compressed) | |
|
2283 | lastNCount = op; | |
|
1790 | 2284 | op += countSize; |
|
1791 | 2285 | } } |
|
1792 | 2286 | /* build CTable for MatchLengths */ |
|
1793 | 2287 | { U32 max = MaxML; |
|
1794 |
size_t const mostFrequent = |
|
|
2288 | size_t const mostFrequent = HIST_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace); /* can't fail */ | |
|
1795 | 2289 | DEBUGLOG(5, "Building ML table"); |
|
1796 | nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; | |
|
1797 | MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed); | |
|
2290 | nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; | |
|
2291 | MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, count, max, mostFrequent, nbSeq, MLFSELog, prevEntropy->fse.matchlengthCTable, ML_defaultNorm, ML_defaultNormLog, ZSTD_defaultAllowed, strategy); | |
|
2292 | assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ | |
|
1798 | 2293 | { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, |
|
1799 | count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, | |
|
1800 | prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable), | |
|
1801 | workspace, HUF_WORKSPACE_SIZE); | |
|
2294 | count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, | |
|
2295 | prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable), | |
|
2296 | workspace, HUF_WORKSPACE_SIZE); | |
|
1802 | 2297 | if (ZSTD_isError(countSize)) return countSize; |
|
2298 | if (MLtype == set_compressed) | |
|
2299 | lastNCount = op; | |
|
1803 | 2300 | op += countSize; |
|
1804 | 2301 | } } |
|
1805 | 2302 | |
@@ -1814,21 +2311,37 b' MEM_STATIC size_t ZSTD_compressSequences' | |||
|
1814 | 2311 | longOffsets, bmi2); |
|
1815 | 2312 | if (ZSTD_isError(bitstreamSize)) return bitstreamSize; |
|
1816 | 2313 | op += bitstreamSize; |
|
2314 | /* zstd versions <= 1.3.4 mistakenly report corruption when | |
|
2315 | * FSE_readNCount() recieves a buffer < 4 bytes. | |
|
2316 | * Fixed by https://github.com/facebook/zstd/pull/1146. | |
|
2317 | * This can happen when the last set_compressed table present is 2 | |
|
2318 | * bytes and the bitstream is only one byte. | |
|
2319 | * In this exceedingly rare case, we will simply emit an uncompressed | |
|
2320 | * block, since it isn't worth optimizing. | |
|
2321 | */ | |
|
2322 | if (lastNCount && (op - lastNCount) < 4) { | |
|
2323 | /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ | |
|
2324 | assert(op - lastNCount == 3); | |
|
2325 | DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " | |
|
2326 | "emitting an uncompressed block."); | |
|
2327 | return 0; | |
|
2328 | } | |
|
1817 | 2329 | } |
|
1818 | 2330 | |
|
1819 | 2331 | return op - ostart; |
|
1820 | 2332 | } |
|
1821 | 2333 | |
|
1822 | 2334 | MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr, |
|
1823 |
|
|
|
2335 | const ZSTD_entropyCTables_t* prevEntropy, | |
|
1824 | 2336 | ZSTD_entropyCTables_t* nextEntropy, |
|
1825 |
|
|
|
2337 | const ZSTD_CCtx_params* cctxParams, | |
|
1826 | 2338 | void* dst, size_t dstCapacity, |
|
1827 | 2339 | size_t srcSize, U32* workspace, int bmi2) |
|
1828 | 2340 | { |
|
1829 | 2341 | size_t const cSize = ZSTD_compressSequences_internal( |
|
1830 | 2342 | seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity, |
|
1831 | 2343 | workspace, bmi2); |
|
2344 | if (cSize == 0) return 0; | |
|
1832 | 2345 | /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. |
|
1833 | 2346 | * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. |
|
1834 | 2347 | */ |
@@ -1837,40 +2350,55 b' MEM_STATIC size_t ZSTD_compressSequences' | |||
|
1837 | 2350 | if (ZSTD_isError(cSize)) return cSize; |
|
1838 | 2351 | |
|
1839 | 2352 | /* Check compressibility */ |
|
1840 |
{ size_t const maxCSize = srcSize - ZSTD_minGain(srcSize); |
|
|
2353 | { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); | |
|
1841 | 2354 | if (cSize >= maxCSize) return 0; /* block not compressed */ |
|
1842 | 2355 | } |
|
1843 | 2356 | |
|
1844 | /* We check that dictionaries have offset codes available for the first | |
|
1845 | * block. After the first block, the offcode table might not have large | |
|
1846 | * enough codes to represent the offsets in the data. | |
|
1847 | */ | |
|
1848 | if (nextEntropy->offcode_repeatMode == FSE_repeat_valid) | |
|
1849 | nextEntropy->offcode_repeatMode = FSE_repeat_check; | |
|
1850 | ||
|
1851 | 2357 | return cSize; |
|
1852 | 2358 | } |
|
1853 | 2359 | |
|
1854 | 2360 | /* ZSTD_selectBlockCompressor() : |
|
1855 | 2361 | * Not static, but internal use only (used by long distance matcher) |
|
1856 | 2362 | * assumption : strat is a valid strategy */ |
|
1857 |
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, |
|
|
2363 | ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) | |
|
1858 | 2364 | { |
|
1859 |
static const ZSTD_blockCompressor blockCompressor[ |
|
|
2365 | static const ZSTD_blockCompressor blockCompressor[3][(unsigned)ZSTD_btultra+1] = { | |
|
1860 | 2366 | { ZSTD_compressBlock_fast /* default for 0 */, |
|
1861 | ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, | |
|
1862 | ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, | |
|
1863 |
ZSTD_compressBlock_ |
|
|
2367 | ZSTD_compressBlock_fast, | |
|
2368 | ZSTD_compressBlock_doubleFast, | |
|
2369 | ZSTD_compressBlock_greedy, | |
|
2370 | ZSTD_compressBlock_lazy, | |
|
2371 | ZSTD_compressBlock_lazy2, | |
|
2372 | ZSTD_compressBlock_btlazy2, | |
|
2373 | ZSTD_compressBlock_btopt, | |
|
2374 | ZSTD_compressBlock_btultra }, | |
|
1864 | 2375 | { ZSTD_compressBlock_fast_extDict /* default for 0 */, |
|
1865 | ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, | |
|
1866 | ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, | |
|
1867 |
ZSTD_compressBlock_ |
|
|
2376 | ZSTD_compressBlock_fast_extDict, | |
|
2377 | ZSTD_compressBlock_doubleFast_extDict, | |
|
2378 | ZSTD_compressBlock_greedy_extDict, | |
|
2379 | ZSTD_compressBlock_lazy_extDict, | |
|
2380 | ZSTD_compressBlock_lazy2_extDict, | |
|
2381 | ZSTD_compressBlock_btlazy2_extDict, | |
|
2382 | ZSTD_compressBlock_btopt_extDict, | |
|
2383 | ZSTD_compressBlock_btultra_extDict }, | |
|
2384 | { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, | |
|
2385 | ZSTD_compressBlock_fast_dictMatchState, | |
|
2386 | ZSTD_compressBlock_doubleFast_dictMatchState, | |
|
2387 | ZSTD_compressBlock_greedy_dictMatchState, | |
|
2388 | ZSTD_compressBlock_lazy_dictMatchState, | |
|
2389 | ZSTD_compressBlock_lazy2_dictMatchState, | |
|
2390 | ZSTD_compressBlock_btlazy2_dictMatchState, | |
|
2391 | ZSTD_compressBlock_btopt_dictMatchState, | |
|
2392 | ZSTD_compressBlock_btultra_dictMatchState } | |
|
1868 | 2393 | }; |
|
2394 | ZSTD_blockCompressor selectedCompressor; | |
|
1869 | 2395 | ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); |
|
1870 | 2396 | |
|
1871 | 2397 | assert((U32)strat >= (U32)ZSTD_fast); |
|
1872 | 2398 | assert((U32)strat <= (U32)ZSTD_btultra); |
|
1873 |
|
|
|
2399 | selectedCompressor = blockCompressor[(int)dictMode][(U32)strat]; | |
|
2400 | assert(selectedCompressor != NULL); | |
|
2401 | return selectedCompressor; | |
|
1874 | 2402 | } |
|
1875 | 2403 | |
|
1876 | 2404 | static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, |
@@ -1880,7 +2408,7 b' static void ZSTD_storeLastLiterals(seqSt' | |||
|
1880 | 2408 | seqStorePtr->lit += lastLLSize; |
|
1881 | 2409 | } |
|
1882 | 2410 | |
|
1883 |
|
|
|
2411 | void ZSTD_resetSeqStore(seqStore_t* ssPtr) | |
|
1884 | 2412 | { |
|
1885 | 2413 | ssPtr->lit = ssPtr->litStart; |
|
1886 | 2414 | ssPtr->sequences = ssPtr->sequencesStart; |
@@ -1892,24 +2420,38 b' static size_t ZSTD_compressBlock_interna' | |||
|
1892 | 2420 | const void* src, size_t srcSize) |
|
1893 | 2421 | { |
|
1894 | 2422 | ZSTD_matchState_t* const ms = &zc->blockState.matchState; |
|
1895 | DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", | |
|
1896 | (U32)dstCapacity, ms->window.dictLimit, ms->nextToUpdate); | |
|
2423 | size_t cSize; | |
|
2424 | DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%zu, dictLimit=%u, nextToUpdate=%u)", | |
|
2425 | dstCapacity, ms->window.dictLimit, ms->nextToUpdate); | |
|
2426 | assert(srcSize <= ZSTD_BLOCKSIZE_MAX); | |
|
2427 | ||
|
2428 | /* Assert that we have correctly flushed the ctx params into the ms's copy */ | |
|
2429 | ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); | |
|
2430 | ||
|
1897 | 2431 | if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { |
|
1898 | 2432 | ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.searchLength); |
|
1899 | return 0; /* don't even attempt compression below a certain srcSize */ | |
|
2433 | cSize = 0; | |
|
2434 | goto out; /* don't even attempt compression below a certain srcSize */ | |
|
1900 | 2435 | } |
|
1901 | 2436 | ZSTD_resetSeqStore(&(zc->seqStore)); |
|
2437 | ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; /* required for optimal parser to read stats from dictionary */ | |
|
2438 | ||
|
2439 | /* a gap between an attached dict and the current window is not safe, | |
|
2440 | * they must remain adjacent, and when that stops being the case, the dict | |
|
2441 | * must be unset */ | |
|
2442 | assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit); | |
|
1902 | 2443 | |
|
1903 | 2444 | /* limited update after a very long match */ |
|
1904 | 2445 | { const BYTE* const base = ms->window.base; |
|
1905 | 2446 | const BYTE* const istart = (const BYTE*)src; |
|
1906 | 2447 | const U32 current = (U32)(istart-base); |
|
2448 | if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ | |
|
1907 | 2449 | if (current > ms->nextToUpdate + 384) |
|
1908 | 2450 | ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); |
|
1909 | 2451 | } |
|
1910 | 2452 | |
|
1911 | 2453 | /* select and store sequences */ |
|
1912 | { U32 const extDict = ZSTD_window_hasExtDict(ms->window); | |
|
2454 | { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms); | |
|
1913 | 2455 | size_t lastLLSize; |
|
1914 | 2456 | { int i; |
|
1915 | 2457 | for (i = 0; i < ZSTD_REP_NUM; ++i) |
@@ -1922,8 +2464,7 b' static size_t ZSTD_compressBlock_interna' | |||
|
1922 | 2464 | ZSTD_ldm_blockCompress(&zc->externSeqStore, |
|
1923 | 2465 | ms, &zc->seqStore, |
|
1924 | 2466 | zc->blockState.nextCBlock->rep, |
|
1925 |
|
|
|
1926 | src, srcSize, extDict); | |
|
2467 | src, srcSize); | |
|
1927 | 2468 | assert(zc->externSeqStore.pos <= zc->externSeqStore.size); |
|
1928 | 2469 | } else if (zc->appliedParams.ldmParams.enableLdm) { |
|
1929 | 2470 | rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; |
@@ -1939,31 +2480,38 b' static size_t ZSTD_compressBlock_interna' | |||
|
1939 | 2480 | ZSTD_ldm_blockCompress(&ldmSeqStore, |
|
1940 | 2481 | ms, &zc->seqStore, |
|
1941 | 2482 | zc->blockState.nextCBlock->rep, |
|
1942 |
|
|
|
1943 | src, srcSize, extDict); | |
|
2483 | src, srcSize); | |
|
1944 | 2484 | assert(ldmSeqStore.pos == ldmSeqStore.size); |
|
1945 | 2485 | } else { /* not long range mode */ |
|
1946 |
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, |
|
|
1947 |
lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, |
|
|
2486 | ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); | |
|
2487 | lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); | |
|
1948 | 2488 | } |
|
1949 | 2489 | { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; |
|
1950 | 2490 | ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); |
|
1951 | 2491 | } } |
|
1952 | 2492 | |
|
1953 | 2493 | /* encode sequences and literals */ |
|
1954 |
|
|
|
1955 |
|
|
|
1956 |
|
|
|
1957 |
|
|
|
1958 |
|
|
|
1959 | if (ZSTD_isError(cSize) || cSize == 0) return cSize; | |
|
1960 | /* confirm repcodes and entropy tables */ | |
|
1961 | { ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; | |
|
1962 | zc->blockState.prevCBlock = zc->blockState.nextCBlock; | |
|
1963 | zc->blockState.nextCBlock = tmp; | |
|
1964 | } | |
|
1965 | return cSize; | |
|
2494 | cSize = ZSTD_compressSequences(&zc->seqStore, | |
|
2495 | &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, | |
|
2496 | &zc->appliedParams, | |
|
2497 | dst, dstCapacity, | |
|
2498 | srcSize, zc->entropyWorkspace, zc->bmi2); | |
|
2499 | ||
|
2500 | out: | |
|
2501 | if (!ZSTD_isError(cSize) && cSize != 0) { | |
|
2502 | /* confirm repcodes and entropy tables when emitting a compressed block */ | |
|
2503 | ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; | |
|
2504 | zc->blockState.prevCBlock = zc->blockState.nextCBlock; | |
|
2505 | zc->blockState.nextCBlock = tmp; | |
|
1966 | 2506 | } |
|
2507 | /* We check that dictionaries have offset codes available for the first | |
|
2508 | * block. After the first block, the offcode table might not have large | |
|
2509 | * enough codes to represent the offsets in the data. | |
|
2510 | */ | |
|
2511 | if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) | |
|
2512 | zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; | |
|
2513 | ||
|
2514 | return cSize; | |
|
1967 | 2515 | } |
|
1968 | 2516 | |
|
1969 | 2517 | |
@@ -2005,13 +2553,13 b' static size_t ZSTD_compress_frameChunk (' | |||
|
2005 | 2553 | ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); |
|
2006 | 2554 | ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); |
|
2007 | 2555 | ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); |
|
2008 | ||
|
2009 | 2556 | ZSTD_reduceIndex(cctx, correction); |
|
2010 | 2557 | if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; |
|
2011 | 2558 | else ms->nextToUpdate -= correction; |
|
2012 | 2559 | ms->loadedDictEnd = 0; |
|
2560 | ms->dictMatchState = NULL; | |
|
2013 | 2561 | } |
|
2014 | ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd); | |
|
2562 | ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); | |
|
2015 | 2563 | if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; |
|
2016 | 2564 | |
|
2017 | 2565 | { size_t cSize = ZSTD_compressBlock_internal(cctx, |
@@ -2020,11 +2568,8 b' static size_t ZSTD_compress_frameChunk (' | |||
|
2020 | 2568 | if (ZSTD_isError(cSize)) return cSize; |
|
2021 | 2569 | |
|
2022 | 2570 | if (cSize == 0) { /* block is not compressible */ |
|
2023 | U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3); | |
|
2024 | if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall); | |
|
2025 | MEM_writeLE32(op, cBlockHeader24); /* 4th byte will be overwritten */ | |
|
2026 | memcpy(op + ZSTD_blockHeaderSize, ip, blockSize); | |
|
2027 | cSize = ZSTD_blockHeaderSize + blockSize; | |
|
2571 | cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); | |
|
2572 | if (ZSTD_isError(cSize)) return cSize; | |
|
2028 | 2573 | } else { |
|
2029 | 2574 | U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); |
|
2030 | 2575 | MEM_writeLE24(op, cBlockHeader24); |
@@ -2060,6 +2605,7 b' static size_t ZSTD_writeFrameHeader(void' | |||
|
2060 | 2605 | BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); |
|
2061 | 2606 | size_t pos=0; |
|
2062 | 2607 | |
|
2608 | assert(!(params.fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); | |
|
2063 | 2609 | if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall); |
|
2064 | 2610 | DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", |
|
2065 | 2611 | !params.fParams.noDictIDFlag, dictID, dictIDSizeCode); |
@@ -2122,7 +2668,7 b' static size_t ZSTD_compressContinue_inte' | |||
|
2122 | 2668 | const void* src, size_t srcSize, |
|
2123 | 2669 | U32 frame, U32 lastFrameChunk) |
|
2124 | 2670 | { |
|
2125 | ZSTD_matchState_t* ms = &cctx->blockState.matchState; | |
|
2671 | ZSTD_matchState_t* const ms = &cctx->blockState.matchState; | |
|
2126 | 2672 | size_t fhSize = 0; |
|
2127 | 2673 | |
|
2128 | 2674 | DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u", |
@@ -2143,8 +2689,25 b' static size_t ZSTD_compressContinue_inte' | |||
|
2143 | 2689 | if (!ZSTD_window_update(&ms->window, src, srcSize)) { |
|
2144 | 2690 | ms->nextToUpdate = ms->window.dictLimit; |
|
2145 | 2691 | } |
|
2146 | if (cctx->appliedParams.ldmParams.enableLdm) | |
|
2692 | if (cctx->appliedParams.ldmParams.enableLdm) { | |
|
2147 | 2693 | ZSTD_window_update(&cctx->ldmState.window, src, srcSize); |
|
2694 | } | |
|
2695 | ||
|
2696 | if (!frame) { | |
|
2697 | /* overflow check and correction for block mode */ | |
|
2698 | if (ZSTD_window_needOverflowCorrection(ms->window, (const char*)src + srcSize)) { | |
|
2699 | U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy); | |
|
2700 | U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, 1 << cctx->appliedParams.cParams.windowLog, src); | |
|
2701 | ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); | |
|
2702 | ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); | |
|
2703 | ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); | |
|
2704 | ZSTD_reduceIndex(cctx, correction); | |
|
2705 | if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; | |
|
2706 | else ms->nextToUpdate -= correction; | |
|
2707 | ms->loadedDictEnd = 0; | |
|
2708 | ms->dictMatchState = NULL; | |
|
2709 | } | |
|
2710 | } | |
|
2148 | 2711 | |
|
2149 | 2712 | DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize); |
|
2150 | 2713 | { size_t const cSize = frame ? |
@@ -2153,7 +2716,9 b' static size_t ZSTD_compressContinue_inte' | |||
|
2153 | 2716 | if (ZSTD_isError(cSize)) return cSize; |
|
2154 | 2717 | cctx->consumedSrcSize += srcSize; |
|
2155 | 2718 | cctx->producedCSize += (cSize + fhSize); |
|
2156 |
|
|
|
2719 | assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); | |
|
2720 | if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ | |
|
2721 | ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); | |
|
2157 | 2722 | if (cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne) { |
|
2158 | 2723 | DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize >= %u", |
|
2159 | 2724 | (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize); |
@@ -2184,44 +2749,50 b' size_t ZSTD_compressBlock(ZSTD_CCtx* cct' | |||
|
2184 | 2749 | { |
|
2185 | 2750 | size_t const blockSizeMax = ZSTD_getBlockSize(cctx); |
|
2186 | 2751 | if (srcSize > blockSizeMax) return ERROR(srcSize_wrong); |
|
2752 | ||
|
2187 | 2753 | return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); |
|
2188 | 2754 | } |
|
2189 | 2755 | |
|
2190 | 2756 | /*! ZSTD_loadDictionaryContent() : |
|
2191 | 2757 | * @return : 0, or an error code |
|
2192 | 2758 | */ |
|
2193 |
static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, |
|
|
2759 | static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, | |
|
2760 | ZSTD_CCtx_params const* params, | |
|
2761 | const void* src, size_t srcSize, | |
|
2762 | ZSTD_dictTableLoadMethod_e dtlm) | |
|
2194 | 2763 | { |
|
2195 | 2764 | const BYTE* const ip = (const BYTE*) src; |
|
2196 | 2765 | const BYTE* const iend = ip + srcSize; |
|
2197 | ZSTD_compressionParameters const* cParams = ¶ms->cParams; | |
|
2198 | 2766 | |
|
2199 | 2767 | ZSTD_window_update(&ms->window, src, srcSize); |
|
2200 | 2768 | ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); |
|
2201 | 2769 | |
|
2770 | /* Assert that we the ms params match the params we're being given */ | |
|
2771 | ZSTD_assertEqualCParams(params->cParams, ms->cParams); | |
|
2772 | ||
|
2202 | 2773 | if (srcSize <= HASH_READ_SIZE) return 0; |
|
2203 | 2774 | |
|
2204 | 2775 | switch(params->cParams.strategy) |
|
2205 | 2776 | { |
|
2206 | 2777 | case ZSTD_fast: |
|
2207 |
ZSTD_fillHashTable(ms, |
|
|
2778 | ZSTD_fillHashTable(ms, iend, dtlm); | |
|
2208 | 2779 | break; |
|
2209 | 2780 | case ZSTD_dfast: |
|
2210 |
ZSTD_fillDoubleHashTable(ms, |
|
|
2781 | ZSTD_fillDoubleHashTable(ms, iend, dtlm); | |
|
2211 | 2782 | break; |
|
2212 | 2783 | |
|
2213 | 2784 | case ZSTD_greedy: |
|
2214 | 2785 | case ZSTD_lazy: |
|
2215 | 2786 | case ZSTD_lazy2: |
|
2216 | 2787 | if (srcSize >= HASH_READ_SIZE) |
|
2217 |
ZSTD_insertAndFindFirstIndex(ms |
|
|
2788 | ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); | |
|
2218 | 2789 | break; |
|
2219 | 2790 | |
|
2220 | 2791 | case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ |
|
2221 | 2792 | case ZSTD_btopt: |
|
2222 | 2793 | case ZSTD_btultra: |
|
2223 | 2794 | if (srcSize >= HASH_READ_SIZE) |
|
2224 |
ZSTD_updateTree(ms |
|
|
2795 | ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); | |
|
2225 | 2796 | break; |
|
2226 | 2797 | |
|
2227 | 2798 | default: |
@@ -2256,7 +2827,12 b' static size_t ZSTD_checkDictNCount(short' | |||
|
2256 | 2827 | * assumptions : magic number supposed already checked |
|
2257 | 2828 | * dictSize supposed > 8 |
|
2258 | 2829 | */ |
|
2259 | static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, void* workspace) | |
|
2830 | static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, | |
|
2831 | ZSTD_matchState_t* ms, | |
|
2832 | ZSTD_CCtx_params const* params, | |
|
2833 | const void* dict, size_t dictSize, | |
|
2834 | ZSTD_dictTableLoadMethod_e dtlm, | |
|
2835 | void* workspace) | |
|
2260 | 2836 | { |
|
2261 | 2837 | const BYTE* dictPtr = (const BYTE*)dict; |
|
2262 | 2838 | const BYTE* const dictEnd = dictPtr + dictSize; |
@@ -2265,13 +2841,15 b' static size_t ZSTD_loadZstdDictionary(ZS' | |||
|
2265 | 2841 | size_t dictID; |
|
2266 | 2842 | |
|
2267 | 2843 | ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); |
|
2844 | assert(dictSize > 8); | |
|
2845 | assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); | |
|
2268 | 2846 | |
|
2269 | 2847 | dictPtr += 4; /* skip magic number */ |
|
2270 | 2848 | dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); |
|
2271 | 2849 | dictPtr += 4; |
|
2272 | 2850 | |
|
2273 | 2851 | { unsigned maxSymbolValue = 255; |
|
2274 | size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); | |
|
2852 | size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); | |
|
2275 | 2853 | if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted); |
|
2276 | 2854 | if (maxSymbolValue < 255) return ERROR(dictionary_corrupted); |
|
2277 | 2855 | dictPtr += hufHeaderSize; |
@@ -2282,7 +2860,8 b' static size_t ZSTD_loadZstdDictionary(ZS' | |||
|
2282 | 2860 | if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); |
|
2283 | 2861 | if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted); |
|
2284 | 2862 | /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ |
|
2285 | CHECK_E( FSE_buildCTable_wksp(bs->entropy.offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, workspace, HUF_WORKSPACE_SIZE), | |
|
2863 | /* fill all offset symbols to avoid garbage at end of table */ | |
|
2864 | CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.offcodeCTable, offcodeNCount, MaxOff, offcodeLog, workspace, HUF_WORKSPACE_SIZE), | |
|
2286 | 2865 | dictionary_corrupted); |
|
2287 | 2866 | dictPtr += offcodeHeaderSize; |
|
2288 | 2867 | } |
@@ -2294,7 +2873,7 b' static size_t ZSTD_loadZstdDictionary(ZS' | |||
|
2294 | 2873 | if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted); |
|
2295 | 2874 | /* Every match length code must have non-zero probability */ |
|
2296 | 2875 | CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); |
|
2297 | CHECK_E( FSE_buildCTable_wksp(bs->entropy.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE), | |
|
2876 | CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE), | |
|
2298 | 2877 | dictionary_corrupted); |
|
2299 | 2878 | dictPtr += matchlengthHeaderSize; |
|
2300 | 2879 | } |
@@ -2306,7 +2885,7 b' static size_t ZSTD_loadZstdDictionary(ZS' | |||
|
2306 | 2885 | if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted); |
|
2307 | 2886 | /* Every literal length code must have non-zero probability */ |
|
2308 | 2887 | CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); |
|
2309 | CHECK_E( FSE_buildCTable_wksp(bs->entropy.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE), | |
|
2888 | CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE), | |
|
2310 | 2889 | dictionary_corrupted); |
|
2311 | 2890 | dictPtr += litlengthHeaderSize; |
|
2312 | 2891 | } |
@@ -2332,22 +2911,25 b' static size_t ZSTD_loadZstdDictionary(ZS' | |||
|
2332 | 2911 | if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted); |
|
2333 | 2912 | } } |
|
2334 | 2913 | |
|
2335 |
bs->entropy.huf |
|
|
2336 | bs->entropy.offcode_repeatMode = FSE_repeat_valid; | |
|
2337 | bs->entropy.matchlength_repeatMode = FSE_repeat_valid; | |
|
2338 | bs->entropy.litlength_repeatMode = FSE_repeat_valid; | |
|
2339 | CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize)); | |
|
2914 | bs->entropy.huf.repeatMode = HUF_repeat_valid; | |
|
2915 | bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; | |
|
2916 | bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; | |
|
2917 | bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; | |
|
2918 | CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize, dtlm)); | |
|
2340 | 2919 | return dictID; |
|
2341 | 2920 | } |
|
2342 | 2921 | } |
|
2343 | 2922 | |
|
2344 | 2923 | /** ZSTD_compress_insertDictionary() : |
|
2345 | 2924 | * @return : dictID, or an error code */ |
|
2346 | static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms, | |
|
2347 | ZSTD_CCtx_params const* params, | |
|
2348 |
|
|
|
2349 | ZSTD_dictContentType_e dictContentType, | |
|
2350 | void* workspace) | |
|
2925 | static size_t | |
|
2926 | ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, | |
|
2927 | ZSTD_matchState_t* ms, | |
|
2928 | const ZSTD_CCtx_params* params, | |
|
2929 | const void* dict, size_t dictSize, | |
|
2930 | ZSTD_dictContentType_e dictContentType, | |
|
2931 | ZSTD_dictTableLoadMethod_e dtlm, | |
|
2932 | void* workspace) | |
|
2351 | 2933 | { |
|
2352 | 2934 | DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); |
|
2353 | 2935 | if ((dict==NULL) || (dictSize<=8)) return 0; |
@@ -2356,12 +2938,12 b' static size_t ZSTD_compress_insertDictio' | |||
|
2356 | 2938 | |
|
2357 | 2939 | /* dict restricted modes */ |
|
2358 | 2940 | if (dictContentType == ZSTD_dct_rawContent) |
|
2359 | return ZSTD_loadDictionaryContent(ms, params, dict, dictSize); | |
|
2941 | return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm); | |
|
2360 | 2942 | |
|
2361 | 2943 | if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { |
|
2362 | 2944 | if (dictContentType == ZSTD_dct_auto) { |
|
2363 | 2945 | DEBUGLOG(4, "raw content dictionary detected"); |
|
2364 | return ZSTD_loadDictionaryContent(ms, params, dict, dictSize); | |
|
2946 | return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm); | |
|
2365 | 2947 | } |
|
2366 | 2948 | if (dictContentType == ZSTD_dct_fullDict) |
|
2367 | 2949 | return ERROR(dictionary_wrong); |
@@ -2369,17 +2951,18 b' static size_t ZSTD_compress_insertDictio' | |||
|
2369 | 2951 | } |
|
2370 | 2952 | |
|
2371 | 2953 | /* dict as full zstd dictionary */ |
|
2372 | return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, workspace); | |
|
2954 | return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, dtlm, workspace); | |
|
2373 | 2955 | } |
|
2374 | 2956 | |
|
2375 | 2957 | /*! ZSTD_compressBegin_internal() : |
|
2376 | 2958 | * @return : 0, or an error code */ |
|
2377 | size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, | |
|
2378 | const void* dict, size_t dictSize, | |
|
2379 | ZSTD_dictContentType_e dictContentType, | |
|
2380 |
|
|
|
2381 |
|
|
|
2382 | ZSTD_buffered_policy_e zbuff) | |
|
2959 | static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, | |
|
2960 | const void* dict, size_t dictSize, | |
|
2961 | ZSTD_dictContentType_e dictContentType, | |
|
2962 | ZSTD_dictTableLoadMethod_e dtlm, | |
|
2963 | const ZSTD_CDict* cdict, | |
|
2964 | ZSTD_CCtx_params params, U64 pledgedSrcSize, | |
|
2965 | ZSTD_buffered_policy_e zbuff) | |
|
2383 | 2966 | { |
|
2384 | 2967 | DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog); |
|
2385 | 2968 | /* params are supposed to be fully validated at this point */ |
@@ -2387,9 +2970,7 b' size_t ZSTD_compressBegin_internal(ZSTD_' | |||
|
2387 | 2970 | assert(!((dict) && (cdict))); /* either dict or cdict, not both */ |
|
2388 | 2971 | |
|
2389 | 2972 | if (cdict && cdict->dictContentSize>0) { |
|
2390 | cctx->requestedParams = params; | |
|
2391 | return ZSTD_resetCCtx_usingCDict(cctx, cdict, params.cParams.windowLog, | |
|
2392 | params.fParams, pledgedSrcSize, zbuff); | |
|
2973 | return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); | |
|
2393 | 2974 | } |
|
2394 | 2975 | |
|
2395 | 2976 | CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, |
@@ -2397,7 +2978,7 b' size_t ZSTD_compressBegin_internal(ZSTD_' | |||
|
2397 | 2978 | { |
|
2398 | 2979 | size_t const dictID = ZSTD_compress_insertDictionary( |
|
2399 | 2980 | cctx->blockState.prevCBlock, &cctx->blockState.matchState, |
|
2400 | ¶ms, dict, dictSize, dictContentType, cctx->entropyWorkspace); | |
|
2981 | ¶ms, dict, dictSize, dictContentType, dtlm, cctx->entropyWorkspace); | |
|
2401 | 2982 | if (ZSTD_isError(dictID)) return dictID; |
|
2402 | 2983 | assert(dictID <= (size_t)(U32)-1); |
|
2403 | 2984 | cctx->dictID = (U32)dictID; |
@@ -2408,6 +2989,7 b' size_t ZSTD_compressBegin_internal(ZSTD_' | |||
|
2408 | 2989 | size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, |
|
2409 | 2990 | const void* dict, size_t dictSize, |
|
2410 | 2991 | ZSTD_dictContentType_e dictContentType, |
|
2992 | ZSTD_dictTableLoadMethod_e dtlm, | |
|
2411 | 2993 | const ZSTD_CDict* cdict, |
|
2412 | 2994 | ZSTD_CCtx_params params, |
|
2413 | 2995 | unsigned long long pledgedSrcSize) |
@@ -2416,7 +2998,7 b' size_t ZSTD_compressBegin_advanced_inter' | |||
|
2416 | 2998 | /* compression parameters verification and optimization */ |
|
2417 | 2999 | CHECK_F( ZSTD_checkCParams(params.cParams) ); |
|
2418 | 3000 | return ZSTD_compressBegin_internal(cctx, |
|
2419 | dict, dictSize, dictContentType, | |
|
3001 | dict, dictSize, dictContentType, dtlm, | |
|
2420 | 3002 | cdict, |
|
2421 | 3003 | params, pledgedSrcSize, |
|
2422 | 3004 | ZSTDb_not_buffered); |
@@ -2431,7 +3013,7 b' size_t ZSTD_compressBegin_advanced(ZSTD_' | |||
|
2431 | 3013 | ZSTD_CCtx_params const cctxParams = |
|
2432 | 3014 | ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); |
|
2433 | 3015 | return ZSTD_compressBegin_advanced_internal(cctx, |
|
2434 | dict, dictSize, ZSTD_dct_auto, | |
|
3016 | dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, | |
|
2435 | 3017 | NULL /*cdict*/, |
|
2436 | 3018 | cctxParams, pledgedSrcSize); |
|
2437 | 3019 | } |
@@ -2442,7 +3024,7 b' size_t ZSTD_compressBegin_usingDict(ZSTD' | |||
|
2442 | 3024 | ZSTD_CCtx_params const cctxParams = |
|
2443 | 3025 | ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); |
|
2444 | 3026 | DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (U32)dictSize); |
|
2445 | return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL, | |
|
3027 | return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, | |
|
2446 | 3028 | cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); |
|
2447 | 3029 | } |
|
2448 | 3030 | |
@@ -2505,7 +3087,9 b' size_t ZSTD_compressEnd (ZSTD_CCtx* cctx' | |||
|
2505 | 3087 | if (ZSTD_isError(cSize)) return cSize; |
|
2506 | 3088 | endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); |
|
2507 | 3089 | if (ZSTD_isError(endResult)) return endResult; |
|
2508 |
|
|
|
3090 | assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); | |
|
3091 | if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ | |
|
3092 | ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); | |
|
2509 | 3093 | DEBUGLOG(4, "end of frame : controlling src size"); |
|
2510 | 3094 | if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) { |
|
2511 | 3095 | DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u", |
@@ -2517,22 +3101,22 b' size_t ZSTD_compressEnd (ZSTD_CCtx* cctx' | |||
|
2517 | 3101 | |
|
2518 | 3102 | |
|
2519 | 3103 | static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, |
|
2520 | void* dst, size_t dstCapacity, | |
|
2521 | const void* src, size_t srcSize, | |
|
2522 | const void* dict,size_t dictSize, | |
|
2523 | ZSTD_parameters params) | |
|
3104 | void* dst, size_t dstCapacity, | |
|
3105 | const void* src, size_t srcSize, | |
|
3106 | const void* dict,size_t dictSize, | |
|
3107 | ZSTD_parameters params) | |
|
2524 | 3108 | { |
|
2525 | 3109 | ZSTD_CCtx_params const cctxParams = |
|
2526 | 3110 | ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); |
|
2527 | 3111 | DEBUGLOG(4, "ZSTD_compress_internal"); |
|
2528 | 3112 | return ZSTD_compress_advanced_internal(cctx, |
|
2529 | dst, dstCapacity, | |
|
2530 | src, srcSize, | |
|
2531 | dict, dictSize, | |
|
2532 | cctxParams); | |
|
3113 | dst, dstCapacity, | |
|
3114 | src, srcSize, | |
|
3115 | dict, dictSize, | |
|
3116 | cctxParams); | |
|
2533 | 3117 | } |
|
2534 | 3118 | |
|
2535 | size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, | |
|
3119 | size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, | |
|
2536 | 3120 | void* dst, size_t dstCapacity, |
|
2537 | 3121 | const void* src, size_t srcSize, |
|
2538 | 3122 | const void* dict,size_t dictSize, |
@@ -2540,7 +3124,11 b' size_t ZSTD_compress_advanced (ZSTD_CCtx' | |||
|
2540 | 3124 | { |
|
2541 | 3125 | DEBUGLOG(4, "ZSTD_compress_advanced"); |
|
2542 | 3126 | CHECK_F(ZSTD_checkCParams(params.cParams)); |
|
2543 | return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); | |
|
3127 | return ZSTD_compress_internal(cctx, | |
|
3128 | dst, dstCapacity, | |
|
3129 | src, srcSize, | |
|
3130 | dict, dictSize, | |
|
3131 | params); | |
|
2544 | 3132 | } |
|
2545 | 3133 | |
|
2546 | 3134 | /* Internal */ |
@@ -2551,37 +3139,44 b' size_t ZSTD_compress_advanced_internal(' | |||
|
2551 | 3139 | const void* dict,size_t dictSize, |
|
2552 | 3140 | ZSTD_CCtx_params params) |
|
2553 | 3141 | { |
|
2554 | DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", | |
|
2555 | (U32)srcSize); | |
|
2556 | CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL, | |
|
2557 |
|
|
|
3142 | DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (U32)srcSize); | |
|
3143 | CHECK_F( ZSTD_compressBegin_internal(cctx, | |
|
3144 | dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, | |
|
3145 | params, srcSize, ZSTDb_not_buffered) ); | |
|
2558 | 3146 | return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); |
|
2559 | 3147 | } |
|
2560 | 3148 | |
|
2561 |
size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, |
|
|
2562 |
|
|
|
3149 | size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, | |
|
3150 | void* dst, size_t dstCapacity, | |
|
3151 | const void* src, size_t srcSize, | |
|
3152 | const void* dict, size_t dictSize, | |
|
3153 | int compressionLevel) | |
|
2563 | 3154 | { |
|
2564 |
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize |
|
|
3155 | ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0); | |
|
2565 | 3156 | ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); |
|
2566 | 3157 | assert(params.fParams.contentSizeFlag == 1); |
|
2567 | ZSTD_CCtxParam_setParameter(&cctxParams, ZSTD_p_compressLiterals, compressionLevel>=0); | |
|
2568 | 3158 | return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams); |
|
2569 | 3159 | } |
|
2570 | 3160 | |
|
2571 | size_t ZSTD_compressCCtx (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) | |
|
3161 | size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, | |
|
3162 | void* dst, size_t dstCapacity, | |
|
3163 | const void* src, size_t srcSize, | |
|
3164 | int compressionLevel) | |
|
2572 | 3165 | { |
|
2573 | 3166 | DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (U32)srcSize); |
|
3167 | assert(cctx != NULL); | |
|
2574 | 3168 | return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); |
|
2575 | 3169 | } |
|
2576 | 3170 | |
|
2577 |
size_t ZSTD_compress(void* dst, size_t dstCapacity, |
|
|
3171 | size_t ZSTD_compress(void* dst, size_t dstCapacity, | |
|
3172 | const void* src, size_t srcSize, | |
|
3173 | int compressionLevel) | |
|
2578 | 3174 | { |
|
2579 | 3175 | size_t result; |
|
2580 | 3176 | ZSTD_CCtx ctxBody; |
|
2581 | memset(&ctxBody, 0, sizeof(ctxBody)); | |
|
2582 | ctxBody.customMem = ZSTD_defaultCMem; | |
|
3177 | ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); | |
|
2583 | 3178 | result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); |
|
2584 |
ZSTD_free(ctxBody |
|
|
3179 | ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ | |
|
2585 | 3180 | return result; |
|
2586 | 3181 | } |
|
2587 | 3182 | |
@@ -2619,9 +3214,9 b' static size_t ZSTD_initCDict_internal(' | |||
|
2619 | 3214 | ZSTD_dictContentType_e dictContentType, |
|
2620 | 3215 | ZSTD_compressionParameters cParams) |
|
2621 | 3216 | { |
|
2622 |
DEBUGLOG(3, "ZSTD_initCDict_internal |
|
|
3217 | DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (U32)dictContentType); | |
|
2623 | 3218 | assert(!ZSTD_checkCParams(cParams)); |
|
2624 | cdict->cParams = cParams; | |
|
3219 | cdict->matchState.cParams = cParams; | |
|
2625 | 3220 | if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { |
|
2626 | 3221 | cdict->dictBuffer = NULL; |
|
2627 | 3222 | cdict->dictContent = dictBuffer; |
@@ -2654,7 +3249,7 b' static size_t ZSTD_initCDict_internal(' | |||
|
2654 | 3249 | { size_t const dictID = ZSTD_compress_insertDictionary( |
|
2655 | 3250 | &cdict->cBlockState, &cdict->matchState, ¶ms, |
|
2656 | 3251 | cdict->dictContent, cdict->dictContentSize, |
|
2657 | dictContentType, cdict->workspace); | |
|
3252 | dictContentType, ZSTD_dtlm_full, cdict->workspace); | |
|
2658 | 3253 | if (ZSTD_isError(dictID)) return dictID; |
|
2659 | 3254 | assert(dictID <= (size_t)(U32)-1); |
|
2660 | 3255 | cdict->dictID = (U32)dictID; |
@@ -2775,7 +3370,7 b' const ZSTD_CDict* ZSTD_initStaticCDict(' | |||
|
2775 | 3370 | ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) |
|
2776 | 3371 | { |
|
2777 | 3372 | assert(cdict != NULL); |
|
2778 | return cdict->cParams; | |
|
3373 | return cdict->matchState.cParams; | |
|
2779 | 3374 | } |
|
2780 | 3375 | |
|
2781 | 3376 | /* ZSTD_compressBegin_usingCDict_advanced() : |
@@ -2799,7 +3394,7 b' size_t ZSTD_compressBegin_usingCDict_adv' | |||
|
2799 | 3394 | } |
|
2800 | 3395 | params.fParams = fParams; |
|
2801 | 3396 | return ZSTD_compressBegin_internal(cctx, |
|
2802 | NULL, 0, ZSTD_dct_auto, | |
|
3397 | NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, | |
|
2803 | 3398 | cdict, |
|
2804 | 3399 | params, pledgedSrcSize, |
|
2805 | 3400 | ZSTDb_not_buffered); |
@@ -2813,7 +3408,7 b' size_t ZSTD_compressBegin_usingCDict(ZST' | |||
|
2813 | 3408 | { |
|
2814 | 3409 | ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; |
|
2815 | 3410 | DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); |
|
2816 |
return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, |
|
|
3411 | return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); | |
|
2817 | 3412 | } |
|
2818 | 3413 | |
|
2819 | 3414 | size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, |
@@ -2880,16 +3475,17 b' size_t ZSTD_CStreamOutSize(void)' | |||
|
2880 | 3475 | static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, |
|
2881 | 3476 | const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, |
|
2882 | 3477 | const ZSTD_CDict* const cdict, |
|
2883 |
ZSTD_CCtx_params |
|
|
3478 | ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) | |
|
2884 | 3479 | { |
|
2885 |
DEBUGLOG(4, "ZSTD_resetCStream_internal |
|
|
2886 | params.disableLiteralCompression); | |
|
3480 | DEBUGLOG(4, "ZSTD_resetCStream_internal"); | |
|
3481 | /* Finalize the compression parameters */ | |
|
3482 | params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); | |
|
2887 | 3483 | /* params are supposed to be fully validated at this point */ |
|
2888 | 3484 | assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); |
|
2889 | 3485 | assert(!((dict) && (cdict))); /* either dict or cdict, not both */ |
|
2890 | 3486 | |
|
2891 | 3487 | CHECK_F( ZSTD_compressBegin_internal(cctx, |
|
2892 | dict, dictSize, dictContentType, | |
|
3488 | dict, dictSize, dictContentType, ZSTD_dtlm_fast, | |
|
2893 | 3489 | cdict, |
|
2894 | 3490 | params, pledgedSrcSize, |
|
2895 | 3491 | ZSTDb_buffered) ); |
@@ -2912,7 +3508,6 b' size_t ZSTD_resetCStream(ZSTD_CStream* z' | |||
|
2912 | 3508 | DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (U32)pledgedSrcSize); |
|
2913 | 3509 | if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; |
|
2914 | 3510 | params.fParams.contentSizeFlag = 1; |
|
2915 | params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, 0); | |
|
2916 | 3511 | return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize); |
|
2917 | 3512 | } |
|
2918 | 3513 | |
@@ -2925,6 +3520,7 b' size_t ZSTD_initCStream_internal(ZSTD_CS' | |||
|
2925 | 3520 | ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) |
|
2926 | 3521 | { |
|
2927 | 3522 | DEBUGLOG(4, "ZSTD_initCStream_internal"); |
|
3523 | params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); | |
|
2928 | 3524 | assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); |
|
2929 | 3525 | assert(!((dict) && (cdict))); /* either dict or cdict, not both */ |
|
2930 | 3526 | |
@@ -2991,25 +3587,21 b' size_t ZSTD_initCStream_advanced(ZSTD_CS' | |||
|
2991 | 3587 | (U32)pledgedSrcSize, params.fParams.contentSizeFlag); |
|
2992 | 3588 | CHECK_F( ZSTD_checkCParams(params.cParams) ); |
|
2993 | 3589 | if ((pledgedSrcSize==0) && (params.fParams.contentSizeFlag==0)) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* for compatibility with older programs relying on this behavior. Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. This line will be removed in the future. */ |
|
2994 |
|
|
|
2995 |
|
|
|
2996 | } | |
|
3590 | zcs->requestedParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); | |
|
3591 | return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, zcs->requestedParams, pledgedSrcSize); | |
|
2997 | 3592 | } |
|
2998 | 3593 | |
|
2999 | 3594 | size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) |
|
3000 | 3595 | { |
|
3001 | ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); | |
|
3002 | ZSTD_CCtx_params const cctxParams = | |
|
3003 | ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); | |
|
3004 | return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN); | |
|
3596 | ZSTD_CCtxParams_init(&zcs->requestedParams, compressionLevel); | |
|
3597 | return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, zcs->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN); | |
|
3005 | 3598 | } |
|
3006 | 3599 | |
|
3007 | 3600 | size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) |
|
3008 | 3601 | { |
|
3009 | 3602 | U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; /* temporary : 0 interpreted as "unknown" during transition period. Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. `0` will be interpreted as "empty" in the future */ |
|
3010 | ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); | |
|
3011 | ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); | |
|
3012 | return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize); | |
|
3603 | ZSTD_CCtxParams_init(&zcs->requestedParams, compressionLevel); | |
|
3604 | return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, zcs->requestedParams, pledgedSrcSize); | |
|
3013 | 3605 | } |
|
3014 | 3606 | |
|
3015 | 3607 | size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) |
@@ -3073,7 +3665,7 b' size_t ZSTD_compressStream_generic(ZSTD_' | |||
|
3073 | 3665 | ip = iend; |
|
3074 | 3666 | op += cSize; |
|
3075 | 3667 | zcs->frameEnded = 1; |
|
3076 |
ZSTD_ |
|
|
3668 | ZSTD_CCtx_reset(zcs); | |
|
3077 | 3669 | someMoreWork = 0; break; |
|
3078 | 3670 | } |
|
3079 | 3671 | /* complete loading into inBuffer */ |
@@ -3126,7 +3718,7 b' size_t ZSTD_compressStream_generic(ZSTD_' | |||
|
3126 | 3718 | if (zcs->frameEnded) { |
|
3127 | 3719 | DEBUGLOG(5, "Frame completed directly in outBuffer"); |
|
3128 | 3720 | someMoreWork = 0; |
|
3129 |
ZSTD_ |
|
|
3721 | ZSTD_CCtx_reset(zcs); | |
|
3130 | 3722 | } |
|
3131 | 3723 | break; |
|
3132 | 3724 | } |
@@ -3154,7 +3746,7 b' size_t ZSTD_compressStream_generic(ZSTD_' | |||
|
3154 | 3746 | if (zcs->frameEnded) { |
|
3155 | 3747 | DEBUGLOG(5, "Frame completed on flush"); |
|
3156 | 3748 | someMoreWork = 0; |
|
3157 |
ZSTD_ |
|
|
3749 | ZSTD_CCtx_reset(zcs); | |
|
3158 | 3750 | break; |
|
3159 | 3751 | } |
|
3160 | 3752 | zcs->streamStage = zcss_load; |
@@ -3207,19 +3799,16 b' size_t ZSTD_compress_generic (ZSTD_CCtx*' | |||
|
3207 | 3799 | params.cParams = ZSTD_getCParamsFromCCtxParams( |
|
3208 | 3800 | &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); |
|
3209 | 3801 | |
|
3802 | ||
|
3210 | 3803 | #ifdef ZSTD_MULTITHREAD |
|
3211 | 3804 | if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { |
|
3212 | 3805 | params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ |
|
3213 | 3806 | } |
|
3214 | 3807 | if (params.nbWorkers > 0) { |
|
3215 | 3808 | /* mt context creation */ |
|
3216 | if (cctx->mtctx == NULL || (params.nbWorkers != ZSTDMT_getNbWorkers(cctx->mtctx))) { | |
|
3809 | if (cctx->mtctx == NULL) { | |
|
3217 | 3810 | DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbWorkers=%u", |
|
3218 | 3811 | params.nbWorkers); |
|
3219 | if (cctx->mtctx != NULL) | |
|
3220 | DEBUGLOG(4, "ZSTD_compress_generic: previous nbWorkers was %u", | |
|
3221 | ZSTDMT_getNbWorkers(cctx->mtctx)); | |
|
3222 | ZSTDMT_freeCCtx(cctx->mtctx); | |
|
3223 | 3812 | cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem); |
|
3224 | 3813 | if (cctx->mtctx == NULL) return ERROR(memory_allocation); |
|
3225 | 3814 | } |
@@ -3251,8 +3840,9 b' size_t ZSTD_compress_generic (ZSTD_CCtx*' | |||
|
3251 | 3840 | { size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); |
|
3252 | 3841 | if ( ZSTD_isError(flushMin) |
|
3253 | 3842 | || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ |
|
3254 |
ZSTD_ |
|
|
3843 | ZSTD_CCtx_reset(cctx); | |
|
3255 | 3844 | } |
|
3845 | DEBUGLOG(5, "completed ZSTD_compress_generic delegating to ZSTDMT_compressStream_generic"); | |
|
3256 | 3846 | return flushMin; |
|
3257 | 3847 | } } |
|
3258 | 3848 | #endif |
@@ -3308,82 +3898,83 b' size_t ZSTD_endStream(ZSTD_CStream* zcs,' | |||
|
3308 | 3898 | |
|
3309 | 3899 | #define ZSTD_MAX_CLEVEL 22 |
|
3310 | 3900 | int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } |
|
3901 | int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } | |
|
3311 | 3902 | |
|
3312 | 3903 | static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { |
|
3313 | 3904 | { /* "default" - guarantees a monotonically increasing memory budget */ |
|
3314 | 3905 | /* W, C, H, S, L, TL, strat */ |
|
3315 | 3906 | { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ |
|
3316 |
{ 19, 13, 14, 1, 7, |
|
|
3317 |
{ 19, 15, 16, 1, 6, |
|
|
3318 |
{ 20, 16, 17, 1, 5, |
|
|
3319 |
{ 20, 1 |
|
|
3320 |
{ 20, 1 |
|
|
3321 |
{ 21, 1 |
|
|
3322 |
{ 21, 18, 19, 3, 5, |
|
|
3323 |
{ 21, 1 |
|
|
3324 |
{ 21, 19, 20, |
|
|
3325 |
{ 21, |
|
|
3326 |
{ 2 |
|
|
3907 | { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ | |
|
3908 | { 19, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ | |
|
3909 | { 20, 16, 17, 1, 5, 1, ZSTD_dfast }, /* level 3 */ | |
|
3910 | { 20, 18, 18, 1, 5, 1, ZSTD_dfast }, /* level 4 */ | |
|
3911 | { 20, 18, 18, 2, 5, 2, ZSTD_greedy }, /* level 5 */ | |
|
3912 | { 21, 18, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */ | |
|
3913 | { 21, 18, 19, 3, 5, 8, ZSTD_lazy2 }, /* level 7 */ | |
|
3914 | { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ | |
|
3915 | { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ | |
|
3916 | { 21, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ | |
|
3917 | { 21, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ | |
|
3327 | 3918 | { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ |
|
3328 | 3919 | { 22, 21, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */ |
|
3329 | 3920 | { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ |
|
3330 | 3921 | { 22, 22, 22, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ |
|
3331 | 3922 | { 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */ |
|
3332 |
{ 23, 22, 22, 4, 4, 4 |
|
|
3333 |
{ 23, 2 |
|
|
3334 |
{ 23, 2 |
|
|
3335 |
{ 25, 25, 23, 7, 3, |
|
|
3336 |
{ 26, 26, 24, 7, 3, |
|
|
3337 |
{ 27, 27, 25, 9, 3, |
|
|
3923 | { 23, 22, 22, 4, 4, 64, ZSTD_btopt }, /* level 17 */ | |
|
3924 | { 23, 23, 22, 6, 3,256, ZSTD_btopt }, /* level 18 */ | |
|
3925 | { 23, 24, 22, 7, 3,256, ZSTD_btultra }, /* level 19 */ | |
|
3926 | { 25, 25, 23, 7, 3,256, ZSTD_btultra }, /* level 20 */ | |
|
3927 | { 26, 26, 24, 7, 3,512, ZSTD_btultra }, /* level 21 */ | |
|
3928 | { 27, 27, 25, 9, 3,999, ZSTD_btultra }, /* level 22 */ | |
|
3338 | 3929 | }, |
|
3339 | 3930 | { /* for srcSize <= 256 KB */ |
|
3340 | 3931 | /* W, C, H, S, L, T, strat */ |
|
3341 | 3932 | { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ |
|
3342 |
{ 18, 13, 14, 1, 6, |
|
|
3343 |
{ 18, 14, 1 |
|
|
3344 |
{ 18, 16, 1 |
|
|
3345 |
{ 18, 1 |
|
|
3346 |
{ 18, 1 |
|
|
3347 |
{ 18, 1 |
|
|
3348 |
{ 18, 1 |
|
|
3349 |
{ 18, 1 |
|
|
3350 |
{ 18, 1 |
|
|
3351 |
{ 18, 1 |
|
|
3352 |
{ 18, 18, 1 |
|
|
3353 |
{ 18, 1 |
|
|
3354 |
{ 18, 19, 1 |
|
|
3355 |
{ 18, 18, 1 |
|
|
3356 |
{ 18, 18, 1 |
|
|
3357 |
{ 18, 19, 1 |
|
|
3358 |
{ 18, 19, 1 |
|
|
3359 |
{ 18, 19, 1 |
|
|
3360 |
{ 18, 19, 1 |
|
|
3361 |
{ 18, 19, 1 |
|
|
3362 |
{ 18, 19, 1 |
|
|
3363 |
{ 18, 19, 1 |
|
|
3933 | { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ | |
|
3934 | { 18, 14, 14, 1, 5, 1, ZSTD_dfast }, /* level 2 */ | |
|
3935 | { 18, 16, 16, 1, 4, 1, ZSTD_dfast }, /* level 3 */ | |
|
3936 | { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ | |
|
3937 | { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ | |
|
3938 | { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ | |
|
3939 | { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ | |
|
3940 | { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ | |
|
3941 | { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ | |
|
3942 | { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ | |
|
3943 | { 18, 18, 19, 5, 4, 16, ZSTD_btlazy2 }, /* level 11.*/ | |
|
3944 | { 18, 19, 19, 6, 4, 16, ZSTD_btlazy2 }, /* level 12.*/ | |
|
3945 | { 18, 19, 19, 8, 4, 16, ZSTD_btlazy2 }, /* level 13 */ | |
|
3946 | { 18, 18, 19, 4, 4, 24, ZSTD_btopt }, /* level 14.*/ | |
|
3947 | { 18, 18, 19, 4, 3, 24, ZSTD_btopt }, /* level 15.*/ | |
|
3948 | { 18, 19, 19, 6, 3, 64, ZSTD_btopt }, /* level 16.*/ | |
|
3949 | { 18, 19, 19, 8, 3,128, ZSTD_btopt }, /* level 17.*/ | |
|
3950 | { 18, 19, 19, 10, 3,256, ZSTD_btopt }, /* level 18.*/ | |
|
3951 | { 18, 19, 19, 10, 3,256, ZSTD_btultra }, /* level 19.*/ | |
|
3952 | { 18, 19, 19, 11, 3,512, ZSTD_btultra }, /* level 20.*/ | |
|
3953 | { 18, 19, 19, 12, 3,512, ZSTD_btultra }, /* level 21.*/ | |
|
3954 | { 18, 19, 19, 13, 3,999, ZSTD_btultra }, /* level 22.*/ | |
|
3364 | 3955 | }, |
|
3365 | 3956 | { /* for srcSize <= 128 KB */ |
|
3366 | 3957 | /* W, C, H, S, L, T, strat */ |
|
3367 |
{ 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* |
|
|
3368 |
{ 17, 12, 13, 1, 6, |
|
|
3369 |
{ 17, 13, 1 |
|
|
3370 |
{ 17, 1 |
|
|
3371 |
{ 17, 1 |
|
|
3372 |
{ 17, 1 |
|
|
3373 |
{ 17, 1 |
|
|
3374 |
{ 17, 1 |
|
|
3958 | { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ | |
|
3959 | { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ | |
|
3960 | { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ | |
|
3961 | { 17, 15, 16, 2, 5, 1, ZSTD_dfast }, /* level 3 */ | |
|
3962 | { 17, 17, 17, 2, 4, 1, ZSTD_dfast }, /* level 4 */ | |
|
3963 | { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ | |
|
3964 | { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ | |
|
3965 | { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ | |
|
3375 | 3966 | { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ |
|
3376 | 3967 | { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ |
|
3377 | 3968 | { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ |
|
3378 | 3969 | { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */ |
|
3379 |
{ 17, 1 |
|
|
3380 |
{ 17, 18, 17, |
|
|
3381 |
{ 17, 1 |
|
|
3382 |
{ 17, 1 |
|
|
3383 |
{ 17, 18, 17, 7, 3, |
|
|
3384 |
{ 17, 18, 17, 7, 3, |
|
|
3385 |
{ 17, 18, 17, |
|
|
3386 |
{ 17, 18, 17, 8, 3,256, ZSTD_bt |
|
|
3970 | { 17, 18, 17, 6, 4, 16, ZSTD_btlazy2 }, /* level 12 */ | |
|
3971 | { 17, 18, 17, 8, 4, 16, ZSTD_btlazy2 }, /* level 13.*/ | |
|
3972 | { 17, 18, 17, 4, 4, 32, ZSTD_btopt }, /* level 14.*/ | |
|
3973 | { 17, 18, 17, 6, 3, 64, ZSTD_btopt }, /* level 15.*/ | |
|
3974 | { 17, 18, 17, 7, 3,128, ZSTD_btopt }, /* level 16.*/ | |
|
3975 | { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 17.*/ | |
|
3976 | { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 18.*/ | |
|
3977 | { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 19.*/ | |
|
3387 | 3978 | { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/ |
|
3388 | 3979 | { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/ |
|
3389 | 3980 | { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/ |
@@ -3391,28 +3982,28 b' static const ZSTD_compressionParameters ' | |||
|
3391 | 3982 | { /* for srcSize <= 16 KB */ |
|
3392 | 3983 | /* W, C, H, S, L, T, strat */ |
|
3393 | 3984 | { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ |
|
3394 |
{ 14, 14, 1 |
|
|
3395 |
{ 14, 14, 1 |
|
|
3396 |
{ 14, 14, 14, |
|
|
3397 |
{ 14, 14, 14, 4, 4, |
|
|
3398 |
{ 14, 14, 14, 3, 4, |
|
|
3399 |
{ 14, 14, 14, 4, 4, |
|
|
3400 |
{ 14, 14, 14, |
|
|
3401 |
{ 14, 14, 14, |
|
|
3402 |
{ 14, 15, 14, |
|
|
3403 |
{ 14, 15, 14, |
|
|
3404 |
{ 14, 15, 14, |
|
|
3985 | { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ | |
|
3986 | { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ | |
|
3987 | { 14, 14, 14, 2, 4, 1, ZSTD_dfast }, /* level 3.*/ | |
|
3988 | { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4.*/ | |
|
3989 | { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ | |
|
3990 | { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ | |
|
3991 | { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ | |
|
3992 | { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ | |
|
3993 | { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ | |
|
3994 | { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ | |
|
3995 | { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ | |
|
3405 | 3996 | { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/ |
|
3406 | 3997 | { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/ |
|
3407 | 3998 | { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/ |
|
3408 | 3999 | { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/ |
|
3409 | 4000 | { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/ |
|
3410 | 4001 | { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/ |
|
3411 |
{ 14, 15, 15, |
|
|
3412 |
{ 14, 15, 15, |
|
|
4002 | { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 18.*/ | |
|
4003 | { 14, 15, 15, 6, 3,256, ZSTD_btultra }, /* level 19.*/ | |
|
3413 | 4004 | { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/ |
|
3414 | 4005 | { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/ |
|
3415 |
{ 14, 15, 15, 10, 3, |
|
|
4006 | { 14, 15, 15, 10, 3,512, ZSTD_btultra }, /* level 22.*/ | |
|
3416 | 4007 | }, |
|
3417 | 4008 | }; |
|
3418 | 4009 |
@@ -27,6 +27,7 b'' | |||
|
27 | 27 | extern "C" { |
|
28 | 28 | #endif |
|
29 | 29 | |
|
30 | ||
|
30 | 31 | /*-************************************* |
|
31 | 32 | * Constants |
|
32 | 33 | ***************************************/ |
@@ -37,7 +38,8 b' extern "C" {' | |||
|
37 | 38 | It's not a big deal though : candidate will just be sorted again. |
|
38 | 39 | Additionnally, candidate position 1 will be lost. |
|
39 | 40 | But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss. |
|
40 |
The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy |
|
|
41 | The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy | |
|
42 | Constant required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */ | |
|
41 | 43 | |
|
42 | 44 | |
|
43 | 45 | /*-************************************* |
@@ -46,6 +48,12 b' extern "C" {' | |||
|
46 | 48 | typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e; |
|
47 | 49 | typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage; |
|
48 | 50 | |
|
51 | typedef enum { | |
|
52 | ZSTD_dictDefaultAttach = 0, | |
|
53 | ZSTD_dictForceAttach = 1, | |
|
54 | ZSTD_dictForceCopy = -1, | |
|
55 | } ZSTD_dictAttachPref_e; | |
|
56 | ||
|
49 | 57 | typedef struct ZSTD_prefixDict_s { |
|
50 | 58 | const void* dict; |
|
51 | 59 | size_t dictSize; |
@@ -53,14 +61,22 b' typedef struct ZSTD_prefixDict_s {' | |||
|
53 | 61 | } ZSTD_prefixDict; |
|
54 | 62 | |
|
55 | 63 | typedef struct { |
|
56 |
U32 |
|
|
64 | U32 CTable[HUF_CTABLE_SIZE_U32(255)]; | |
|
65 | HUF_repeat repeatMode; | |
|
66 | } ZSTD_hufCTables_t; | |
|
67 | ||
|
68 | typedef struct { | |
|
57 | 69 | FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)]; |
|
58 | 70 | FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)]; |
|
59 | 71 | FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)]; |
|
60 | HUF_repeat hufCTable_repeatMode; | |
|
61 | 72 | FSE_repeat offcode_repeatMode; |
|
62 | 73 | FSE_repeat matchlength_repeatMode; |
|
63 | 74 | FSE_repeat litlength_repeatMode; |
|
75 | } ZSTD_fseCTables_t; | |
|
76 | ||
|
77 | typedef struct { | |
|
78 | ZSTD_hufCTables_t huf; | |
|
79 | ZSTD_fseCTables_t fse; | |
|
64 | 80 | } ZSTD_entropyCTables_t; |
|
65 | 81 | |
|
66 | 82 | typedef struct { |
@@ -76,26 +92,27 b' typedef struct {' | |||
|
76 | 92 | U32 rep[ZSTD_REP_NUM]; |
|
77 | 93 | } ZSTD_optimal_t; |
|
78 | 94 | |
|
95 | typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e; | |
|
96 | ||
|
79 | 97 | typedef struct { |
|
80 | 98 | /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */ |
|
81 | U32* litFreq; /* table of literals statistics, of size 256 */ | |
|
82 | U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */ | |
|
83 | U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */ | |
|
84 | U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */ | |
|
85 | ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */ | |
|
86 | ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */ | |
|
99 | U32* litFreq; /* table of literals statistics, of size 256 */ | |
|
100 | U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */ | |
|
101 | U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */ | |
|
102 | U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */ | |
|
103 | ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */ | |
|
104 | ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */ | |
|
87 | 105 | |
|
88 | 106 | U32 litSum; /* nb of literals */ |
|
89 | 107 | U32 litLengthSum; /* nb of litLength codes */ |
|
90 | 108 | U32 matchLengthSum; /* nb of matchLength codes */ |
|
91 | 109 | U32 offCodeSum; /* nb of offset codes */ |
|
92 | /* begin updated by ZSTD_setLog2Prices */ | |
|
93 |
U32 |
|
|
94 |
U32 |
|
|
95 |
U32 |
|
|
96 | U32 log2offCodeSum; /* pow2 to compare log2(offreq) to */ | |
|
97 | /* end : updated by ZSTD_setLog2Prices */ | |
|
98 | U32 staticPrices; /* prices follow a pre-defined cost structure, statistics are irrelevant */ | |
|
110 | U32 litSumBasePrice; /* to compare to log2(litfreq) */ | |
|
111 | U32 litLengthSumBasePrice; /* to compare to log2(llfreq) */ | |
|
112 | U32 matchLengthSumBasePrice;/* to compare to log2(mlfreq) */ | |
|
113 | U32 offCodeSumBasePrice; /* to compare to log2(offreq) */ | |
|
114 | ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */ | |
|
115 | const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */ | |
|
99 | 116 | } optState_t; |
|
100 | 117 | |
|
101 | 118 | typedef struct { |
@@ -111,17 +128,20 b' typedef struct {' | |||
|
111 | 128 | U32 lowLimit; /* below that point, no more data */ |
|
112 | 129 | } ZSTD_window_t; |
|
113 | 130 | |
|
114 | typedef struct { | |
|
115 | ZSTD_window_t window; /* State for window round buffer management */ | |
|
116 | U32 loadedDictEnd; /* index of end of dictionary */ | |
|
117 | U32 nextToUpdate; /* index from which to continue table update */ | |
|
118 |
U32 nextToUpdate |
|
|
119 | U32 hashLog3; /* dispatch table : larger == faster, more memory */ | |
|
131 | typedef struct ZSTD_matchState_t ZSTD_matchState_t; | |
|
132 | struct ZSTD_matchState_t { | |
|
133 | ZSTD_window_t window; /* State for window round buffer management */ | |
|
134 | U32 loadedDictEnd; /* index of end of dictionary */ | |
|
135 | U32 nextToUpdate; /* index from which to continue table update */ | |
|
136 | U32 nextToUpdate3; /* index from which to continue table update */ | |
|
137 | U32 hashLog3; /* dispatch table : larger == faster, more memory */ | |
|
120 | 138 | U32* hashTable; |
|
121 | 139 | U32* hashTable3; |
|
122 | 140 | U32* chainTable; |
|
123 | 141 | optState_t opt; /* optimal parser state */ |
|
124 | } ZSTD_matchState_t; | |
|
142 | const ZSTD_matchState_t *dictMatchState; | |
|
143 | ZSTD_compressionParameters cParams; | |
|
144 | }; | |
|
125 | 145 | |
|
126 | 146 | typedef struct { |
|
127 | 147 | ZSTD_compressedBlockState_t* prevCBlock; |
@@ -161,7 +181,7 b' typedef struct {' | |||
|
161 | 181 | rawSeq* seq; /* The start of the sequences */ |
|
162 | 182 | size_t pos; /* The position where reading stopped. <= size. */ |
|
163 | 183 | size_t size; /* The number of sequences. <= capacity. */ |
|
164 |
size_t capacity; /* The capacity |
|
|
184 | size_t capacity; /* The capacity starting from `seq` pointer */ | |
|
165 | 185 | } rawSeqStore_t; |
|
166 | 186 | |
|
167 | 187 | struct ZSTD_CCtx_params_s { |
@@ -170,10 +190,11 b' struct ZSTD_CCtx_params_s {' | |||
|
170 | 190 | ZSTD_frameParameters fParams; |
|
171 | 191 | |
|
172 | 192 | int compressionLevel; |
|
173 | int disableLiteralCompression; | |
|
174 | 193 | int forceWindow; /* force back-references to respect limit of |
|
175 | 194 | * 1<<wLog, even for dictionary */ |
|
176 | 195 | |
|
196 | ZSTD_dictAttachPref_e attachDictPref; | |
|
197 | ||
|
177 | 198 | /* Multithreading: used to pass parameters to mtctx */ |
|
178 | 199 | unsigned nbWorkers; |
|
179 | 200 | unsigned jobSize; |
@@ -193,6 +214,8 b' struct ZSTD_CCtx_s {' | |||
|
193 | 214 | ZSTD_CCtx_params requestedParams; |
|
194 | 215 | ZSTD_CCtx_params appliedParams; |
|
195 | 216 | U32 dictID; |
|
217 | ||
|
218 | int workSpaceOversizedDuration; | |
|
196 | 219 | void* workSpace; |
|
197 | 220 | size_t workSpaceSize; |
|
198 | 221 | size_t blockSize; |
@@ -235,11 +258,15 b' struct ZSTD_CCtx_s {' | |||
|
235 | 258 | #endif |
|
236 | 259 | }; |
|
237 | 260 | |
|
261 | typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; | |
|
262 | ||
|
263 | typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e; | |
|
264 | ||
|
238 | 265 | |
|
239 | 266 | typedef size_t (*ZSTD_blockCompressor) ( |
|
240 | 267 | ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
241 |
|
|
|
242 |
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, |
|
|
268 | void const* src, size_t srcSize); | |
|
269 | ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode); | |
|
243 | 270 | |
|
244 | 271 | |
|
245 | 272 | MEM_STATIC U32 ZSTD_LLcode(U32 litLength) |
@@ -280,16 +307,18 b' MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)' | |||
|
280 | 307 | */ |
|
281 | 308 | MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t mlBase) |
|
282 | 309 | { |
|
283 |
#if defined( |
|
|
310 | #if defined(DEBUGLEVEL) && (DEBUGLEVEL >= 6) | |
|
284 | 311 | static const BYTE* g_start = NULL; |
|
285 | 312 | if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */ |
|
286 | 313 | { U32 const pos = (U32)((const BYTE*)literals - g_start); |
|
287 |
DEBUGLOG(6, "Cpos%7u :%3u literals, match% |
|
|
314 | DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u", | |
|
288 | 315 | pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offsetCode); |
|
289 | 316 | } |
|
290 | 317 | #endif |
|
318 | assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq); | |
|
291 | 319 | /* copy Literals */ |
|
292 |
assert(seqStorePtr-> |
|
|
320 | assert(seqStorePtr->maxNbLit <= 128 KB); | |
|
321 | assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit); | |
|
293 | 322 | ZSTD_wildcopy(seqStorePtr->lit, literals, litLength); |
|
294 | 323 | seqStorePtr->lit += litLength; |
|
295 | 324 | |
@@ -420,6 +449,11 b' ZSTD_count_2segments(const BYTE* ip, con' | |||
|
420 | 449 | const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd); |
|
421 | 450 | size_t const matchLength = ZSTD_count(ip, match, vEnd); |
|
422 | 451 | if (match + matchLength != mEnd) return matchLength; |
|
452 | DEBUGLOG(7, "ZSTD_count_2segments: found a 2-parts match (current length==%zu)", matchLength); | |
|
453 | DEBUGLOG(7, "distance from match beginning to end dictionary = %zi", mEnd - match); | |
|
454 | DEBUGLOG(7, "distance from current pos to end buffer = %zi", iEnd - ip); | |
|
455 | DEBUGLOG(7, "next byte : ip==%02X, istart==%02X", ip[matchLength], *iStart); | |
|
456 | DEBUGLOG(7, "final match length = %zu", matchLength + ZSTD_count(ip+matchLength, iStart, iEnd)); | |
|
423 | 457 | return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd); |
|
424 | 458 | } |
|
425 | 459 | |
@@ -497,6 +531,20 b' MEM_STATIC U32 ZSTD_window_hasExtDict(ZS' | |||
|
497 | 531 | } |
|
498 | 532 | |
|
499 | 533 | /** |
|
534 | * ZSTD_matchState_dictMode(): | |
|
535 | * Inspects the provided matchState and figures out what dictMode should be | |
|
536 | * passed to the compressor. | |
|
537 | */ | |
|
538 | MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms) | |
|
539 | { | |
|
540 | return ZSTD_window_hasExtDict(ms->window) ? | |
|
541 | ZSTD_extDict : | |
|
542 | ms->dictMatchState != NULL ? | |
|
543 | ZSTD_dictMatchState : | |
|
544 | ZSTD_noDict; | |
|
545 | } | |
|
546 | ||
|
547 | /** | |
|
500 | 548 | * ZSTD_window_needOverflowCorrection(): |
|
501 | 549 | * Returns non-zero if the indices are getting too large and need overflow |
|
502 | 550 | * protection. |
@@ -563,31 +611,41 b' MEM_STATIC U32 ZSTD_window_correctOverfl' | |||
|
563 | 611 | * ZSTD_window_enforceMaxDist(): |
|
564 | 612 | * Updates lowLimit so that: |
|
565 | 613 | * (srcEnd - base) - lowLimit == maxDist + loadedDictEnd |
|
614 | * | |
|
566 | 615 | * This allows a simple check that index >= lowLimit to see if index is valid. |
|
567 | 616 | * This must be called before a block compression call, with srcEnd as the block |
|
568 | 617 | * source end. |
|
618 | * | |
|
569 | 619 | * If loadedDictEndPtr is not NULL, we set it to zero once we update lowLimit. |
|
570 | 620 | * This is because dictionaries are allowed to be referenced as long as the last |
|
571 | 621 | * byte of the dictionary is in the window, but once they are out of range, |
|
572 | 622 | * they cannot be referenced. If loadedDictEndPtr is NULL, we use |
|
573 | 623 | * loadedDictEnd == 0. |
|
624 | * | |
|
625 | * In normal dict mode, the dict is between lowLimit and dictLimit. In | |
|
626 | * dictMatchState mode, lowLimit and dictLimit are the same, and the dictionary | |
|
627 | * is below them. forceWindow and dictMatchState are therefore incompatible. | |
|
574 | 628 | */ |
|
575 | 629 | MEM_STATIC void ZSTD_window_enforceMaxDist(ZSTD_window_t* window, |
|
576 | 630 | void const* srcEnd, U32 maxDist, |
|
577 |
U32* loadedDictEndPtr |
|
|
631 | U32* loadedDictEndPtr, | |
|
632 | const ZSTD_matchState_t** dictMatchStatePtr) | |
|
578 | 633 | { |
|
579 | 634 | U32 const current = (U32)((BYTE const*)srcEnd - window->base); |
|
580 | 635 | U32 loadedDictEnd = loadedDictEndPtr != NULL ? *loadedDictEndPtr : 0; |
|
636 | DEBUGLOG(5, "ZSTD_window_enforceMaxDist: current=%u, maxDist=%u", current, maxDist); | |
|
581 | 637 | if (current > maxDist + loadedDictEnd) { |
|
582 | 638 | U32 const newLowLimit = current - maxDist; |
|
583 | 639 | if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit; |
|
584 | 640 | if (window->dictLimit < window->lowLimit) { |
|
585 |
DEBUGLOG(5, "Update dictLimit from %u to %u", |
|
|
586 | window->lowLimit); | |
|
641 | DEBUGLOG(5, "Update dictLimit to match lowLimit, from %u to %u", | |
|
642 | window->dictLimit, window->lowLimit); | |
|
587 | 643 | window->dictLimit = window->lowLimit; |
|
588 | 644 | } |
|
589 | 645 | if (loadedDictEndPtr) |
|
590 | 646 | *loadedDictEndPtr = 0; |
|
647 | if (dictMatchStatePtr) | |
|
648 | *dictMatchStatePtr = NULL; | |
|
591 | 649 | } |
|
592 | 650 | } |
|
593 | 651 | |
@@ -603,12 +661,12 b' MEM_STATIC U32 ZSTD_window_update(ZSTD_w' | |||
|
603 | 661 | { |
|
604 | 662 | BYTE const* const ip = (BYTE const*)src; |
|
605 | 663 | U32 contiguous = 1; |
|
664 | DEBUGLOG(5, "ZSTD_window_update"); | |
|
606 | 665 | /* Check if blocks follow each other */ |
|
607 | 666 | if (src != window->nextSrc) { |
|
608 | 667 | /* not contiguous */ |
|
609 | 668 | size_t const distanceFromBase = (size_t)(window->nextSrc - window->base); |
|
610 | DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", | |
|
611 | window->dictLimit); | |
|
669 | DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit); | |
|
612 | 670 | window->lowLimit = window->dictLimit; |
|
613 | 671 | assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */ |
|
614 | 672 | window->dictLimit = (U32)distanceFromBase; |
@@ -625,10 +683,38 b' MEM_STATIC U32 ZSTD_window_update(ZSTD_w' | |||
|
625 | 683 | ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase; |
|
626 | 684 | U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx; |
|
627 | 685 | window->lowLimit = lowLimitMax; |
|
686 | DEBUGLOG(5, "Overlapping extDict and input : new lowLimit = %u", window->lowLimit); | |
|
628 | 687 | } |
|
629 | 688 | return contiguous; |
|
630 | 689 | } |
|
631 | 690 | |
|
691 | ||
|
692 | /* debug functions */ | |
|
693 | ||
|
694 | MEM_STATIC double ZSTD_fWeight(U32 rawStat) | |
|
695 | { | |
|
696 | U32 const fp_accuracy = 8; | |
|
697 | U32 const fp_multiplier = (1 << fp_accuracy); | |
|
698 | U32 const stat = rawStat + 1; | |
|
699 | U32 const hb = ZSTD_highbit32(stat); | |
|
700 | U32 const BWeight = hb * fp_multiplier; | |
|
701 | U32 const FWeight = (stat << fp_accuracy) >> hb; | |
|
702 | U32 const weight = BWeight + FWeight; | |
|
703 | assert(hb + fp_accuracy < 31); | |
|
704 | return (double)weight / fp_multiplier; | |
|
705 | } | |
|
706 | ||
|
707 | MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max) | |
|
708 | { | |
|
709 | unsigned u, sum; | |
|
710 | for (u=0, sum=0; u<=max; u++) sum += table[u]; | |
|
711 | DEBUGLOG(2, "total nb elts: %u", sum); | |
|
712 | for (u=0; u<=max; u++) { | |
|
713 | DEBUGLOG(2, "%2u: %5u (%.2f)", | |
|
714 | u, table[u], ZSTD_fWeight(sum) - ZSTD_fWeight(table[u]) ); | |
|
715 | } | |
|
716 | } | |
|
717 | ||
|
632 | 718 | #if defined (__cplusplus) |
|
633 | 719 | } |
|
634 | 720 | #endif |
@@ -640,7 +726,7 b' MEM_STATIC U32 ZSTD_window_update(ZSTD_w' | |||
|
640 | 726 | * ============================================================== */ |
|
641 | 727 | |
|
642 | 728 | /* ZSTD_getCParamsFromCCtxParams() : |
|
643 |
* cParams are built depending on compressionLevel, src size hints, |
|
|
729 | * cParams are built depending on compressionLevel, src size hints, | |
|
644 | 730 | * LDM and manually set compression parameters. |
|
645 | 731 | */ |
|
646 | 732 | ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( |
@@ -656,6 +742,8 b' size_t ZSTD_initCStream_internal(ZSTD_CS' | |||
|
656 | 742 | const ZSTD_CDict* cdict, |
|
657 | 743 | ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); |
|
658 | 744 | |
|
745 | void ZSTD_resetSeqStore(seqStore_t* ssPtr); | |
|
746 | ||
|
659 | 747 | /*! ZSTD_compressStream_generic() : |
|
660 | 748 | * Private use only. To be called from zstdmt_compress.c in single-thread mode. */ |
|
661 | 749 | size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, |
@@ -672,6 +760,7 b' ZSTD_compressionParameters ZSTD_getCPara' | |||
|
672 | 760 | size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, |
|
673 | 761 | const void* dict, size_t dictSize, |
|
674 | 762 | ZSTD_dictContentType_e dictContentType, |
|
763 | ZSTD_dictTableLoadMethod_e dtlm, | |
|
675 | 764 | const ZSTD_CDict* cdict, |
|
676 | 765 | ZSTD_CCtx_params params, |
|
677 | 766 | unsigned long long pledgedSrcSize); |
@@ -13,9 +13,9 b'' | |||
|
13 | 13 | |
|
14 | 14 | |
|
15 | 15 | void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, |
|
16 | ZSTD_compressionParameters const* cParams, | |
|
17 | void const* end) | |
|
16 | void const* end, ZSTD_dictTableLoadMethod_e dtlm) | |
|
18 | 17 | { |
|
18 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
19 | 19 | U32* const hashLarge = ms->hashTable; |
|
20 | 20 | U32 const hBitsL = cParams->hashLog; |
|
21 | 21 | U32 const mls = cParams->searchLength; |
@@ -40,6 +40,9 b' void ZSTD_fillDoubleHashTable(ZSTD_match' | |||
|
40 | 40 | hashSmall[smHash] = current + i; |
|
41 | 41 | if (i == 0 || hashLarge[lgHash] == 0) |
|
42 | 42 | hashLarge[lgHash] = current + i; |
|
43 | /* Only load extra positions for ZSTD_dtlm_full */ | |
|
44 | if (dtlm == ZSTD_dtlm_fast) | |
|
45 | break; | |
|
43 | 46 | } |
|
44 | 47 | } |
|
45 | 48 | } |
@@ -48,9 +51,10 b' void ZSTD_fillDoubleHashTable(ZSTD_match' | |||
|
48 | 51 | FORCE_INLINE_TEMPLATE |
|
49 | 52 | size_t ZSTD_compressBlock_doubleFast_generic( |
|
50 | 53 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
51 |
|
|
|
52 | U32 const mls /* template */) | |
|
54 | void const* src, size_t srcSize, | |
|
55 | U32 const mls /* template */, ZSTD_dictMode_e const dictMode) | |
|
53 | 56 | { |
|
57 | ZSTD_compressionParameters const* cParams = &ms->cParams; | |
|
54 | 58 | U32* const hashLong = ms->hashTable; |
|
55 | 59 | const U32 hBitsL = cParams->hashLog; |
|
56 | 60 | U32* const hashSmall = ms->chainTable; |
@@ -59,70 +63,188 b' size_t ZSTD_compressBlock_doubleFast_gen' | |||
|
59 | 63 | const BYTE* const istart = (const BYTE*)src; |
|
60 | 64 | const BYTE* ip = istart; |
|
61 | 65 | const BYTE* anchor = istart; |
|
62 |
const U32 |
|
|
63 |
const BYTE* const |
|
|
66 | const U32 prefixLowestIndex = ms->window.dictLimit; | |
|
67 | const BYTE* const prefixLowest = base + prefixLowestIndex; | |
|
64 | 68 | const BYTE* const iend = istart + srcSize; |
|
65 | 69 | const BYTE* const ilimit = iend - HASH_READ_SIZE; |
|
66 | 70 | U32 offset_1=rep[0], offset_2=rep[1]; |
|
67 | 71 | U32 offsetSaved = 0; |
|
68 | 72 | |
|
73 | const ZSTD_matchState_t* const dms = ms->dictMatchState; | |
|
74 | const ZSTD_compressionParameters* const dictCParams = | |
|
75 | dictMode == ZSTD_dictMatchState ? | |
|
76 | &dms->cParams : NULL; | |
|
77 | const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ? | |
|
78 | dms->hashTable : NULL; | |
|
79 | const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ? | |
|
80 | dms->chainTable : NULL; | |
|
81 | const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ? | |
|
82 | dms->window.dictLimit : 0; | |
|
83 | const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? | |
|
84 | dms->window.base : NULL; | |
|
85 | const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ? | |
|
86 | dictBase + dictStartIndex : NULL; | |
|
87 | const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? | |
|
88 | dms->window.nextSrc : NULL; | |
|
89 | const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? | |
|
90 | prefixLowestIndex - (U32)(dictEnd - dictBase) : | |
|
91 | 0; | |
|
92 | const U32 dictHBitsL = dictMode == ZSTD_dictMatchState ? | |
|
93 | dictCParams->hashLog : hBitsL; | |
|
94 | const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ? | |
|
95 | dictCParams->chainLog : hBitsS; | |
|
96 | const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart); | |
|
97 | ||
|
98 | assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState); | |
|
99 | ||
|
69 | 100 | /* init */ |
|
70 | ip += (ip==lowest); | |
|
71 | { U32 const maxRep = (U32)(ip-lowest); | |
|
101 | ip += (dictAndPrefixLength == 0); | |
|
102 | if (dictMode == ZSTD_noDict) { | |
|
103 | U32 const maxRep = (U32)(ip - prefixLowest); | |
|
72 | 104 | if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; |
|
73 | 105 | if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; |
|
74 | 106 | } |
|
107 | if (dictMode == ZSTD_dictMatchState) { | |
|
108 | /* dictMatchState repCode checks don't currently handle repCode == 0 | |
|
109 | * disabling. */ | |
|
110 | assert(offset_1 <= dictAndPrefixLength); | |
|
111 | assert(offset_2 <= dictAndPrefixLength); | |
|
112 | } | |
|
75 | 113 | |
|
76 | 114 | /* Main Search Loop */ |
|
77 | 115 | while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ |
|
78 | 116 | size_t mLength; |
|
117 | U32 offset; | |
|
79 | 118 | size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8); |
|
80 | 119 | size_t const h = ZSTD_hashPtr(ip, hBitsS, mls); |
|
120 | size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8); | |
|
121 | size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls); | |
|
81 | 122 | U32 const current = (U32)(ip-base); |
|
82 | 123 | U32 const matchIndexL = hashLong[h2]; |
|
83 |
U32 |
|
|
124 | U32 matchIndexS = hashSmall[h]; | |
|
84 | 125 | const BYTE* matchLong = base + matchIndexL; |
|
85 | 126 | const BYTE* match = base + matchIndexS; |
|
127 | const U32 repIndex = current + 1 - offset_1; | |
|
128 | const BYTE* repMatch = (dictMode == ZSTD_dictMatchState | |
|
129 | && repIndex < prefixLowestIndex) ? | |
|
130 | dictBase + (repIndex - dictIndexDelta) : | |
|
131 | base + repIndex; | |
|
86 | 132 | hashLong[h2] = hashSmall[h] = current; /* update hash tables */ |
|
87 | 133 | |
|
88 | assert(offset_1 <= current); /* supposed guaranteed by construction */ | |
|
89 | if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { | |
|
90 | /* favor repcode */ | |
|
134 | /* check dictMatchState repcode */ | |
|
135 | if (dictMode == ZSTD_dictMatchState | |
|
136 | && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) | |
|
137 | && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { | |
|
138 | const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; | |
|
139 | mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; | |
|
140 | ip++; | |
|
141 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); | |
|
142 | goto _match_stored; | |
|
143 | } | |
|
144 | ||
|
145 | /* check noDict repcode */ | |
|
146 | if ( dictMode == ZSTD_noDict | |
|
147 | && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) { | |
|
91 | 148 | mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; |
|
92 | 149 | ip++; |
|
93 | 150 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); |
|
94 | } else { | |
|
95 | U32 offset; | |
|
96 | if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) { | |
|
151 | goto _match_stored; | |
|
152 | } | |
|
153 | ||
|
154 | if (matchIndexL > prefixLowestIndex) { | |
|
155 | /* check prefix long match */ | |
|
156 | if (MEM_read64(matchLong) == MEM_read64(ip)) { | |
|
97 | 157 | mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8; |
|
98 | 158 | offset = (U32)(ip-matchLong); |
|
99 |
while (((ip>anchor) & (matchLong> |
|
|
100 | } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) { | |
|
101 | size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); | |
|
102 | U32 const matchIndexL3 = hashLong[hl3]; | |
|
103 | const BYTE* matchL3 = base + matchIndexL3; | |
|
104 | hashLong[hl3] = current + 1; | |
|
105 | if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) { | |
|
159 | while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ | |
|
160 | goto _match_found; | |
|
161 | } | |
|
162 | } else if (dictMode == ZSTD_dictMatchState) { | |
|
163 | /* check dictMatchState long match */ | |
|
164 | U32 const dictMatchIndexL = dictHashLong[dictHL]; | |
|
165 | const BYTE* dictMatchL = dictBase + dictMatchIndexL; | |
|
166 | assert(dictMatchL < dictEnd); | |
|
167 | ||
|
168 | if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) { | |
|
169 | mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8; | |
|
170 | offset = (U32)(current - dictMatchIndexL - dictIndexDelta); | |
|
171 | while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */ | |
|
172 | goto _match_found; | |
|
173 | } | |
|
174 | } | |
|
175 | ||
|
176 | if (matchIndexS > prefixLowestIndex) { | |
|
177 | /* check prefix short match */ | |
|
178 | if (MEM_read32(match) == MEM_read32(ip)) { | |
|
179 | goto _search_next_long; | |
|
180 | } | |
|
181 | } else if (dictMode == ZSTD_dictMatchState) { | |
|
182 | /* check dictMatchState short match */ | |
|
183 | U32 const dictMatchIndexS = dictHashSmall[dictHS]; | |
|
184 | match = dictBase + dictMatchIndexS; | |
|
185 | matchIndexS = dictMatchIndexS + dictIndexDelta; | |
|
186 | ||
|
187 | if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) { | |
|
188 | goto _search_next_long; | |
|
189 | } | |
|
190 | } | |
|
191 | ||
|
192 | ip += ((ip-anchor) >> kSearchStrength) + 1; | |
|
193 | continue; | |
|
194 | ||
|
195 | _search_next_long: | |
|
196 | ||
|
197 | { | |
|
198 | size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); | |
|
199 | size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8); | |
|
200 | U32 const matchIndexL3 = hashLong[hl3]; | |
|
201 | const BYTE* matchL3 = base + matchIndexL3; | |
|
202 | hashLong[hl3] = current + 1; | |
|
203 | ||
|
204 | /* check prefix long +1 match */ | |
|
205 | if (matchIndexL3 > prefixLowestIndex) { | |
|
206 | if (MEM_read64(matchL3) == MEM_read64(ip+1)) { | |
|
106 | 207 | mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8; |
|
107 | 208 | ip++; |
|
108 | 209 | offset = (U32)(ip-matchL3); |
|
109 |
while (((ip>anchor) & (matchL3> |
|
|
110 | } else { | |
|
111 | mLength = ZSTD_count(ip+4, match+4, iend) + 4; | |
|
112 | offset = (U32)(ip-match); | |
|
113 | while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ | |
|
210 | while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */ | |
|
211 | goto _match_found; | |
|
114 | 212 | } |
|
115 | } else { | |
|
116 | ip += ((ip-anchor) >> kSearchStrength) + 1; | |
|
117 | continue; | |
|
213 | } else if (dictMode == ZSTD_dictMatchState) { | |
|
214 | /* check dict long +1 match */ | |
|
215 | U32 const dictMatchIndexL3 = dictHashLong[dictHLNext]; | |
|
216 | const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3; | |
|
217 | assert(dictMatchL3 < dictEnd); | |
|
218 | if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) { | |
|
219 | mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8; | |
|
220 | ip++; | |
|
221 | offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta); | |
|
222 | while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */ | |
|
223 | goto _match_found; | |
|
224 | } | |
|
118 | 225 | } |
|
119 | ||
|
120 | offset_2 = offset_1; | |
|
121 | offset_1 = offset; | |
|
122 | ||
|
123 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | |
|
124 | 226 | } |
|
125 | 227 | |
|
228 | /* if no long +1 match, explore the short match we found */ | |
|
229 | if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) { | |
|
230 | mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4; | |
|
231 | offset = (U32)(current - matchIndexS); | |
|
232 | while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ | |
|
233 | } else { | |
|
234 | mLength = ZSTD_count(ip+4, match+4, iend) + 4; | |
|
235 | offset = (U32)(ip - match); | |
|
236 | while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ | |
|
237 | } | |
|
238 | ||
|
239 | /* fall-through */ | |
|
240 | ||
|
241 | _match_found: | |
|
242 | offset_2 = offset_1; | |
|
243 | offset_1 = offset; | |
|
244 | ||
|
245 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | |
|
246 | ||
|
247 | _match_stored: | |
|
126 | 248 | /* match found */ |
|
127 | 249 | ip += mLength; |
|
128 | 250 | anchor = ip; |
@@ -135,19 +257,44 b' size_t ZSTD_compressBlock_doubleFast_gen' | |||
|
135 | 257 | hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base); |
|
136 | 258 | |
|
137 | 259 | /* check immediate repcode */ |
|
138 | while ( (ip <= ilimit) | |
|
139 | && ( (offset_2>0) | |
|
140 | & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { | |
|
141 | /* store sequence */ | |
|
142 | size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | |
|
143 | { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */ | |
|
144 | hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); | |
|
145 | hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); | |
|
146 | ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH); | |
|
147 | ip += rLength; | |
|
148 | anchor = ip; | |
|
149 | continue; /* faster when present ... (?) */ | |
|
150 | } } } | |
|
260 | if (dictMode == ZSTD_dictMatchState) { | |
|
261 | while (ip <= ilimit) { | |
|
262 | U32 const current2 = (U32)(ip-base); | |
|
263 | U32 const repIndex2 = current2 - offset_2; | |
|
264 | const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState | |
|
265 | && repIndex2 < prefixLowestIndex ? | |
|
266 | dictBase - dictIndexDelta + repIndex2 : | |
|
267 | base + repIndex2; | |
|
268 | if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) | |
|
269 | && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { | |
|
270 | const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; | |
|
271 | size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; | |
|
272 | U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ | |
|
273 | ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH); | |
|
274 | hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; | |
|
275 | hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; | |
|
276 | ip += repLength2; | |
|
277 | anchor = ip; | |
|
278 | continue; | |
|
279 | } | |
|
280 | break; | |
|
281 | } | |
|
282 | } | |
|
283 | ||
|
284 | if (dictMode == ZSTD_noDict) { | |
|
285 | while ( (ip <= ilimit) | |
|
286 | && ( (offset_2>0) | |
|
287 | & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { | |
|
288 | /* store sequence */ | |
|
289 | size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | |
|
290 | U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ | |
|
291 | hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); | |
|
292 | hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); | |
|
293 | ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH); | |
|
294 | ip += rLength; | |
|
295 | anchor = ip; | |
|
296 | continue; /* faster when present ... (?) */ | |
|
297 | } } } } | |
|
151 | 298 | |
|
152 | 299 | /* save reps for next block */ |
|
153 | 300 | rep[0] = offset_1 ? offset_1 : offsetSaved; |
@@ -160,102 +307,126 b' size_t ZSTD_compressBlock_doubleFast_gen' | |||
|
160 | 307 | |
|
161 | 308 | size_t ZSTD_compressBlock_doubleFast( |
|
162 | 309 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
163 |
|
|
|
310 | void const* src, size_t srcSize) | |
|
164 | 311 | { |
|
165 |
const U32 mls = |
|
|
312 | const U32 mls = ms->cParams.searchLength; | |
|
166 | 313 | switch(mls) |
|
167 | 314 | { |
|
168 | 315 | default: /* includes case 3 */ |
|
169 | 316 | case 4 : |
|
170 |
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, |
|
|
317 | return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict); | |
|
171 | 318 | case 5 : |
|
172 |
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, |
|
|
319 | return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict); | |
|
173 | 320 | case 6 : |
|
174 |
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, |
|
|
321 | return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict); | |
|
175 | 322 | case 7 : |
|
176 |
return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, |
|
|
323 | return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict); | |
|
324 | } | |
|
325 | } | |
|
326 | ||
|
327 | ||
|
328 | size_t ZSTD_compressBlock_doubleFast_dictMatchState( | |
|
329 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
330 | void const* src, size_t srcSize) | |
|
331 | { | |
|
332 | const U32 mls = ms->cParams.searchLength; | |
|
333 | switch(mls) | |
|
334 | { | |
|
335 | default: /* includes case 3 */ | |
|
336 | case 4 : | |
|
337 | return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState); | |
|
338 | case 5 : | |
|
339 | return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState); | |
|
340 | case 6 : | |
|
341 | return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState); | |
|
342 | case 7 : | |
|
343 | return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState); | |
|
177 | 344 | } |
|
178 | 345 | } |
|
179 | 346 | |
|
180 | 347 | |
|
181 | 348 | static size_t ZSTD_compressBlock_doubleFast_extDict_generic( |
|
182 | 349 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
183 |
|
|
|
350 | void const* src, size_t srcSize, | |
|
184 | 351 | U32 const mls /* template */) |
|
185 | 352 | { |
|
353 | ZSTD_compressionParameters const* cParams = &ms->cParams; | |
|
186 | 354 | U32* const hashLong = ms->hashTable; |
|
187 | 355 | U32 const hBitsL = cParams->hashLog; |
|
188 | 356 | U32* const hashSmall = ms->chainTable; |
|
189 | 357 | U32 const hBitsS = cParams->chainLog; |
|
190 | const BYTE* const base = ms->window.base; | |
|
191 | const BYTE* const dictBase = ms->window.dictBase; | |
|
192 | 358 | const BYTE* const istart = (const BYTE*)src; |
|
193 | 359 | const BYTE* ip = istart; |
|
194 | 360 | const BYTE* anchor = istart; |
|
195 | const U32 lowestIndex = ms->window.lowLimit; | |
|
196 | const BYTE* const dictStart = dictBase + lowestIndex; | |
|
197 | const U32 dictLimit = ms->window.dictLimit; | |
|
198 | const BYTE* const lowPrefixPtr = base + dictLimit; | |
|
199 | const BYTE* const dictEnd = dictBase + dictLimit; | |
|
200 | 361 | const BYTE* const iend = istart + srcSize; |
|
201 | 362 | const BYTE* const ilimit = iend - 8; |
|
363 | const U32 prefixStartIndex = ms->window.dictLimit; | |
|
364 | const BYTE* const base = ms->window.base; | |
|
365 | const BYTE* const prefixStart = base + prefixStartIndex; | |
|
366 | const U32 dictStartIndex = ms->window.lowLimit; | |
|
367 | const BYTE* const dictBase = ms->window.dictBase; | |
|
368 | const BYTE* const dictStart = dictBase + dictStartIndex; | |
|
369 | const BYTE* const dictEnd = dictBase + prefixStartIndex; | |
|
202 | 370 | U32 offset_1=rep[0], offset_2=rep[1]; |
|
203 | 371 | |
|
372 | DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize); | |
|
373 | ||
|
204 | 374 | /* Search Loop */ |
|
205 | 375 | while (ip < ilimit) { /* < instead of <=, because (ip+1) */ |
|
206 | 376 | const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls); |
|
207 | 377 | const U32 matchIndex = hashSmall[hSmall]; |
|
208 |
const BYTE* matchBase = matchIndex < |
|
|
378 | const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base; | |
|
209 | 379 | const BYTE* match = matchBase + matchIndex; |
|
210 | 380 | |
|
211 | 381 | const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8); |
|
212 | 382 | const U32 matchLongIndex = hashLong[hLong]; |
|
213 |
const BYTE* matchLongBase = matchLongIndex < |
|
|
383 | const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base; | |
|
214 | 384 | const BYTE* matchLong = matchLongBase + matchLongIndex; |
|
215 | 385 | |
|
216 | 386 | const U32 current = (U32)(ip-base); |
|
217 | 387 | const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */ |
|
218 |
const BYTE* repBase = repIndex < |
|
|
219 | const BYTE* repMatch = repBase + repIndex; | |
|
388 | const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; | |
|
389 | const BYTE* const repMatch = repBase + repIndex; | |
|
220 | 390 | size_t mLength; |
|
221 | 391 | hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */ |
|
222 | 392 | |
|
223 |
if ( |
|
|
224 | && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { | |
|
225 | const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend; | |
|
226 | mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4; | |
|
393 | if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */ | |
|
394 | & (repIndex > dictStartIndex)) | |
|
395 | && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { | |
|
396 | const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; | |
|
397 | mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; | |
|
227 | 398 | ip++; |
|
228 | 399 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); |
|
229 | 400 | } else { |
|
230 |
if ((matchLongIndex > |
|
|
231 |
const BYTE* matchEnd = matchLongIndex < |
|
|
232 |
const BYTE* lowMatchPtr = matchLongIndex < |
|
|
401 | if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) { | |
|
402 | const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend; | |
|
403 | const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart; | |
|
233 | 404 | U32 offset; |
|
234 |
mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, |
|
|
405 | mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8; | |
|
235 | 406 | offset = current - matchLongIndex; |
|
236 | 407 | while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ |
|
237 | 408 | offset_2 = offset_1; |
|
238 | 409 | offset_1 = offset; |
|
239 | 410 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); |
|
240 | 411 | |
|
241 |
} else if ((matchIndex > |
|
|
412 | } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) { | |
|
242 | 413 | size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8); |
|
243 | 414 | U32 const matchIndex3 = hashLong[h3]; |
|
244 |
const BYTE* const match3Base = matchIndex3 < |
|
|
415 | const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base; | |
|
245 | 416 | const BYTE* match3 = match3Base + matchIndex3; |
|
246 | 417 | U32 offset; |
|
247 | 418 | hashLong[h3] = current + 1; |
|
248 |
if ( (matchIndex3 > |
|
|
249 |
const BYTE* matchEnd = matchIndex3 < |
|
|
250 |
const BYTE* lowMatchPtr = matchIndex3 < |
|
|
251 |
mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, |
|
|
419 | if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) { | |
|
420 | const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend; | |
|
421 | const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart; | |
|
422 | mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8; | |
|
252 | 423 | ip++; |
|
253 | 424 | offset = current+1 - matchIndex3; |
|
254 | 425 | while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */ |
|
255 | 426 | } else { |
|
256 |
const BYTE* matchEnd = matchIndex < |
|
|
257 |
const BYTE* lowMatchPtr = matchIndex < |
|
|
258 |
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, |
|
|
427 | const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; | |
|
428 | const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; | |
|
429 | mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; | |
|
259 | 430 | offset = current - matchIndex; |
|
260 | 431 | while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ |
|
261 | 432 | } |
@@ -282,12 +453,13 b' static size_t ZSTD_compressBlock_doubleF' | |||
|
282 | 453 | while (ip <= ilimit) { |
|
283 | 454 | U32 const current2 = (U32)(ip-base); |
|
284 | 455 | U32 const repIndex2 = current2 - offset_2; |
|
285 |
const BYTE* repMatch2 = repIndex2 < |
|
|
286 |
if ( (((U32)(( |
|
|
287 | && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { | |
|
288 | const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend; | |
|
289 | size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4; | |
|
290 | U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ | |
|
456 | const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; | |
|
457 | if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */ | |
|
458 | & (repIndex2 > dictStartIndex)) | |
|
459 | && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { | |
|
460 | const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; | |
|
461 | size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; | |
|
462 | U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ | |
|
291 | 463 | ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH); |
|
292 | 464 | hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; |
|
293 | 465 | hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; |
@@ -309,19 +481,19 b' static size_t ZSTD_compressBlock_doubleF' | |||
|
309 | 481 | |
|
310 | 482 | size_t ZSTD_compressBlock_doubleFast_extDict( |
|
311 | 483 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
312 |
|
|
|
484 | void const* src, size_t srcSize) | |
|
313 | 485 | { |
|
314 |
U32 const mls = |
|
|
486 | U32 const mls = ms->cParams.searchLength; | |
|
315 | 487 | switch(mls) |
|
316 | 488 | { |
|
317 | 489 | default: /* includes case 3 */ |
|
318 | 490 | case 4 : |
|
319 |
return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, |
|
|
491 | return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); | |
|
320 | 492 | case 5 : |
|
321 |
return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, |
|
|
493 | return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); | |
|
322 | 494 | case 6 : |
|
323 |
return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, |
|
|
495 | return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); | |
|
324 | 496 | case 7 : |
|
325 |
return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, |
|
|
497 | return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); | |
|
326 | 498 | } |
|
327 | 499 | } |
@@ -19,14 +19,16 b' extern "C" {' | |||
|
19 | 19 | #include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */ |
|
20 | 20 | |
|
21 | 21 | void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, |
|
22 | ZSTD_compressionParameters const* cParams, | |
|
23 | void const* end); | |
|
22 | void const* end, ZSTD_dictTableLoadMethod_e dtlm); | |
|
24 | 23 | size_t ZSTD_compressBlock_doubleFast( |
|
25 | 24 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
26 |
|
|
|
25 | void const* src, size_t srcSize); | |
|
26 | size_t ZSTD_compressBlock_doubleFast_dictMatchState( | |
|
27 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
28 | void const* src, size_t srcSize); | |
|
27 | 29 | size_t ZSTD_compressBlock_doubleFast_extDict( |
|
28 | 30 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
29 |
|
|
|
31 | void const* src, size_t srcSize); | |
|
30 | 32 | |
|
31 | 33 | |
|
32 | 34 | #if defined (__cplusplus) |
@@ -13,9 +13,9 b'' | |||
|
13 | 13 | |
|
14 | 14 | |
|
15 | 15 | void ZSTD_fillHashTable(ZSTD_matchState_t* ms, |
|
16 | ZSTD_compressionParameters const* cParams, | |
|
17 | void const* end) | |
|
16 | void const* end, ZSTD_dictTableLoadMethod_e dtlm) | |
|
18 | 17 | { |
|
18 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
19 | 19 | U32* const hashTable = ms->hashTable; |
|
20 | 20 | U32 const hBits = cParams->hashLog; |
|
21 | 21 | U32 const mls = cParams->searchLength; |
@@ -34,6 +34,9 b' void ZSTD_fillHashTable(ZSTD_matchState_' | |||
|
34 | 34 | size_t const hash = ZSTD_hashPtr(ip + i, hBits, mls); |
|
35 | 35 | if (i == 0 || hashTable[hash] == 0) |
|
36 | 36 | hashTable[hash] = current + i; |
|
37 | /* Only load extra positions for ZSTD_dtlm_full */ | |
|
38 | if (dtlm == ZSTD_dtlm_fast) | |
|
39 | break; | |
|
37 | 40 | } |
|
38 | 41 | } |
|
39 | 42 | } |
@@ -42,26 +45,65 b' FORCE_INLINE_TEMPLATE' | |||
|
42 | 45 | size_t ZSTD_compressBlock_fast_generic( |
|
43 | 46 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
44 | 47 | void const* src, size_t srcSize, |
|
45 | U32 const hlog, U32 const stepSize, U32 const mls) | |
|
48 | U32 const mls, ZSTD_dictMode_e const dictMode) | |
|
46 | 49 | { |
|
50 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
47 | 51 | U32* const hashTable = ms->hashTable; |
|
52 | U32 const hlog = cParams->hashLog; | |
|
53 | /* support stepSize of 0 */ | |
|
54 | U32 const stepSize = cParams->targetLength + !(cParams->targetLength); | |
|
48 | 55 | const BYTE* const base = ms->window.base; |
|
49 | 56 | const BYTE* const istart = (const BYTE*)src; |
|
50 | 57 | const BYTE* ip = istart; |
|
51 | 58 | const BYTE* anchor = istart; |
|
52 |
const U32 |
|
|
53 |
const BYTE* const |
|
|
59 | const U32 prefixStartIndex = ms->window.dictLimit; | |
|
60 | const BYTE* const prefixStart = base + prefixStartIndex; | |
|
54 | 61 | const BYTE* const iend = istart + srcSize; |
|
55 | 62 | const BYTE* const ilimit = iend - HASH_READ_SIZE; |
|
56 | 63 | U32 offset_1=rep[0], offset_2=rep[1]; |
|
57 | 64 | U32 offsetSaved = 0; |
|
58 | 65 | |
|
66 | const ZSTD_matchState_t* const dms = ms->dictMatchState; | |
|
67 | const ZSTD_compressionParameters* const dictCParams = | |
|
68 | dictMode == ZSTD_dictMatchState ? | |
|
69 | &dms->cParams : NULL; | |
|
70 | const U32* const dictHashTable = dictMode == ZSTD_dictMatchState ? | |
|
71 | dms->hashTable : NULL; | |
|
72 | const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ? | |
|
73 | dms->window.dictLimit : 0; | |
|
74 | const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? | |
|
75 | dms->window.base : NULL; | |
|
76 | const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ? | |
|
77 | dictBase + dictStartIndex : NULL; | |
|
78 | const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? | |
|
79 | dms->window.nextSrc : NULL; | |
|
80 | const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? | |
|
81 | prefixStartIndex - (U32)(dictEnd - dictBase) : | |
|
82 | 0; | |
|
83 | const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart); | |
|
84 | const U32 dictHLog = dictMode == ZSTD_dictMatchState ? | |
|
85 | dictCParams->hashLog : hlog; | |
|
86 | ||
|
87 | assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState); | |
|
88 | ||
|
89 | /* otherwise, we would get index underflow when translating a dict index | |
|
90 | * into a local index */ | |
|
91 | assert(dictMode != ZSTD_dictMatchState | |
|
92 | || prefixStartIndex >= (U32)(dictEnd - dictBase)); | |
|
93 | ||
|
59 | 94 | /* init */ |
|
60 | ip += (ip==lowest); | |
|
61 | { U32 const maxRep = (U32)(ip-lowest); | |
|
95 | ip += (dictAndPrefixLength == 0); | |
|
96 | if (dictMode == ZSTD_noDict) { | |
|
97 | U32 const maxRep = (U32)(ip - prefixStart); | |
|
62 | 98 | if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; |
|
63 | 99 | if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; |
|
64 | 100 | } |
|
101 | if (dictMode == ZSTD_dictMatchState) { | |
|
102 | /* dictMatchState repCode checks don't currently handle repCode == 0 | |
|
103 | * disabling. */ | |
|
104 | assert(offset_1 <= dictAndPrefixLength); | |
|
105 | assert(offset_2 <= dictAndPrefixLength); | |
|
106 | } | |
|
65 | 107 | |
|
66 | 108 | /* Main Search Loop */ |
|
67 | 109 | while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ |
@@ -70,26 +112,67 b' size_t ZSTD_compressBlock_fast_generic(' | |||
|
70 | 112 | U32 const current = (U32)(ip-base); |
|
71 | 113 | U32 const matchIndex = hashTable[h]; |
|
72 | 114 | const BYTE* match = base + matchIndex; |
|
115 | const U32 repIndex = current + 1 - offset_1; | |
|
116 | const BYTE* repMatch = (dictMode == ZSTD_dictMatchState | |
|
117 | && repIndex < prefixStartIndex) ? | |
|
118 | dictBase + (repIndex - dictIndexDelta) : | |
|
119 | base + repIndex; | |
|
73 | 120 | hashTable[h] = current; /* update hash table */ |
|
74 | 121 | |
|
75 | if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { | |
|
122 | if ( (dictMode == ZSTD_dictMatchState) | |
|
123 | && ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ | |
|
124 | && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { | |
|
125 | const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; | |
|
126 | mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; | |
|
127 | ip++; | |
|
128 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); | |
|
129 | } else if ( dictMode == ZSTD_noDict | |
|
130 | && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) { | |
|
76 | 131 | mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; |
|
77 | 132 | ip++; |
|
78 | 133 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); |
|
79 | } else { | |
|
80 | if ( (matchIndex <= lowestIndex) | |
|
81 | || (MEM_read32(match) != MEM_read32(ip)) ) { | |
|
134 | } else if ( (matchIndex <= prefixStartIndex) ) { | |
|
135 | if (dictMode == ZSTD_dictMatchState) { | |
|
136 | size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls); | |
|
137 | U32 const dictMatchIndex = dictHashTable[dictHash]; | |
|
138 | const BYTE* dictMatch = dictBase + dictMatchIndex; | |
|
139 | if (dictMatchIndex <= dictStartIndex || | |
|
140 | MEM_read32(dictMatch) != MEM_read32(ip)) { | |
|
141 | assert(stepSize >= 1); | |
|
142 | ip += ((ip-anchor) >> kSearchStrength) + stepSize; | |
|
143 | continue; | |
|
144 | } else { | |
|
145 | /* found a dict match */ | |
|
146 | U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta); | |
|
147 | mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4; | |
|
148 | while (((ip>anchor) & (dictMatch>dictStart)) | |
|
149 | && (ip[-1] == dictMatch[-1])) { | |
|
150 | ip--; dictMatch--; mLength++; | |
|
151 | } /* catch up */ | |
|
152 | offset_2 = offset_1; | |
|
153 | offset_1 = offset; | |
|
154 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | |
|
155 | } | |
|
156 | } else { | |
|
82 | 157 | assert(stepSize >= 1); |
|
83 | 158 | ip += ((ip-anchor) >> kSearchStrength) + stepSize; |
|
84 | 159 | continue; |
|
85 | 160 | } |
|
161 | } else if (MEM_read32(match) != MEM_read32(ip)) { | |
|
162 | /* it's not a match, and we're not going to check the dictionary */ | |
|
163 | assert(stepSize >= 1); | |
|
164 | ip += ((ip-anchor) >> kSearchStrength) + stepSize; | |
|
165 | continue; | |
|
166 | } else { | |
|
167 | /* found a regular match */ | |
|
168 | U32 const offset = (U32)(ip-match); | |
|
86 | 169 | mLength = ZSTD_count(ip+4, match+4, iend) + 4; |
|
87 | { U32 const offset = (U32)(ip-match); | |
|
88 |
|
|
|
89 |
|
|
|
90 |
|
|
|
91 |
|
|
|
92 |
} |
|
|
170 | while (((ip>anchor) & (match>prefixStart)) | |
|
171 | && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ | |
|
172 | offset_2 = offset_1; | |
|
173 | offset_1 = offset; | |
|
174 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | |
|
175 | } | |
|
93 | 176 | |
|
94 | 177 | /* match found */ |
|
95 | 178 | ip += mLength; |
@@ -97,21 +180,46 b' size_t ZSTD_compressBlock_fast_generic(' | |||
|
97 | 180 | |
|
98 | 181 | if (ip <= ilimit) { |
|
99 | 182 | /* Fill Table */ |
|
183 | assert(base+current+2 > istart); /* check base overflow */ | |
|
100 | 184 | hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */ |
|
101 | 185 | hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); |
|
186 | ||
|
102 | 187 | /* check immediate repcode */ |
|
103 | while ( (ip <= ilimit) | |
|
104 | && ( (offset_2>0) | |
|
105 | & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { | |
|
106 | /* store sequence */ | |
|
107 | size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | |
|
108 | { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */ | |
|
109 | hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base); | |
|
110 | ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH); | |
|
111 | ip += rLength; | |
|
112 | anchor = ip; | |
|
113 | continue; /* faster when present ... (?) */ | |
|
114 | } } } | |
|
188 | if (dictMode == ZSTD_dictMatchState) { | |
|
189 | while (ip <= ilimit) { | |
|
190 | U32 const current2 = (U32)(ip-base); | |
|
191 | U32 const repIndex2 = current2 - offset_2; | |
|
192 | const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? | |
|
193 | dictBase - dictIndexDelta + repIndex2 : | |
|
194 | base + repIndex2; | |
|
195 | if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) | |
|
196 | && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { | |
|
197 | const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; | |
|
198 | size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; | |
|
199 | U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ | |
|
200 | ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH); | |
|
201 | hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; | |
|
202 | ip += repLength2; | |
|
203 | anchor = ip; | |
|
204 | continue; | |
|
205 | } | |
|
206 | break; | |
|
207 | } | |
|
208 | } | |
|
209 | ||
|
210 | if (dictMode == ZSTD_noDict) { | |
|
211 | while ( (ip <= ilimit) | |
|
212 | && ( (offset_2>0) | |
|
213 | & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { | |
|
214 | /* store sequence */ | |
|
215 | size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | |
|
216 | U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ | |
|
217 | hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base); | |
|
218 | ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH); | |
|
219 | ip += rLength; | |
|
220 | anchor = ip; | |
|
221 | continue; /* faster when present ... (?) */ | |
|
222 | } } } } | |
|
115 | 223 | |
|
116 | 224 | /* save reps for next block */ |
|
117 | 225 | rep[0] = offset_1 ? offset_1 : offsetSaved; |
@@ -124,42 +232,66 b' size_t ZSTD_compressBlock_fast_generic(' | |||
|
124 | 232 | |
|
125 | 233 | size_t ZSTD_compressBlock_fast( |
|
126 | 234 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
127 |
|
|
|
235 | void const* src, size_t srcSize) | |
|
128 | 236 | { |
|
129 | U32 const hlog = cParams->hashLog; | |
|
237 | ZSTD_compressionParameters const* cParams = &ms->cParams; | |
|
130 | 238 | U32 const mls = cParams->searchLength; |
|
131 | U32 const stepSize = cParams->targetLength; | |
|
239 | assert(ms->dictMatchState == NULL); | |
|
132 | 240 | switch(mls) |
|
133 | 241 | { |
|
134 | 242 | default: /* includes case 3 */ |
|
135 | 243 | case 4 : |
|
136 |
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, |
|
|
244 | return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict); | |
|
137 | 245 | case 5 : |
|
138 |
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, |
|
|
246 | return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict); | |
|
139 | 247 | case 6 : |
|
140 |
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, |
|
|
248 | return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict); | |
|
141 | 249 | case 7 : |
|
142 |
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, |
|
|
250 | return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict); | |
|
251 | } | |
|
252 | } | |
|
253 | ||
|
254 | size_t ZSTD_compressBlock_fast_dictMatchState( | |
|
255 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
256 | void const* src, size_t srcSize) | |
|
257 | { | |
|
258 | ZSTD_compressionParameters const* cParams = &ms->cParams; | |
|
259 | U32 const mls = cParams->searchLength; | |
|
260 | assert(ms->dictMatchState != NULL); | |
|
261 | switch(mls) | |
|
262 | { | |
|
263 | default: /* includes case 3 */ | |
|
264 | case 4 : | |
|
265 | return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState); | |
|
266 | case 5 : | |
|
267 | return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState); | |
|
268 | case 6 : | |
|
269 | return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState); | |
|
270 | case 7 : | |
|
271 | return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState); | |
|
143 | 272 | } |
|
144 | 273 | } |
|
145 | 274 | |
|
146 | 275 | |
|
147 | 276 | static size_t ZSTD_compressBlock_fast_extDict_generic( |
|
148 | 277 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
149 | void const* src, size_t srcSize, | |
|
150 | U32 const hlog, U32 const stepSize, U32 const mls) | |
|
278 | void const* src, size_t srcSize, U32 const mls) | |
|
151 | 279 | { |
|
152 | U32* hashTable = ms->hashTable; | |
|
280 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
281 | U32* const hashTable = ms->hashTable; | |
|
282 | U32 const hlog = cParams->hashLog; | |
|
283 | /* support stepSize of 0 */ | |
|
284 | U32 const stepSize = cParams->targetLength + !(cParams->targetLength); | |
|
153 | 285 | const BYTE* const base = ms->window.base; |
|
154 | 286 | const BYTE* const dictBase = ms->window.dictBase; |
|
155 | 287 | const BYTE* const istart = (const BYTE*)src; |
|
156 | 288 | const BYTE* ip = istart; |
|
157 | 289 | const BYTE* anchor = istart; |
|
158 |
const U32 |
|
|
159 |
const BYTE* const dictStart = dictBase + |
|
|
160 |
const U32 |
|
|
161 |
const BYTE* const |
|
|
162 |
const BYTE* const dictEnd = dictBase + |
|
|
290 | const U32 dictStartIndex = ms->window.lowLimit; | |
|
291 | const BYTE* const dictStart = dictBase + dictStartIndex; | |
|
292 | const U32 prefixStartIndex = ms->window.dictLimit; | |
|
293 | const BYTE* const prefixStart = base + prefixStartIndex; | |
|
294 | const BYTE* const dictEnd = dictBase + prefixStartIndex; | |
|
163 | 295 | const BYTE* const iend = istart + srcSize; |
|
164 | 296 | const BYTE* const ilimit = iend - 8; |
|
165 | 297 | U32 offset_1=rep[0], offset_2=rep[1]; |
@@ -167,33 +299,34 b' static size_t ZSTD_compressBlock_fast_ex' | |||
|
167 | 299 | /* Search Loop */ |
|
168 | 300 | while (ip < ilimit) { /* < instead of <=, because (ip+1) */ |
|
169 | 301 | const size_t h = ZSTD_hashPtr(ip, hlog, mls); |
|
170 | const U32 matchIndex = hashTable[h]; | |
|
171 |
const BYTE* matchBase = matchIndex < |
|
|
172 | const BYTE* match = matchBase + matchIndex; | |
|
173 | const U32 current = (U32)(ip-base); | |
|
174 |
const U32 repIndex = current + 1 - offset_1; |
|
|
175 |
const BYTE* repBase = repIndex < |
|
|
176 | const BYTE* repMatch = repBase + repIndex; | |
|
302 | const U32 matchIndex = hashTable[h]; | |
|
303 | const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base; | |
|
304 | const BYTE* match = matchBase + matchIndex; | |
|
305 | const U32 current = (U32)(ip-base); | |
|
306 | const U32 repIndex = current + 1 - offset_1; | |
|
307 | const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; | |
|
308 | const BYTE* const repMatch = repBase + repIndex; | |
|
177 | 309 | size_t mLength; |
|
178 | 310 | hashTable[h] = current; /* update hash table */ |
|
311 | assert(offset_1 <= current +1); /* check repIndex */ | |
|
179 | 312 | |
|
180 |
if ( (((U32)(( |
|
|
313 | if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex)) | |
|
181 | 314 | && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { |
|
182 |
const BYTE* repMatchEnd = repIndex < |
|
|
183 |
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, |
|
|
315 | const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; | |
|
316 | mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; | |
|
184 | 317 | ip++; |
|
185 | 318 | ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH); |
|
186 | 319 | } else { |
|
187 |
if ( (matchIndex < |
|
|
320 | if ( (matchIndex < dictStartIndex) || | |
|
188 | 321 | (MEM_read32(match) != MEM_read32(ip)) ) { |
|
189 | 322 | assert(stepSize >= 1); |
|
190 | 323 | ip += ((ip-anchor) >> kSearchStrength) + stepSize; |
|
191 | 324 | continue; |
|
192 | 325 | } |
|
193 |
{ const BYTE* matchEnd = matchIndex < |
|
|
194 |
const BYTE* lowMatchPtr = matchIndex < |
|
|
326 | { const BYTE* matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; | |
|
327 | const BYTE* lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; | |
|
195 | 328 | U32 offset; |
|
196 |
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, |
|
|
329 | mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; | |
|
197 | 330 | while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ |
|
198 | 331 | offset = current - matchIndex; |
|
199 | 332 | offset_2 = offset_1; |
@@ -213,11 +346,11 b' static size_t ZSTD_compressBlock_fast_ex' | |||
|
213 | 346 | while (ip <= ilimit) { |
|
214 | 347 | U32 const current2 = (U32)(ip-base); |
|
215 | 348 | U32 const repIndex2 = current2 - offset_2; |
|
216 |
const BYTE* repMatch2 = repIndex2 < |
|
|
217 |
if ( (((U32)(( |
|
|
349 | const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; | |
|
350 | if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */ | |
|
218 | 351 | && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { |
|
219 |
const BYTE* const repEnd2 = repIndex2 < |
|
|
220 |
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, |
|
|
352 | const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; | |
|
353 | size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; | |
|
221 | 354 | U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ |
|
222 | 355 | ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH); |
|
223 | 356 | hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; |
@@ -239,21 +372,20 b' static size_t ZSTD_compressBlock_fast_ex' | |||
|
239 | 372 | |
|
240 | 373 | size_t ZSTD_compressBlock_fast_extDict( |
|
241 | 374 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
242 |
|
|
|
375 | void const* src, size_t srcSize) | |
|
243 | 376 | { |
|
244 | U32 const hlog = cParams->hashLog; | |
|
377 | ZSTD_compressionParameters const* cParams = &ms->cParams; | |
|
245 | 378 | U32 const mls = cParams->searchLength; |
|
246 | U32 const stepSize = cParams->targetLength; | |
|
247 | 379 | switch(mls) |
|
248 | 380 | { |
|
249 | 381 | default: /* includes case 3 */ |
|
250 | 382 | case 4 : |
|
251 |
return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, |
|
|
383 | return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); | |
|
252 | 384 | case 5 : |
|
253 |
return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, |
|
|
385 | return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); | |
|
254 | 386 | case 6 : |
|
255 |
return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, |
|
|
387 | return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); | |
|
256 | 388 | case 7 : |
|
257 |
return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, |
|
|
389 | return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); | |
|
258 | 390 | } |
|
259 | 391 | } |
@@ -19,14 +19,16 b' extern "C" {' | |||
|
19 | 19 | #include "zstd_compress_internal.h" |
|
20 | 20 | |
|
21 | 21 | void ZSTD_fillHashTable(ZSTD_matchState_t* ms, |
|
22 | ZSTD_compressionParameters const* cParams, | |
|
23 | void const* end); | |
|
22 | void const* end, ZSTD_dictTableLoadMethod_e dtlm); | |
|
24 | 23 | size_t ZSTD_compressBlock_fast( |
|
25 | 24 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
26 |
|
|
|
25 | void const* src, size_t srcSize); | |
|
26 | size_t ZSTD_compressBlock_fast_dictMatchState( | |
|
27 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
28 | void const* src, size_t srcSize); | |
|
27 | 29 | size_t ZSTD_compressBlock_fast_extDict( |
|
28 | 30 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
29 |
|
|
|
31 | void const* src, size_t srcSize); | |
|
30 | 32 | |
|
31 | 33 | #if defined (__cplusplus) |
|
32 | 34 | } |
This diff has been collapsed as it changes many lines, (522 lines changed) Show them Hide them | |||
@@ -16,11 +16,12 b'' | |||
|
16 | 16 | * Binary Tree search |
|
17 | 17 | ***************************************/ |
|
18 | 18 | |
|
19 | void ZSTD_updateDUBT( | |
|
20 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
19 | static void | |
|
20 | ZSTD_updateDUBT(ZSTD_matchState_t* ms, | |
|
21 | 21 | const BYTE* ip, const BYTE* iend, |
|
22 | 22 | U32 mls) |
|
23 | 23 | { |
|
24 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
24 | 25 | U32* const hashTable = ms->hashTable; |
|
25 | 26 | U32 const hashLog = cParams->hashLog; |
|
26 | 27 | |
@@ -59,11 +60,12 b' void ZSTD_updateDUBT(' | |||
|
59 | 60 | * sort one already inserted but unsorted position |
|
60 | 61 | * assumption : current >= btlow == (current - btmask) |
|
61 | 62 | * doesn't fail */ |
|
62 | static void ZSTD_insertDUBT1( | |
|
63 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
63 | static void | |
|
64 | ZSTD_insertDUBT1(ZSTD_matchState_t* ms, | |
|
64 | 65 | U32 current, const BYTE* inputEnd, |
|
65 |
U32 nbCompares, U32 btLow, |
|
|
66 | U32 nbCompares, U32 btLow, const ZSTD_dictMode_e dictMode) | |
|
66 | 67 | { |
|
68 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
67 | 69 | U32* const bt = ms->chainTable; |
|
68 | 70 | U32 const btLog = cParams->chainLog - 1; |
|
69 | 71 | U32 const btMask = (1 << btLog) - 1; |
@@ -92,10 +94,12 b' static void ZSTD_insertDUBT1(' | |||
|
92 | 94 | size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ |
|
93 | 95 | assert(matchIndex < current); |
|
94 | 96 | |
|
95 | if ( (!extDict) | |
|
97 | if ( (dictMode != ZSTD_extDict) | |
|
96 | 98 | || (matchIndex+matchLength >= dictLimit) /* both in current segment*/ |
|
97 | 99 | || (current < dictLimit) /* both in extDict */) { |
|
98 | const BYTE* const mBase = !extDict || ((matchIndex+matchLength) >= dictLimit) ? base : dictBase; | |
|
100 | const BYTE* const mBase = ( (dictMode != ZSTD_extDict) | |
|
101 | || (matchIndex+matchLength >= dictLimit)) ? | |
|
102 | base : dictBase; | |
|
99 | 103 | assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */ |
|
100 | 104 | || (current < dictLimit) ); |
|
101 | 105 | match = mBase + matchIndex; |
@@ -138,13 +142,95 b' static void ZSTD_insertDUBT1(' | |||
|
138 | 142 | } |
|
139 | 143 | |
|
140 | 144 | |
|
141 | static size_t ZSTD_DUBT_findBestMatch ( | |
|
142 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
143 | const BYTE* const ip, const BYTE* const iend, | |
|
144 | size_t* offsetPtr, | |
|
145 | U32 const mls, | |
|
146 | U32 const extDict) | |
|
145 | static size_t | |
|
146 | ZSTD_DUBT_findBetterDictMatch ( | |
|
147 | ZSTD_matchState_t* ms, | |
|
148 | const BYTE* const ip, const BYTE* const iend, | |
|
149 | size_t* offsetPtr, | |
|
150 | U32 nbCompares, | |
|
151 | U32 const mls, | |
|
152 | const ZSTD_dictMode_e dictMode) | |
|
147 | 153 | { |
|
154 | const ZSTD_matchState_t * const dms = ms->dictMatchState; | |
|
155 | const ZSTD_compressionParameters* const dmsCParams = &dms->cParams; | |
|
156 | const U32 * const dictHashTable = dms->hashTable; | |
|
157 | U32 const hashLog = dmsCParams->hashLog; | |
|
158 | size_t const h = ZSTD_hashPtr(ip, hashLog, mls); | |
|
159 | U32 dictMatchIndex = dictHashTable[h]; | |
|
160 | ||
|
161 | const BYTE* const base = ms->window.base; | |
|
162 | const BYTE* const prefixStart = base + ms->window.dictLimit; | |
|
163 | U32 const current = (U32)(ip-base); | |
|
164 | const BYTE* const dictBase = dms->window.base; | |
|
165 | const BYTE* const dictEnd = dms->window.nextSrc; | |
|
166 | U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base); | |
|
167 | U32 const dictLowLimit = dms->window.lowLimit; | |
|
168 | U32 const dictIndexDelta = ms->window.lowLimit - dictHighLimit; | |
|
169 | ||
|
170 | U32* const dictBt = dms->chainTable; | |
|
171 | U32 const btLog = dmsCParams->chainLog - 1; | |
|
172 | U32 const btMask = (1 << btLog) - 1; | |
|
173 | U32 const btLow = (btMask >= dictHighLimit - dictLowLimit) ? dictLowLimit : dictHighLimit - btMask; | |
|
174 | ||
|
175 | size_t commonLengthSmaller=0, commonLengthLarger=0, bestLength=0; | |
|
176 | U32 matchEndIdx = current+8+1; | |
|
177 | ||
|
178 | (void)dictMode; | |
|
179 | assert(dictMode == ZSTD_dictMatchState); | |
|
180 | ||
|
181 | while (nbCompares-- && (dictMatchIndex > dictLowLimit)) { | |
|
182 | U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask); | |
|
183 | size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ | |
|
184 | const BYTE* match = dictBase + dictMatchIndex; | |
|
185 | matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart); | |
|
186 | if (dictMatchIndex+matchLength >= dictHighLimit) | |
|
187 | match = base + dictMatchIndex + dictIndexDelta; /* to prepare for next usage of match[matchLength] */ | |
|
188 | ||
|
189 | if (matchLength > bestLength) { | |
|
190 | U32 matchIndex = dictMatchIndex + dictIndexDelta; | |
|
191 | if (matchLength > matchEndIdx - matchIndex) | |
|
192 | matchEndIdx = matchIndex + (U32)matchLength; | |
|
193 | if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { | |
|
194 | DEBUGLOG(2, "ZSTD_DUBT_findBestDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)", | |
|
195 | current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex); | |
|
196 | bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; | |
|
197 | } | |
|
198 | if (ip+matchLength == iend) { /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */ | |
|
199 | break; /* drop, to guarantee consistency (miss a little bit of compression) */ | |
|
200 | } | |
|
201 | } | |
|
202 | ||
|
203 | DEBUGLOG(2, "matchLength:%6zu, match:%p, prefixStart:%p, ip:%p", matchLength, match, prefixStart, ip); | |
|
204 | if (match[matchLength] < ip[matchLength]) { | |
|
205 | if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */ | |
|
206 | commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */ | |
|
207 | dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */ | |
|
208 | } else { | |
|
209 | /* match is larger than current */ | |
|
210 | if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */ | |
|
211 | commonLengthLarger = matchLength; | |
|
212 | dictMatchIndex = nextPtr[0]; | |
|
213 | } | |
|
214 | } | |
|
215 | ||
|
216 | if (bestLength >= MINMATCH) { | |
|
217 | U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; | |
|
218 | DEBUGLOG(2, "ZSTD_DUBT_findBestDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)", | |
|
219 | current, (U32)bestLength, (U32)*offsetPtr, mIndex); | |
|
220 | } | |
|
221 | return bestLength; | |
|
222 | ||
|
223 | } | |
|
224 | ||
|
225 | ||
|
226 | static size_t | |
|
227 | ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, | |
|
228 | const BYTE* const ip, const BYTE* const iend, | |
|
229 | size_t* offsetPtr, | |
|
230 | U32 const mls, | |
|
231 | const ZSTD_dictMode_e dictMode) | |
|
232 | { | |
|
233 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
148 | 234 | U32* const hashTable = ms->hashTable; |
|
149 | 235 | U32 const hashLog = cParams->hashLog; |
|
150 | 236 | size_t const h = ZSTD_hashPtr(ip, hashLog, mls); |
@@ -195,8 +281,8 b' static size_t ZSTD_DUBT_findBestMatch (' | |||
|
195 | 281 | while (matchIndex) { /* will end on matchIndex == 0 */ |
|
196 | 282 | U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1; |
|
197 | 283 | U32 const nextCandidateIdx = *nextCandidateIdxPtr; |
|
198 |
ZSTD_insertDUBT1(ms |
|
|
199 |
nbCandidates, unsortLimit, |
|
|
284 | ZSTD_insertDUBT1(ms, matchIndex, iend, | |
|
285 | nbCandidates, unsortLimit, dictMode); | |
|
200 | 286 | matchIndex = nextCandidateIdx; |
|
201 | 287 | nbCandidates++; |
|
202 | 288 | } |
@@ -221,7 +307,7 b' static size_t ZSTD_DUBT_findBestMatch (' | |||
|
221 | 307 | size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ |
|
222 | 308 | const BYTE* match; |
|
223 | 309 | |
|
224 | if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { | |
|
310 | if ((dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) { | |
|
225 | 311 | match = base + matchIndex; |
|
226 | 312 | matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend); |
|
227 | 313 | } else { |
@@ -259,6 +345,10 b' static size_t ZSTD_DUBT_findBestMatch (' | |||
|
259 | 345 | |
|
260 | 346 | *smallerPtr = *largerPtr = 0; |
|
261 | 347 | |
|
348 | if (dictMode == ZSTD_dictMatchState && nbCompares) { | |
|
349 | bestLength = ZSTD_DUBT_findBetterDictMatch(ms, ip, iend, offsetPtr, nbCompares, mls, dictMode); | |
|
350 | } | |
|
351 | ||
|
262 | 352 | assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */ |
|
263 | 353 | ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ |
|
264 | 354 | if (bestLength >= MINMATCH) { |
@@ -272,61 +362,64 b' static size_t ZSTD_DUBT_findBestMatch (' | |||
|
272 | 362 | |
|
273 | 363 | |
|
274 | 364 | /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */ |
|
275 | static size_t ZSTD_BtFindBestMatch ( | |
|
276 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
277 |
|
|
|
278 |
|
|
|
279 |
|
|
|
365 | FORCE_INLINE_TEMPLATE size_t | |
|
366 | ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms, | |
|
367 | const BYTE* const ip, const BYTE* const iLimit, | |
|
368 | size_t* offsetPtr, | |
|
369 | const U32 mls /* template */, | |
|
370 | const ZSTD_dictMode_e dictMode) | |
|
280 | 371 | { |
|
281 | 372 | DEBUGLOG(7, "ZSTD_BtFindBestMatch"); |
|
282 | 373 | if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ |
|
283 |
ZSTD_updateDUBT(ms |
|
|
284 |
return ZSTD_DUBT_findBestMatch(ms |
|
|
374 | ZSTD_updateDUBT(ms, ip, iLimit, mls); | |
|
375 | return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode); | |
|
285 | 376 | } |
|
286 | 377 | |
|
287 | 378 | |
|
288 | static size_t ZSTD_BtFindBestMatch_selectMLS ( | |
|
289 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
290 | const BYTE* ip, const BYTE* const iLimit, | |
|
291 | size_t* offsetPtr) | |
|
379 | static size_t | |
|
380 | ZSTD_BtFindBestMatch_selectMLS ( ZSTD_matchState_t* ms, | |
|
381 | const BYTE* ip, const BYTE* const iLimit, | |
|
382 | size_t* offsetPtr) | |
|
292 | 383 | { |
|
293 |
switch( |
|
|
384 | switch(ms->cParams.searchLength) | |
|
294 | 385 | { |
|
295 | 386 | default : /* includes case 3 */ |
|
296 |
case 4 : return ZSTD_BtFindBestMatch(ms, |
|
|
297 |
case 5 : return ZSTD_BtFindBestMatch(ms, |
|
|
387 | case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); | |
|
388 | case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); | |
|
298 | 389 | case 7 : |
|
299 |
case 6 : return ZSTD_BtFindBestMatch(ms, |
|
|
390 | case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); | |
|
300 | 391 | } |
|
301 | 392 | } |
|
302 | 393 | |
|
303 | 394 | |
|
304 | /** Tree updater, providing best match */ | |
|
305 | static size_t ZSTD_BtFindBestMatch_extDict ( | |
|
306 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
307 | const BYTE* const ip, const BYTE* const iLimit, | |
|
308 | size_t* offsetPtr, | |
|
309 | const U32 mls) | |
|
395 | static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS ( | |
|
396 | ZSTD_matchState_t* ms, | |
|
397 | const BYTE* ip, const BYTE* const iLimit, | |
|
398 | size_t* offsetPtr) | |
|
310 | 399 | { |
|
311 | DEBUGLOG(7, "ZSTD_BtFindBestMatch_extDict"); | |
|
312 | if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ | |
|
313 | ZSTD_updateDUBT(ms, cParams, ip, iLimit, mls); | |
|
314 |
return ZSTD_ |
|
|
400 | switch(ms->cParams.searchLength) | |
|
401 | { | |
|
402 | default : /* includes case 3 */ | |
|
403 | case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); | |
|
404 | case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); | |
|
405 | case 7 : | |
|
406 | case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); | |
|
407 | } | |
|
315 | 408 | } |
|
316 | 409 | |
|
317 | 410 | |
|
318 |
static size_t ZSTD_BtFindBestMatch_selectMLS |
|
|
319 |
ZSTD_matchState_t* ms, |
|
|
411 | static size_t ZSTD_BtFindBestMatch_extDict_selectMLS ( | |
|
412 | ZSTD_matchState_t* ms, | |
|
320 | 413 | const BYTE* ip, const BYTE* const iLimit, |
|
321 | 414 | size_t* offsetPtr) |
|
322 | 415 | { |
|
323 |
switch( |
|
|
416 | switch(ms->cParams.searchLength) | |
|
324 | 417 | { |
|
325 | 418 | default : /* includes case 3 */ |
|
326 |
case 4 : return ZSTD_BtFindBestMatch |
|
|
327 |
case 5 : return ZSTD_BtFindBestMatch |
|
|
419 | case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); | |
|
420 | case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); | |
|
328 | 421 | case 7 : |
|
329 |
case 6 : return ZSTD_BtFindBestMatch |
|
|
422 | case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); | |
|
330 | 423 | } |
|
331 | 424 | } |
|
332 | 425 | |
@@ -340,7 +433,8 b' static size_t ZSTD_BtFindBestMatch_selec' | |||
|
340 | 433 | /* Update chains up to ip (excluded) |
|
341 | 434 | Assumption : always within prefix (i.e. not within extDict) */ |
|
342 | 435 | static U32 ZSTD_insertAndFindFirstIndex_internal( |
|
343 |
ZSTD_matchState_t* ms, |
|
|
436 | ZSTD_matchState_t* ms, | |
|
437 | const ZSTD_compressionParameters* const cParams, | |
|
344 | 438 | const BYTE* ip, U32 const mls) |
|
345 | 439 | { |
|
346 | 440 | U32* const hashTable = ms->hashTable; |
@@ -362,22 +456,21 b' static U32 ZSTD_insertAndFindFirstIndex_' | |||
|
362 | 456 | return hashTable[ZSTD_hashPtr(ip, hashLog, mls)]; |
|
363 | 457 | } |
|
364 | 458 | |
|
365 | U32 ZSTD_insertAndFindFirstIndex( | |
|
366 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
367 | const BYTE* ip) | |
|
368 | { | |
|
369 | return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, cParams->searchLength); | |
|
459 | U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) { | |
|
460 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
461 | return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.searchLength); | |
|
370 | 462 | } |
|
371 | 463 | |
|
372 | 464 | |
|
373 | 465 | /* inlining is important to hardwire a hot branch (template emulation) */ |
|
374 | 466 | FORCE_INLINE_TEMPLATE |
|
375 | 467 | size_t ZSTD_HcFindBestMatch_generic ( |
|
376 |
ZSTD_matchState_t* ms, |
|
|
468 | ZSTD_matchState_t* ms, | |
|
377 | 469 | const BYTE* const ip, const BYTE* const iLimit, |
|
378 | 470 | size_t* offsetPtr, |
|
379 |
const U32 mls, const |
|
|
471 | const U32 mls, const ZSTD_dictMode_e dictMode) | |
|
380 | 472 | { |
|
473 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
381 | 474 | U32* const chainTable = ms->chainTable; |
|
382 | 475 | const U32 chainSize = (1 << cParams->chainLog); |
|
383 | 476 | const U32 chainMask = chainSize-1; |
@@ -397,7 +490,7 b' size_t ZSTD_HcFindBestMatch_generic (' | |||
|
397 | 490 | |
|
398 | 491 | for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) { |
|
399 | 492 | size_t currentMl=0; |
|
400 | if ((!extDict) || matchIndex >= dictLimit) { | |
|
493 | if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { | |
|
401 | 494 | const BYTE* const match = base + matchIndex; |
|
402 | 495 | if (match[ml] == ip[ml]) /* potentially better */ |
|
403 | 496 | currentMl = ZSTD_count(ip, match, iLimit); |
@@ -419,38 +512,87 b' size_t ZSTD_HcFindBestMatch_generic (' | |||
|
419 | 512 | matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask); |
|
420 | 513 | } |
|
421 | 514 | |
|
515 | if (dictMode == ZSTD_dictMatchState) { | |
|
516 | const ZSTD_matchState_t* const dms = ms->dictMatchState; | |
|
517 | const U32* const dmsChainTable = dms->chainTable; | |
|
518 | const U32 dmsChainSize = (1 << dms->cParams.chainLog); | |
|
519 | const U32 dmsChainMask = dmsChainSize - 1; | |
|
520 | const U32 dmsLowestIndex = dms->window.dictLimit; | |
|
521 | const BYTE* const dmsBase = dms->window.base; | |
|
522 | const BYTE* const dmsEnd = dms->window.nextSrc; | |
|
523 | const U32 dmsSize = (U32)(dmsEnd - dmsBase); | |
|
524 | const U32 dmsIndexDelta = dictLimit - dmsSize; | |
|
525 | const U32 dmsMinChain = dmsSize > dmsChainSize ? dmsSize - dmsChainSize : 0; | |
|
526 | ||
|
527 | matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)]; | |
|
528 | ||
|
529 | for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { | |
|
530 | size_t currentMl=0; | |
|
531 | const BYTE* const match = dmsBase + matchIndex; | |
|
532 | assert(match+4 <= dmsEnd); | |
|
533 | if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ | |
|
534 | currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4; | |
|
535 | ||
|
536 | /* save best solution */ | |
|
537 | if (currentMl > ml) { | |
|
538 | ml = currentMl; | |
|
539 | *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE; | |
|
540 | if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ | |
|
541 | } | |
|
542 | ||
|
543 | if (matchIndex <= dmsMinChain) break; | |
|
544 | matchIndex = dmsChainTable[matchIndex & dmsChainMask]; | |
|
545 | } | |
|
546 | } | |
|
547 | ||
|
422 | 548 | return ml; |
|
423 | 549 | } |
|
424 | 550 | |
|
425 | 551 | |
|
426 | 552 | FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS ( |
|
427 |
ZSTD_matchState_t* ms, |
|
|
553 | ZSTD_matchState_t* ms, | |
|
428 | 554 | const BYTE* ip, const BYTE* const iLimit, |
|
429 | 555 | size_t* offsetPtr) |
|
430 | 556 | { |
|
431 |
switch( |
|
|
557 | switch(ms->cParams.searchLength) | |
|
432 | 558 | { |
|
433 | 559 | default : /* includes case 3 */ |
|
434 |
case 4 : return ZSTD_HcFindBestMatch_generic(ms, |
|
|
435 |
case 5 : return ZSTD_HcFindBestMatch_generic(ms, |
|
|
560 | case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); | |
|
561 | case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); | |
|
436 | 562 | case 7 : |
|
437 |
case 6 : return ZSTD_HcFindBestMatch_generic(ms, |
|
|
563 | case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); | |
|
564 | } | |
|
565 | } | |
|
566 | ||
|
567 | ||
|
568 | static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS ( | |
|
569 | ZSTD_matchState_t* ms, | |
|
570 | const BYTE* ip, const BYTE* const iLimit, | |
|
571 | size_t* offsetPtr) | |
|
572 | { | |
|
573 | switch(ms->cParams.searchLength) | |
|
574 | { | |
|
575 | default : /* includes case 3 */ | |
|
576 | case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); | |
|
577 | case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); | |
|
578 | case 7 : | |
|
579 | case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); | |
|
438 | 580 | } |
|
439 | 581 | } |
|
440 | 582 | |
|
441 | 583 | |
|
442 | 584 | FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( |
|
443 |
ZSTD_matchState_t* ms, |
|
|
585 | ZSTD_matchState_t* ms, | |
|
444 | 586 | const BYTE* ip, const BYTE* const iLimit, |
|
445 |
size_t* |
|
|
587 | size_t* offsetPtr) | |
|
446 | 588 | { |
|
447 |
switch( |
|
|
589 | switch(ms->cParams.searchLength) | |
|
448 | 590 | { |
|
449 | 591 | default : /* includes case 3 */ |
|
450 |
case 4 : return ZSTD_HcFindBestMatch_generic(ms, |
|
|
451 |
case 5 : return ZSTD_HcFindBestMatch_generic(ms, |
|
|
592 | case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); | |
|
593 | case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); | |
|
452 | 594 | case 7 : |
|
453 |
case 6 : return ZSTD_HcFindBestMatch_generic(ms, |
|
|
595 | case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); | |
|
454 | 596 | } |
|
455 | 597 | } |
|
456 | 598 | |
@@ -462,30 +604,55 b' FORCE_INLINE_TEMPLATE' | |||
|
462 | 604 | size_t ZSTD_compressBlock_lazy_generic( |
|
463 | 605 | ZSTD_matchState_t* ms, seqStore_t* seqStore, |
|
464 | 606 | U32 rep[ZSTD_REP_NUM], |
|
465 | ZSTD_compressionParameters const* cParams, | |
|
466 | 607 | const void* src, size_t srcSize, |
|
467 |
const U32 searchMethod, const U32 depth |
|
|
608 | const U32 searchMethod, const U32 depth, | |
|
609 | ZSTD_dictMode_e const dictMode) | |
|
468 | 610 | { |
|
469 | 611 | const BYTE* const istart = (const BYTE*)src; |
|
470 | 612 | const BYTE* ip = istart; |
|
471 | 613 | const BYTE* anchor = istart; |
|
472 | 614 | const BYTE* const iend = istart + srcSize; |
|
473 | 615 | const BYTE* const ilimit = iend - 8; |
|
474 |
const BYTE* const base = ms->window.base |
|
|
616 | const BYTE* const base = ms->window.base; | |
|
617 | const U32 prefixLowestIndex = ms->window.dictLimit; | |
|
618 | const BYTE* const prefixLowest = base + prefixLowestIndex; | |
|
475 | 619 | |
|
476 | 620 | typedef size_t (*searchMax_f)( |
|
477 |
ZSTD_matchState_t* ms, |
|
|
621 | ZSTD_matchState_t* ms, | |
|
478 | 622 | const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); |
|
479 |
searchMax_f const searchMax = |
|
|
623 | searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ? | |
|
624 | (searchMethod ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) : | |
|
625 | (searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS); | |
|
480 | 626 | U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0; |
|
481 | 627 | |
|
628 | const ZSTD_matchState_t* const dms = ms->dictMatchState; | |
|
629 | const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ? | |
|
630 | dms->window.dictLimit : 0; | |
|
631 | const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? | |
|
632 | dms->window.base : NULL; | |
|
633 | const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ? | |
|
634 | dictBase + dictLowestIndex : NULL; | |
|
635 | const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? | |
|
636 | dms->window.nextSrc : NULL; | |
|
637 | const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? | |
|
638 | prefixLowestIndex - (U32)(dictEnd - dictBase) : | |
|
639 | 0; | |
|
640 | const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictLowest); | |
|
641 | ||
|
482 | 642 | /* init */ |
|
483 | ip += (ip==base); | |
|
643 | ip += (dictAndPrefixLength == 0); | |
|
484 | 644 | ms->nextToUpdate3 = ms->nextToUpdate; |
|
485 | { U32 const maxRep = (U32)(ip-base); | |
|
645 | if (dictMode == ZSTD_noDict) { | |
|
646 | U32 const maxRep = (U32)(ip - prefixLowest); | |
|
486 | 647 | if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0; |
|
487 | 648 | if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0; |
|
488 | 649 | } |
|
650 | if (dictMode == ZSTD_dictMatchState) { | |
|
651 | /* dictMatchState repCode checks don't currently handle repCode == 0 | |
|
652 | * disabling. */ | |
|
653 | assert(offset_1 <= dictAndPrefixLength); | |
|
654 | assert(offset_2 <= dictAndPrefixLength); | |
|
655 | } | |
|
489 | 656 | |
|
490 | 657 | /* Match Loop */ |
|
491 | 658 | while (ip < ilimit) { |
@@ -494,15 +661,28 b' size_t ZSTD_compressBlock_lazy_generic(' | |||
|
494 | 661 | const BYTE* start=ip+1; |
|
495 | 662 | |
|
496 | 663 | /* check repCode */ |
|
497 | if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) { | |
|
498 | /* repcode : we take it */ | |
|
664 | if (dictMode == ZSTD_dictMatchState) { | |
|
665 | const U32 repIndex = (U32)(ip - base) + 1 - offset_1; | |
|
666 | const BYTE* repMatch = (dictMode == ZSTD_dictMatchState | |
|
667 | && repIndex < prefixLowestIndex) ? | |
|
668 | dictBase + (repIndex - dictIndexDelta) : | |
|
669 | base + repIndex; | |
|
670 | if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) | |
|
671 | && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { | |
|
672 | const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; | |
|
673 | matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; | |
|
674 | if (depth==0) goto _storeSequence; | |
|
675 | } | |
|
676 | } | |
|
677 | if ( dictMode == ZSTD_noDict | |
|
678 | && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) { | |
|
499 | 679 | matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; |
|
500 | 680 | if (depth==0) goto _storeSequence; |
|
501 | 681 | } |
|
502 | 682 | |
|
503 | 683 | /* first search (depth 0) */ |
|
504 | { size_t offsetFound = 99999999; | |
|
505 |
size_t const ml2 = searchMax(ms, |
|
|
684 | { size_t offsetFound = 999999999; | |
|
685 | size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); | |
|
506 | 686 | if (ml2 > matchLength) |
|
507 | 687 | matchLength = ml2, start = ip, offset=offsetFound; |
|
508 | 688 | } |
@@ -516,15 +696,31 b' size_t ZSTD_compressBlock_lazy_generic(' | |||
|
516 | 696 | if (depth>=1) |
|
517 | 697 | while (ip<ilimit) { |
|
518 | 698 | ip ++; |
|
519 | if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { | |
|
699 | if ( (dictMode == ZSTD_noDict) | |
|
700 | && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { | |
|
520 | 701 | size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; |
|
521 | 702 | int const gain2 = (int)(mlRep * 3); |
|
522 | 703 | int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); |
|
523 | 704 | if ((mlRep >= 4) && (gain2 > gain1)) |
|
524 | 705 | matchLength = mlRep, offset = 0, start = ip; |
|
525 | 706 | } |
|
526 | { size_t offset2=99999999; | |
|
527 | size_t const ml2 = searchMax(ms, cParams, ip, iend, &offset2); | |
|
707 | if (dictMode == ZSTD_dictMatchState) { | |
|
708 | const U32 repIndex = (U32)(ip - base) - offset_1; | |
|
709 | const BYTE* repMatch = repIndex < prefixLowestIndex ? | |
|
710 | dictBase + (repIndex - dictIndexDelta) : | |
|
711 | base + repIndex; | |
|
712 | if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) | |
|
713 | && (MEM_read32(repMatch) == MEM_read32(ip)) ) { | |
|
714 | const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; | |
|
715 | size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; | |
|
716 | int const gain2 = (int)(mlRep * 3); | |
|
717 | int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); | |
|
718 | if ((mlRep >= 4) && (gain2 > gain1)) | |
|
719 | matchLength = mlRep, offset = 0, start = ip; | |
|
720 | } | |
|
721 | } | |
|
722 | { size_t offset2=999999999; | |
|
723 | size_t const ml2 = searchMax(ms, ip, iend, &offset2); | |
|
528 | 724 | int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ |
|
529 | 725 | int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); |
|
530 | 726 | if ((ml2 >= 4) && (gain2 > gain1)) { |
@@ -535,15 +731,31 b' size_t ZSTD_compressBlock_lazy_generic(' | |||
|
535 | 731 | /* let's find an even better one */ |
|
536 | 732 | if ((depth==2) && (ip<ilimit)) { |
|
537 | 733 | ip ++; |
|
538 | if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { | |
|
539 | size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; | |
|
540 | int const gain2 = (int)(ml2 * 4); | |
|
734 | if ( (dictMode == ZSTD_noDict) | |
|
735 | && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { | |
|
736 | size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; | |
|
737 | int const gain2 = (int)(mlRep * 4); | |
|
541 | 738 | int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); |
|
542 |
if ((ml |
|
|
543 |
matchLength = ml |
|
|
739 | if ((mlRep >= 4) && (gain2 > gain1)) | |
|
740 | matchLength = mlRep, offset = 0, start = ip; | |
|
544 | 741 | } |
|
545 | { size_t offset2=99999999; | |
|
546 | size_t const ml2 = searchMax(ms, cParams, ip, iend, &offset2); | |
|
742 | if (dictMode == ZSTD_dictMatchState) { | |
|
743 | const U32 repIndex = (U32)(ip - base) - offset_1; | |
|
744 | const BYTE* repMatch = repIndex < prefixLowestIndex ? | |
|
745 | dictBase + (repIndex - dictIndexDelta) : | |
|
746 | base + repIndex; | |
|
747 | if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) | |
|
748 | && (MEM_read32(repMatch) == MEM_read32(ip)) ) { | |
|
749 | const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; | |
|
750 | size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; | |
|
751 | int const gain2 = (int)(mlRep * 4); | |
|
752 | int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); | |
|
753 | if ((mlRep >= 4) && (gain2 > gain1)) | |
|
754 | matchLength = mlRep, offset = 0, start = ip; | |
|
755 | } | |
|
756 | } | |
|
757 | { size_t offset2=999999999; | |
|
758 | size_t const ml2 = searchMax(ms, ip, iend, &offset2); | |
|
547 | 759 | int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ |
|
548 | 760 | int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); |
|
549 | 761 | if ((ml2 >= 4) && (gain2 > gain1)) { |
@@ -560,9 +772,17 b' size_t ZSTD_compressBlock_lazy_generic(' | |||
|
560 | 772 | */ |
|
561 | 773 | /* catch up */ |
|
562 | 774 | if (offset) { |
|
563 | while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > base)) | |
|
564 | && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */ | |
|
565 | { start--; matchLength++; } | |
|
775 | if (dictMode == ZSTD_noDict) { | |
|
776 | while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest)) | |
|
777 | && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */ | |
|
778 | { start--; matchLength++; } | |
|
779 | } | |
|
780 | if (dictMode == ZSTD_dictMatchState) { | |
|
781 | U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); | |
|
782 | const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex; | |
|
783 | const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest; | |
|
784 | while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ | |
|
785 | } | |
|
566 | 786 | offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); |
|
567 | 787 | } |
|
568 | 788 | /* store sequence */ |
@@ -573,16 +793,39 b' size_t ZSTD_compressBlock_lazy_generic(' | |||
|
573 | 793 | } |
|
574 | 794 | |
|
575 | 795 | /* check immediate repcode */ |
|
576 | while ( ((ip <= ilimit) & (offset_2>0)) | |
|
577 | && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { | |
|
578 | /* store sequence */ | |
|
579 | matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | |
|
580 | offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */ | |
|
581 | ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH); | |
|
582 | ip += matchLength; | |
|
583 | anchor = ip; | |
|
584 | continue; /* faster when present ... (?) */ | |
|
585 | } } | |
|
796 | if (dictMode == ZSTD_dictMatchState) { | |
|
797 | while (ip <= ilimit) { | |
|
798 | U32 const current2 = (U32)(ip-base); | |
|
799 | U32 const repIndex = current2 - offset_2; | |
|
800 | const BYTE* repMatch = dictMode == ZSTD_dictMatchState | |
|
801 | && repIndex < prefixLowestIndex ? | |
|
802 | dictBase - dictIndexDelta + repIndex : | |
|
803 | base + repIndex; | |
|
804 | if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */) | |
|
805 | && (MEM_read32(repMatch) == MEM_read32(ip)) ) { | |
|
806 | const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend; | |
|
807 | matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4; | |
|
808 | offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */ | |
|
809 | ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH); | |
|
810 | ip += matchLength; | |
|
811 | anchor = ip; | |
|
812 | continue; | |
|
813 | } | |
|
814 | break; | |
|
815 | } | |
|
816 | } | |
|
817 | ||
|
818 | if (dictMode == ZSTD_noDict) { | |
|
819 | while ( ((ip <= ilimit) & (offset_2>0)) | |
|
820 | && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { | |
|
821 | /* store sequence */ | |
|
822 | matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | |
|
823 | offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */ | |
|
824 | ZSTD_storeSeq(seqStore, 0, anchor, 0, matchLength-MINMATCH); | |
|
825 | ip += matchLength; | |
|
826 | anchor = ip; | |
|
827 | continue; /* faster when present ... (?) */ | |
|
828 | } } } | |
|
586 | 829 | |
|
587 | 830 | /* Save reps for next block */ |
|
588 | 831 | rep[0] = offset_1 ? offset_1 : savedOffset; |
@@ -595,30 +838,58 b' size_t ZSTD_compressBlock_lazy_generic(' | |||
|
595 | 838 | |
|
596 | 839 | size_t ZSTD_compressBlock_btlazy2( |
|
597 | 840 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
598 |
|
|
|
841 | void const* src, size_t srcSize) | |
|
599 | 842 | { |
|
600 |
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, |
|
|
843 | return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 1, 2, ZSTD_noDict); | |
|
601 | 844 | } |
|
602 | 845 | |
|
603 | 846 | size_t ZSTD_compressBlock_lazy2( |
|
604 | 847 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
605 |
|
|
|
848 | void const* src, size_t srcSize) | |
|
606 | 849 | { |
|
607 |
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, |
|
|
850 | return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 2, ZSTD_noDict); | |
|
608 | 851 | } |
|
609 | 852 | |
|
610 | 853 | size_t ZSTD_compressBlock_lazy( |
|
611 | 854 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
612 |
|
|
|
855 | void const* src, size_t srcSize) | |
|
613 | 856 | { |
|
614 |
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, |
|
|
857 | return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 1, ZSTD_noDict); | |
|
615 | 858 | } |
|
616 | 859 | |
|
617 | 860 | size_t ZSTD_compressBlock_greedy( |
|
618 | 861 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
619 |
|
|
|
862 | void const* src, size_t srcSize) | |
|
863 | { | |
|
864 | return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 0, ZSTD_noDict); | |
|
865 | } | |
|
866 | ||
|
867 | size_t ZSTD_compressBlock_btlazy2_dictMatchState( | |
|
868 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
869 | void const* src, size_t srcSize) | |
|
870 | { | |
|
871 | return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 1, 2, ZSTD_dictMatchState); | |
|
872 | } | |
|
873 | ||
|
874 | size_t ZSTD_compressBlock_lazy2_dictMatchState( | |
|
875 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
876 | void const* src, size_t srcSize) | |
|
620 | 877 | { |
|
621 |
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, |
|
|
878 | return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 2, ZSTD_dictMatchState); | |
|
879 | } | |
|
880 | ||
|
881 | size_t ZSTD_compressBlock_lazy_dictMatchState( | |
|
882 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
883 | void const* src, size_t srcSize) | |
|
884 | { | |
|
885 | return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 1, ZSTD_dictMatchState); | |
|
886 | } | |
|
887 | ||
|
888 | size_t ZSTD_compressBlock_greedy_dictMatchState( | |
|
889 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
890 | void const* src, size_t srcSize) | |
|
891 | { | |
|
892 | return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 0, ZSTD_dictMatchState); | |
|
622 | 893 | } |
|
623 | 894 | |
|
624 | 895 | |
@@ -626,7 +897,6 b' FORCE_INLINE_TEMPLATE' | |||
|
626 | 897 | size_t ZSTD_compressBlock_lazy_extDict_generic( |
|
627 | 898 | ZSTD_matchState_t* ms, seqStore_t* seqStore, |
|
628 | 899 | U32 rep[ZSTD_REP_NUM], |
|
629 | ZSTD_compressionParameters const* cParams, | |
|
630 | 900 | const void* src, size_t srcSize, |
|
631 | 901 | const U32 searchMethod, const U32 depth) |
|
632 | 902 | { |
@@ -644,9 +914,9 b' size_t ZSTD_compressBlock_lazy_extDict_g' | |||
|
644 | 914 | const BYTE* const dictStart = dictBase + lowestIndex; |
|
645 | 915 | |
|
646 | 916 | typedef size_t (*searchMax_f)( |
|
647 |
ZSTD_matchState_t* ms, |
|
|
917 | ZSTD_matchState_t* ms, | |
|
648 | 918 | const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); |
|
649 |
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS |
|
|
919 | searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS; | |
|
650 | 920 | |
|
651 | 921 | U32 offset_1 = rep[0], offset_2 = rep[1]; |
|
652 | 922 | |
@@ -674,8 +944,8 b' size_t ZSTD_compressBlock_lazy_extDict_g' | |||
|
674 | 944 | } } |
|
675 | 945 | |
|
676 | 946 | /* first search (depth 0) */ |
|
677 | { size_t offsetFound = 99999999; | |
|
678 |
size_t const ml2 = searchMax(ms, |
|
|
947 | { size_t offsetFound = 999999999; | |
|
948 | size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); | |
|
679 | 949 | if (ml2 > matchLength) |
|
680 | 950 | matchLength = ml2, start = ip, offset=offsetFound; |
|
681 | 951 | } |
@@ -707,8 +977,8 b' size_t ZSTD_compressBlock_lazy_extDict_g' | |||
|
707 | 977 | } } |
|
708 | 978 | |
|
709 | 979 | /* search match, depth 1 */ |
|
710 | { size_t offset2=99999999; | |
|
711 |
size_t const ml2 = searchMax(ms, |
|
|
980 | { size_t offset2=999999999; | |
|
981 | size_t const ml2 = searchMax(ms, ip, iend, &offset2); | |
|
712 | 982 | int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ |
|
713 | 983 | int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); |
|
714 | 984 | if ((ml2 >= 4) && (gain2 > gain1)) { |
@@ -737,8 +1007,8 b' size_t ZSTD_compressBlock_lazy_extDict_g' | |||
|
737 | 1007 | } } |
|
738 | 1008 | |
|
739 | 1009 | /* search match, depth 2 */ |
|
740 | { size_t offset2=99999999; | |
|
741 |
size_t const ml2 = searchMax(ms, |
|
|
1010 | { size_t offset2=999999999; | |
|
1011 | size_t const ml2 = searchMax(ms, ip, iend, &offset2); | |
|
742 | 1012 | int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ |
|
743 | 1013 | int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); |
|
744 | 1014 | if ((ml2 >= 4) && (gain2 > gain1)) { |
@@ -794,31 +1064,31 b' size_t ZSTD_compressBlock_lazy_extDict_g' | |||
|
794 | 1064 | |
|
795 | 1065 | size_t ZSTD_compressBlock_greedy_extDict( |
|
796 | 1066 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
797 |
|
|
|
1067 | void const* src, size_t srcSize) | |
|
798 | 1068 | { |
|
799 |
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, |
|
|
1069 | return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 0); | |
|
800 | 1070 | } |
|
801 | 1071 | |
|
802 | 1072 | size_t ZSTD_compressBlock_lazy_extDict( |
|
803 | 1073 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
804 |
|
|
|
1074 | void const* src, size_t srcSize) | |
|
805 | 1075 | |
|
806 | 1076 | { |
|
807 |
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, |
|
|
1077 | return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 1); | |
|
808 | 1078 | } |
|
809 | 1079 | |
|
810 | 1080 | size_t ZSTD_compressBlock_lazy2_extDict( |
|
811 | 1081 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
812 |
|
|
|
1082 | void const* src, size_t srcSize) | |
|
813 | 1083 | |
|
814 | 1084 | { |
|
815 |
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, |
|
|
1085 | return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 2); | |
|
816 | 1086 | } |
|
817 | 1087 | |
|
818 | 1088 | size_t ZSTD_compressBlock_btlazy2_extDict( |
|
819 | 1089 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
820 |
|
|
|
1090 | void const* src, size_t srcSize) | |
|
821 | 1091 | |
|
822 | 1092 | { |
|
823 |
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, |
|
|
1093 | return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 1, 2); | |
|
824 | 1094 | } |
@@ -17,37 +17,48 b' extern "C" {' | |||
|
17 | 17 | |
|
18 | 18 | #include "zstd_compress_internal.h" |
|
19 | 19 | |
|
20 | U32 ZSTD_insertAndFindFirstIndex( | |
|
21 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
22 | const BYTE* ip); | |
|
20 | U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip); | |
|
23 | 21 | |
|
24 | 22 | void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). pre-emptively increase value of ZSTD_DUBT_UNSORTED_MARK */ |
|
25 | 23 | |
|
26 | 24 | size_t ZSTD_compressBlock_btlazy2( |
|
27 | 25 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
28 |
|
|
|
26 | void const* src, size_t srcSize); | |
|
29 | 27 | size_t ZSTD_compressBlock_lazy2( |
|
30 | 28 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
31 |
|
|
|
29 | void const* src, size_t srcSize); | |
|
32 | 30 | size_t ZSTD_compressBlock_lazy( |
|
33 | 31 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
34 |
|
|
|
32 | void const* src, size_t srcSize); | |
|
35 | 33 | size_t ZSTD_compressBlock_greedy( |
|
36 | 34 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
37 |
|
|
|
35 | void const* src, size_t srcSize); | |
|
36 | ||
|
37 | size_t ZSTD_compressBlock_btlazy2_dictMatchState( | |
|
38 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
39 | void const* src, size_t srcSize); | |
|
40 | size_t ZSTD_compressBlock_lazy2_dictMatchState( | |
|
41 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
42 | void const* src, size_t srcSize); | |
|
43 | size_t ZSTD_compressBlock_lazy_dictMatchState( | |
|
44 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
45 | void const* src, size_t srcSize); | |
|
46 | size_t ZSTD_compressBlock_greedy_dictMatchState( | |
|
47 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
48 | void const* src, size_t srcSize); | |
|
38 | 49 | |
|
39 | 50 | size_t ZSTD_compressBlock_greedy_extDict( |
|
40 | 51 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
41 |
|
|
|
52 | void const* src, size_t srcSize); | |
|
42 | 53 | size_t ZSTD_compressBlock_lazy_extDict( |
|
43 | 54 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
44 |
|
|
|
55 | void const* src, size_t srcSize); | |
|
45 | 56 | size_t ZSTD_compressBlock_lazy2_extDict( |
|
46 | 57 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
47 |
|
|
|
58 | void const* src, size_t srcSize); | |
|
48 | 59 | size_t ZSTD_compressBlock_btlazy2_extDict( |
|
49 | 60 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
50 |
|
|
|
61 | void const* src, size_t srcSize); | |
|
51 | 62 | |
|
52 | 63 | #if defined (__cplusplus) |
|
53 | 64 | } |
@@ -9,6 +9,7 b'' | |||
|
9 | 9 | |
|
10 | 10 | #include "zstd_ldm.h" |
|
11 | 11 | |
|
12 | #include "debug.h" | |
|
12 | 13 | #include "zstd_fast.h" /* ZSTD_fillHashTable() */ |
|
13 | 14 | #include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */ |
|
14 | 15 | |
@@ -20,7 +21,7 b'' | |||
|
20 | 21 | void ZSTD_ldm_adjustParameters(ldmParams_t* params, |
|
21 | 22 | ZSTD_compressionParameters const* cParams) |
|
22 | 23 | { |
|
23 |
|
|
|
24 | params->windowLog = cParams->windowLog; | |
|
24 | 25 | ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX); |
|
25 | 26 | DEBUGLOG(4, "ZSTD_ldm_adjustParameters"); |
|
26 | 27 | if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; |
@@ -33,12 +34,13 b' void ZSTD_ldm_adjustParameters(ldmParams' | |||
|
33 | 34 | params->minMatchLength = minMatch; |
|
34 | 35 | } |
|
35 | 36 | if (params->hashLog == 0) { |
|
36 | params->hashLog = MAX(ZSTD_HASHLOG_MIN, windowLog - LDM_HASH_RLOG); | |
|
37 | params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG); | |
|
37 | 38 | assert(params->hashLog <= ZSTD_HASHLOG_MAX); |
|
38 | 39 | } |
|
39 | 40 | if (params->hashEveryLog == 0) { |
|
40 | params->hashEveryLog = | |
|
41 | windowLog < params->hashLog ? 0 : windowLog - params->hashLog; | |
|
41 | params->hashEveryLog = params->windowLog < params->hashLog | |
|
42 | ? 0 | |
|
43 | : params->windowLog - params->hashLog; | |
|
42 | 44 | } |
|
43 | 45 | params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog); |
|
44 | 46 | } |
@@ -216,21 +218,18 b' static size_t ZSTD_ldm_countBackwardsMat' | |||
|
216 | 218 | * The tables for the other strategies are filled within their |
|
217 | 219 | * block compressors. */ |
|
218 | 220 | static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, |
|
219 | ZSTD_compressionParameters const* cParams, | |
|
220 | 221 | void const* end) |
|
221 | 222 | { |
|
222 | 223 | const BYTE* const iend = (const BYTE*)end; |
|
223 | 224 | |
|
224 |
switch( |
|
|
225 | switch(ms->cParams.strategy) | |
|
225 | 226 | { |
|
226 | 227 | case ZSTD_fast: |
|
227 |
ZSTD_fillHashTable(ms, |
|
|
228 | ms->nextToUpdate = (U32)(iend - ms->window.base); | |
|
228 | ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast); | |
|
229 | 229 | break; |
|
230 | 230 | |
|
231 | 231 | case ZSTD_dfast: |
|
232 |
ZSTD_fillDoubleHashTable(ms, |
|
|
233 | ms->nextToUpdate = (U32)(iend - ms->window.base); | |
|
232 | ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast); | |
|
234 | 233 | break; |
|
235 | 234 | |
|
236 | 235 | case ZSTD_greedy: |
@@ -508,7 +507,7 b' size_t ZSTD_ldm_generateSequences(' | |||
|
508 | 507 | * * Try invalidation after the sequence generation and test the |
|
509 | 508 | * the offset against maxDist directly. |
|
510 | 509 | */ |
|
511 | ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL); | |
|
510 | ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, NULL, NULL); | |
|
512 | 511 | /* 3. Generate the sequences for the chunk, and get newLeftoverSize. */ |
|
513 | 512 | newLeftoverSize = ZSTD_ldm_generateSequences_internal( |
|
514 | 513 | ldmState, sequences, params, chunkStart, chunkSize); |
@@ -591,19 +590,19 b' static rawSeq maybeSplitSequence(rawSeqS' | |||
|
591 | 590 | |
|
592 | 591 | size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, |
|
593 | 592 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
594 |
|
|
|
595 | int const extDict) | |
|
593 | void const* src, size_t srcSize) | |
|
596 | 594 | { |
|
595 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
597 | 596 | unsigned const minMatch = cParams->searchLength; |
|
598 | 597 | ZSTD_blockCompressor const blockCompressor = |
|
599 |
ZSTD_selectBlockCompressor(cParams->strategy, |
|
|
600 | BYTE const* const base = ms->window.base; | |
|
598 | ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms)); | |
|
601 | 599 | /* Input bounds */ |
|
602 | 600 | BYTE const* const istart = (BYTE const*)src; |
|
603 | 601 | BYTE const* const iend = istart + srcSize; |
|
604 | 602 | /* Input positions */ |
|
605 | 603 | BYTE const* ip = istart; |
|
606 | 604 | |
|
605 | DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize); | |
|
607 | 606 | assert(rawSeqStore->pos <= rawSeqStore->size); |
|
608 | 607 | assert(rawSeqStore->size <= rawSeqStore->capacity); |
|
609 | 608 | /* Loop through each sequence and apply the block compressor to the lits */ |
@@ -621,14 +620,13 b' size_t ZSTD_ldm_blockCompress(rawSeqStor' | |||
|
621 | 620 | |
|
622 | 621 | /* Fill tables for block compressor */ |
|
623 | 622 | ZSTD_ldm_limitTableUpdate(ms, ip); |
|
624 |
ZSTD_ldm_fillFastTables(ms, |
|
|
623 | ZSTD_ldm_fillFastTables(ms, ip); | |
|
625 | 624 | /* Run the block compressor */ |
|
625 | DEBUGLOG(5, "calling block compressor on segment of size %u", sequence.litLength); | |
|
626 | 626 | { |
|
627 | 627 | size_t const newLitLength = |
|
628 |
blockCompressor(ms, seqStore, rep, |
|
|
629 | sequence.litLength); | |
|
628 | blockCompressor(ms, seqStore, rep, ip, sequence.litLength); | |
|
630 | 629 | ip += sequence.litLength; |
|
631 | ms->nextToUpdate = (U32)(ip - base); | |
|
632 | 630 | /* Update the repcodes */ |
|
633 | 631 | for (i = ZSTD_REP_NUM - 1; i > 0; i--) |
|
634 | 632 | rep[i] = rep[i-1]; |
@@ -642,12 +640,7 b' size_t ZSTD_ldm_blockCompress(rawSeqStor' | |||
|
642 | 640 | } |
|
643 | 641 | /* Fill the tables for the block compressor */ |
|
644 | 642 | ZSTD_ldm_limitTableUpdate(ms, ip); |
|
645 |
ZSTD_ldm_fillFastTables(ms, |
|
|
643 | ZSTD_ldm_fillFastTables(ms, ip); | |
|
646 | 644 | /* Compress the last literals */ |
|
647 | { | |
|
648 | size_t const lastLiterals = blockCompressor(ms, seqStore, rep, cParams, | |
|
649 | ip, iend - ip); | |
|
650 | ms->nextToUpdate = (U32)(iend - base); | |
|
651 | return lastLiterals; | |
|
652 | } | |
|
645 | return blockCompressor(ms, seqStore, rep, ip, iend - ip); | |
|
653 | 646 | } |
@@ -61,9 +61,7 b' size_t ZSTD_ldm_generateSequences(' | |||
|
61 | 61 | */ |
|
62 | 62 | size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, |
|
63 | 63 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
64 | ZSTD_compressionParameters const* cParams, | |
|
65 | void const* src, size_t srcSize, | |
|
66 | int const extDict); | |
|
64 | void const* src, size_t srcSize); | |
|
67 | 65 | |
|
68 | 66 | /** |
|
69 | 67 | * ZSTD_ldm_skipSequences(): |
This diff has been collapsed as it changes many lines, (813 lines changed) Show them Hide them | |||
@@ -9,10 +9,11 b'' | |||
|
9 | 9 | */ |
|
10 | 10 | |
|
11 | 11 | #include "zstd_compress_internal.h" |
|
12 | #include "hist.h" | |
|
12 | 13 | #include "zstd_opt.h" |
|
13 | 14 | |
|
14 | 15 | |
|
15 |
#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats |
|
|
16 | #define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */ | |
|
16 | 17 | #define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */ |
|
17 | 18 | #define ZSTD_MAX_PRICE (1<<30) |
|
18 | 19 | |
@@ -20,128 +21,210 b'' | |||
|
20 | 21 | /*-************************************* |
|
21 | 22 | * Price functions for optimal parser |
|
22 | 23 | ***************************************/ |
|
23 | static void ZSTD_setLog2Prices(optState_t* optPtr) | |
|
24 | ||
|
25 | #if 0 /* approximation at bit level */ | |
|
26 | # define BITCOST_ACCURACY 0 | |
|
27 | # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) | |
|
28 | # define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat)) | |
|
29 | #elif 0 /* fractional bit accuracy */ | |
|
30 | # define BITCOST_ACCURACY 8 | |
|
31 | # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) | |
|
32 | # define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat)) | |
|
33 | #else /* opt==approx, ultra==accurate */ | |
|
34 | # define BITCOST_ACCURACY 8 | |
|
35 | # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) | |
|
36 | # define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat)) | |
|
37 | #endif | |
|
38 | ||
|
39 | MEM_STATIC U32 ZSTD_bitWeight(U32 stat) | |
|
40 | { | |
|
41 | return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER); | |
|
42 | } | |
|
43 | ||
|
44 | MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) | |
|
24 | 45 | { |
|
25 | optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1); | |
|
26 | optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1); | |
|
27 | optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1); | |
|
28 | optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1); | |
|
46 | U32 const stat = rawStat + 1; | |
|
47 | U32 const hb = ZSTD_highbit32(stat); | |
|
48 | U32 const BWeight = hb * BITCOST_MULTIPLIER; | |
|
49 | U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb; | |
|
50 | U32 const weight = BWeight + FWeight; | |
|
51 | assert(hb + BITCOST_ACCURACY < 31); | |
|
52 | return weight; | |
|
53 | } | |
|
54 | ||
|
55 | /* debugging function, @return price in bytes */ | |
|
56 | MEM_STATIC double ZSTD_fCost(U32 price) | |
|
57 | { | |
|
58 | return (double)price / (BITCOST_MULTIPLIER*8); | |
|
59 | } | |
|
60 | ||
|
61 | static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) | |
|
62 | { | |
|
63 | optPtr->litSumBasePrice = WEIGHT(optPtr->litSum, optLevel); | |
|
64 | optPtr->litLengthSumBasePrice = WEIGHT(optPtr->litLengthSum, optLevel); | |
|
65 | optPtr->matchLengthSumBasePrice = WEIGHT(optPtr->matchLengthSum, optLevel); | |
|
66 | optPtr->offCodeSumBasePrice = WEIGHT(optPtr->offCodeSum, optLevel); | |
|
29 | 67 | } |
|
30 | 68 | |
|
31 | 69 | |
|
70 | static U32 ZSTD_downscaleStat(U32* table, U32 lastEltIndex, int malus) | |
|
71 | { | |
|
72 | U32 s, sum=0; | |
|
73 | assert(ZSTD_FREQ_DIV+malus > 0 && ZSTD_FREQ_DIV+malus < 31); | |
|
74 | for (s=0; s<=lastEltIndex; s++) { | |
|
75 | table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus)); | |
|
76 | sum += table[s]; | |
|
77 | } | |
|
78 | return sum; | |
|
79 | } | |
|
80 | ||
|
32 | 81 | static void ZSTD_rescaleFreqs(optState_t* const optPtr, |
|
33 |
const BYTE* const src, size_t const srcSize |
|
|
82 | const BYTE* const src, size_t const srcSize, | |
|
83 | int optLevel) | |
|
34 | 84 | { |
|
35 |
optPtr-> |
|
|
85 | optPtr->priceType = zop_dynamic; | |
|
86 | ||
|
87 | if (optPtr->litLengthSum == 0) { /* first block : init */ | |
|
88 | if (srcSize <= 1024) /* heuristic */ | |
|
89 | optPtr->priceType = zop_predef; | |
|
90 | ||
|
91 | assert(optPtr->symbolCosts != NULL); | |
|
92 | if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) { /* huffman table presumed generated by dictionary */ | |
|
93 | optPtr->priceType = zop_dynamic; | |
|
36 | 94 | |
|
37 | if (optPtr->litLengthSum == 0) { /* first init */ | |
|
38 | unsigned u; | |
|
39 | if (srcSize <= 1024) optPtr->staticPrices = 1; | |
|
95 | assert(optPtr->litFreq != NULL); | |
|
96 | optPtr->litSum = 0; | |
|
97 | { unsigned lit; | |
|
98 | for (lit=0; lit<=MaxLit; lit++) { | |
|
99 | U32 const scaleLog = 11; /* scale to 2K */ | |
|
100 | U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit); | |
|
101 | assert(bitCost <= scaleLog); | |
|
102 | optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/; | |
|
103 | optPtr->litSum += optPtr->litFreq[lit]; | |
|
104 | } } | |
|
105 | ||
|
106 | { unsigned ll; | |
|
107 | FSE_CState_t llstate; | |
|
108 | FSE_initCState(&llstate, optPtr->symbolCosts->fse.litlengthCTable); | |
|
109 | optPtr->litLengthSum = 0; | |
|
110 | for (ll=0; ll<=MaxLL; ll++) { | |
|
111 | U32 const scaleLog = 10; /* scale to 1K */ | |
|
112 | U32 const bitCost = FSE_getMaxNbBits(llstate.symbolTT, ll); | |
|
113 | assert(bitCost < scaleLog); | |
|
114 | optPtr->litLengthFreq[ll] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/; | |
|
115 | optPtr->litLengthSum += optPtr->litLengthFreq[ll]; | |
|
116 | } } | |
|
40 | 117 | |
|
41 | assert(optPtr->litFreq!=NULL); | |
|
42 | for (u=0; u<=MaxLit; u++) | |
|
43 | optPtr->litFreq[u] = 0; | |
|
44 | for (u=0; u<srcSize; u++) | |
|
45 | optPtr->litFreq[src[u]]++; | |
|
46 | optPtr->litSum = 0; | |
|
47 | for (u=0; u<=MaxLit; u++) { | |
|
48 | optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> ZSTD_FREQ_DIV); | |
|
49 | optPtr->litSum += optPtr->litFreq[u]; | |
|
118 | { unsigned ml; | |
|
119 | FSE_CState_t mlstate; | |
|
120 | FSE_initCState(&mlstate, optPtr->symbolCosts->fse.matchlengthCTable); | |
|
121 | optPtr->matchLengthSum = 0; | |
|
122 | for (ml=0; ml<=MaxML; ml++) { | |
|
123 | U32 const scaleLog = 10; | |
|
124 | U32 const bitCost = FSE_getMaxNbBits(mlstate.symbolTT, ml); | |
|
125 | assert(bitCost < scaleLog); | |
|
126 | optPtr->matchLengthFreq[ml] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/; | |
|
127 | optPtr->matchLengthSum += optPtr->matchLengthFreq[ml]; | |
|
128 | } } | |
|
129 | ||
|
130 | { unsigned of; | |
|
131 | FSE_CState_t ofstate; | |
|
132 | FSE_initCState(&ofstate, optPtr->symbolCosts->fse.offcodeCTable); | |
|
133 | optPtr->offCodeSum = 0; | |
|
134 | for (of=0; of<=MaxOff; of++) { | |
|
135 | U32 const scaleLog = 10; | |
|
136 | U32 const bitCost = FSE_getMaxNbBits(ofstate.symbolTT, of); | |
|
137 | assert(bitCost < scaleLog); | |
|
138 | optPtr->offCodeFreq[of] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/; | |
|
139 | optPtr->offCodeSum += optPtr->offCodeFreq[of]; | |
|
140 | } } | |
|
141 | ||
|
142 | } else { /* not a dictionary */ | |
|
143 | ||
|
144 | assert(optPtr->litFreq != NULL); | |
|
145 | { unsigned lit = MaxLit; | |
|
146 | HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */ | |
|
147 | } | |
|
148 | optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); | |
|
149 | ||
|
150 | { unsigned ll; | |
|
151 | for (ll=0; ll<=MaxLL; ll++) | |
|
152 | optPtr->litLengthFreq[ll] = 1; | |
|
153 | } | |
|
154 | optPtr->litLengthSum = MaxLL+1; | |
|
155 | ||
|
156 | { unsigned ml; | |
|
157 | for (ml=0; ml<=MaxML; ml++) | |
|
158 | optPtr->matchLengthFreq[ml] = 1; | |
|
159 | } | |
|
160 | optPtr->matchLengthSum = MaxML+1; | |
|
161 | ||
|
162 | { unsigned of; | |
|
163 | for (of=0; of<=MaxOff; of++) | |
|
164 | optPtr->offCodeFreq[of] = 1; | |
|
165 | } | |
|
166 | optPtr->offCodeSum = MaxOff+1; | |
|
167 | ||
|
50 | 168 | } |
|
51 | 169 | |
|
52 | for (u=0; u<=MaxLL; u++) | |
|
53 | optPtr->litLengthFreq[u] = 1; | |
|
54 | optPtr->litLengthSum = MaxLL+1; | |
|
55 | for (u=0; u<=MaxML; u++) | |
|
56 | optPtr->matchLengthFreq[u] = 1; | |
|
57 | optPtr->matchLengthSum = MaxML+1; | |
|
58 | for (u=0; u<=MaxOff; u++) | |
|
59 | optPtr->offCodeFreq[u] = 1; | |
|
60 | optPtr->offCodeSum = (MaxOff+1); | |
|
61 | ||
|
62 | } else { | |
|
63 | unsigned u; | |
|
170 | } else { /* new block : re-use previous statistics, scaled down */ | |
|
64 | 171 | |
|
65 | optPtr->litSum = 0; | |
|
66 | for (u=0; u<=MaxLit; u++) { | |
|
67 | optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> (ZSTD_FREQ_DIV+1)); | |
|
68 | optPtr->litSum += optPtr->litFreq[u]; | |
|
69 | } | |
|
70 | optPtr->litLengthSum = 0; | |
|
71 | for (u=0; u<=MaxLL; u++) { | |
|
72 | optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1)); | |
|
73 | optPtr->litLengthSum += optPtr->litLengthFreq[u]; | |
|
74 | } | |
|
75 | optPtr->matchLengthSum = 0; | |
|
76 | for (u=0; u<=MaxML; u++) { | |
|
77 | optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV); | |
|
78 | optPtr->matchLengthSum += optPtr->matchLengthFreq[u]; | |
|
79 | } | |
|
80 | optPtr->offCodeSum = 0; | |
|
81 | for (u=0; u<=MaxOff; u++) { | |
|
82 | optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV); | |
|
83 | optPtr->offCodeSum += optPtr->offCodeFreq[u]; | |
|
84 | } | |
|
172 | optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); | |
|
173 | optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0); | |
|
174 | optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0); | |
|
175 | optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0); | |
|
85 | 176 | } |
|
86 | 177 | |
|
87 |
ZSTD_set |
|
|
178 | ZSTD_setBasePrices(optPtr, optLevel); | |
|
88 | 179 | } |
|
89 | 180 | |
|
90 | ||
|
91 | 181 | /* ZSTD_rawLiteralsCost() : |
|
92 |
* |
|
|
93 |
* does not include |
|
|
182 | * price of literals (only) in specified segment (which length can be 0). | |
|
183 | * does not include price of literalLength symbol */ | |
|
94 | 184 | static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, |
|
95 |
const optState_t* const optPtr |
|
|
185 | const optState_t* const optPtr, | |
|
186 | int optLevel) | |
|
96 | 187 | { |
|
97 | if (optPtr->staticPrices) return (litLength*6); /* 6 bit per literal - no statistic used */ | |
|
98 | 188 | if (litLength == 0) return 0; |
|
189 | if (optPtr->priceType == zop_predef) | |
|
190 | return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */ | |
|
99 | 191 | |
|
100 |
/* |
|
|
101 | { U32 u; | |
|
102 | U32 cost = litLength * optPtr->log2litSum; | |
|
103 | for (u=0; u < litLength; u++) | |
|
104 | cost -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1); | |
|
105 | return cost; | |
|
192 | /* dynamic statistics */ | |
|
193 | { U32 price = litLength * optPtr->litSumBasePrice; | |
|
194 | U32 u; | |
|
195 | for (u=0; u < litLength; u++) { | |
|
196 | assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */ | |
|
197 | price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel); | |
|
198 | } | |
|
199 | return price; | |
|
106 | 200 | } |
|
107 | 201 | } |
|
108 | 202 | |
|
109 | 203 | /* ZSTD_litLengthPrice() : |
|
110 | 204 | * cost of literalLength symbol */ |
|
111 | static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr) | |
|
205 | static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel) | |
|
112 | 206 | { |
|
113 | if (optPtr->staticPrices) return ZSTD_highbit32((U32)litLength+1); | |
|
207 | if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel); | |
|
114 | 208 | |
|
115 | /* literal Length */ | |
|
209 | /* dynamic statistics */ | |
|
116 | 210 | { U32 const llCode = ZSTD_LLcode(litLength); |
|
117 |
|
|
|
118 | return price; | |
|
211 | return (LL_bits[llCode] * BITCOST_MULTIPLIER) + (optPtr->litLengthSumBasePrice - WEIGHT(optPtr->litLengthFreq[llCode], optLevel)); | |
|
119 | 212 | } |
|
120 | 213 | } |
|
121 | 214 | |
|
122 | /* ZSTD_litLengthPrice() : | |
|
123 | * cost of the literal part of a sequence, | |
|
124 | * including literals themselves, and literalLength symbol */ | |
|
125 | static U32 ZSTD_fullLiteralsCost(const BYTE* const literals, U32 const litLength, | |
|
126 | const optState_t* const optPtr) | |
|
127 | { | |
|
128 | return ZSTD_rawLiteralsCost(literals, litLength, optPtr) | |
|
129 | + ZSTD_litLengthPrice(litLength, optPtr); | |
|
130 | } | |
|
131 | ||
|
132 | 215 | /* ZSTD_litLengthContribution() : |
|
133 | 216 | * @return ( cost(litlength) - cost(0) ) |
|
134 | 217 | * this value can then be added to rawLiteralsCost() |
|
135 | 218 | * to provide a cost which is directly comparable to a match ending at same position */ |
|
136 | static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr) | |
|
219 | static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr, int optLevel) | |
|
137 | 220 | { |
|
138 | if (optPtr->staticPrices) return ZSTD_highbit32(litLength+1); | |
|
221 | if (optPtr->priceType >= zop_predef) return WEIGHT(litLength, optLevel); | |
|
139 | 222 | |
|
140 | /* literal Length */ | |
|
223 | /* dynamic statistics */ | |
|
141 | 224 | { U32 const llCode = ZSTD_LLcode(litLength); |
|
142 | int const contribution = LL_bits[llCode] | |
|
143 | + ZSTD_highbit32(optPtr->litLengthFreq[0]+1) | |
|
144 |
- |
|
|
225 | int const contribution = (LL_bits[llCode] * BITCOST_MULTIPLIER) | |
|
226 | + WEIGHT(optPtr->litLengthFreq[0], optLevel) /* note: log2litLengthSum cancel out */ | |
|
227 | - WEIGHT(optPtr->litLengthFreq[llCode], optLevel); | |
|
145 | 228 | #if 1 |
|
146 | 229 | return contribution; |
|
147 | 230 | #else |
@@ -155,10 +238,11 b' static int ZSTD_litLengthContribution(U3' | |||
|
155 | 238 | * which can be compared to the ending cost of a match |
|
156 | 239 | * should a new match start at this position */ |
|
157 | 240 | static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength, |
|
158 |
const optState_t* const optPtr |
|
|
241 | const optState_t* const optPtr, | |
|
242 | int optLevel) | |
|
159 | 243 | { |
|
160 | int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr) | |
|
161 | + ZSTD_litLengthContribution(litLength, optPtr); | |
|
244 | int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel) | |
|
245 | + ZSTD_litLengthContribution(litLength, optPtr, optLevel); | |
|
162 | 246 | return contribution; |
|
163 | 247 | } |
|
164 | 248 | |
@@ -166,31 +250,38 b' static int ZSTD_literalsContribution(con' | |||
|
166 | 250 | * Provides the cost of the match part (offset + matchLength) of a sequence |
|
167 | 251 | * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence. |
|
168 | 252 | * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */ |
|
169 |
FORCE_INLINE_TEMPLATE U32 |
|
|
170 | U32 const offset, U32 const matchLength, | |
|
171 | const optState_t* const optPtr, | |
|
172 | int const optLevel) | |
|
253 | FORCE_INLINE_TEMPLATE U32 | |
|
254 | ZSTD_getMatchPrice(U32 const offset, | |
|
255 | U32 const matchLength, | |
|
256 | const optState_t* const optPtr, | |
|
257 | int const optLevel) | |
|
173 | 258 | { |
|
174 | 259 | U32 price; |
|
175 | 260 | U32 const offCode = ZSTD_highbit32(offset+1); |
|
176 | 261 | U32 const mlBase = matchLength - MINMATCH; |
|
177 | 262 | assert(matchLength >= MINMATCH); |
|
178 | 263 | |
|
179 |
if (optPtr-> |
|
|
180 | return ZSTD_highbit32((U32)mlBase+1) + 16 + offCode; | |
|
264 | if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */ | |
|
265 | return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER); | |
|
181 | 266 | |
|
182 | price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1); | |
|
183 | if ((optLevel<2) /*static*/ && offCode >= 20) price += (offCode-19)*2; /* handicap for long distance offsets, favor decompression speed */ | |
|
267 | /* dynamic statistics */ | |
|
268 | price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel)); | |
|
269 | if ((optLevel<2) /*static*/ && offCode >= 20) | |
|
270 | price += (offCode-19)*2 * BITCOST_MULTIPLIER; /* handicap for long distance offsets, favor decompression speed */ | |
|
184 | 271 | |
|
185 | 272 | /* match Length */ |
|
186 | 273 | { U32 const mlCode = ZSTD_MLcode(mlBase); |
|
187 |
price += ML_bits[mlCode] + optPtr-> |
|
|
274 | price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel)); | |
|
188 | 275 | } |
|
189 | 276 | |
|
277 | price += BITCOST_MULTIPLIER / 5; /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */ | |
|
278 | ||
|
190 | 279 | DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price); |
|
191 | 280 | return price; |
|
192 | 281 | } |
|
193 | 282 | |
|
283 | /* ZSTD_updateStats() : | |
|
284 | * assumption : literals + litLengtn <= iend */ | |
|
194 | 285 | static void ZSTD_updateStats(optState_t* const optPtr, |
|
195 | 286 | U32 litLength, const BYTE* literals, |
|
196 | 287 | U32 offsetCode, U32 matchLength) |
@@ -269,10 +360,11 b' static U32 ZSTD_insertAndFindFirstIndexH' | |||
|
269 | 360 | * ip : assumed <= iend-8 . |
|
270 | 361 | * @return : nb of positions added */ |
|
271 | 362 | static U32 ZSTD_insertBt1( |
|
272 |
ZSTD_matchState_t* ms, |
|
|
363 | ZSTD_matchState_t* ms, | |
|
273 | 364 | const BYTE* const ip, const BYTE* const iend, |
|
274 |
U32 const mls, |
|
|
365 | U32 const mls, const int extDict) | |
|
275 | 366 | { |
|
367 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
276 | 368 | U32* const hashTable = ms->hashTable; |
|
277 | 369 | U32 const hashLog = cParams->hashLog; |
|
278 | 370 | size_t const h = ZSTD_hashPtr(ip, hashLog, mls); |
@@ -293,6 +385,7 b' static U32 ZSTD_insertBt1(' | |||
|
293 | 385 | U32* largerPtr = smallerPtr + 1; |
|
294 | 386 | U32 dummy32; /* to be nullified at the end */ |
|
295 | 387 | U32 const windowLow = ms->window.lowLimit; |
|
388 | U32 const matchLow = windowLow ? windowLow : 1; | |
|
296 | 389 | U32 matchEndIdx = current+8+1; |
|
297 | 390 | size_t bestLength = 8; |
|
298 | 391 | U32 nbCompares = 1U << cParams->searchLog; |
@@ -308,7 +401,7 b' static U32 ZSTD_insertBt1(' | |||
|
308 | 401 | assert(ip <= iend-8); /* required for h calculation */ |
|
309 | 402 | hashTable[h] = current; /* Update Hash Table */ |
|
310 | 403 | |
|
311 |
while (nbCompares-- && (matchIndex > |
|
|
404 | while (nbCompares-- && (matchIndex >= matchLow)) { | |
|
312 | 405 | U32* const nextPtr = bt + 2*(matchIndex & btMask); |
|
313 | 406 | size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ |
|
314 | 407 | assert(matchIndex < current); |
@@ -334,8 +427,8 b' static U32 ZSTD_insertBt1(' | |||
|
334 | 427 | } |
|
335 | 428 | #endif |
|
336 | 429 | |
|
337 |
if ( |
|
|
338 |
assert(matchIndex+matchLength >= dictLimit); /* might be wrong if |
|
|
430 | if (!extDict || (matchIndex+matchLength >= dictLimit)) { | |
|
431 | assert(matchIndex+matchLength >= dictLimit); /* might be wrong if actually extDict */ | |
|
339 | 432 | match = base + matchIndex; |
|
340 | 433 | matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend); |
|
341 | 434 | } else { |
@@ -379,35 +472,33 b' static U32 ZSTD_insertBt1(' | |||
|
379 | 472 | |
|
380 | 473 | FORCE_INLINE_TEMPLATE |
|
381 | 474 | void ZSTD_updateTree_internal( |
|
382 |
ZSTD_matchState_t* ms, |
|
|
475 | ZSTD_matchState_t* ms, | |
|
383 | 476 | const BYTE* const ip, const BYTE* const iend, |
|
384 |
const U32 mls, const |
|
|
477 | const U32 mls, const ZSTD_dictMode_e dictMode) | |
|
385 | 478 | { |
|
386 | 479 | const BYTE* const base = ms->window.base; |
|
387 | 480 | U32 const target = (U32)(ip - base); |
|
388 | 481 | U32 idx = ms->nextToUpdate; |
|
389 |
DEBUGLOG( |
|
|
390 |
idx, target, |
|
|
482 | DEBUGLOG(5, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)", | |
|
483 | idx, target, dictMode); | |
|
391 | 484 | |
|
392 | 485 | while(idx < target) |
|
393 |
idx += ZSTD_insertBt1(ms |
|
|
486 | idx += ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict); | |
|
394 | 487 | ms->nextToUpdate = target; |
|
395 | 488 | } |
|
396 | 489 | |
|
397 | void ZSTD_updateTree( | |
|
398 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
399 | const BYTE* ip, const BYTE* iend) | |
|
400 | { | |
|
401 | ZSTD_updateTree_internal(ms, cParams, ip, iend, cParams->searchLength, 0 /*extDict*/); | |
|
490 | void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) { | |
|
491 | ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.searchLength, ZSTD_noDict); | |
|
402 | 492 | } |
|
403 | 493 | |
|
404 | 494 | FORCE_INLINE_TEMPLATE |
|
405 | 495 | U32 ZSTD_insertBtAndGetAllMatches ( |
|
406 |
ZSTD_matchState_t* ms, |
|
|
407 |
const BYTE* const ip, const BYTE* const iLimit, |
|
|
496 | ZSTD_matchState_t* ms, | |
|
497 | const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode, | |
|
408 | 498 | U32 rep[ZSTD_REP_NUM], U32 const ll0, |
|
409 | 499 | ZSTD_match_t* matches, const U32 lengthToBeat, U32 const mls /* template */) |
|
410 | 500 | { |
|
501 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
411 | 502 | U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); |
|
412 | 503 | const BYTE* const base = ms->window.base; |
|
413 | 504 | U32 const current = (U32)(ip-base); |
@@ -426,6 +517,7 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
426 | 517 | const BYTE* const prefixStart = base + dictLimit; |
|
427 | 518 | U32 const btLow = btMask >= current ? 0 : current - btMask; |
|
428 | 519 | U32 const windowLow = ms->window.lowLimit; |
|
520 | U32 const matchLow = windowLow ? windowLow : 1; | |
|
429 | 521 | U32* smallerPtr = bt + 2*(current&btMask); |
|
430 | 522 | U32* largerPtr = bt + 2*(current&btMask) + 1; |
|
431 | 523 | U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */ |
@@ -433,8 +525,21 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
433 | 525 | U32 mnum = 0; |
|
434 | 526 | U32 nbCompares = 1U << cParams->searchLog; |
|
435 | 527 | |
|
528 | const ZSTD_matchState_t* dms = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL; | |
|
529 | const ZSTD_compressionParameters* const dmsCParams = | |
|
530 | dictMode == ZSTD_dictMatchState ? &dms->cParams : NULL; | |
|
531 | const BYTE* const dmsBase = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL; | |
|
532 | const BYTE* const dmsEnd = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL; | |
|
533 | U32 const dmsHighLimit = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0; | |
|
534 | U32 const dmsLowLimit = dictMode == ZSTD_dictMatchState ? dms->window.lowLimit : 0; | |
|
535 | U32 const dmsIndexDelta = dictMode == ZSTD_dictMatchState ? windowLow - dmsHighLimit : 0; | |
|
536 | U32 const dmsHashLog = dictMode == ZSTD_dictMatchState ? dmsCParams->hashLog : hashLog; | |
|
537 | U32 const dmsBtLog = dictMode == ZSTD_dictMatchState ? dmsCParams->chainLog - 1 : btLog; | |
|
538 | U32 const dmsBtMask = dictMode == ZSTD_dictMatchState ? (1U << dmsBtLog) - 1 : 0; | |
|
539 | U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit; | |
|
540 | ||
|
436 | 541 | size_t bestLength = lengthToBeat-1; |
|
437 |
DEBUGLOG( |
|
|
542 | DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current); | |
|
438 | 543 | |
|
439 | 544 | /* check repCode */ |
|
440 | 545 | { U32 const lastR = ZSTD_REP_NUM + ll0; |
@@ -449,18 +554,26 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
449 | 554 | repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch; |
|
450 | 555 | } |
|
451 | 556 | } else { /* repIndex < dictLimit || repIndex >= current */ |
|
452 |
const BYTE* const repMatch = dict |
|
|
557 | const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ? | |
|
558 | dmsBase + repIndex - dmsIndexDelta : | |
|
559 | dictBase + repIndex; | |
|
453 | 560 | assert(current >= windowLow); |
|
454 | if ( extDict /* this case only valid in extDict mode */ | |
|
561 | if ( dictMode == ZSTD_extDict | |
|
455 | 562 | && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */ |
|
456 | 563 | & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */) |
|
457 | 564 | && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { |
|
458 | 565 | repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch; |
|
566 | } | |
|
567 | if (dictMode == ZSTD_dictMatchState | |
|
568 | && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */ | |
|
569 | & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */ | |
|
570 | && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { | |
|
571 | repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch; | |
|
459 | 572 | } } |
|
460 | 573 | /* save longer solution */ |
|
461 | 574 | if (repLen > bestLength) { |
|
462 |
DEBUGLOG(8, "found rep |
|
|
463 |
repCode |
|
|
575 | DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u", | |
|
576 | repCode, ll0, repOffset, repLen); | |
|
464 | 577 | bestLength = repLen; |
|
465 | 578 | matches[mnum].off = repCode - ll0; |
|
466 | 579 | matches[mnum].len = (U32)repLen; |
@@ -473,10 +586,10 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
473 | 586 | /* HC3 match finder */ |
|
474 | 587 | if ((mls == 3) /*static*/ && (bestLength < mls)) { |
|
475 | 588 | U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip); |
|
476 |
if ((matchIndex3 > |
|
|
589 | if ((matchIndex3 >= matchLow) | |
|
477 | 590 | & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { |
|
478 | 591 | size_t mlen; |
|
479 |
if (( |
|
|
592 | if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) { | |
|
480 | 593 | const BYTE* const match = base + matchIndex3; |
|
481 | 594 | mlen = ZSTD_count(ip, match, iLimit); |
|
482 | 595 | } else { |
@@ -498,17 +611,21 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
498 | 611 | (ip+mlen == iLimit) ) { /* best possible length */ |
|
499 | 612 | ms->nextToUpdate = current+1; /* skip insertion */ |
|
500 | 613 | return 1; |
|
501 | } } } } | |
|
614 | } | |
|
615 | } | |
|
616 | } | |
|
617 | /* no dictMatchState lookup: dicts don't have a populated HC3 table */ | |
|
618 | } | |
|
502 | 619 | |
|
503 | 620 | hashTable[h] = current; /* Update Hash Table */ |
|
504 | 621 | |
|
505 |
while (nbCompares-- && (matchIndex > |
|
|
622 | while (nbCompares-- && (matchIndex >= matchLow)) { | |
|
506 | 623 | U32* const nextPtr = bt + 2*(matchIndex & btMask); |
|
507 | 624 | size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ |
|
508 | 625 | const BYTE* match; |
|
509 | 626 | assert(current > matchIndex); |
|
510 | 627 | |
|
511 |
if (( |
|
|
628 | if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) { | |
|
512 | 629 | assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */ |
|
513 | 630 | match = base + matchIndex; |
|
514 | 631 | matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit); |
@@ -520,8 +637,8 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
520 | 637 | } |
|
521 | 638 | |
|
522 | 639 | if (matchLength > bestLength) { |
|
523 | DEBUGLOG(8, "found match of length %u at distance %u", | |
|
524 | (U32)matchLength, current - matchIndex); | |
|
640 | DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)", | |
|
641 | (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); | |
|
525 | 642 | assert(matchEndIdx > matchIndex); |
|
526 | 643 | if (matchLength > matchEndIdx - matchIndex) |
|
527 | 644 | matchEndIdx = matchIndex + (U32)matchLength; |
@@ -529,9 +646,10 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
529 | 646 | matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; |
|
530 | 647 | matches[mnum].len = (U32)matchLength; |
|
531 | 648 | mnum++; |
|
532 |
if (matchLength > ZSTD_OPT_NUM) |
|
|
533 |
|
|
|
534 | break; /* drop, to preserve bt consistency (miss a little bit of compression) */ | |
|
649 | if ( (matchLength > ZSTD_OPT_NUM) | |
|
650 | | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { | |
|
651 | if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */ | |
|
652 | break; /* drop, to preserve bt consistency (miss a little bit of compression) */ | |
|
535 | 653 | } |
|
536 | 654 | } |
|
537 | 655 | |
@@ -552,6 +670,47 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
552 | 670 | |
|
553 | 671 | *smallerPtr = *largerPtr = 0; |
|
554 | 672 | |
|
673 | if (dictMode == ZSTD_dictMatchState && nbCompares) { | |
|
674 | size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls); | |
|
675 | U32 dictMatchIndex = dms->hashTable[dmsH]; | |
|
676 | const U32* const dmsBt = dms->chainTable; | |
|
677 | commonLengthSmaller = commonLengthLarger = 0; | |
|
678 | while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) { | |
|
679 | const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask); | |
|
680 | size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ | |
|
681 | const BYTE* match = dmsBase + dictMatchIndex; | |
|
682 | matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dmsEnd, prefixStart); | |
|
683 | if (dictMatchIndex+matchLength >= dmsHighLimit) | |
|
684 | match = base + dictMatchIndex + dmsIndexDelta; /* to prepare for next usage of match[matchLength] */ | |
|
685 | ||
|
686 | if (matchLength > bestLength) { | |
|
687 | matchIndex = dictMatchIndex + dmsIndexDelta; | |
|
688 | DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)", | |
|
689 | (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); | |
|
690 | if (matchLength > matchEndIdx - matchIndex) | |
|
691 | matchEndIdx = matchIndex + (U32)matchLength; | |
|
692 | bestLength = matchLength; | |
|
693 | matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; | |
|
694 | matches[mnum].len = (U32)matchLength; | |
|
695 | mnum++; | |
|
696 | if ( (matchLength > ZSTD_OPT_NUM) | |
|
697 | | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { | |
|
698 | break; /* drop, to guarantee consistency (miss a little bit of compression) */ | |
|
699 | } | |
|
700 | } | |
|
701 | ||
|
702 | if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */ | |
|
703 | if (match[matchLength] < ip[matchLength]) { | |
|
704 | commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */ | |
|
705 | dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */ | |
|
706 | } else { | |
|
707 | /* match is larger than current */ | |
|
708 | commonLengthLarger = matchLength; | |
|
709 | dictMatchIndex = nextPtr[0]; | |
|
710 | } | |
|
711 | } | |
|
712 | } | |
|
713 | ||
|
555 | 714 | assert(matchEndIdx > current+8); |
|
556 | 715 | ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ |
|
557 | 716 | return mnum; |
@@ -559,23 +718,24 b' U32 ZSTD_insertBtAndGetAllMatches (' | |||
|
559 | 718 | |
|
560 | 719 | |
|
561 | 720 | FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches ( |
|
562 |
ZSTD_matchState_t* ms, |
|
|
563 |
const BYTE* ip, const BYTE* const iHighLimit, |
|
|
721 | ZSTD_matchState_t* ms, | |
|
722 | const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode, | |
|
564 | 723 | U32 rep[ZSTD_REP_NUM], U32 const ll0, |
|
565 | 724 | ZSTD_match_t* matches, U32 const lengthToBeat) |
|
566 | 725 | { |
|
726 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
567 | 727 | U32 const matchLengthSearch = cParams->searchLength; |
|
568 |
DEBUGLOG( |
|
|
728 | DEBUGLOG(8, "ZSTD_BtGetAllMatches"); | |
|
569 | 729 | if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ |
|
570 |
ZSTD_updateTree_internal(ms |
|
|
730 | ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode); | |
|
571 | 731 | switch(matchLengthSearch) |
|
572 | 732 | { |
|
573 |
case 3 : return ZSTD_insertBtAndGetAllMatches(ms, |
|
|
733 | case 3 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 3); | |
|
574 | 734 | default : |
|
575 |
case 4 : return ZSTD_insertBtAndGetAllMatches(ms, |
|
|
576 |
case 5 : return ZSTD_insertBtAndGetAllMatches(ms, |
|
|
735 | case 4 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 4); | |
|
736 | case 5 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 5); | |
|
577 | 737 | case 7 : |
|
578 |
case 6 : return ZSTD_insertBtAndGetAllMatches(ms, |
|
|
738 | case 6 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 6); | |
|
579 | 739 | } |
|
580 | 740 | } |
|
581 | 741 | |
@@ -587,7 +747,7 b' typedef struct repcodes_s {' | |||
|
587 | 747 | U32 rep[3]; |
|
588 | 748 | } repcodes_t; |
|
589 | 749 | |
|
590 | repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0) | |
|
750 | static repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0) | |
|
591 | 751 | { |
|
592 | 752 | repcodes_t newReps; |
|
593 | 753 | if (offset >= ZSTD_REP_NUM) { /* full offset */ |
@@ -609,65 +769,17 b' repcodes_t ZSTD_updateRep(U32 const rep[' | |||
|
609 | 769 | } |
|
610 | 770 | |
|
611 | 771 | |
|
612 | typedef struct { | |
|
613 | const BYTE* anchor; | |
|
614 | U32 litlen; | |
|
615 | U32 rawLitCost; | |
|
616 | } cachedLiteralPrice_t; | |
|
617 | ||
|
618 | static U32 ZSTD_rawLiteralsCost_cached( | |
|
619 | cachedLiteralPrice_t* const cachedLitPrice, | |
|
620 | const BYTE* const anchor, U32 const litlen, | |
|
621 | const optState_t* const optStatePtr) | |
|
772 | static U32 ZSTD_totalLen(ZSTD_optimal_t sol) | |
|
622 | 773 | { |
|
623 | U32 startCost; | |
|
624 | U32 remainingLength; | |
|
625 | const BYTE* startPosition; | |
|
626 | ||
|
627 | if (anchor == cachedLitPrice->anchor) { | |
|
628 | startCost = cachedLitPrice->rawLitCost; | |
|
629 | startPosition = anchor + cachedLitPrice->litlen; | |
|
630 | assert(litlen >= cachedLitPrice->litlen); | |
|
631 | remainingLength = litlen - cachedLitPrice->litlen; | |
|
632 | } else { | |
|
633 | startCost = 0; | |
|
634 | startPosition = anchor; | |
|
635 | remainingLength = litlen; | |
|
636 | } | |
|
637 | ||
|
638 | { U32 const rawLitCost = startCost + ZSTD_rawLiteralsCost(startPosition, remainingLength, optStatePtr); | |
|
639 | cachedLitPrice->anchor = anchor; | |
|
640 | cachedLitPrice->litlen = litlen; | |
|
641 | cachedLitPrice->rawLitCost = rawLitCost; | |
|
642 | return rawLitCost; | |
|
643 | } | |
|
774 | return sol.litlen + sol.mlen; | |
|
644 | 775 | } |
|
645 | 776 | |
|
646 | static U32 ZSTD_fullLiteralsCost_cached( | |
|
647 | cachedLiteralPrice_t* const cachedLitPrice, | |
|
648 |
|
|
|
649 | const optState_t* const optStatePtr) | |
|
650 | { | |
|
651 | return ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr) | |
|
652 | + ZSTD_litLengthPrice(litlen, optStatePtr); | |
|
653 | } | |
|
654 | ||
|
655 | static int ZSTD_literalsContribution_cached( | |
|
656 | cachedLiteralPrice_t* const cachedLitPrice, | |
|
657 | const BYTE* const anchor, U32 const litlen, | |
|
658 | const optState_t* const optStatePtr) | |
|
659 | { | |
|
660 | int const contribution = ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr) | |
|
661 | + ZSTD_litLengthContribution(litlen, optStatePtr); | |
|
662 | return contribution; | |
|
663 | } | |
|
664 | ||
|
665 | FORCE_INLINE_TEMPLATE | |
|
666 | size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,seqStore_t* seqStore, | |
|
667 | U32 rep[ZSTD_REP_NUM], | |
|
668 | ZSTD_compressionParameters const* cParams, | |
|
669 | const void* src, size_t srcSize, | |
|
670 | const int optLevel, const int extDict) | |
|
777 | FORCE_INLINE_TEMPLATE size_t | |
|
778 | ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, | |
|
779 | seqStore_t* seqStore, | |
|
780 | U32 rep[ZSTD_REP_NUM], | |
|
781 | const void* src, size_t srcSize, | |
|
782 | const int optLevel, const ZSTD_dictMode_e dictMode) | |
|
671 | 783 | { |
|
672 | 784 | optState_t* const optStatePtr = &ms->opt; |
|
673 | 785 | const BYTE* const istart = (const BYTE*)src; |
@@ -677,72 +789,76 b' size_t ZSTD_compressBlock_opt_generic(ZS' | |||
|
677 | 789 | const BYTE* const ilimit = iend - 8; |
|
678 | 790 | const BYTE* const base = ms->window.base; |
|
679 | 791 | const BYTE* const prefixStart = base + ms->window.dictLimit; |
|
792 | const ZSTD_compressionParameters* const cParams = &ms->cParams; | |
|
680 | 793 | |
|
681 | 794 | U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); |
|
682 | 795 | U32 const minMatch = (cParams->searchLength == 3) ? 3 : 4; |
|
683 | 796 | |
|
684 | 797 | ZSTD_optimal_t* const opt = optStatePtr->priceTable; |
|
685 | 798 | ZSTD_match_t* const matches = optStatePtr->matchTable; |
|
686 | cachedLiteralPrice_t cachedLitPrice; | |
|
799 | ZSTD_optimal_t lastSequence; | |
|
687 | 800 | |
|
688 | 801 | /* init */ |
|
689 | 802 | DEBUGLOG(5, "ZSTD_compressBlock_opt_generic"); |
|
803 | assert(optLevel <= 2); | |
|
690 | 804 | ms->nextToUpdate3 = ms->nextToUpdate; |
|
691 | ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize); | |
|
805 | ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel); | |
|
692 | 806 | ip += (ip==prefixStart); |
|
693 | memset(&cachedLitPrice, 0, sizeof(cachedLitPrice)); | |
|
694 | 807 | |
|
695 | 808 | /* Match Loop */ |
|
696 | 809 | while (ip < ilimit) { |
|
697 | 810 | U32 cur, last_pos = 0; |
|
698 | U32 best_mlen, best_off; | |
|
699 | 811 | |
|
700 | 812 | /* find first match */ |
|
701 | 813 | { U32 const litlen = (U32)(ip - anchor); |
|
702 | 814 | U32 const ll0 = !litlen; |
|
703 |
U32 const nbMatches = ZSTD_BtGetAllMatches(ms, |
|
|
815 | U32 const nbMatches = ZSTD_BtGetAllMatches(ms, ip, iend, dictMode, rep, ll0, matches, minMatch); | |
|
704 | 816 | if (!nbMatches) { ip++; continue; } |
|
705 | 817 | |
|
706 | 818 | /* initialize opt[0] */ |
|
707 | 819 | { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; } |
|
708 |
opt[0].mlen = |
|
|
820 | opt[0].mlen = 0; /* means is_a_literal */ | |
|
709 | 821 | opt[0].litlen = litlen; |
|
822 | opt[0].price = ZSTD_literalsContribution(anchor, litlen, optStatePtr, optLevel); | |
|
710 | 823 | |
|
711 | 824 | /* large match -> immediate encoding */ |
|
712 | 825 | { U32 const maxML = matches[nbMatches-1].len; |
|
713 | DEBUGLOG(7, "found %u matches of maxLength=%u and offset=%u at cPos=%u => start new serie", | |
|
714 | nbMatches, maxML, matches[nbMatches-1].off, (U32)(ip-prefixStart)); | |
|
826 | U32 const maxOffset = matches[nbMatches-1].off; | |
|
827 | DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new serie", | |
|
828 | nbMatches, maxML, maxOffset, (U32)(ip-prefixStart)); | |
|
715 | 829 | |
|
716 | 830 | if (maxML > sufficient_len) { |
|
717 |
|
|
|
718 | best_off = matches[nbMatches-1].off; | |
|
719 | DEBUGLOG(7, "large match (%u>%u), immediate encoding", | |
|
720 | best_mlen, sufficient_len); | |
|
831 | lastSequence.litlen = litlen; | |
|
832 | lastSequence.mlen = maxML; | |
|
833 | lastSequence.off = maxOffset; | |
|
834 | DEBUGLOG(6, "large match (%u>%u), immediate encoding", | |
|
835 | maxML, sufficient_len); | |
|
721 | 836 | cur = 0; |
|
722 |
last_pos = |
|
|
837 | last_pos = ZSTD_totalLen(lastSequence); | |
|
723 | 838 | goto _shortestPath; |
|
724 | 839 | } } |
|
725 | 840 | |
|
726 | 841 | /* set prices for first matches starting position == 0 */ |
|
727 |
{ U32 const literalsPrice = |
|
|
842 | { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel); | |
|
728 | 843 | U32 pos; |
|
729 | 844 | U32 matchNb; |
|
730 |
for (pos = |
|
|
731 | opt[pos].mlen = 1; | |
|
732 | opt[pos].price = ZSTD_MAX_PRICE; | |
|
845 | for (pos = 1; pos < minMatch; pos++) { | |
|
846 | opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */ | |
|
733 | 847 | } |
|
734 | 848 | for (matchNb = 0; matchNb < nbMatches; matchNb++) { |
|
735 | 849 | U32 const offset = matches[matchNb].off; |
|
736 | 850 | U32 const end = matches[matchNb].len; |
|
737 | 851 | repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0); |
|
738 | 852 | for ( ; pos <= end ; pos++ ) { |
|
739 |
U32 const matchPrice = |
|
|
740 | DEBUGLOG(7, "rPos:%u => set initial price : %u", | |
|
741 | pos, matchPrice); | |
|
853 | U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel); | |
|
854 | U32 const sequencePrice = literalsPrice + matchPrice; | |
|
855 | DEBUGLOG(7, "rPos:%u => set initial price : %.2f", | |
|
856 | pos, ZSTD_fCost(sequencePrice)); | |
|
742 | 857 | opt[pos].mlen = pos; |
|
743 | 858 | opt[pos].off = offset; |
|
744 | 859 | opt[pos].litlen = litlen; |
|
745 |
opt[pos].price = |
|
|
860 | opt[pos].price = sequencePrice; | |
|
861 | ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory)); | |
|
746 | 862 | memcpy(opt[pos].rep, &repHistory, sizeof(repHistory)); |
|
747 | 863 | } } |
|
748 | 864 | last_pos = pos-1; |
@@ -753,55 +869,67 b' size_t ZSTD_compressBlock_opt_generic(ZS' | |||
|
753 | 869 | for (cur = 1; cur <= last_pos; cur++) { |
|
754 | 870 | const BYTE* const inr = ip + cur; |
|
755 | 871 | assert(cur < ZSTD_OPT_NUM); |
|
872 | DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur) | |
|
756 | 873 | |
|
757 | 874 | /* Fix current position with one literal if cheaper */ |
|
758 |
{ U32 const litlen = (opt[cur-1].mlen == |
|
|
759 | int price; /* note : contribution can be negative */ | |
|
760 | if (cur > litlen) { | |
|
761 |
|
|
|
762 | } else { | |
|
763 | price = ZSTD_literalsContribution_cached(&cachedLitPrice, anchor, litlen, optStatePtr); | |
|
764 | } | |
|
875 | { U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1; | |
|
876 | int const price = opt[cur-1].price | |
|
877 | + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel) | |
|
878 | + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel) | |
|
879 | - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel); | |
|
765 | 880 | assert(price < 1000000000); /* overflow check */ |
|
766 | 881 | if (price <= opt[cur].price) { |
|
767 |
DEBUGLOG(7, "rPos:%u : better price (% |
|
|
768 |
cur, price, opt[cur].price) |
|
|
769 | opt[cur].mlen = 1; | |
|
882 | DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)", | |
|
883 | inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen, | |
|
884 | opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]); | |
|
885 | opt[cur].mlen = 0; | |
|
770 | 886 | opt[cur].off = 0; |
|
771 | 887 | opt[cur].litlen = litlen; |
|
772 | 888 | opt[cur].price = price; |
|
773 | 889 | memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep)); |
|
774 |
} |
|
|
890 | } else { | |
|
891 | DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)", | |
|
892 | inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), | |
|
893 | opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]); | |
|
894 | } | |
|
895 | } | |
|
775 | 896 | |
|
776 | 897 | /* last match must start at a minimum distance of 8 from oend */ |
|
777 | 898 | if (inr > ilimit) continue; |
|
778 | 899 | |
|
779 | 900 | if (cur == last_pos) break; |
|
780 | 901 | |
|
781 |
|
|
|
782 |
|
|
|
902 | if ( (optLevel==0) /*static_test*/ | |
|
903 | && (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) { | |
|
904 | DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1); | |
|
783 | 905 | continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */ |
|
906 | } | |
|
784 | 907 | |
|
785 |
{ U32 const ll0 = (opt[cur].mlen != |
|
|
786 |
U32 const litlen = (opt[cur].mlen == |
|
|
787 |
U32 const previousPrice = |
|
|
788 |
U32 const basePrice = previousPrice + ZSTD_ |
|
|
789 |
U32 const nbMatches = ZSTD_BtGetAllMatches(ms, |
|
|
908 | { U32 const ll0 = (opt[cur].mlen != 0); | |
|
909 | U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0; | |
|
910 | U32 const previousPrice = opt[cur].price; | |
|
911 | U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel); | |
|
912 | U32 const nbMatches = ZSTD_BtGetAllMatches(ms, inr, iend, dictMode, opt[cur].rep, ll0, matches, minMatch); | |
|
790 | 913 | U32 matchNb; |
|
791 |
if (!nbMatches) |
|
|
914 | if (!nbMatches) { | |
|
915 | DEBUGLOG(7, "rPos:%u : no match found", cur); | |
|
916 | continue; | |
|
917 | } | |
|
792 | 918 | |
|
793 | 919 | { U32 const maxML = matches[nbMatches-1].len; |
|
794 | DEBUGLOG(7, "rPos:%u, found %u matches, of maxLength=%u", | |
|
795 | cur, nbMatches, maxML); | |
|
920 | DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u", | |
|
921 | inr-istart, cur, nbMatches, maxML); | |
|
796 | 922 | |
|
797 | 923 | if ( (maxML > sufficient_len) |
|
798 |
|
|
|
799 |
|
|
|
800 |
|
|
|
801 |
last |
|
|
924 | || (cur + maxML >= ZSTD_OPT_NUM) ) { | |
|
925 | lastSequence.mlen = maxML; | |
|
926 | lastSequence.off = matches[nbMatches-1].off; | |
|
927 | lastSequence.litlen = litlen; | |
|
928 | cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */ | |
|
929 | last_pos = cur + ZSTD_totalLen(lastSequence); | |
|
930 | if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */ | |
|
802 | 931 | goto _shortestPath; |
|
803 |
|
|
|
804 | } | |
|
932 | } } | |
|
805 | 933 | |
|
806 | 934 | /* set prices using matches found at position == cur */ |
|
807 | 935 | for (matchNb = 0; matchNb < nbMatches; matchNb++) { |
@@ -811,81 +939,97 b' size_t ZSTD_compressBlock_opt_generic(ZS' | |||
|
811 | 939 | U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch; |
|
812 | 940 | U32 mlen; |
|
813 | 941 | |
|
814 | DEBUGLOG(7, "testing match %u => offCode=%u, mlen=%u, llen=%u", | |
|
942 | DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u", | |
|
815 | 943 | matchNb, matches[matchNb].off, lastML, litlen); |
|
816 | 944 | |
|
817 | for (mlen = lastML; mlen >= startML; mlen--) { | |
|
945 | for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */ | |
|
818 | 946 | U32 const pos = cur + mlen; |
|
819 | 947 | int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); |
|
820 | 948 | |
|
821 | 949 | if ((pos > last_pos) || (price < opt[pos].price)) { |
|
822 |
DEBUGLOG(7, "rPos:%u => new better price (% |
|
|
823 |
pos, |
|
|
824 | while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } | |
|
950 | DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)", | |
|
951 | pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price)); | |
|
952 | while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */ | |
|
825 | 953 | opt[pos].mlen = mlen; |
|
826 | 954 | opt[pos].off = offset; |
|
827 | 955 | opt[pos].litlen = litlen; |
|
828 | 956 | opt[pos].price = price; |
|
957 | ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory)); | |
|
829 | 958 | memcpy(opt[pos].rep, &repHistory, sizeof(repHistory)); |
|
830 | 959 | } else { |
|
831 | if (optLevel==0) break; /* gets ~+10% speed for about -0.01 ratio loss */ | |
|
960 | DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)", | |
|
961 | pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price)); | |
|
962 | if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */ | |
|
832 | 963 | } |
|
833 | 964 | } } } |
|
834 | 965 | } /* for (cur = 1; cur <= last_pos; cur++) */ |
|
835 | 966 | |
|
836 |
|
|
|
837 | best_off = opt[last_pos].off; | |
|
838 | cur = last_pos - best_mlen; | |
|
967 | lastSequence = opt[last_pos]; | |
|
968 | cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */ | |
|
969 | assert(cur < ZSTD_OPT_NUM); /* control overflow*/ | |
|
839 | 970 | |
|
840 | 971 | _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ |
|
841 |
assert(opt[0].mlen == |
|
|
972 | assert(opt[0].mlen == 0); | |
|
973 | ||
|
974 | { U32 const storeEnd = cur + 1; | |
|
975 | U32 storeStart = storeEnd; | |
|
976 | U32 seqPos = cur; | |
|
842 | 977 | |
|
843 | /* reverse traversal */ | |
|
844 | DEBUGLOG(7, "start reverse traversal (last_pos:%u, cur:%u)", | |
|
845 | last_pos, cur); | |
|
846 | { U32 selectedMatchLength = best_mlen; | |
|
847 | U32 selectedOffset = best_off; | |
|
848 | U32 pos = cur; | |
|
849 |
while ( |
|
|
850 |
U32 const |
|
|
851 | U32 const off = opt[pos].off; | |
|
852 | opt[pos].mlen = selectedMatchLength; | |
|
853 | opt[pos].off = selectedOffset; | |
|
854 | selectedMatchLength = mlen; | |
|
855 | selectedOffset = off; | |
|
856 | if (mlen > pos) break; | |
|
857 | pos -= mlen; | |
|
858 | } } | |
|
978 | DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)", | |
|
979 | last_pos, cur); (void)last_pos; | |
|
980 | assert(storeEnd < ZSTD_OPT_NUM); | |
|
981 | DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", | |
|
982 | storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off); | |
|
983 | opt[storeEnd] = lastSequence; | |
|
984 | while (seqPos > 0) { | |
|
985 | U32 const backDist = ZSTD_totalLen(opt[seqPos]); | |
|
986 | storeStart--; | |
|
987 | DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", | |
|
988 | seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off); | |
|
989 | opt[storeStart] = opt[seqPos]; | |
|
990 | seqPos = (seqPos > backDist) ? seqPos - backDist : 0; | |
|
991 | } | |
|
859 | 992 | |
|
860 | /* save sequences */ | |
|
861 | { U32 pos; | |
|
862 | for (pos=0; pos < last_pos; ) { | |
|
863 | U32 const llen = (U32)(ip - anchor); | |
|
864 |
U32 const |
|
|
865 |
U32 const |
|
|
866 | if (mlen == 1) { ip++; pos++; continue; } /* literal position => move on */ | |
|
867 | pos += mlen; ip += mlen; | |
|
993 | /* save sequences */ | |
|
994 | DEBUGLOG(6, "sending selected sequences into seqStore") | |
|
995 | { U32 storePos; | |
|
996 | for (storePos=storeStart; storePos <= storeEnd; storePos++) { | |
|
997 | U32 const llen = opt[storePos].litlen; | |
|
998 | U32 const mlen = opt[storePos].mlen; | |
|
999 | U32 const offCode = opt[storePos].off; | |
|
1000 | U32 const advance = llen + mlen; | |
|
1001 | DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u", | |
|
1002 | anchor - istart, llen, mlen); | |
|
1003 | ||
|
1004 | if (mlen==0) { /* only literals => must be last "sequence", actually starting a new stream of sequences */ | |
|
1005 | assert(storePos == storeEnd); /* must be last sequence */ | |
|
1006 | ip = anchor + llen; /* last "sequence" is a bunch of literals => don't progress anchor */ | |
|
1007 | continue; /* will finish */ | |
|
1008 | } | |
|
868 | 1009 | |
|
869 | /* repcodes update : like ZSTD_updateRep(), but update in place */ | |
|
870 |
if (off |
|
|
871 | rep[2] = rep[1]; | |
|
872 | rep[1] = rep[0]; | |
|
873 | rep[0] = offset - ZSTD_REP_MOVE; | |
|
874 | } else { /* repcode */ | |
|
875 | U32 const repCode = offset + (llen==0); | |
|
876 | if (repCode) { /* note : if repCode==0, no change */ | |
|
877 | U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; | |
|
878 | if (repCode >= 2) rep[2] = rep[1]; | |
|
1010 | /* repcodes update : like ZSTD_updateRep(), but update in place */ | |
|
1011 | if (offCode >= ZSTD_REP_NUM) { /* full offset */ | |
|
1012 | rep[2] = rep[1]; | |
|
879 | 1013 | rep[1] = rep[0]; |
|
880 |
rep[0] = |
|
|
881 | } | |
|
882 | } | |
|
1014 | rep[0] = offCode - ZSTD_REP_MOVE; | |
|
1015 | } else { /* repcode */ | |
|
1016 | U32 const repCode = offCode + (llen==0); | |
|
1017 | if (repCode) { /* note : if repCode==0, no change */ | |
|
1018 | U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; | |
|
1019 | if (repCode >= 2) rep[2] = rep[1]; | |
|
1020 | rep[1] = rep[0]; | |
|
1021 | rep[0] = currentOffset; | |
|
1022 | } } | |
|
883 | 1023 | |
|
884 | ZSTD_updateStats(optStatePtr, llen, anchor, offset, mlen); | |
|
885 |
|
|
|
886 | anchor = ip; | |
|
887 | } } | |
|
888 | ZSTD_setLog2Prices(optStatePtr); | |
|
1024 | assert(anchor + llen <= iend); | |
|
1025 | ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen); | |
|
1026 | ZSTD_storeSeq(seqStore, llen, anchor, offCode, mlen-MINMATCH); | |
|
1027 | anchor += advance; | |
|
1028 | ip = anchor; | |
|
1029 | } } | |
|
1030 | ZSTD_setBasePrices(optStatePtr, optLevel); | |
|
1031 | } | |
|
1032 | ||
|
889 | 1033 | } /* while (ip < ilimit) */ |
|
890 | 1034 | |
|
891 | 1035 | /* Return the last literals size */ |
@@ -895,29 +1039,94 b' size_t ZSTD_compressBlock_opt_generic(ZS' | |||
|
895 | 1039 | |
|
896 | 1040 | size_t ZSTD_compressBlock_btopt( |
|
897 | 1041 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
898 |
|
|
|
1042 | const void* src, size_t srcSize) | |
|
899 | 1043 | { |
|
900 | 1044 | DEBUGLOG(5, "ZSTD_compressBlock_btopt"); |
|
901 |
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, |
|
|
1045 | return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict); | |
|
1046 | } | |
|
1047 | ||
|
1048 | ||
|
1049 | /* used in 2-pass strategy */ | |
|
1050 | static U32 ZSTD_upscaleStat(U32* table, U32 lastEltIndex, int bonus) | |
|
1051 | { | |
|
1052 | U32 s, sum=0; | |
|
1053 | assert(ZSTD_FREQ_DIV+bonus > 0); | |
|
1054 | for (s=0; s<=lastEltIndex; s++) { | |
|
1055 | table[s] <<= ZSTD_FREQ_DIV+bonus; | |
|
1056 | table[s]--; | |
|
1057 | sum += table[s]; | |
|
1058 | } | |
|
1059 | return sum; | |
|
1060 | } | |
|
1061 | ||
|
1062 | /* used in 2-pass strategy */ | |
|
1063 | MEM_STATIC void ZSTD_upscaleStats(optState_t* optPtr) | |
|
1064 | { | |
|
1065 | optPtr->litSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0); | |
|
1066 | optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 1); | |
|
1067 | optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 1); | |
|
1068 | optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 1); | |
|
902 | 1069 | } |
|
903 | 1070 | |
|
904 | 1071 | size_t ZSTD_compressBlock_btultra( |
|
905 | 1072 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
906 |
|
|
|
1073 | const void* src, size_t srcSize) | |
|
907 | 1074 | { |
|
908 | return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, 0 /*extDict*/); | |
|
1075 | DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize); | |
|
1076 | #if 0 | |
|
1077 | /* 2-pass strategy (disabled) | |
|
1078 | * this strategy makes a first pass over first block to collect statistics | |
|
1079 | * and seed next round's statistics with it. | |
|
1080 | * The compression ratio gain is generally small (~0.5% on first block), | |
|
1081 | * the cost is 2x cpu time on first block. */ | |
|
1082 | assert(srcSize <= ZSTD_BLOCKSIZE_MAX); | |
|
1083 | if ( (ms->opt.litLengthSum==0) /* first block */ | |
|
1084 | && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */ | |
|
1085 | && (ms->window.dictLimit == ms->window.lowLimit) ) { /* no dictionary */ | |
|
1086 | U32 tmpRep[ZSTD_REP_NUM]; | |
|
1087 | DEBUGLOG(5, "ZSTD_compressBlock_btultra: first block: collecting statistics"); | |
|
1088 | assert(ms->nextToUpdate >= ms->window.dictLimit | |
|
1089 | && ms->nextToUpdate <= ms->window.dictLimit + 1); | |
|
1090 | memcpy(tmpRep, rep, sizeof(tmpRep)); | |
|
1091 | ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/ | |
|
1092 | ZSTD_resetSeqStore(seqStore); | |
|
1093 | /* invalidate first scan from history */ | |
|
1094 | ms->window.base -= srcSize; | |
|
1095 | ms->window.dictLimit += (U32)srcSize; | |
|
1096 | ms->window.lowLimit = ms->window.dictLimit; | |
|
1097 | ms->nextToUpdate = ms->window.dictLimit; | |
|
1098 | ms->nextToUpdate3 = ms->window.dictLimit; | |
|
1099 | /* re-inforce weight of collected statistics */ | |
|
1100 | ZSTD_upscaleStats(&ms->opt); | |
|
1101 | } | |
|
1102 | #endif | |
|
1103 | return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); | |
|
1104 | } | |
|
1105 | ||
|
1106 | size_t ZSTD_compressBlock_btopt_dictMatchState( | |
|
1107 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
1108 | const void* src, size_t srcSize) | |
|
1109 | { | |
|
1110 | return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState); | |
|
1111 | } | |
|
1112 | ||
|
1113 | size_t ZSTD_compressBlock_btultra_dictMatchState( | |
|
1114 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
1115 | const void* src, size_t srcSize) | |
|
1116 | { | |
|
1117 | return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState); | |
|
909 | 1118 | } |
|
910 | 1119 | |
|
911 | 1120 | size_t ZSTD_compressBlock_btopt_extDict( |
|
912 | 1121 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
913 |
|
|
|
1122 | const void* src, size_t srcSize) | |
|
914 | 1123 | { |
|
915 |
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, |
|
|
1124 | return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict); | |
|
916 | 1125 | } |
|
917 | 1126 | |
|
918 | 1127 | size_t ZSTD_compressBlock_btultra_extDict( |
|
919 | 1128 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
920 |
|
|
|
1129 | const void* src, size_t srcSize) | |
|
921 | 1130 | { |
|
922 |
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, |
|
|
1131 | return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict); | |
|
923 | 1132 | } |
@@ -17,23 +17,29 b' extern "C" {' | |||
|
17 | 17 | |
|
18 | 18 | #include "zstd_compress_internal.h" |
|
19 | 19 | |
|
20 | void ZSTD_updateTree( | |
|
21 | ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams, | |
|
22 | const BYTE* ip, const BYTE* iend); /* used in ZSTD_loadDictionaryContent() */ | |
|
20 | /* used in ZSTD_loadDictionaryContent() */ | |
|
21 | void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend); | |
|
23 | 22 | |
|
24 | 23 | size_t ZSTD_compressBlock_btopt( |
|
25 | 24 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
26 |
|
|
|
25 | void const* src, size_t srcSize); | |
|
27 | 26 | size_t ZSTD_compressBlock_btultra( |
|
28 | 27 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
29 |
|
|
|
28 | void const* src, size_t srcSize); | |
|
29 | ||
|
30 | size_t ZSTD_compressBlock_btopt_dictMatchState( | |
|
31 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
32 | void const* src, size_t srcSize); | |
|
33 | size_t ZSTD_compressBlock_btultra_dictMatchState( | |
|
34 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], | |
|
35 | void const* src, size_t srcSize); | |
|
30 | 36 | |
|
31 | 37 | size_t ZSTD_compressBlock_btopt_extDict( |
|
32 | 38 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
33 |
|
|
|
39 | void const* src, size_t srcSize); | |
|
34 | 40 | size_t ZSTD_compressBlock_btultra_extDict( |
|
35 | 41 | ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], |
|
36 |
|
|
|
42 | void const* src, size_t srcSize); | |
|
37 | 43 | |
|
38 | 44 | #if defined (__cplusplus) |
|
39 | 45 | } |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
General Comments 0
You need to be logged in to leave comments.
Login now