blob: cfc098ac539c4582d857ad0d99b4d4c4bdbf07b8 [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 Collet805a52a2015-11-06 10:52:17 +0100158 memset(zc->workSpace, 0, tableSpace );
159 zc->hashTable = (U32*)(zc->workSpace);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100160 zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog);
161 zc->seqStore.buffer = (void*) (zc->contentTable + ((size_t)1 << contentLog));
Yann Collet083fcc82015-10-25 14:06:35 +0100162 }
Yann Collet083fcc82015-10-25 14:06:35 +0100163
Yann Colletf48e35c2015-11-07 01:13:31 +0100164 zc->nextToUpdate = 1;
Yann Collet2acb5d32015-10-29 16:49:43 +0100165 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;
Yann Colletf12c1302015-11-05 18:16:59 +0100228 const size_t maxDist = ((size_t)1 << ctx->params.windowLog);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100229
230 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100231 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100232 const BYTE* anchor = istart;
Yann Colletf12c1302015-11-05 18:16:59 +0100233 const BYTE* const lowest = (size_t)(istart-base) > maxDist ? istart-maxDist : base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100234 const BYTE* const iend = istart + srcSize;
235 const BYTE* const ilimit = iend - 8;
236
237 size_t offset_2=4, offset_1=4;
238
239
240 /* init */
241 if (ip == base)
242 {
243 hashTable[ZSTD_HC_hashPtr(base+1, hBits, mls)] = 1;
244 hashTable[ZSTD_HC_hashPtr(base+2, hBits, mls)] = 2;
245 hashTable[ZSTD_HC_hashPtr(base+3, hBits, mls)] = 3;
246 ip = base+4;
247 }
248 ZSTD_resetSeqStore(seqStorePtr);
249
250 /* Main Search Loop */
251 while (ip < ilimit) /* < instead of <=, because unconditionnal ZSTD_addPtr(ip+1) */
252 {
253 const size_t h = ZSTD_HC_hashPtr(ip, hBits, mls);
254 const BYTE* match = base + hashTable[h];
255 hashTable[h] = (U32)(ip-base);
256
257 if (MEM_read32(ip-offset_2) == MEM_read32(ip)) match = ip-offset_2;
Yann Colletf12c1302015-11-05 18:16:59 +0100258 if ( (match < lowest) ||
259 (MEM_read32(match) != MEM_read32(ip)) )
260 { ip += ((ip-anchor) >> g_searchStrength) + 1; offset_2 = offset_1; continue; }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100261 while ((ip>anchor) && (match>base) && (ip[-1] == match[-1])) { ip--; match--; } /* catch up */
262
263 {
264 size_t litLength = ip-anchor;
265 size_t matchLength = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
266 size_t offsetCode = ip-match;
267 if (offsetCode == offset_2) offsetCode = 0;
268 offset_2 = offset_1;
269 offset_1 = ip-match;
270 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offsetCode, matchLength);
271
272 /* Fill Table */
273 hashTable[ZSTD_HC_hashPtr(ip+1, hBits, mls)] = (U32)(ip+1-base);
274 ip += matchLength + MINMATCH;
275 anchor = ip;
276 if (ip < ilimit) /* same test as loop, for speed */
277 hashTable[ZSTD_HC_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
278 }
279 }
280
281 /* Last Literals */
282 {
283 size_t lastLLSize = iend - anchor;
284 memcpy(seqStorePtr->lit, anchor, lastLLSize);
285 seqStorePtr->lit += lastLLSize;
286 }
287
288 /* Finale compression stage */
289 return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
290 seqStorePtr, srcSize);
291}
292
293
294size_t ZSTD_HC_compressBlock_fast(ZSTD_HC_CCtx* ctx,
295 void* dst, size_t maxDstSize,
296 const void* src, size_t srcSize)
297{
298 const U32 mls = ctx->params.searchLength;
299 switch(mls)
300 {
301 default:
302 case 4 :
303 return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 4);
304 case 5 :
305 return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 5);
306 case 6 :
307 return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 6);
308 case 7 :
309 return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 7);
310 }
311}
Yann Colletf3eca252015-10-22 15:31:46 +0100312
Yann Colletf3eca252015-10-22 15:31:46 +0100313
Yann Colletf3eca252015-10-22 15:31:46 +0100314/* *************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +0100315* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +0100316***************************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +0100317/** ZSTD_HC_insertBt1 : add one ptr to tree
318 @ip : assumed <= iend-8 */
Yann Collete9eba602015-11-08 15:08:03 +0100319static U32 ZSTD_HC_insertBt1(ZSTD_HC_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares)
Yann Collet96b9f0b2015-11-04 03:52:54 +0100320{
321 U32* const hashTable = zc->hashTable;
322 const U32 hashLog = zc->params.hashLog;
323 const size_t h = ZSTD_HC_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100324 U32* const bt = zc->contentTable;
325 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100326 const U32 btMask= (1 << btLog) - 1;
327 U32 matchIndex = hashTable[h];
328 size_t commonLengthSmaller=0, commonLengthLarger=0;
329 const BYTE* const base = zc->base;
Yann Colletf48e35c2015-11-07 01:13:31 +0100330 const BYTE* match = base + matchIndex;
331 U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +0100332 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100333 U32* smallerPtr = bt + 2*(current&btMask);
334 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet59d70632015-11-04 12:05:27 +0100335 U32 dummy32; /* to be nullified at the end */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100336 const U32 windowSize = 1 << zc->params.windowLog;
337 const U32 windowLow = windowSize >= current ? 0 : current - windowSize;
338
Yann Collete9eba602015-11-08 15:08:03 +0100339 if ((current-matchIndex == 1) /* RLE */
Yann Colletd1ade5a2015-11-08 15:49:20 +0100340 && MEM_read64(match) == MEM_read64(ip))
Yann Colletf48e35c2015-11-07 01:13:31 +0100341 {
Yann Collete9eba602015-11-08 15:08:03 +0100342 size_t rleLength = ZSTD_count(ip+sizeof(size_t), match+sizeof(size_t), iend) + sizeof(size_t);
343 return (U32)(rleLength - mls);
Yann Colletf48e35c2015-11-07 01:13:31 +0100344 }
345
346 hashTable[h] = (U32)(ip - base); /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100347
348 while (nbCompares-- && (matchIndex > windowLow))
349 {
350 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +0100351 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
352
Yann Colletf48e35c2015-11-07 01:13:31 +0100353 match = base + matchIndex;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100354 matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
355
Yann Collet59d70632015-11-04 12:05:27 +0100356 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Colletf48e35c2015-11-07 01:13:31 +0100357 break; /* just drop , to guarantee consistency (miss a bit of compression; if someone knows better, please tell) */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100358
359 if (match[matchLength] < ip[matchLength])
Yann Collet59d70632015-11-04 12:05:27 +0100360 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100361 /* match is smaller than current */
362 *smallerPtr = matchIndex; /* update smaller idx */
363 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +0100364 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100365 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +0100366 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet59d70632015-11-04 12:05:27 +0100367 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100368 else
Yann Collet59d70632015-11-04 12:05:27 +0100369 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100370 /* match is larger than current */
371 *largerPtr = matchIndex;
372 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +0100373 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100374 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +0100375 matchIndex = nextPtr[0];
Yann Collet59d70632015-11-04 12:05:27 +0100376 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100377 }
378
Yann Collet59d70632015-11-04 12:05:27 +0100379 *smallerPtr = *largerPtr = 0;
Yann Collete9eba602015-11-08 15:08:03 +0100380 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100381}
382
383
384FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
385size_t ZSTD_HC_insertBtAndFindBestMatch (
386 ZSTD_HC_CCtx* zc,
387 const BYTE* const ip, const BYTE* const iend,
388 size_t* offsetPtr,
389 U32 nbCompares, const U32 mls)
390{
391 U32* const hashTable = zc->hashTable;
392 const U32 hashLog = zc->params.hashLog;
393 const size_t h = ZSTD_HC_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100394 U32* const bt = zc->contentTable;
395 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100396 const U32 btMask= (1 << btLog) - 1;
397 U32 matchIndex = hashTable[h];
398 size_t commonLengthSmaller=0, commonLengthLarger=0;
399 const BYTE* const base = zc->base;
400 const U32 current = (U32)(ip-base);
401 const U32 btLow = btMask >= current ? 0 : current - btMask;
402 const U32 windowSize = 1 << zc->params.windowLog;
403 const U32 windowLow = windowSize >= current ? 0 : current - windowSize;
404 U32* smallerPtr = bt + 2*(current&btMask);
405 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Colletb241e9d2015-11-04 13:57:24 +0100406 size_t bestLength = 0;
Yann Collet59d70632015-11-04 12:05:27 +0100407 U32 dummy32; /* to be nullified at the end */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100408
Yann Collet59d70632015-11-04 12:05:27 +0100409 hashTable[h] = (U32)(ip-base); /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100410
411 while (nbCompares-- && (matchIndex > windowLow))
412 {
413 U32* nextPtr = bt + 2*(matchIndex & btMask);
414 const BYTE* match = base + matchIndex;
415 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
416
417 matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
418
419 if (matchLength > bestLength)
420 {
Yann Collete8455f52015-11-04 17:41:20 +0100421 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
Yann Colletb241e9d2015-11-04 13:57:24 +0100422 bestLength = matchLength, *offsetPtr = current - matchIndex;
Yann Collet59d70632015-11-04 12:05:27 +0100423 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Colleta81d9ac2015-11-06 19:03:59 +0100424 break; /* just drop, to guarantee consistency (miss a little bit of compression) */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100425 }
426
427 if (match[matchLength] < ip[matchLength])
Yann Collet59d70632015-11-04 12:05:27 +0100428 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100429 /* match is smaller than current */
430 *smallerPtr = matchIndex; /* update smaller idx */
431 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Collet59d70632015-11-04 12:05:27 +0100432 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colleta81d9ac2015-11-06 19:03:59 +0100433 if (matchIndex <= btLow) smallerPtr=&dummy32; /* beyond tree size, stop the search */
434 matchIndex = (matchIndex <= btLow) ? windowLow : nextPtr[1];
Yann Collet59d70632015-11-04 12:05:27 +0100435 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100436 else
Yann Collet59d70632015-11-04 12:05:27 +0100437 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100438 /* match is larger than current */
439 *largerPtr = matchIndex;
440 commonLengthLarger = matchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100441 largerPtr = nextPtr;
Yann Colleta81d9ac2015-11-06 19:03:59 +0100442 if (matchIndex <= btLow) largerPtr=&dummy32; /* beyond tree size, stop the search */
443 matchIndex = (matchIndex <= btLow) ? windowLow : nextPtr[0];
Yann Collet59d70632015-11-04 12:05:27 +0100444 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100445 }
446
Yann Collet59d70632015-11-04 12:05:27 +0100447 *smallerPtr = *largerPtr = 0;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100448
449 zc->nextToUpdate = current+1; /* current has been inserted */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100450 return bestLength;
451}
452
453
Yann Colletf48e35c2015-11-07 01:13:31 +0100454static const BYTE* ZSTD_HC_updateTree(ZSTD_HC_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
Yann Collet96b9f0b2015-11-04 03:52:54 +0100455{
456 const BYTE* const base = zc->base;
457 const U32 target = (U32)(ip - base);
458 U32 idx = zc->nextToUpdate;
Yann Collet59d70632015-11-04 12:05:27 +0100459 //size_t dummy;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100460
Yann Colletf48e35c2015-11-07 01:13:31 +0100461 for( ; idx < target ; )
462 idx += ZSTD_HC_insertBt1(zc, base+idx, mls, iend, nbCompares);
Yann Collet96b9f0b2015-11-04 03:52:54 +0100463 //ZSTD_HC_insertBtAndFindBestMatch(zc, base+idx, iend, &dummy, nbCompares, mls);
464
Yann Colletf48e35c2015-11-07 01:13:31 +0100465 zc->nextToUpdate = idx;
466 return base + idx;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100467}
468
469
470/** Tree updater, providing best match */
471FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
472size_t ZSTD_HC_BtFindBestMatch (
473 ZSTD_HC_CCtx* zc,
474 const BYTE* const ip, const BYTE* const iLimit,
475 size_t* offsetPtr,
476 const U32 maxNbAttempts, const U32 mls)
477{
Yann Colletf48e35c2015-11-07 01:13:31 +0100478 const BYTE* nextToUpdate = ZSTD_HC_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
479 if (nextToUpdate > ip)
480 {
481 /* RLE data */
482 *offsetPtr = 1;
483 return ZSTD_count(ip, ip-1, iLimit);
484 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100485 return ZSTD_HC_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls);
486}
487
488
489FORCE_INLINE size_t ZSTD_HC_BtFindBestMatch_selectMLS (
490 ZSTD_HC_CCtx* zc, /* Index table will be updated */
491 const BYTE* ip, const BYTE* const iLimit,
492 size_t* offsetPtr,
493 const U32 maxNbAttempts, const U32 matchLengthSearch)
494{
495 switch(matchLengthSearch)
496 {
497 default :
498 case 4 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
499 case 5 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
500 case 6 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
501 }
502}
503
504
Yann Collet5106a762015-11-05 15:00:24 +0100505/* ***********************
506* Hash Chain
507*************************/
508
Yann Collet1f44b3f2015-11-05 17:32:18 +0100509#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
510
Yann Collet5106a762015-11-05 15:00:24 +0100511/* Update chains up to ip (excluded) */
512static U32 ZSTD_HC_insertAndFindFirstIndex (ZSTD_HC_CCtx* zc, const BYTE* ip, U32 mls)
513{
514 U32* const hashTable = zc->hashTable;
515 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100516 U32* const chainTable = zc->contentTable;
517 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +0100518 const BYTE* const base = zc->base;
519 const U32 target = (U32)(ip - base);
520 U32 idx = zc->nextToUpdate;
521
522 while(idx < target)
523 {
524 size_t h = ZSTD_HC_hashPtr(base+idx, hashLog, mls);
525 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
526 hashTable[h] = idx;
527 idx++;
528 }
529
530 zc->nextToUpdate = target;
531 return hashTable[ZSTD_HC_hashPtr(ip, hashLog, mls)];
532}
533
534
535FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100536size_t ZSTD_HC_HcFindBestMatch (
Yann Collet5106a762015-11-05 15:00:24 +0100537 ZSTD_HC_CCtx* zc, /* Index table will be updated */
538 const BYTE* const ip, const BYTE* const iLimit,
539 size_t* offsetPtr,
540 const U32 maxNbAttempts, const U32 matchLengthSearch)
541{
Yann Collet1f44b3f2015-11-05 17:32:18 +0100542 U32* const chainTable = zc->contentTable;
543 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +0100544 const U32 chainMask = chainSize-1;
545 const BYTE* const base = zc->base;
546 const BYTE* const dictBase = zc->dictBase;
547 const U32 dictLimit = zc->dictLimit;
548 const U32 maxDistance = (1 << zc->params.windowLog);
549 const U32 lowLimit = (zc->lowLimit + maxDistance > (U32)(ip-base)) ? zc->lowLimit : (U32)(ip - base) - (maxDistance - 1);
550 U32 matchIndex;
551 const BYTE* match;
552 int nbAttempts=maxNbAttempts;
553 size_t ml=0;
554
555 /* HC4 match finder */
556 matchIndex = ZSTD_HC_insertAndFindFirstIndex (zc, ip, matchLengthSearch);
557
558 while ((matchIndex>lowLimit) && (nbAttempts))
559 {
560 nbAttempts--;
561 if (matchIndex >= dictLimit)
562 {
563 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +0100564 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5106a762015-11-05 15:00:24 +0100565 {
Yann Collet4baee502015-11-09 03:19:33 +0100566 const size_t mlt = ZSTD_count(ip, match, iLimit);
Yann Collet5106a762015-11-05 15:00:24 +0100567 if (mlt > ml)
568 //if (((int)(4*mlt) - (int)ZSTD_highbit((U32)(ip-match)+1)) > ((int)(4*ml) - (int)ZSTD_highbit((U32)((*offsetPtr)+1))))
569 {
570 ml = mlt; *offsetPtr = ip-match;
Yann Collet4baee502015-11-09 03:19:33 +0100571 if (ip+mlt >= iLimit) break;
Yann Collet5106a762015-11-05 15:00:24 +0100572 }
573 }
574 }
575 else
576 {
577 match = dictBase + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +0100578 if (MEM_read32(match) == MEM_read32(ip)) /* beware of end of dict */
Yann Collet5106a762015-11-05 15:00:24 +0100579 {
580 size_t mlt;
581 const BYTE* vLimit = ip + (dictLimit - matchIndex);
582 if (vLimit > iLimit) vLimit = iLimit;
583 mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
584 if ((ip+mlt == vLimit) && (vLimit < iLimit))
585 mlt += ZSTD_count(ip+mlt, base+dictLimit, iLimit);
586 if (mlt > ml) { ml = mlt; *offsetPtr = (ip-base) - matchIndex; }
587 }
588 }
589
590 if (base + matchIndex <= ip - chainSize) break;
591 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
592 }
593
594 return ml;
595}
596
597
Yann Collet1f44b3f2015-11-05 17:32:18 +0100598FORCE_INLINE size_t ZSTD_HC_HcFindBestMatch_selectMLS (
Yann Collet5106a762015-11-05 15:00:24 +0100599 ZSTD_HC_CCtx* zc, /* Index table will be updated */
600 const BYTE* ip, const BYTE* const iLimit,
601 size_t* offsetPtr,
602 const U32 maxNbAttempts, const U32 matchLengthSearch)
603{
604 switch(matchLengthSearch)
605 {
606 default :
Yann Collet1f44b3f2015-11-05 17:32:18 +0100607 case 4 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
608 case 5 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
609 case 6 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
Yann Collet5106a762015-11-05 15:00:24 +0100610 }
611}
612
613
Yann Collet90361052015-11-05 15:03:12 +0100614/* common lazy function, to be inlined */
Yann Collet5106a762015-11-05 15:00:24 +0100615FORCE_INLINE
616size_t ZSTD_HC_compressBlock_lazy_generic(ZSTD_HC_CCtx* ctx,
617 void* dst, size_t maxDstSize, const void* src, size_t srcSize,
618 const U32 searchMethod, const U32 deep) /* 0 : hc; 1 : bt */
619{
620 seqStore_t* seqStorePtr = &(ctx->seqStore);
621 const BYTE* const istart = (const BYTE*)src;
622 const BYTE* ip = istart;
623 const BYTE* anchor = istart;
624 const BYTE* const iend = istart + srcSize;
625 const BYTE* const ilimit = iend - 8;
626
627 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
628 const U32 maxSearches = 1 << ctx->params.searchLog;
629 const U32 mls = ctx->params.searchLength;
630
631 typedef size_t (*searchMax_f)(ZSTD_HC_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
632 size_t* offsetPtr,
633 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100634 searchMax_f searchMax = searchMethod ? ZSTD_HC_BtFindBestMatch_selectMLS : ZSTD_HC_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +0100635
636 /* init */
637 ZSTD_resetSeqStore(seqStorePtr);
638 if (((ip-ctx->base) - ctx->dictLimit) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
639
640 /* Match Loop */
641 while (ip <= ilimit)
642 {
643 size_t matchLength;
644 size_t offset=999999;
645 const BYTE* start;
646
647 /* try to find a first match */
648 if (MEM_read32(ip) == MEM_read32(ip - offset_2))
649 {
650 /* repcode : we take it*/
651 size_t offtmp = offset_2;
652 size_t litLength = ip - anchor;
653 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
654 offset_2 = offset_1;
655 offset_1 = offtmp;
656 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
657 ip += matchLength+MINMATCH;
658 anchor = ip;
659 continue;
660 }
661
662 offset_2 = offset_1;
663 matchLength = searchMax(ctx, ip, iend, &offset, maxSearches, mls);
Yann Collet4baee502015-11-09 03:19:33 +0100664 if (matchLength < MINMATCH)
Yann Colletfc2afcf2015-11-06 15:40:14 +0100665 {
666 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
667 continue;
668 }
Yann Collet5106a762015-11-05 15:00:24 +0100669
670 /* let's try to find a better solution */
671 start = ip;
672
673 while (ip<ilimit)
674 {
675 ip ++;
676 if (MEM_read32(ip) == MEM_read32(ip - offset_1))
677 {
678 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
679 int gain2 = (int)(ml2 * 3);
680 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +0100681 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +0100682 matchLength = ml2, offset = 0, start = ip;
683 }
684 {
685 size_t offset2=999999;
686 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +0100687 int gain2 = (int)(ml2*(3+deep) - ZSTD_highbit((U32)offset2+1)); /* raw approx */
688 int gain1 = (int)(matchLength*(3+deep) - ZSTD_highbit((U32)offset+1) + (3+deep));
Yann Collet4baee502015-11-09 03:19:33 +0100689 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +0100690 {
Yann Collet628065c2015-11-06 18:44:54 +0100691 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +0100692 continue; /* search a better one */
693 }
694 }
695
696 /* let's find an even better one */
697 if (deep && (ip<ilimit))
698 {
699 ip ++;
700 if (MEM_read32(ip) == MEM_read32(ip - offset_1))
701 {
702 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
703 int gain2 = (int)(ml2 * 4);
704 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +0100705 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +0100706 matchLength = ml2, offset = 0, start = ip;
707 }
708 {
709 size_t offset2=999999;
710 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +0100711 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
712 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Collet4baee502015-11-09 03:19:33 +0100713 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +0100714 {
Yann Collet628065c2015-11-06 18:44:54 +0100715 matchLength = ml2, offset = offset2, start = ip;
716 continue;
Yann Collet5106a762015-11-05 15:00:24 +0100717 }
718 }
719 }
720 break; /* nothing found : store previous solution */
721 }
722
Yann Collet4baee502015-11-09 03:19:33 +0100723 /* catch up */
Yann Collet628065c2015-11-06 18:44:54 +0100724 if (offset)
Yann Collet4baee502015-11-09 03:19:33 +0100725 {
726 while ((start>anchor) && (start>ctx->base+offset) && (start[-1] == start[-1-offset]))
727 { start--; matchLength++; }
728 }
729
730 /* store sequence */
Yann Collet5106a762015-11-05 15:00:24 +0100731 {
732 size_t litLength = start - anchor;
733 if (offset) offset_1 = offset;
734 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +0100735 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +0100736 }
737
738 }
739
740 /* Last Literals */
741 {
742 size_t lastLLSize = iend - anchor;
743 memcpy(seqStorePtr->lit, anchor, lastLLSize);
744 seqStorePtr->lit += lastLLSize;
745 }
746
747 /* Final compression stage */
748 return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
749 seqStorePtr, srcSize);
750}
751
752size_t ZSTD_HC_compressBlock_btlazy2(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
753{
754 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 1, 1);
755}
756
Yann Collet47b68902015-11-05 15:14:17 +0100757size_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 +0100758{
759 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1);
760}
761
762size_t ZSTD_HC_compressBlock_lazy(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
763{
764 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0);
765}
766
Yann Collet5106a762015-11-05 15:00:24 +0100767
Yann Colletbe2010e2015-10-31 12:57:14 +0100768size_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 +0100769{
770 seqStore_t* seqStorePtr = &(ctx->seqStore);
771 const BYTE* const istart = (const BYTE*)src;
Yann Colleted0a7812015-10-23 19:25:06 +0100772 const BYTE* ip = istart;
Yann Colletf3eca252015-10-22 15:31:46 +0100773 const BYTE* anchor = istart;
774 const BYTE* const iend = istart + srcSize;
775 const BYTE* const ilimit = iend - 8;
776
Yann Colleted0a7812015-10-23 19:25:06 +0100777 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet083fcc82015-10-25 14:06:35 +0100778 const U32 maxSearches = 1 << ctx->params.searchLog;
Yann Collet4b100f42015-10-30 15:49:48 +0100779 const U32 mls = ctx->params.searchLength;
Yann Colletf3eca252015-10-22 15:31:46 +0100780
781 /* init */
782 ZSTD_resetSeqStore(seqStorePtr);
Yann Colleted0a7812015-10-23 19:25:06 +0100783 if (((ip-ctx->base) - ctx->dictLimit) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Colletf3eca252015-10-22 15:31:46 +0100784
Yann Colleted0a7812015-10-23 19:25:06 +0100785 /* Match Loop */
Yann Colletf3eca252015-10-22 15:31:46 +0100786 while (ip < ilimit)
787 {
Yann Colleted0a7812015-10-23 19:25:06 +0100788 /* repcode */
789 if (MEM_read32(ip) == MEM_read32(ip - offset_2))
Yann Colletf3eca252015-10-22 15:31:46 +0100790 {
Yann Collet4114f952015-10-30 06:40:22 +0100791 /* store sequence */
Yann Collet342892c2015-10-26 17:44:04 +0100792 size_t matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
Yann Colletf3eca252015-10-22 15:31:46 +0100793 size_t litLength = ip-anchor;
Yann Colleted0a7812015-10-23 19:25:06 +0100794 size_t offset = offset_2;
Yann Colletf3eca252015-10-22 15:31:46 +0100795 offset_2 = offset_1;
Yann Colleted0a7812015-10-23 19:25:06 +0100796 offset_1 = offset;
797 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
798 ip += matchLength+MINMATCH;
Yann Colletf3eca252015-10-22 15:31:46 +0100799 anchor = ip;
Yann Colleted0a7812015-10-23 19:25:06 +0100800 continue;
801 }
802
Yann Collet4114f952015-10-30 06:40:22 +0100803 offset_2 = offset_1; /* failed once : necessarily offset_1 now */
804
Yann Collet342892c2015-10-26 17:44:04 +0100805 /* repcode at ip+1 */
806 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))
807 {
808 size_t matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
809 size_t litLength = ip+1-anchor;
Yann Collet342892c2015-10-26 17:44:04 +0100810 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
811 ip += 1+matchLength+MINMATCH;
812 anchor = ip;
813 continue;
814 }
815
Yann Colleted0a7812015-10-23 19:25:06 +0100816 /* search */
817 {
Yann Collet050efba2015-11-03 09:49:30 +0100818 size_t offset=999999;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100819 size_t matchLength = ZSTD_HC_HcFindBestMatch_selectMLS(ctx, ip, iend, &offset, maxSearches, mls);
Yann Collet4baee502015-11-09 03:19:33 +0100820 if (matchLength < MINMATCH)
Yann Colletfc2afcf2015-11-06 15:40:14 +0100821 {
822 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
823 continue;
824 }
Yann Colleteb283712015-11-06 16:33:11 +0100825 while ((ip>anchor) && (ip-offset>ctx->base) && (ip[-1] == ip[-1-offset])) { ip--; matchLength++; } /* catch up */
Yann Colleted0a7812015-10-23 19:25:06 +0100826 /* store sequence */
827 {
828 size_t litLength = ip-anchor;
Yann Collet050efba2015-11-03 09:49:30 +0100829 offset_1 = offset;
Yann Collet342892c2015-10-26 17:44:04 +0100830 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset_1, matchLength-MINMATCH);
Yann Colleted0a7812015-10-23 19:25:06 +0100831 ip += matchLength;
832 anchor = ip;
833 }
Yann Colletf3eca252015-10-22 15:31:46 +0100834 }
835 }
836
837 /* Last Literals */
838 {
839 size_t lastLLSize = iend - anchor;
840 memcpy(seqStorePtr->lit, anchor, lastLLSize);
841 seqStorePtr->lit += lastLLSize;
842 }
843
Yann Collet2c6992e2015-10-27 12:18:00 +0100844 /* Final compression stage */
Yann Colletf3eca252015-10-22 15:31:46 +0100845 return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
Yann Colletf3eca252015-10-22 15:31:46 +0100846
Yann Colletbe2010e2015-10-31 12:57:14 +0100847 seqStorePtr, srcSize);
848}
849
850
Yann Collet59d70632015-11-04 12:05:27 +0100851typedef size_t (*ZSTD_HC_blockCompressor) (ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
852
Yann Collet59d70632015-11-04 12:05:27 +0100853static ZSTD_HC_blockCompressor ZSTD_HC_selectBlockCompressor(ZSTD_HC_strategy strat)
854{
855 switch(strat)
856 {
857 default :
Yann Collet1f44b3f2015-11-05 17:32:18 +0100858 case ZSTD_HC_fast:
859 return ZSTD_HC_compressBlock_fast;
Yann Collet59d70632015-11-04 12:05:27 +0100860 case ZSTD_HC_greedy:
861 return ZSTD_HC_compressBlock_greedy;
862 case ZSTD_HC_lazy:
863 return ZSTD_HC_compressBlock_lazy;
Yann Collet47b68902015-11-05 15:14:17 +0100864 case ZSTD_HC_lazy2:
865 return ZSTD_HC_compressBlock_lazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100866 case ZSTD_HC_btlazy2:
Yann Collet5106a762015-11-05 15:00:24 +0100867 return ZSTD_HC_compressBlock_btlazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100868 }
869}
870
871
Yann Colletbe2010e2015-10-31 12:57:14 +0100872size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
873{
Yann Collet59d70632015-11-04 12:05:27 +0100874 ZSTD_HC_blockCompressor blockCompressor = ZSTD_HC_selectBlockCompressor(ctx->params.strategy);
875 return blockCompressor(ctx, dst, maxDstSize, src, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +0100876}
877
878
Yann Colletf3eca252015-10-22 15:31:46 +0100879static size_t ZSTD_HC_compress_generic (ZSTD_HC_CCtx* ctxPtr,
880 void* dst, size_t maxDstSize,
881 const void* src, size_t srcSize)
882{
Yann Collet3e358272015-11-04 18:19:39 +0100883 size_t blockSize = BLOCKSIZE;
Yann Colletf3eca252015-10-22 15:31:46 +0100884 size_t remaining = srcSize;
885 const BYTE* ip = (const BYTE*)src;
886 BYTE* const ostart = (BYTE*)dst;
887 BYTE* op = ostart;
Yann Collet59d70632015-11-04 12:05:27 +0100888 const ZSTD_HC_blockCompressor blockCompressor = ZSTD_HC_selectBlockCompressor(ctxPtr->params.strategy);
Yann Collet9b11b462015-11-01 12:40:22 +0100889
Yann Collet3e358272015-11-04 18:19:39 +0100890 while (remaining)
Yann Colletf3eca252015-10-22 15:31:46 +0100891 {
Yann Collet3e358272015-11-04 18:19:39 +0100892 size_t cSize;
893
Yann Collet3137d1a2015-11-04 23:36:36 +0100894 if (maxDstSize < 3 + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +0100895
896 if (remaining < blockSize) blockSize = remaining;
897 cSize = blockCompressor(ctxPtr, op+3, maxDstSize-3, ip, blockSize);
898 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100899
900 if (cSize == 0)
901 {
902 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); /* block is not compressible */
903 }
904 else
905 {
906 op[0] = (BYTE)(cSize>>16);
907 op[1] = (BYTE)(cSize>>8);
908 op[2] = (BYTE)cSize;
909 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
910 cSize += 3;
911 }
912
913 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +0100914 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100915 ip += blockSize;
916 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100917 }
918
919 return op-ostart;
920}
921
922
Yann Collet2acb5d32015-10-29 16:49:43 +0100923size_t ZSTD_HC_compressContinue (ZSTD_HC_CCtx* ctxPtr,
924 void* dst, size_t dstSize,
925 const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +0100926{
Yann Collet2acb5d32015-10-29 16:49:43 +0100927 const BYTE* const ip = (const BYTE*) src;
Yann Colletf3eca252015-10-22 15:31:46 +0100928
929 /* Check if blocks follow each other */
Yann Collet2acb5d32015-10-29 16:49:43 +0100930 if (ip != ctxPtr->end)
Yann Colletf3eca252015-10-22 15:31:46 +0100931 {
Yann Collet2acb5d32015-10-29 16:49:43 +0100932 if (ctxPtr->end != NULL)
Yann Collet805a52a2015-11-06 10:52:17 +0100933 ZSTD_HC_resetCCtx_advanced(ctxPtr, ctxPtr->params);
Yann Collet2acb5d32015-10-29 16:49:43 +0100934 ctxPtr->base = ip;
Yann Colletf3eca252015-10-22 15:31:46 +0100935 }
936
Yann Collet2acb5d32015-10-29 16:49:43 +0100937 ctxPtr->end = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100938 return ZSTD_HC_compress_generic (ctxPtr, dst, dstSize, src, srcSize);
939}
940
941
Yann Collet083fcc82015-10-25 14:06:35 +0100942size_t ZSTD_HC_compressBegin_advanced(ZSTD_HC_CCtx* ctx,
943 void* dst, size_t maxDstSize,
Yann Collet2acb5d32015-10-29 16:49:43 +0100944 const ZSTD_HC_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +0100945{
Yann Collet4114f952015-10-30 06:40:22 +0100946 size_t errorCode;
Yann Colletf3eca252015-10-22 15:31:46 +0100947 if (maxDstSize < 4) return ERROR(dstSize_tooSmall);
Yann Collet4114f952015-10-30 06:40:22 +0100948 errorCode = ZSTD_HC_resetCCtx_advanced(ctx, params);
949 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet2acb5d32015-10-29 16:49:43 +0100950 MEM_writeLE32(dst, ZSTD_magicNumber); /* Write Header */
Yann Colletf3eca252015-10-22 15:31:46 +0100951 return 4;
952}
953
Yann Collet083fcc82015-10-25 14:06:35 +0100954
Yann Collet2acb5d32015-10-29 16:49:43 +0100955size_t ZSTD_HC_compressBegin(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +0100956{
Yann Collet2acb5d32015-10-29 16:49:43 +0100957 if (compressionLevel<=0) compressionLevel = 1;
Yann Collet786f5b52015-10-26 15:45:58 +0100958 if (compressionLevel > ZSTD_HC_MAX_CLEVEL) compressionLevel = ZSTD_HC_MAX_CLEVEL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100959 return ZSTD_HC_compressBegin_advanced(ctx, dst, maxDstSize, ZSTD_HC_defaultParameters[compressionLevel]);
Yann Collet083fcc82015-10-25 14:06:35 +0100960}
961
962
Yann Collet2acb5d32015-10-29 16:49:43 +0100963size_t ZSTD_HC_compressEnd(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize)
964{
965 BYTE* op = (BYTE*)dst;
966
967 /* Sanity check */
968 (void)ctx;
969 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
970
971 /* End of frame */
972 op[0] = (BYTE)(bt_end << 6);
973 op[1] = 0;
974 op[2] = 0;
975
976 return 3;
977}
978
Yann Collet083fcc82015-10-25 14:06:35 +0100979size_t ZSTD_HC_compress_advanced (ZSTD_HC_CCtx* ctx,
980 void* dst, size_t maxDstSize,
981 const void* src, size_t srcSize,
982 ZSTD_HC_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +0100983{
984 BYTE* const ostart = (BYTE*)dst;
985 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +0100986 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100987
Yann Collet71bcdb52015-10-29 17:08:03 +0100988 /* correct params, to use less memory */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100989 {
990 U32 srcLog = ZSTD_highbit((U32)srcSize-1) + 1;
991 U32 contentBtPlus = (ctx->params.strategy == ZSTD_HC_btlazy2);
992 if (params.windowLog > srcLog) params.windowLog = srcLog;
993 if (params.contentLog > srcLog+contentBtPlus) params.contentLog = srcLog+contentBtPlus;
994 }
Yann Collet71bcdb52015-10-29 17:08:03 +0100995
Yann Colletf3eca252015-10-22 15:31:46 +0100996 /* Header */
Yann Collet4114f952015-10-30 06:40:22 +0100997 oSize = ZSTD_HC_compressBegin_advanced(ctx, dst, maxDstSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +0100998 if(ZSTD_isError(oSize)) return oSize;
999 op += oSize;
1000 maxDstSize -= oSize;
1001
1002 /* body (compression) */
Yann Collet3d9cf7a2015-10-29 17:15:14 +01001003 ctx->base = (const BYTE*)src;
Yann Collet3e358272015-11-04 18:19:39 +01001004 oSize = ZSTD_HC_compress_generic (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01001005 if(ZSTD_isError(oSize)) return oSize;
1006 op += oSize;
1007 maxDstSize -= oSize;
1008
1009 /* Close frame */
Yann Collet2acb5d32015-10-29 16:49:43 +01001010 oSize = ZSTD_HC_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01001011 if(ZSTD_isError(oSize)) return oSize;
1012 op += oSize;
1013
1014 return (op - ostart);
1015}
1016
Yann Collet2acb5d32015-10-29 16:49:43 +01001017size_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 +01001018{
Yann Collet2acb5d32015-10-29 16:49:43 +01001019 if (compressionLevel<=1) return ZSTD_compress(dst, maxDstSize, src, srcSize); /* fast mode */
Yann Collet786f5b52015-10-26 15:45:58 +01001020 if (compressionLevel > ZSTD_HC_MAX_CLEVEL) compressionLevel = ZSTD_HC_MAX_CLEVEL;
Yann Collet083fcc82015-10-25 14:06:35 +01001021 return ZSTD_HC_compress_advanced(ctx, dst, maxDstSize, src, srcSize, ZSTD_HC_defaultParameters[compressionLevel]);
1022}
1023
Yann Collet2acb5d32015-10-29 16:49:43 +01001024size_t ZSTD_HC_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01001025{
Yann Collet44fe9912015-10-29 22:02:40 +01001026 size_t result;
Yann Collet712def92015-10-29 18:41:45 +01001027 ZSTD_HC_CCtx ctxBody;
1028 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet44fe9912015-10-29 22:02:40 +01001029 result = ZSTD_HC_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
1030 free(ctxBody.workSpace);
1031 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01001032}