blob: fa059cb97921d9b7df850ee4c382f365ecef6cd6 [file] [log] [blame]
Yann Colletf3eca252015-10-22 15:31:46 +01001/*
2 ZSTD HC - High Compression Mode of Zstandard
3 Copyright (C) 2015, Yann Collet.
4
5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are
9 met:
10
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above
14 copyright notice, this list of conditions and the following disclaimer
15 in the documentation and/or other materials provided with the
16 distribution.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 You can contact the author at :
31 - Zstd source repository : https://www.zstd.net
32*/
33
34
Yann Collet4b100f42015-10-30 15:49:48 +010035/* *******************************************************
36* Compiler specifics
37*********************************************************/
38#ifdef _MSC_VER /* Visual Studio */
39# define FORCE_INLINE static __forceinline
40# include <intrin.h> /* For Visual 2005 */
41# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
42# pragma warning(disable : 4324) /* disable: C4324: padded structure */
43#else
44# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
45# ifdef __GNUC__
46# define FORCE_INLINE static inline __attribute__((always_inline))
47# else
48# define FORCE_INLINE static inline
49# endif
50#endif
51
52
Yann Colletf3eca252015-10-22 15:31:46 +010053/* *************************************
54* Includes
55***************************************/
56#include <stdlib.h> /* malloc */
57#include <string.h> /* memset */
Yann Collet083fcc82015-10-25 14:06:35 +010058#include "zstdhc_static.h"
Yann Colletf3eca252015-10-22 15:31:46 +010059#include "zstd_static.h"
Yann Collet3d9cf7a2015-10-29 17:15:14 +010060#include "zstd_internal.h"
Yann Colletf3eca252015-10-22 15:31:46 +010061#include "mem.h"
62
63
64/* *************************************
Yann Colletf3eca252015-10-22 15:31:46 +010065* Local Constants
66***************************************/
67#define MINMATCH 4
Yann Collet53fff6c2015-10-24 13:48:37 +010068#define MAXD_LOG 26
Yann Colletf3eca252015-10-22 15:31:46 +010069
70#define KB *1024
71#define MB *1024*1024
72#define GB *(1ULL << 30)
73
74/* *************************************
75* Local Types
76***************************************/
77#define BLOCKSIZE (128 KB) /* define, for static allocation */
78#define WORKPLACESIZE (BLOCKSIZE*3)
79
80struct ZSTD_HC_CCtx_s
81{
Yann Colletf3eca252015-10-22 15:31:46 +010082 const BYTE* end; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010083 const BYTE* base; /* All regular indexes relative to this position */
84 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010085 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010086 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010087 U32 nextToUpdate; /* index from which to continue dictionary update */
Yann Collet083fcc82015-10-25 14:06:35 +010088 ZSTD_HC_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010089 void* workSpace;
90 size_t workSpaceSize;
91
92 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010093 U32* hashTable;
Yann Collet1f44b3f2015-11-05 17:32:18 +010094 U32* contentTable;
Yann Colletf3eca252015-10-22 15:31:46 +010095};
96
97
98ZSTD_HC_CCtx* ZSTD_HC_createCCtx(void)
99{
Yann Collet712def92015-10-29 18:41:45 +0100100 return (ZSTD_HC_CCtx*) calloc(1, sizeof(ZSTD_HC_CCtx));
Yann Colletf3eca252015-10-22 15:31:46 +0100101}
102
Yann Collet083fcc82015-10-25 14:06:35 +0100103size_t ZSTD_HC_freeCCtx(ZSTD_HC_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100104{
Yann Collet712def92015-10-29 18:41:45 +0100105 free(cctx->workSpace);
Yann Collet083fcc82015-10-25 14:06:35 +0100106 free(cctx);
107 return 0;
108}
109
Yann Collet59d70632015-11-04 12:05:27 +0100110
111/** ZSTD_HC_validateParams
112 correct params value to remain within authorized range
113 optimize for srcSize if srcSize > 0 */
114void ZSTD_HC_validateParams(ZSTD_HC_parameters* params, size_t srcSize)
115{
Yann Collet1f44b3f2015-11-05 17:32:18 +0100116 const U32 btPlus = (params->strategy == ZSTD_HC_btlazy2);
Yann Collet59d70632015-11-04 12:05:27 +0100117
118 /* validate params */
119 if (params->windowLog > ZSTD_HC_WINDOWLOG_MAX) params->windowLog = ZSTD_HC_WINDOWLOG_MAX;
120 if (params->windowLog < ZSTD_HC_WINDOWLOG_MIN) params->windowLog = ZSTD_HC_WINDOWLOG_MIN;
121
122 /* correct params, to use less memory */
123 if (srcSize > 0)
124 {
125 U32 srcLog = ZSTD_highbit((U32)srcSize-1) + 1;
126 if (params->windowLog > srcLog) params->windowLog = srcLog;
127 }
128
Yann Collet1f44b3f2015-11-05 17:32:18 +0100129 if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_HC_CONTENTLOG_MAX */
130 if (params->contentLog < ZSTD_HC_CONTENTLOG_MIN) params->contentLog = ZSTD_HC_CONTENTLOG_MIN;
Yann Collet59d70632015-11-04 12:05:27 +0100131 if (params->hashLog > ZSTD_HC_HASHLOG_MAX) params->hashLog = ZSTD_HC_HASHLOG_MAX;
132 if (params->hashLog < ZSTD_HC_HASHLOG_MIN) params->hashLog = ZSTD_HC_HASHLOG_MIN;
133 if (params->searchLog > ZSTD_HC_SEARCHLOG_MAX) params->searchLog = ZSTD_HC_SEARCHLOG_MAX;
134 if (params->searchLog < ZSTD_HC_SEARCHLOG_MIN) params->searchLog = ZSTD_HC_SEARCHLOG_MIN;
135 if (params->searchLength> ZSTD_HC_SEARCHLENGTH_MAX) params->searchLength = ZSTD_HC_SEARCHLENGTH_MAX;
136 if (params->searchLength< ZSTD_HC_SEARCHLENGTH_MIN) params->searchLength = ZSTD_HC_SEARCHLENGTH_MIN;
137 if ((U32)params->strategy>(U32)ZSTD_HC_btlazy2) params->strategy = ZSTD_HC_btlazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100138}
139
140
Yann Collet4114f952015-10-30 06:40:22 +0100141static size_t ZSTD_HC_resetCCtx_advanced (ZSTD_HC_CCtx* zc,
142 ZSTD_HC_parameters params)
Yann Collet083fcc82015-10-25 14:06:35 +0100143{
Yann Collet59d70632015-11-04 12:05:27 +0100144 ZSTD_HC_validateParams(&params, 0);
Yann Collet083fcc82015-10-25 14:06:35 +0100145
Yann Collet2acb5d32015-10-29 16:49:43 +0100146 /* reserve table memory */
Yann Collet083fcc82015-10-25 14:06:35 +0100147 {
Yann Collet1f44b3f2015-11-05 17:32:18 +0100148 const U32 contentLog = params.strategy == ZSTD_HC_fast ? 1 : params.contentLog;
149 const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog)) * sizeof(U32);
Yann Collet712def92015-10-29 18:41:45 +0100150 const size_t neededSpace = tableSpace + WORKPLACESIZE;
151 if (zc->workSpaceSize < neededSpace)
Yann Collet2acb5d32015-10-29 16:49:43 +0100152 {
Yann Collet712def92015-10-29 18:41:45 +0100153 free(zc->workSpace);
154 zc->workSpaceSize = neededSpace;
155 zc->workSpace = malloc(neededSpace);
Yann Collet4114f952015-10-30 06:40:22 +0100156 if (zc->workSpace == NULL) return ERROR(memory_allocation);
Yann Collet2acb5d32015-10-29 16:49:43 +0100157 }
Yann Collet712def92015-10-29 18:41:45 +0100158 zc->hashTable = (U32*)zc->workSpace;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100159 zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog);
160 zc->seqStore.buffer = (void*) (zc->contentTable + ((size_t)1 << contentLog));
Yann Collet712def92015-10-29 18:41:45 +0100161 memset(zc->hashTable, 0, tableSpace );
Yann Collet083fcc82015-10-25 14:06:35 +0100162 }
Yann Collet083fcc82015-10-25 14:06:35 +0100163
Yann Collet2acb5d32015-10-29 16:49:43 +0100164 zc->nextToUpdate = 0;
165 zc->end = NULL;
166 zc->base = NULL;
167 zc->dictBase = NULL;
168 zc->dictLimit = 0;
169 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100170 zc->params = params;
Yann Colletf3eca252015-10-22 15:31:46 +0100171 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
172 zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + (BLOCKSIZE>>2));
173 zc->seqStore.litStart = zc->seqStore.offCodeStart + (BLOCKSIZE>>2);
174 zc->seqStore.litLengthStart = zc->seqStore.litStart + BLOCKSIZE;
175 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (BLOCKSIZE>>2);
176 zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (BLOCKSIZE>>2);
Yann Collet2acb5d32015-10-29 16:49:43 +0100177
Yann Collet4114f952015-10-30 06:40:22 +0100178 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100179}
180
Yann Collet083fcc82015-10-25 14:06:35 +0100181
Yann Colletf3eca252015-10-22 15:31:46 +0100182/* *************************************
Yann Collet4b100f42015-10-30 15:49:48 +0100183* Inline functions and Macros
Yann Colletf3eca252015-10-22 15:31:46 +0100184***************************************/
Yann Collet2acb5d32015-10-29 16:49:43 +0100185
Yann Collet4b100f42015-10-30 15:49:48 +0100186static const U32 prime4bytes = 2654435761U;
187static U32 ZSTD_HC_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
188static size_t ZSTD_HC_hash4Ptr(const void* ptr, U32 h) { return ZSTD_HC_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100189
Yann Collet4b100f42015-10-30 15:49:48 +0100190static const U64 prime5bytes = 889523592379ULL;
191static size_t ZSTD_HC_hash5(U64 u, U32 h) { return (size_t)((u * prime5bytes) << (64-40) >> (64-h)) ; }
192static size_t ZSTD_HC_hash5Ptr(const void* p, U32 h) { return ZSTD_HC_hash5(MEM_read64(p), h); }
193
194static const U64 prime6bytes = 227718039650203ULL;
195static size_t ZSTD_HC_hash6(U64 u, U32 h) { return (size_t)((u * prime6bytes) << (64-48) >> (64-h)) ; }
196static size_t ZSTD_HC_hash6Ptr(const void* p, U32 h) { return ZSTD_HC_hash6(MEM_read64(p), h); }
197
Yann Collet1f44b3f2015-11-05 17:32:18 +0100198static const U64 prime7bytes = 58295818150454627ULL;
199static size_t ZSTD_HC_hash7(U64 u, U32 h) { return (size_t)((u * prime7bytes) << (64-56) >> (64-h)) ; }
200static size_t ZSTD_HC_hash7Ptr(const void* p, U32 h) { return ZSTD_HC_hash7(MEM_read64(p), h); }
201
Yann Collet96b9f0b2015-11-04 03:52:54 +0100202static size_t ZSTD_HC_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100203{
204 switch(mls)
205 {
206 default:
Yann Collet96b9f0b2015-11-04 03:52:54 +0100207 case 4: return ZSTD_HC_hash4Ptr(p, hBits);
208 case 5: return ZSTD_HC_hash5Ptr(p, hBits);
209 case 6: return ZSTD_HC_hash6Ptr(p, hBits);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100210 case 7: return ZSTD_HC_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100211 }
212}
Yann Collet2acb5d32015-10-29 16:49:43 +0100213
Yann Collet1f44b3f2015-11-05 17:32:18 +0100214/* *************************************
215* Fast Scan
216***************************************/
217
218FORCE_INLINE
219size_t ZSTD_HC_compressBlock_fast_generic(ZSTD_HC_CCtx* ctx,
220 void* dst, size_t maxDstSize,
221 const void* src, size_t srcSize,
222 const U32 mls)
223{
224 U32* hashTable = ctx->hashTable;
225 const U32 hBits = ctx->params.hashLog;
226 seqStore_t* seqStorePtr = &(ctx->seqStore);
227 const BYTE* const base = ctx->base;
228
229 const BYTE* const istart = (const BYTE*)src;
230 const BYTE* ip = istart + 1;
231 const BYTE* anchor = istart;
232 const BYTE* const iend = istart + srcSize;
233 const BYTE* const ilimit = iend - 8;
234
235 size_t offset_2=4, offset_1=4;
236
237
238 /* init */
239 if (ip == base)
240 {
241 hashTable[ZSTD_HC_hashPtr(base+1, hBits, mls)] = 1;
242 hashTable[ZSTD_HC_hashPtr(base+2, hBits, mls)] = 2;
243 hashTable[ZSTD_HC_hashPtr(base+3, hBits, mls)] = 3;
244 ip = base+4;
245 }
246 ZSTD_resetSeqStore(seqStorePtr);
247
248 /* Main Search Loop */
249 while (ip < ilimit) /* < instead of <=, because unconditionnal ZSTD_addPtr(ip+1) */
250 {
251 const size_t h = ZSTD_HC_hashPtr(ip, hBits, mls);
252 const BYTE* match = base + hashTable[h];
253 hashTable[h] = (U32)(ip-base);
254
255 if (MEM_read32(ip-offset_2) == MEM_read32(ip)) match = ip-offset_2;
256 if (MEM_read32(match) != MEM_read32(ip)) { ip += ((ip-anchor) >> g_searchStrength) + 1; offset_2 = offset_1; continue; }
257 while ((ip>anchor) && (match>base) && (ip[-1] == match[-1])) { ip--; match--; } /* catch up */
258
259 {
260 size_t litLength = ip-anchor;
261 size_t matchLength = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
262 size_t offsetCode = ip-match;
263 if (offsetCode == offset_2) offsetCode = 0;
264 offset_2 = offset_1;
265 offset_1 = ip-match;
266 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offsetCode, matchLength);
267
268 /* Fill Table */
269 hashTable[ZSTD_HC_hashPtr(ip+1, hBits, mls)] = (U32)(ip+1-base);
270 ip += matchLength + MINMATCH;
271 anchor = ip;
272 if (ip < ilimit) /* same test as loop, for speed */
273 hashTable[ZSTD_HC_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
274 }
275 }
276
277 /* Last Literals */
278 {
279 size_t lastLLSize = iend - anchor;
280 memcpy(seqStorePtr->lit, anchor, lastLLSize);
281 seqStorePtr->lit += lastLLSize;
282 }
283
284 /* Finale compression stage */
285 return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
286 seqStorePtr, srcSize);
287}
288
289
290size_t ZSTD_HC_compressBlock_fast(ZSTD_HC_CCtx* ctx,
291 void* dst, size_t maxDstSize,
292 const void* src, size_t srcSize)
293{
294 const U32 mls = ctx->params.searchLength;
295 switch(mls)
296 {
297 default:
298 case 4 :
299 return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 4);
300 case 5 :
301 return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 5);
302 case 6 :
303 return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 6);
304 case 7 :
305 return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 7);
306 }
307}
Yann Colletf3eca252015-10-22 15:31:46 +0100308
Yann Colletf3eca252015-10-22 15:31:46 +0100309
Yann Colletf3eca252015-10-22 15:31:46 +0100310/* *************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +0100311* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +0100312***************************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +0100313/** ZSTD_HC_insertBt1 : add one ptr to tree
314 @ip : assumed <= iend-8 */
315static void ZSTD_HC_insertBt1(ZSTD_HC_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares)
316{
317 U32* const hashTable = zc->hashTable;
318 const U32 hashLog = zc->params.hashLog;
319 const size_t h = ZSTD_HC_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100320 U32* const bt = zc->contentTable;
321 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100322 const U32 btMask= (1 << btLog) - 1;
323 U32 matchIndex = hashTable[h];
324 size_t commonLengthSmaller=0, commonLengthLarger=0;
325 const BYTE* const base = zc->base;
326 const U32 current = (U32)(ip-base);
327 const U32 btLow = btMask >= current ? 0 : current - btMask;
328 U32* smallerPtr = bt + 2*(current&btMask);
329 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet59d70632015-11-04 12:05:27 +0100330 U32 dummy32; /* to be nullified at the end */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100331 const U32 windowSize = 1 << zc->params.windowLog;
332 const U32 windowLow = windowSize >= current ? 0 : current - windowSize;
333
334 hashTable[h] = (U32)(ip-base); /* Update Hash Table */
335
336 while (nbCompares-- && (matchIndex > windowLow))
337 {
338 U32* nextPtr = bt + 2*(matchIndex & btMask);
339 const BYTE* match = base + matchIndex;
340 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
341
342 matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
343
Yann Collet59d70632015-11-04 12:05:27 +0100344 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
345 break; /* just drop , to guarantee consistency (miss a bit of compression; if someone knows better, please tell) */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100346
347 if (match[matchLength] < ip[matchLength])
Yann Collet59d70632015-11-04 12:05:27 +0100348 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100349 /* match is smaller than current */
350 *smallerPtr = matchIndex; /* update smaller idx */
351 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Collet59d70632015-11-04 12:05:27 +0100352 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100353 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
354 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet59d70632015-11-04 12:05:27 +0100355 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100356 else
Yann Collet59d70632015-11-04 12:05:27 +0100357 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100358 /* match is larger than current */
359 *largerPtr = matchIndex;
360 commonLengthLarger = matchLength;
Yann Collet59d70632015-11-04 12:05:27 +0100361 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100362 largerPtr = nextPtr;
363 matchIndex = nextPtr[0];
Yann Collet59d70632015-11-04 12:05:27 +0100364 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100365 }
366
Yann Collet59d70632015-11-04 12:05:27 +0100367 *smallerPtr = *largerPtr = 0;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100368}
369
370
371FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
372size_t ZSTD_HC_insertBtAndFindBestMatch (
373 ZSTD_HC_CCtx* zc,
374 const BYTE* const ip, const BYTE* const iend,
375 size_t* offsetPtr,
376 U32 nbCompares, const U32 mls)
377{
378 U32* const hashTable = zc->hashTable;
379 const U32 hashLog = zc->params.hashLog;
380 const size_t h = ZSTD_HC_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100381 U32* const bt = zc->contentTable;
382 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100383 const U32 btMask= (1 << btLog) - 1;
384 U32 matchIndex = hashTable[h];
385 size_t commonLengthSmaller=0, commonLengthLarger=0;
386 const BYTE* const base = zc->base;
387 const U32 current = (U32)(ip-base);
388 const U32 btLow = btMask >= current ? 0 : current - btMask;
389 const U32 windowSize = 1 << zc->params.windowLog;
390 const U32 windowLow = windowSize >= current ? 0 : current - windowSize;
391 U32* smallerPtr = bt + 2*(current&btMask);
392 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Colletb241e9d2015-11-04 13:57:24 +0100393 size_t bestLength = 0;
Yann Collet59d70632015-11-04 12:05:27 +0100394 U32 dummy32; /* to be nullified at the end */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100395
Yann Collet59d70632015-11-04 12:05:27 +0100396 hashTable[h] = (U32)(ip-base); /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100397
398 while (nbCompares-- && (matchIndex > windowLow))
399 {
400 U32* nextPtr = bt + 2*(matchIndex & btMask);
401 const BYTE* match = base + matchIndex;
402 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
403
404 matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
405
406 if (matchLength > bestLength)
407 {
Yann Collete8455f52015-11-04 17:41:20 +0100408 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
Yann Colletb241e9d2015-11-04 13:57:24 +0100409 bestLength = matchLength, *offsetPtr = current - matchIndex;
Yann Collet59d70632015-11-04 12:05:27 +0100410 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
411 break; /* drop, next to null, to guarantee consistency (is there a way to do better ?) */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100412 }
413
414 if (match[matchLength] < ip[matchLength])
Yann Collet59d70632015-11-04 12:05:27 +0100415 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100416 /* match is smaller than current */
417 *smallerPtr = matchIndex; /* update smaller idx */
418 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Collet59d70632015-11-04 12:05:27 +0100419 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
420 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100421 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet59d70632015-11-04 12:05:27 +0100422 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100423 else
Yann Collet59d70632015-11-04 12:05:27 +0100424 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100425 /* match is larger than current */
426 *largerPtr = matchIndex;
427 commonLengthLarger = matchLength;
Yann Collet59d70632015-11-04 12:05:27 +0100428 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100429 largerPtr = nextPtr;
430 matchIndex = nextPtr[0];
Yann Collet59d70632015-11-04 12:05:27 +0100431 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100432 }
433
Yann Collet59d70632015-11-04 12:05:27 +0100434 *smallerPtr = *largerPtr = 0;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100435
436 zc->nextToUpdate = current+1; /* current has been inserted */
Yann Collet59d70632015-11-04 12:05:27 +0100437 if (bestLength < MINMATCH) return 0;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100438 return bestLength;
439}
440
441
442static void ZSTD_HC_updateTree(ZSTD_HC_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
443{
444 const BYTE* const base = zc->base;
445 const U32 target = (U32)(ip - base);
446 U32 idx = zc->nextToUpdate;
Yann Collet59d70632015-11-04 12:05:27 +0100447 //size_t dummy;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100448
449 for( ; idx < target ; idx++)
450 ZSTD_HC_insertBt1(zc, base+idx, mls, iend, nbCompares);
451 //ZSTD_HC_insertBtAndFindBestMatch(zc, base+idx, iend, &dummy, nbCompares, mls);
452
453 zc->nextToUpdate = target;
454}
455
456
457/** Tree updater, providing best match */
458FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
459size_t ZSTD_HC_BtFindBestMatch (
460 ZSTD_HC_CCtx* zc,
461 const BYTE* const ip, const BYTE* const iLimit,
462 size_t* offsetPtr,
463 const U32 maxNbAttempts, const U32 mls)
464{
465 ZSTD_HC_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
466 return ZSTD_HC_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls);
467}
468
469
470FORCE_INLINE size_t ZSTD_HC_BtFindBestMatch_selectMLS (
471 ZSTD_HC_CCtx* zc, /* Index table will be updated */
472 const BYTE* ip, const BYTE* const iLimit,
473 size_t* offsetPtr,
474 const U32 maxNbAttempts, const U32 matchLengthSearch)
475{
476 switch(matchLengthSearch)
477 {
478 default :
479 case 4 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
480 case 5 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
481 case 6 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
482 }
483}
484
485
Yann Collet5106a762015-11-05 15:00:24 +0100486/* ***********************
487* Hash Chain
488*************************/
489
Yann Collet1f44b3f2015-11-05 17:32:18 +0100490#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
491
Yann Collet5106a762015-11-05 15:00:24 +0100492/* Update chains up to ip (excluded) */
493static U32 ZSTD_HC_insertAndFindFirstIndex (ZSTD_HC_CCtx* zc, const BYTE* ip, U32 mls)
494{
495 U32* const hashTable = zc->hashTable;
496 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100497 U32* const chainTable = zc->contentTable;
498 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +0100499 const BYTE* const base = zc->base;
500 const U32 target = (U32)(ip - base);
501 U32 idx = zc->nextToUpdate;
502
503 while(idx < target)
504 {
505 size_t h = ZSTD_HC_hashPtr(base+idx, hashLog, mls);
506 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
507 hashTable[h] = idx;
508 idx++;
509 }
510
511 zc->nextToUpdate = target;
512 return hashTable[ZSTD_HC_hashPtr(ip, hashLog, mls)];
513}
514
515
516FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100517size_t ZSTD_HC_HcFindBestMatch (
Yann Collet5106a762015-11-05 15:00:24 +0100518 ZSTD_HC_CCtx* zc, /* Index table will be updated */
519 const BYTE* const ip, const BYTE* const iLimit,
520 size_t* offsetPtr,
521 const U32 maxNbAttempts, const U32 matchLengthSearch)
522{
Yann Collet1f44b3f2015-11-05 17:32:18 +0100523 U32* const chainTable = zc->contentTable;
524 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +0100525 const U32 chainMask = chainSize-1;
526 const BYTE* const base = zc->base;
527 const BYTE* const dictBase = zc->dictBase;
528 const U32 dictLimit = zc->dictLimit;
529 const U32 maxDistance = (1 << zc->params.windowLog);
530 const U32 lowLimit = (zc->lowLimit + maxDistance > (U32)(ip-base)) ? zc->lowLimit : (U32)(ip - base) - (maxDistance - 1);
531 U32 matchIndex;
532 const BYTE* match;
533 int nbAttempts=maxNbAttempts;
534 size_t ml=0;
535
536 /* HC4 match finder */
537 matchIndex = ZSTD_HC_insertAndFindFirstIndex (zc, ip, matchLengthSearch);
538
539 while ((matchIndex>lowLimit) && (nbAttempts))
540 {
541 nbAttempts--;
542 if (matchIndex >= dictLimit)
543 {
544 match = base + matchIndex;
545 if ( (match[ml] == ip[ml])
546 && (MEM_read32(match) == MEM_read32(ip)) ) /* ensures minimum match of 4 */
547 {
548 const size_t mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
549 if (mlt > ml)
550 //if (((int)(4*mlt) - (int)ZSTD_highbit((U32)(ip-match)+1)) > ((int)(4*ml) - (int)ZSTD_highbit((U32)((*offsetPtr)+1))))
551 {
552 ml = mlt; *offsetPtr = ip-match;
553 if (ip+ml >= iLimit) break;
554 }
555 }
556 }
557 else
558 {
559 match = dictBase + matchIndex;
560 if (MEM_read32(match) == MEM_read32(ip))
561 {
562 size_t mlt;
563 const BYTE* vLimit = ip + (dictLimit - matchIndex);
564 if (vLimit > iLimit) vLimit = iLimit;
565 mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
566 if ((ip+mlt == vLimit) && (vLimit < iLimit))
567 mlt += ZSTD_count(ip+mlt, base+dictLimit, iLimit);
568 if (mlt > ml) { ml = mlt; *offsetPtr = (ip-base) - matchIndex; }
569 }
570 }
571
572 if (base + matchIndex <= ip - chainSize) break;
573 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
574 }
575
576 return ml;
577}
578
579
Yann Collet1f44b3f2015-11-05 17:32:18 +0100580FORCE_INLINE size_t ZSTD_HC_HcFindBestMatch_selectMLS (
Yann Collet5106a762015-11-05 15:00:24 +0100581 ZSTD_HC_CCtx* zc, /* Index table will be updated */
582 const BYTE* ip, const BYTE* const iLimit,
583 size_t* offsetPtr,
584 const U32 maxNbAttempts, const U32 matchLengthSearch)
585{
586 switch(matchLengthSearch)
587 {
588 default :
Yann Collet1f44b3f2015-11-05 17:32:18 +0100589 case 4 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
590 case 5 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
591 case 6 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
Yann Collet5106a762015-11-05 15:00:24 +0100592 }
593}
594
595
Yann Collet90361052015-11-05 15:03:12 +0100596/* common lazy function, to be inlined */
Yann Collet5106a762015-11-05 15:00:24 +0100597FORCE_INLINE
598size_t ZSTD_HC_compressBlock_lazy_generic(ZSTD_HC_CCtx* ctx,
599 void* dst, size_t maxDstSize, const void* src, size_t srcSize,
600 const U32 searchMethod, const U32 deep) /* 0 : hc; 1 : bt */
601{
602 seqStore_t* seqStorePtr = &(ctx->seqStore);
603 const BYTE* const istart = (const BYTE*)src;
604 const BYTE* ip = istart;
605 const BYTE* anchor = istart;
606 const BYTE* const iend = istart + srcSize;
607 const BYTE* const ilimit = iend - 8;
608
609 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
610 const U32 maxSearches = 1 << ctx->params.searchLog;
611 const U32 mls = ctx->params.searchLength;
612
613 typedef size_t (*searchMax_f)(ZSTD_HC_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
614 size_t* offsetPtr,
615 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100616 searchMax_f searchMax = searchMethod ? ZSTD_HC_BtFindBestMatch_selectMLS : ZSTD_HC_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +0100617
618 /* init */
619 ZSTD_resetSeqStore(seqStorePtr);
620 if (((ip-ctx->base) - ctx->dictLimit) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
621
622 /* Match Loop */
623 while (ip <= ilimit)
624 {
625 size_t matchLength;
626 size_t offset=999999;
627 const BYTE* start;
628
629 /* try to find a first match */
630 if (MEM_read32(ip) == MEM_read32(ip - offset_2))
631 {
632 /* repcode : we take it*/
633 size_t offtmp = offset_2;
634 size_t litLength = ip - anchor;
635 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
636 offset_2 = offset_1;
637 offset_1 = offtmp;
638 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
639 ip += matchLength+MINMATCH;
640 anchor = ip;
641 continue;
642 }
643
644 offset_2 = offset_1;
645 matchLength = searchMax(ctx, ip, iend, &offset, maxSearches, mls);
646 if (!matchLength) { ip++; continue; }
647
648 /* let's try to find a better solution */
649 start = ip;
650
651 while (ip<ilimit)
652 {
653 ip ++;
654 if (MEM_read32(ip) == MEM_read32(ip - offset_1))
655 {
656 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
657 int gain2 = (int)(ml2 * 3);
658 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
659 if (gain2 > gain1)
660 matchLength = ml2, offset = 0, start = ip;
661 }
662 {
663 size_t offset2=999999;
664 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
665 int gain2 = (int)(ml2*(3+deep) - ZSTD_highbit((U32)offset2+1)); /* raw approx */
666 int gain1 = (int)(matchLength*(3+deep) - ZSTD_highbit((U32)offset+1) + (3+deep));
667 if (gain2 > gain1)
668 {
669 matchLength = ml2, offset = offset2, start = ip;
670 continue; /* search a better one */
671 }
672 }
673
674 /* let's find an even better one */
675 if (deep && (ip<ilimit))
676 {
677 ip ++;
678 if (MEM_read32(ip) == MEM_read32(ip - offset_1))
679 {
680 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
681 int gain2 = (int)(ml2 * 4);
682 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
683 if (gain2 > gain1)
684 matchLength = ml2, offset = 0, start = ip;
685 }
686 {
687 size_t offset2=999999;
688 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
689 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
690 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
691 if (gain2 > gain1)
692 {
693 matchLength = ml2, offset = offset2, start = ip;
694 continue;
695 }
696 }
697 }
698 break; /* nothing found : store previous solution */
699 }
700
701 /* store sequence */
702 {
703 size_t litLength = start - anchor;
704 if (offset) offset_1 = offset;
705 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
706 ip = start + matchLength;
707 anchor = ip;
708 }
709
710 }
711
712 /* Last Literals */
713 {
714 size_t lastLLSize = iend - anchor;
715 memcpy(seqStorePtr->lit, anchor, lastLLSize);
716 seqStorePtr->lit += lastLLSize;
717 }
718
719 /* Final compression stage */
720 return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
721 seqStorePtr, srcSize);
722}
723
724size_t ZSTD_HC_compressBlock_btlazy2(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
725{
726 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 1, 1);
727}
728
Yann Collet47b68902015-11-05 15:14:17 +0100729size_t ZSTD_HC_compressBlock_lazy2(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +0100730{
731 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1);
732}
733
734size_t ZSTD_HC_compressBlock_lazy(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
735{
736 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0);
737}
738
Yann Collet5106a762015-11-05 15:00:24 +0100739
Yann Colletbe2010e2015-10-31 12:57:14 +0100740size_t ZSTD_HC_compressBlock_greedy(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +0100741{
742 seqStore_t* seqStorePtr = &(ctx->seqStore);
743 const BYTE* const istart = (const BYTE*)src;
Yann Colleted0a7812015-10-23 19:25:06 +0100744 const BYTE* ip = istart;
Yann Colletf3eca252015-10-22 15:31:46 +0100745 const BYTE* anchor = istart;
746 const BYTE* const iend = istart + srcSize;
747 const BYTE* const ilimit = iend - 8;
748
Yann Colleted0a7812015-10-23 19:25:06 +0100749 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet083fcc82015-10-25 14:06:35 +0100750 const U32 maxSearches = 1 << ctx->params.searchLog;
Yann Collet4b100f42015-10-30 15:49:48 +0100751 const U32 mls = ctx->params.searchLength;
Yann Colletf3eca252015-10-22 15:31:46 +0100752
753 /* init */
754 ZSTD_resetSeqStore(seqStorePtr);
Yann Colleted0a7812015-10-23 19:25:06 +0100755 if (((ip-ctx->base) - ctx->dictLimit) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Colletf3eca252015-10-22 15:31:46 +0100756
Yann Colleted0a7812015-10-23 19:25:06 +0100757 /* Match Loop */
Yann Colletf3eca252015-10-22 15:31:46 +0100758 while (ip < ilimit)
759 {
Yann Colleted0a7812015-10-23 19:25:06 +0100760 /* repcode */
761 if (MEM_read32(ip) == MEM_read32(ip - offset_2))
Yann Colletf3eca252015-10-22 15:31:46 +0100762 {
Yann Collet4114f952015-10-30 06:40:22 +0100763 /* store sequence */
Yann Collet342892c2015-10-26 17:44:04 +0100764 size_t matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
Yann Colletf3eca252015-10-22 15:31:46 +0100765 size_t litLength = ip-anchor;
Yann Colleted0a7812015-10-23 19:25:06 +0100766 size_t offset = offset_2;
Yann Colletf3eca252015-10-22 15:31:46 +0100767 offset_2 = offset_1;
Yann Colleted0a7812015-10-23 19:25:06 +0100768 offset_1 = offset;
769 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
770 ip += matchLength+MINMATCH;
Yann Colletf3eca252015-10-22 15:31:46 +0100771 anchor = ip;
Yann Colleted0a7812015-10-23 19:25:06 +0100772 continue;
773 }
774
Yann Collet4114f952015-10-30 06:40:22 +0100775 offset_2 = offset_1; /* failed once : necessarily offset_1 now */
776
Yann Collet342892c2015-10-26 17:44:04 +0100777 /* repcode at ip+1 */
778 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))
779 {
780 size_t matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
781 size_t litLength = ip+1-anchor;
Yann Collet342892c2015-10-26 17:44:04 +0100782 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
783 ip += 1+matchLength+MINMATCH;
784 anchor = ip;
785 continue;
786 }
787
Yann Colleted0a7812015-10-23 19:25:06 +0100788 /* search */
789 {
Yann Collet050efba2015-11-03 09:49:30 +0100790 size_t offset=999999;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100791 size_t matchLength = ZSTD_HC_HcFindBestMatch_selectMLS(ctx, ip, iend, &offset, maxSearches, mls);
Yann Collet4114f952015-10-30 06:40:22 +0100792 if (!matchLength) { ip++; continue; }
Yann Colleted0a7812015-10-23 19:25:06 +0100793 /* store sequence */
794 {
795 size_t litLength = ip-anchor;
Yann Collet050efba2015-11-03 09:49:30 +0100796 offset_1 = offset;
Yann Collet342892c2015-10-26 17:44:04 +0100797 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset_1, matchLength-MINMATCH);
Yann Colleted0a7812015-10-23 19:25:06 +0100798 ip += matchLength;
799 anchor = ip;
800 }
Yann Colletf3eca252015-10-22 15:31:46 +0100801 }
802 }
803
804 /* Last Literals */
805 {
806 size_t lastLLSize = iend - anchor;
807 memcpy(seqStorePtr->lit, anchor, lastLLSize);
808 seqStorePtr->lit += lastLLSize;
809 }
810
Yann Collet2c6992e2015-10-27 12:18:00 +0100811 /* Final compression stage */
Yann Colletf3eca252015-10-22 15:31:46 +0100812 return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
Yann Colletf3eca252015-10-22 15:31:46 +0100813
Yann Colletbe2010e2015-10-31 12:57:14 +0100814 seqStorePtr, srcSize);
815}
816
817
Yann Collet59d70632015-11-04 12:05:27 +0100818typedef size_t (*ZSTD_HC_blockCompressor) (ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
819
Yann Collet59d70632015-11-04 12:05:27 +0100820static ZSTD_HC_blockCompressor ZSTD_HC_selectBlockCompressor(ZSTD_HC_strategy strat)
821{
822 switch(strat)
823 {
824 default :
Yann Collet1f44b3f2015-11-05 17:32:18 +0100825 case ZSTD_HC_fast:
826 return ZSTD_HC_compressBlock_fast;
Yann Collet59d70632015-11-04 12:05:27 +0100827 case ZSTD_HC_greedy:
828 return ZSTD_HC_compressBlock_greedy;
829 case ZSTD_HC_lazy:
830 return ZSTD_HC_compressBlock_lazy;
Yann Collet47b68902015-11-05 15:14:17 +0100831 case ZSTD_HC_lazy2:
832 return ZSTD_HC_compressBlock_lazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100833 case ZSTD_HC_btlazy2:
Yann Collet5106a762015-11-05 15:00:24 +0100834 return ZSTD_HC_compressBlock_btlazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100835 }
836}
837
838
Yann Colletbe2010e2015-10-31 12:57:14 +0100839size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
840{
Yann Collet59d70632015-11-04 12:05:27 +0100841 ZSTD_HC_blockCompressor blockCompressor = ZSTD_HC_selectBlockCompressor(ctx->params.strategy);
842 return blockCompressor(ctx, dst, maxDstSize, src, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +0100843}
844
845
Yann Colletf3eca252015-10-22 15:31:46 +0100846static size_t ZSTD_HC_compress_generic (ZSTD_HC_CCtx* ctxPtr,
847 void* dst, size_t maxDstSize,
848 const void* src, size_t srcSize)
849{
Yann Collet3e358272015-11-04 18:19:39 +0100850 size_t blockSize = BLOCKSIZE;
Yann Colletf3eca252015-10-22 15:31:46 +0100851 size_t remaining = srcSize;
852 const BYTE* ip = (const BYTE*)src;
853 BYTE* const ostart = (BYTE*)dst;
854 BYTE* op = ostart;
Yann Collet59d70632015-11-04 12:05:27 +0100855 const ZSTD_HC_blockCompressor blockCompressor = ZSTD_HC_selectBlockCompressor(ctxPtr->params.strategy);
Yann Collet9b11b462015-11-01 12:40:22 +0100856
Yann Collet3e358272015-11-04 18:19:39 +0100857 while (remaining)
Yann Colletf3eca252015-10-22 15:31:46 +0100858 {
Yann Collet3e358272015-11-04 18:19:39 +0100859 size_t cSize;
860
Yann Collet3137d1a2015-11-04 23:36:36 +0100861 if (maxDstSize < 3 + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +0100862
863 if (remaining < blockSize) blockSize = remaining;
864 cSize = blockCompressor(ctxPtr, op+3, maxDstSize-3, ip, blockSize);
865 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100866
867 if (cSize == 0)
868 {
869 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); /* block is not compressible */
870 }
871 else
872 {
873 op[0] = (BYTE)(cSize>>16);
874 op[1] = (BYTE)(cSize>>8);
875 op[2] = (BYTE)cSize;
876 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
877 cSize += 3;
878 }
879
880 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +0100881 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100882 ip += blockSize;
883 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100884 }
885
886 return op-ostart;
887}
888
889
Yann Collet2acb5d32015-10-29 16:49:43 +0100890size_t ZSTD_HC_compressContinue (ZSTD_HC_CCtx* ctxPtr,
891 void* dst, size_t dstSize,
892 const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +0100893{
Yann Collet2acb5d32015-10-29 16:49:43 +0100894 const BYTE* const ip = (const BYTE*) src;
Yann Colletf3eca252015-10-22 15:31:46 +0100895
896 /* Check if blocks follow each other */
Yann Collet2acb5d32015-10-29 16:49:43 +0100897 if (ip != ctxPtr->end)
Yann Colletf3eca252015-10-22 15:31:46 +0100898 {
Yann Collet2acb5d32015-10-29 16:49:43 +0100899 if (ctxPtr->end != NULL)
Yann Collet4114f952015-10-30 06:40:22 +0100900 ZSTD_HC_resetCCtx_advanced(ctxPtr, ctxPtr->params); /* just reset, but no need to re-alloc */
Yann Collet2acb5d32015-10-29 16:49:43 +0100901 ctxPtr->base = ip;
Yann Colletf3eca252015-10-22 15:31:46 +0100902 }
903
Yann Collet2acb5d32015-10-29 16:49:43 +0100904 ctxPtr->end = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100905 return ZSTD_HC_compress_generic (ctxPtr, dst, dstSize, src, srcSize);
906}
907
908
Yann Collet083fcc82015-10-25 14:06:35 +0100909size_t ZSTD_HC_compressBegin_advanced(ZSTD_HC_CCtx* ctx,
910 void* dst, size_t maxDstSize,
Yann Collet2acb5d32015-10-29 16:49:43 +0100911 const ZSTD_HC_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +0100912{
Yann Collet4114f952015-10-30 06:40:22 +0100913 size_t errorCode;
Yann Colletf3eca252015-10-22 15:31:46 +0100914 if (maxDstSize < 4) return ERROR(dstSize_tooSmall);
Yann Collet4114f952015-10-30 06:40:22 +0100915 errorCode = ZSTD_HC_resetCCtx_advanced(ctx, params);
916 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet2acb5d32015-10-29 16:49:43 +0100917 MEM_writeLE32(dst, ZSTD_magicNumber); /* Write Header */
Yann Colletf3eca252015-10-22 15:31:46 +0100918 return 4;
919}
920
Yann Collet083fcc82015-10-25 14:06:35 +0100921
Yann Collet2acb5d32015-10-29 16:49:43 +0100922size_t ZSTD_HC_compressBegin(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +0100923{
Yann Collet2acb5d32015-10-29 16:49:43 +0100924 if (compressionLevel<=0) compressionLevel = 1;
Yann Collet786f5b52015-10-26 15:45:58 +0100925 if (compressionLevel > ZSTD_HC_MAX_CLEVEL) compressionLevel = ZSTD_HC_MAX_CLEVEL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100926 return ZSTD_HC_compressBegin_advanced(ctx, dst, maxDstSize, ZSTD_HC_defaultParameters[compressionLevel]);
Yann Collet083fcc82015-10-25 14:06:35 +0100927}
928
929
Yann Collet2acb5d32015-10-29 16:49:43 +0100930size_t ZSTD_HC_compressEnd(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize)
931{
932 BYTE* op = (BYTE*)dst;
933
934 /* Sanity check */
935 (void)ctx;
936 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
937
938 /* End of frame */
939 op[0] = (BYTE)(bt_end << 6);
940 op[1] = 0;
941 op[2] = 0;
942
943 return 3;
944}
945
Yann Collet083fcc82015-10-25 14:06:35 +0100946size_t ZSTD_HC_compress_advanced (ZSTD_HC_CCtx* ctx,
947 void* dst, size_t maxDstSize,
948 const void* src, size_t srcSize,
949 ZSTD_HC_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +0100950{
951 BYTE* const ostart = (BYTE*)dst;
952 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +0100953 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100954
Yann Collet71bcdb52015-10-29 17:08:03 +0100955 /* correct params, to use less memory */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100956 {
957 U32 srcLog = ZSTD_highbit((U32)srcSize-1) + 1;
958 U32 contentBtPlus = (ctx->params.strategy == ZSTD_HC_btlazy2);
959 if (params.windowLog > srcLog) params.windowLog = srcLog;
960 if (params.contentLog > srcLog+contentBtPlus) params.contentLog = srcLog+contentBtPlus;
961 }
Yann Collet71bcdb52015-10-29 17:08:03 +0100962
Yann Colletf3eca252015-10-22 15:31:46 +0100963 /* Header */
Yann Collet4114f952015-10-30 06:40:22 +0100964 oSize = ZSTD_HC_compressBegin_advanced(ctx, dst, maxDstSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +0100965 if(ZSTD_isError(oSize)) return oSize;
966 op += oSize;
967 maxDstSize -= oSize;
968
969 /* body (compression) */
Yann Collet3d9cf7a2015-10-29 17:15:14 +0100970 ctx->base = (const BYTE*)src;
Yann Collet3e358272015-11-04 18:19:39 +0100971 oSize = ZSTD_HC_compress_generic (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +0100972 if(ZSTD_isError(oSize)) return oSize;
973 op += oSize;
974 maxDstSize -= oSize;
975
976 /* Close frame */
Yann Collet2acb5d32015-10-29 16:49:43 +0100977 oSize = ZSTD_HC_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +0100978 if(ZSTD_isError(oSize)) return oSize;
979 op += oSize;
980
981 return (op - ostart);
982}
983
Yann Collet2acb5d32015-10-29 16:49:43 +0100984size_t ZSTD_HC_compressCCtx (ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +0100985{
Yann Collet2acb5d32015-10-29 16:49:43 +0100986 if (compressionLevel<=1) return ZSTD_compress(dst, maxDstSize, src, srcSize); /* fast mode */
Yann Collet786f5b52015-10-26 15:45:58 +0100987 if (compressionLevel > ZSTD_HC_MAX_CLEVEL) compressionLevel = ZSTD_HC_MAX_CLEVEL;
Yann Collet083fcc82015-10-25 14:06:35 +0100988 return ZSTD_HC_compress_advanced(ctx, dst, maxDstSize, src, srcSize, ZSTD_HC_defaultParameters[compressionLevel]);
989}
990
Yann Collet2acb5d32015-10-29 16:49:43 +0100991size_t ZSTD_HC_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +0100992{
Yann Collet44fe9912015-10-29 22:02:40 +0100993 size_t result;
Yann Collet712def92015-10-29 18:41:45 +0100994 ZSTD_HC_CCtx ctxBody;
995 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet44fe9912015-10-29 22:02:40 +0100996 result = ZSTD_HC_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
997 free(ctxBody.workSpace);
998 return result;
Yann Colletf3eca252015-10-22 15:31:46 +0100999}