mirror of
				https://github.com/facebook/zstd.git
				synced 2025-10-31 08:37:43 +02:00 
			
		
		
		
	Split parsers out of zstd_compress.c
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										301
									
								
								lib/compress/zstd_compress.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								lib/compress/zstd_compress.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,301 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * This source code is licensed under both the BSD-style license (found in the | ||||||
|  |  * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||||||
|  |  * in the COPYING file in the root directory of this source tree). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #ifndef ZSTD_COMPRESS_H | ||||||
|  | #define ZSTD_COMPRESS_H | ||||||
|  |  | ||||||
|  | /*-************************************* | ||||||
|  | *  Dependencies | ||||||
|  | ***************************************/ | ||||||
|  | #include "zstd_internal.h" | ||||||
|  | #include "zstdmt_compress.h" | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /*-************************************* | ||||||
|  | *  Constants | ||||||
|  | ***************************************/ | ||||||
|  | static const U32 g_searchStrength = 8; | ||||||
|  | #define HASH_READ_SIZE 8 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /*-************************************* | ||||||
|  | *  Context memory management | ||||||
|  | ***************************************/ | ||||||
|  | typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e; | ||||||
|  | typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage; | ||||||
|  |  | ||||||
|  | typedef struct ZSTD_prefixDict_s { | ||||||
|  |     const void* dict; | ||||||
|  |     size_t dictSize; | ||||||
|  |     ZSTD_dictMode_e dictMode; | ||||||
|  | } ZSTD_prefixDict; | ||||||
|  |  | ||||||
|  | struct ZSTD_CCtx_s { | ||||||
|  |     const BYTE* nextSrc;    /* next block here to continue on current prefix */ | ||||||
|  |     const BYTE* base;       /* All regular indexes relative to this position */ | ||||||
|  |     const BYTE* dictBase;   /* extDict indexes relative to this position */ | ||||||
|  |     U32   dictLimit;        /* below that point, need extDict */ | ||||||
|  |     U32   lowLimit;         /* below that point, no more data */ | ||||||
|  |     U32   nextToUpdate;     /* index from which to continue dictionary update */ | ||||||
|  |     U32   nextToUpdate3;    /* index from which to continue dictionary update */ | ||||||
|  |     U32   hashLog3;         /* dispatch table : larger == faster, more memory */ | ||||||
|  |     U32   loadedDictEnd;    /* index of end of dictionary */ | ||||||
|  |     ZSTD_compressionStage_e stage; | ||||||
|  |     U32   dictID; | ||||||
|  |     ZSTD_CCtx_params requestedParams; | ||||||
|  |     ZSTD_CCtx_params appliedParams; | ||||||
|  |     void* workSpace; | ||||||
|  |     size_t workSpaceSize; | ||||||
|  |     size_t blockSize; | ||||||
|  |     U64 pledgedSrcSizePlusOne;  /* this way, 0 (default) == unknown */ | ||||||
|  |     U64 consumedSrcSize; | ||||||
|  |     XXH64_state_t xxhState; | ||||||
|  |     ZSTD_customMem customMem; | ||||||
|  |     size_t staticSize; | ||||||
|  |  | ||||||
|  |     seqStore_t seqStore;    /* sequences storage ptrs */ | ||||||
|  |     optState_t optState; | ||||||
|  |     U32* hashTable; | ||||||
|  |     U32* hashTable3; | ||||||
|  |     U32* chainTable; | ||||||
|  |     ZSTD_entropyCTables_t* entropy; | ||||||
|  |  | ||||||
|  |     /* streaming */ | ||||||
|  |     char*  inBuff; | ||||||
|  |     size_t inBuffSize; | ||||||
|  |     size_t inToCompress; | ||||||
|  |     size_t inBuffPos; | ||||||
|  |     size_t inBuffTarget; | ||||||
|  |     char*  outBuff; | ||||||
|  |     size_t outBuffSize; | ||||||
|  |     size_t outBuffContentSize; | ||||||
|  |     size_t outBuffFlushedSize; | ||||||
|  |     ZSTD_cStreamStage streamStage; | ||||||
|  |     U32    frameEnded; | ||||||
|  |  | ||||||
|  |     /* Dictionary */ | ||||||
|  |     ZSTD_CDict* cdictLocal; | ||||||
|  |     const ZSTD_CDict* cdict; | ||||||
|  |     ZSTD_prefixDict prefixDict;   /* single-usage dictionary */ | ||||||
|  |  | ||||||
|  |     /* Multi-threading */ | ||||||
|  |     ZSTDMT_CCtx* mtctx; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static const BYTE LL_Code[64] = {  0,  1,  2,  3,  4,  5,  6,  7, | ||||||
|  |                                    8,  9, 10, 11, 12, 13, 14, 15, | ||||||
|  |                                   16, 16, 17, 17, 18, 18, 19, 19, | ||||||
|  |                                   20, 20, 20, 20, 21, 21, 21, 21, | ||||||
|  |                                   22, 22, 22, 22, 22, 22, 22, 22, | ||||||
|  |                                   23, 23, 23, 23, 23, 23, 23, 23, | ||||||
|  |                                   24, 24, 24, 24, 24, 24, 24, 24, | ||||||
|  |                                   24, 24, 24, 24, 24, 24, 24, 24 }; | ||||||
|  |  | ||||||
|  | static const BYTE ML_Code[128] = { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, | ||||||
|  |                                   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||||||
|  |                                   32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, | ||||||
|  |                                   38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, | ||||||
|  |                                   40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | ||||||
|  |                                   41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, | ||||||
|  |                                   42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, | ||||||
|  |                                   42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 }; | ||||||
|  |  | ||||||
|  | /*! ZSTD_storeSeq() : | ||||||
|  |     Store a sequence (literal length, literals, offset code and match length code) into seqStore_t. | ||||||
|  |     `offsetCode` : distance to match, or 0 == repCode. | ||||||
|  |     `matchCode` : matchLength - MINMATCH | ||||||
|  | */ | ||||||
|  | MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode) | ||||||
|  | { | ||||||
|  | #if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6) | ||||||
|  |     static const BYTE* g_start = NULL; | ||||||
|  |     U32 const pos = (U32)((const BYTE*)literals - g_start); | ||||||
|  |     if (g_start==NULL) g_start = (const BYTE*)literals; | ||||||
|  |     if ((pos > 0) && (pos < 1000000000)) | ||||||
|  |         DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u", | ||||||
|  |                pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode); | ||||||
|  | #endif | ||||||
|  |     /* copy Literals */ | ||||||
|  |     assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB); | ||||||
|  |     ZSTD_wildcopy(seqStorePtr->lit, literals, litLength); | ||||||
|  |     seqStorePtr->lit += litLength; | ||||||
|  |  | ||||||
|  |     /* literal Length */ | ||||||
|  |     if (litLength>0xFFFF) { | ||||||
|  |         seqStorePtr->longLengthID = 1; | ||||||
|  |         seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); | ||||||
|  |     } | ||||||
|  |     seqStorePtr->sequences[0].litLength = (U16)litLength; | ||||||
|  |  | ||||||
|  |     /* match offset */ | ||||||
|  |     seqStorePtr->sequences[0].offset = offsetCode + 1; | ||||||
|  |  | ||||||
|  |     /* match Length */ | ||||||
|  |     if (matchCode>0xFFFF) { | ||||||
|  |         seqStorePtr->longLengthID = 2; | ||||||
|  |         seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); | ||||||
|  |     } | ||||||
|  |     seqStorePtr->sequences[0].matchLength = (U16)matchCode; | ||||||
|  |  | ||||||
|  |     seqStorePtr->sequences++; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /*-************************************* | ||||||
|  | *  Match length counter | ||||||
|  | ***************************************/ | ||||||
|  | static unsigned ZSTD_NbCommonBytes (register size_t val) | ||||||
|  | { | ||||||
|  |     if (MEM_isLittleEndian()) { | ||||||
|  |         if (MEM_64bits()) { | ||||||
|  | #       if defined(_MSC_VER) && defined(_WIN64) | ||||||
|  |             unsigned long r = 0; | ||||||
|  |             _BitScanForward64( &r, (U64)val ); | ||||||
|  |             return (unsigned)(r>>3); | ||||||
|  | #       elif defined(__GNUC__) && (__GNUC__ >= 3) | ||||||
|  |             return (__builtin_ctzll((U64)val) >> 3); | ||||||
|  | #       else | ||||||
|  |             static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, | ||||||
|  |                                                      0, 3, 1, 3, 1, 4, 2, 7, | ||||||
|  |                                                      0, 2, 3, 6, 1, 5, 3, 5, | ||||||
|  |                                                      1, 3, 4, 4, 2, 5, 6, 7, | ||||||
|  |                                                      7, 0, 1, 2, 3, 3, 4, 6, | ||||||
|  |                                                      2, 6, 5, 5, 3, 4, 5, 6, | ||||||
|  |                                                      7, 1, 2, 4, 6, 4, 4, 5, | ||||||
|  |                                                      7, 2, 6, 5, 7, 6, 7, 7 }; | ||||||
|  |             return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; | ||||||
|  | #       endif | ||||||
|  |         } else { /* 32 bits */ | ||||||
|  | #       if defined(_MSC_VER) | ||||||
|  |             unsigned long r=0; | ||||||
|  |             _BitScanForward( &r, (U32)val ); | ||||||
|  |             return (unsigned)(r>>3); | ||||||
|  | #       elif defined(__GNUC__) && (__GNUC__ >= 3) | ||||||
|  |             return (__builtin_ctz((U32)val) >> 3); | ||||||
|  | #       else | ||||||
|  |             static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, | ||||||
|  |                                                      3, 2, 2, 1, 3, 2, 0, 1, | ||||||
|  |                                                      3, 3, 1, 2, 2, 2, 2, 0, | ||||||
|  |                                                      3, 1, 2, 0, 1, 0, 1, 1 }; | ||||||
|  |             return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; | ||||||
|  | #       endif | ||||||
|  |         } | ||||||
|  |     } else {  /* Big Endian CPU */ | ||||||
|  |         if (MEM_64bits()) { | ||||||
|  | #       if defined(_MSC_VER) && defined(_WIN64) | ||||||
|  |             unsigned long r = 0; | ||||||
|  |             _BitScanReverse64( &r, val ); | ||||||
|  |             return (unsigned)(r>>3); | ||||||
|  | #       elif defined(__GNUC__) && (__GNUC__ >= 3) | ||||||
|  |             return (__builtin_clzll(val) >> 3); | ||||||
|  | #       else | ||||||
|  |             unsigned r; | ||||||
|  |             const unsigned n32 = sizeof(size_t)*4;   /* calculate this way due to compiler complaining in 32-bits mode */ | ||||||
|  |             if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } | ||||||
|  |             if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } | ||||||
|  |             r += (!val); | ||||||
|  |             return r; | ||||||
|  | #       endif | ||||||
|  |         } else { /* 32 bits */ | ||||||
|  | #       if defined(_MSC_VER) | ||||||
|  |             unsigned long r = 0; | ||||||
|  |             _BitScanReverse( &r, (unsigned long)val ); | ||||||
|  |             return (unsigned)(r>>3); | ||||||
|  | #       elif defined(__GNUC__) && (__GNUC__ >= 3) | ||||||
|  |             return (__builtin_clz((U32)val) >> 3); | ||||||
|  | #       else | ||||||
|  |             unsigned r; | ||||||
|  |             if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } | ||||||
|  |             r += (!val); | ||||||
|  |             return r; | ||||||
|  | #       endif | ||||||
|  |     }   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit) | ||||||
|  | { | ||||||
|  |     const BYTE* const pStart = pIn; | ||||||
|  |     const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1); | ||||||
|  |  | ||||||
|  |     while (pIn < pInLoopLimit) { | ||||||
|  |         size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn); | ||||||
|  |         if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; } | ||||||
|  |         pIn += ZSTD_NbCommonBytes(diff); | ||||||
|  |         return (size_t)(pIn - pStart); | ||||||
|  |     } | ||||||
|  |     if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; } | ||||||
|  |     if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; } | ||||||
|  |     if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++; | ||||||
|  |     return (size_t)(pIn - pStart); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** ZSTD_count_2segments() : | ||||||
|  | *   can count match length with `ip` & `match` in 2 different segments. | ||||||
|  | *   convention : on reaching mEnd, match count continue starting from iStart | ||||||
|  | */ | ||||||
|  | MEM_STATIC size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart) | ||||||
|  | { | ||||||
|  |     const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd); | ||||||
|  |     size_t const matchLength = ZSTD_count(ip, match, vEnd); | ||||||
|  |     if (match + matchLength != mEnd) return matchLength; | ||||||
|  |     return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /*-************************************* | ||||||
|  | *  Hashes | ||||||
|  | ***************************************/ | ||||||
|  | static const U32 prime3bytes = 506832829U; | ||||||
|  | static U32    ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes)  >> (32-h) ; } | ||||||
|  | MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */ | ||||||
|  |  | ||||||
|  | static const U32 prime4bytes = 2654435761U; | ||||||
|  | static U32    ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; } | ||||||
|  | static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); } | ||||||
|  |  | ||||||
|  | static const U64 prime5bytes = 889523592379ULL; | ||||||
|  | static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u  << (64-40)) * prime5bytes) >> (64-h)) ; } | ||||||
|  | static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); } | ||||||
|  |  | ||||||
|  | static const U64 prime6bytes = 227718039650203ULL; | ||||||
|  | static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u  << (64-48)) * prime6bytes) >> (64-h)) ; } | ||||||
|  | static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); } | ||||||
|  |  | ||||||
|  | static const U64 prime7bytes = 58295818150454627ULL; | ||||||
|  | static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u  << (64-56)) * prime7bytes) >> (64-h)) ; } | ||||||
|  | static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); } | ||||||
|  |  | ||||||
|  | static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL; | ||||||
|  | static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; } | ||||||
|  | static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); } | ||||||
|  |  | ||||||
|  | MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) | ||||||
|  | { | ||||||
|  |     switch(mls) | ||||||
|  |     { | ||||||
|  |     default: | ||||||
|  |     case 4: return ZSTD_hash4Ptr(p, hBits); | ||||||
|  |     case 5: return ZSTD_hash5Ptr(p, hBits); | ||||||
|  |     case 6: return ZSTD_hash6Ptr(p, hBits); | ||||||
|  |     case 7: return ZSTD_hash7Ptr(p, hBits); | ||||||
|  |     case 8: return ZSTD_hash8Ptr(p, hBits); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* ZSTD_COMPRESS_H */ | ||||||
							
								
								
									
										313
									
								
								lib/compress/zstd_double_fast.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								lib/compress/zstd_double_fast.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,313 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * This source code is licensed under both the BSD-style license (found in the | ||||||
|  |  * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||||||
|  |  * in the COPYING file in the root directory of this source tree). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "zstd_double_fast.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls) | ||||||
|  | { | ||||||
|  |     U32* const hashLarge = cctx->hashTable; | ||||||
|  |     U32  const hBitsL = cctx->appliedParams.cParams.hashLog; | ||||||
|  |     U32* const hashSmall = cctx->chainTable; | ||||||
|  |     U32  const hBitsS = cctx->appliedParams.cParams.chainLog; | ||||||
|  |     const BYTE* const base = cctx->base; | ||||||
|  |     const BYTE* ip = base + cctx->nextToUpdate; | ||||||
|  |     const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; | ||||||
|  |     const size_t fastHashFillStep = 3; | ||||||
|  |  | ||||||
|  |     while(ip <= iend) { | ||||||
|  |         hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base); | ||||||
|  |         hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base); | ||||||
|  |         ip += fastHashFillStep; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FORCE_INLINE_TEMPLATE | ||||||
|  | void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx, | ||||||
|  |                                  const void* src, size_t srcSize, | ||||||
|  |                                  const U32 mls) | ||||||
|  | { | ||||||
|  |     U32* const hashLong = cctx->hashTable; | ||||||
|  |     const U32 hBitsL = cctx->appliedParams.cParams.hashLog; | ||||||
|  |     U32* const hashSmall = cctx->chainTable; | ||||||
|  |     const U32 hBitsS = cctx->appliedParams.cParams.chainLog; | ||||||
|  |     seqStore_t* seqStorePtr = &(cctx->seqStore); | ||||||
|  |     const BYTE* const base = cctx->base; | ||||||
|  |     const BYTE* const istart = (const BYTE*)src; | ||||||
|  |     const BYTE* ip = istart; | ||||||
|  |     const BYTE* anchor = istart; | ||||||
|  |     const U32 lowestIndex = cctx->dictLimit; | ||||||
|  |     const BYTE* const lowest = base + lowestIndex; | ||||||
|  |     const BYTE* const iend = istart + srcSize; | ||||||
|  |     const BYTE* const ilimit = iend - HASH_READ_SIZE; | ||||||
|  |     U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1]; | ||||||
|  |     U32 offsetSaved = 0; | ||||||
|  |  | ||||||
|  |     /* init */ | ||||||
|  |     ip += (ip==lowest); | ||||||
|  |     {   U32 const maxRep = (U32)(ip-lowest); | ||||||
|  |         if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; | ||||||
|  |         if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Main Search Loop */ | ||||||
|  |     while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */ | ||||||
|  |         size_t mLength; | ||||||
|  |         size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8); | ||||||
|  |         size_t const h = ZSTD_hashPtr(ip, hBitsS, mls); | ||||||
|  |         U32 const current = (U32)(ip-base); | ||||||
|  |         U32 const matchIndexL = hashLong[h2]; | ||||||
|  |         U32 const matchIndexS = hashSmall[h]; | ||||||
|  |         const BYTE* matchLong = base + matchIndexL; | ||||||
|  |         const BYTE* match = base + matchIndexS; | ||||||
|  |         hashLong[h2] = hashSmall[h] = current;   /* update hash tables */ | ||||||
|  |  | ||||||
|  |         assert(offset_1 <= current);   /* supposed guaranteed by construction */ | ||||||
|  |         if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { | ||||||
|  |             /* favor repcode */ | ||||||
|  |             mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; | ||||||
|  |             ip++; | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH); | ||||||
|  |         } else { | ||||||
|  |             U32 offset; | ||||||
|  |             if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) { | ||||||
|  |                 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8; | ||||||
|  |                 offset = (U32)(ip-matchLong); | ||||||
|  |                 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ | ||||||
|  |             } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) { | ||||||
|  |                 size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); | ||||||
|  |                 U32 const matchIndexL3 = hashLong[hl3]; | ||||||
|  |                 const BYTE* matchL3 = base + matchIndexL3; | ||||||
|  |                 hashLong[hl3] = current + 1; | ||||||
|  |                 if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) { | ||||||
|  |                     mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8; | ||||||
|  |                     ip++; | ||||||
|  |                     offset = (U32)(ip-matchL3); | ||||||
|  |                     while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */ | ||||||
|  |                 } else { | ||||||
|  |                     mLength = ZSTD_count(ip+4, match+4, iend) + 4; | ||||||
|  |                     offset = (U32)(ip-match); | ||||||
|  |                     while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 ip += ((ip-anchor) >> g_searchStrength) + 1; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             offset_2 = offset_1; | ||||||
|  |             offset_1 = offset; | ||||||
|  |  | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* match found */ | ||||||
|  |         ip += mLength; | ||||||
|  |         anchor = ip; | ||||||
|  |  | ||||||
|  |         if (ip <= ilimit) { | ||||||
|  |             /* Fill Table */ | ||||||
|  |             hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = | ||||||
|  |                 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;  /* here because current+2 could be > iend-8 */ | ||||||
|  |             hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = | ||||||
|  |                 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base); | ||||||
|  |  | ||||||
|  |             /* check immediate repcode */ | ||||||
|  |             while ( (ip <= ilimit) | ||||||
|  |                  && ( (offset_2>0) | ||||||
|  |                  & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { | ||||||
|  |                 /* store sequence */ | ||||||
|  |                 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | ||||||
|  |                 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */ | ||||||
|  |                 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); | ||||||
|  |                 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); | ||||||
|  |                 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH); | ||||||
|  |                 ip += rLength; | ||||||
|  |                 anchor = ip; | ||||||
|  |                 continue;   /* faster when present ... (?) */ | ||||||
|  |     }   }   } | ||||||
|  |  | ||||||
|  |     /* save reps for next block */ | ||||||
|  |     seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved; | ||||||
|  |     seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved; | ||||||
|  |  | ||||||
|  |     /* Last Literals */ | ||||||
|  |     {   size_t const lastLLSize = iend - anchor; | ||||||
|  |         memcpy(seqStorePtr->lit, anchor, lastLLSize); | ||||||
|  |         seqStorePtr->lit += lastLLSize; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     const U32 mls = ctx->appliedParams.cParams.searchLength; | ||||||
|  |     switch(mls) | ||||||
|  |     { | ||||||
|  |     default: /* includes case 3 */ | ||||||
|  |     case 4 : | ||||||
|  |         ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return; | ||||||
|  |     case 5 : | ||||||
|  |         ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return; | ||||||
|  |     case 6 : | ||||||
|  |         ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return; | ||||||
|  |     case 7 : | ||||||
|  |         ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx, | ||||||
|  |                                  const void* src, size_t srcSize, | ||||||
|  |                                  const U32 mls) | ||||||
|  | { | ||||||
|  |     U32* const hashLong = ctx->hashTable; | ||||||
|  |     U32  const hBitsL = ctx->appliedParams.cParams.hashLog; | ||||||
|  |     U32* const hashSmall = ctx->chainTable; | ||||||
|  |     U32  const hBitsS = ctx->appliedParams.cParams.chainLog; | ||||||
|  |     seqStore_t* seqStorePtr = &(ctx->seqStore); | ||||||
|  |     const BYTE* const base = ctx->base; | ||||||
|  |     const BYTE* const dictBase = ctx->dictBase; | ||||||
|  |     const BYTE* const istart = (const BYTE*)src; | ||||||
|  |     const BYTE* ip = istart; | ||||||
|  |     const BYTE* anchor = istart; | ||||||
|  |     const U32   lowestIndex = ctx->lowLimit; | ||||||
|  |     const BYTE* const dictStart = dictBase + lowestIndex; | ||||||
|  |     const U32   dictLimit = ctx->dictLimit; | ||||||
|  |     const BYTE* const lowPrefixPtr = base + dictLimit; | ||||||
|  |     const BYTE* const dictEnd = dictBase + dictLimit; | ||||||
|  |     const BYTE* const iend = istart + srcSize; | ||||||
|  |     const BYTE* const ilimit = iend - 8; | ||||||
|  |     U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1]; | ||||||
|  |  | ||||||
|  |     /* Search Loop */ | ||||||
|  |     while (ip < ilimit) {  /* < instead of <=, because (ip+1) */ | ||||||
|  |         const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls); | ||||||
|  |         const U32 matchIndex = hashSmall[hSmall]; | ||||||
|  |         const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base; | ||||||
|  |         const BYTE* match = matchBase + matchIndex; | ||||||
|  |  | ||||||
|  |         const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8); | ||||||
|  |         const U32 matchLongIndex = hashLong[hLong]; | ||||||
|  |         const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base; | ||||||
|  |         const BYTE* matchLong = matchLongBase + matchLongIndex; | ||||||
|  |  | ||||||
|  |         const U32 current = (U32)(ip-base); | ||||||
|  |         const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */ | ||||||
|  |         const BYTE* repBase = repIndex < dictLimit ? dictBase : base; | ||||||
|  |         const BYTE* repMatch = repBase + repIndex; | ||||||
|  |         size_t mLength; | ||||||
|  |         hashSmall[hSmall] = hashLong[hLong] = current;   /* update hash table */ | ||||||
|  |  | ||||||
|  |         if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex)) | ||||||
|  |            && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { | ||||||
|  |             const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend; | ||||||
|  |             mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4; | ||||||
|  |             ip++; | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH); | ||||||
|  |         } else { | ||||||
|  |             if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) { | ||||||
|  |                 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr; | ||||||
|  |                 U32 offset; | ||||||
|  |                 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8; | ||||||
|  |                 offset = current - matchLongIndex; | ||||||
|  |                 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; }   /* catch up */ | ||||||
|  |                 offset_2 = offset_1; | ||||||
|  |                 offset_1 = offset; | ||||||
|  |                 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | ||||||
|  |  | ||||||
|  |             } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) { | ||||||
|  |                 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8); | ||||||
|  |                 U32 const matchIndex3 = hashLong[h3]; | ||||||
|  |                 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base; | ||||||
|  |                 const BYTE* match3 = match3Base + matchIndex3; | ||||||
|  |                 U32 offset; | ||||||
|  |                 hashLong[h3] = current + 1; | ||||||
|  |                 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) { | ||||||
|  |                     const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend; | ||||||
|  |                     const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr; | ||||||
|  |                     mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8; | ||||||
|  |                     ip++; | ||||||
|  |                     offset = current+1 - matchIndex3; | ||||||
|  |                     while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */ | ||||||
|  |                 } else { | ||||||
|  |                     const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                     const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr; | ||||||
|  |                     mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4; | ||||||
|  |                     offset = current - matchIndex; | ||||||
|  |                     while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */ | ||||||
|  |                 } | ||||||
|  |                 offset_2 = offset_1; | ||||||
|  |                 offset_1 = offset; | ||||||
|  |                 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | ||||||
|  |  | ||||||
|  |             } else { | ||||||
|  |                 ip += ((ip-anchor) >> g_searchStrength) + 1; | ||||||
|  |                 continue; | ||||||
|  |         }   } | ||||||
|  |  | ||||||
|  |         /* found a match : store it */ | ||||||
|  |         ip += mLength; | ||||||
|  |         anchor = ip; | ||||||
|  |  | ||||||
|  |         if (ip <= ilimit) { | ||||||
|  |             /* Fill Table */ | ||||||
|  |             hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; | ||||||
|  |             hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2; | ||||||
|  |             hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base); | ||||||
|  |             hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); | ||||||
|  |             /* check immediate repcode */ | ||||||
|  |             while (ip <= ilimit) { | ||||||
|  |                 U32 const current2 = (U32)(ip-base); | ||||||
|  |                 U32 const repIndex2 = current2 - offset_2; | ||||||
|  |                 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2; | ||||||
|  |                 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex))  /* intentional overflow */ | ||||||
|  |                    && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { | ||||||
|  |                     const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend; | ||||||
|  |                     size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4; | ||||||
|  |                     U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */ | ||||||
|  |                     ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH); | ||||||
|  |                     hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; | ||||||
|  |                     hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; | ||||||
|  |                     ip += repLength2; | ||||||
|  |                     anchor = ip; | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |     }   }   } | ||||||
|  |  | ||||||
|  |     /* save reps for next block */ | ||||||
|  |     seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2; | ||||||
|  |  | ||||||
|  |     /* Last Literals */ | ||||||
|  |     {   size_t const lastLLSize = iend - anchor; | ||||||
|  |         memcpy(seqStorePtr->lit, anchor, lastLLSize); | ||||||
|  |         seqStorePtr->lit += lastLLSize; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, | ||||||
|  |                          const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     U32 const mls = ctx->appliedParams.cParams.searchLength; | ||||||
|  |     switch(mls) | ||||||
|  |     { | ||||||
|  |     default: /* includes case 3 */ | ||||||
|  |     case 4 : | ||||||
|  |         ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return; | ||||||
|  |     case 5 : | ||||||
|  |         ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return; | ||||||
|  |     case 6 : | ||||||
|  |         ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return; | ||||||
|  |     case 7 : | ||||||
|  |         ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								lib/compress/zstd_double_fast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/compress/zstd_double_fast.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * This source code is licensed under both the BSD-style license (found in the | ||||||
|  |  * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||||||
|  |  * in the COPYING file in the root directory of this source tree). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef ZSTD_DOUBLE_FAST_H | ||||||
|  | #define ZSTD_DOUBLE_FAST_H | ||||||
|  |  | ||||||
|  | #include "zstd_compress.h" | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls); | ||||||
|  | void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* ZSTD_DOUBLE_FAST_H */ | ||||||
							
								
								
									
										247
									
								
								lib/compress/zstd_fast.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								lib/compress/zstd_fast.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,247 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * This source code is licensed under both the BSD-style license (found in the | ||||||
|  |  * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||||||
|  |  * in the COPYING file in the root directory of this source tree). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "zstd_fast.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) | ||||||
|  | { | ||||||
|  |     U32* const hashTable = zc->hashTable; | ||||||
|  |     U32  const hBits = zc->appliedParams.cParams.hashLog; | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     const BYTE* ip = base + zc->nextToUpdate; | ||||||
|  |     const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; | ||||||
|  |     const size_t fastHashFillStep = 3; | ||||||
|  |  | ||||||
|  |     while(ip <= iend) { | ||||||
|  |         hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base); | ||||||
|  |         ip += fastHashFillStep; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FORCE_INLINE_TEMPLATE | ||||||
|  | void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx, | ||||||
|  |                                const void* src, size_t srcSize, | ||||||
|  |                                const U32 mls) | ||||||
|  | { | ||||||
|  |     U32* const hashTable = cctx->hashTable; | ||||||
|  |     U32  const hBits = cctx->appliedParams.cParams.hashLog; | ||||||
|  |     seqStore_t* seqStorePtr = &(cctx->seqStore); | ||||||
|  |     const BYTE* const base = cctx->base; | ||||||
|  |     const BYTE* const istart = (const BYTE*)src; | ||||||
|  |     const BYTE* ip = istart; | ||||||
|  |     const BYTE* anchor = istart; | ||||||
|  |     const U32   lowestIndex = cctx->dictLimit; | ||||||
|  |     const BYTE* const lowest = base + lowestIndex; | ||||||
|  |     const BYTE* const iend = istart + srcSize; | ||||||
|  |     const BYTE* const ilimit = iend - HASH_READ_SIZE; | ||||||
|  |     U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1]; | ||||||
|  |     U32 offsetSaved = 0; | ||||||
|  |  | ||||||
|  |     /* init */ | ||||||
|  |     ip += (ip==lowest); | ||||||
|  |     {   U32 const maxRep = (U32)(ip-lowest); | ||||||
|  |         if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; | ||||||
|  |         if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Main Search Loop */ | ||||||
|  |     while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */ | ||||||
|  |         size_t mLength; | ||||||
|  |         size_t const h = ZSTD_hashPtr(ip, hBits, mls); | ||||||
|  |         U32 const current = (U32)(ip-base); | ||||||
|  |         U32 const matchIndex = hashTable[h]; | ||||||
|  |         const BYTE* match = base + matchIndex; | ||||||
|  |         hashTable[h] = current;   /* update hash table */ | ||||||
|  |  | ||||||
|  |         if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { | ||||||
|  |             mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; | ||||||
|  |             ip++; | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH); | ||||||
|  |         } else { | ||||||
|  |             U32 offset; | ||||||
|  |             if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) { | ||||||
|  |                 ip += ((ip-anchor) >> g_searchStrength) + 1; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             mLength = ZSTD_count(ip+4, match+4, iend) + 4; | ||||||
|  |             offset = (U32)(ip-match); | ||||||
|  |             while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ | ||||||
|  |             offset_2 = offset_1; | ||||||
|  |             offset_1 = offset; | ||||||
|  |  | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* match found */ | ||||||
|  |         ip += mLength; | ||||||
|  |         anchor = ip; | ||||||
|  |  | ||||||
|  |         if (ip <= ilimit) { | ||||||
|  |             /* Fill Table */ | ||||||
|  |             hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;  /* here because current+2 could be > iend-8 */ | ||||||
|  |             hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base); | ||||||
|  |             /* check immediate repcode */ | ||||||
|  |             while ( (ip <= ilimit) | ||||||
|  |                  && ( (offset_2>0) | ||||||
|  |                  & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { | ||||||
|  |                 /* store sequence */ | ||||||
|  |                 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | ||||||
|  |                 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; }  /* swap offset_2 <=> offset_1 */ | ||||||
|  |                 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base); | ||||||
|  |                 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH); | ||||||
|  |                 ip += rLength; | ||||||
|  |                 anchor = ip; | ||||||
|  |                 continue;   /* faster when present ... (?) */ | ||||||
|  |     }   }   } | ||||||
|  |  | ||||||
|  |     /* save reps for next block */ | ||||||
|  |     seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved; | ||||||
|  |     seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved; | ||||||
|  |  | ||||||
|  |     /* Last Literals */ | ||||||
|  |     {   size_t const lastLLSize = iend - anchor; | ||||||
|  |         memcpy(seqStorePtr->lit, anchor, lastLLSize); | ||||||
|  |         seqStorePtr->lit += lastLLSize; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, | ||||||
|  |                        const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     const U32 mls = ctx->appliedParams.cParams.searchLength; | ||||||
|  |     switch(mls) | ||||||
|  |     { | ||||||
|  |     default: /* includes case 3 */ | ||||||
|  |     case 4 : | ||||||
|  |         ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return; | ||||||
|  |     case 5 : | ||||||
|  |         ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return; | ||||||
|  |     case 6 : | ||||||
|  |         ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return; | ||||||
|  |     case 7 : | ||||||
|  |         ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, | ||||||
|  |                                  const void* src, size_t srcSize, | ||||||
|  |                                  const U32 mls) | ||||||
|  | { | ||||||
|  |     U32* hashTable = ctx->hashTable; | ||||||
|  |     const U32 hBits = ctx->appliedParams.cParams.hashLog; | ||||||
|  |     seqStore_t* seqStorePtr = &(ctx->seqStore); | ||||||
|  |     const BYTE* const base = ctx->base; | ||||||
|  |     const BYTE* const dictBase = ctx->dictBase; | ||||||
|  |     const BYTE* const istart = (const BYTE*)src; | ||||||
|  |     const BYTE* ip = istart; | ||||||
|  |     const BYTE* anchor = istart; | ||||||
|  |     const U32   lowestIndex = ctx->lowLimit; | ||||||
|  |     const BYTE* const dictStart = dictBase + lowestIndex; | ||||||
|  |     const U32   dictLimit = ctx->dictLimit; | ||||||
|  |     const BYTE* const lowPrefixPtr = base + dictLimit; | ||||||
|  |     const BYTE* const dictEnd = dictBase + dictLimit; | ||||||
|  |     const BYTE* const iend = istart + srcSize; | ||||||
|  |     const BYTE* const ilimit = iend - 8; | ||||||
|  |     U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1]; | ||||||
|  |  | ||||||
|  |     /* Search Loop */ | ||||||
|  |     while (ip < ilimit) {  /* < instead of <=, because (ip+1) */ | ||||||
|  |         const size_t h = ZSTD_hashPtr(ip, hBits, mls); | ||||||
|  |         const U32 matchIndex = hashTable[h]; | ||||||
|  |         const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base; | ||||||
|  |         const BYTE* match = matchBase + matchIndex; | ||||||
|  |         const U32 current = (U32)(ip-base); | ||||||
|  |         const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */ | ||||||
|  |         const BYTE* repBase = repIndex < dictLimit ? dictBase : base; | ||||||
|  |         const BYTE* repMatch = repBase + repIndex; | ||||||
|  |         size_t mLength; | ||||||
|  |         hashTable[h] = current;   /* update hash table */ | ||||||
|  |  | ||||||
|  |         if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex)) | ||||||
|  |            && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { | ||||||
|  |             const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend; | ||||||
|  |             mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4; | ||||||
|  |             ip++; | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH); | ||||||
|  |         } else { | ||||||
|  |             if ( (matchIndex < lowestIndex) || | ||||||
|  |                  (MEM_read32(match) != MEM_read32(ip)) ) { | ||||||
|  |                 ip += ((ip-anchor) >> g_searchStrength) + 1; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             {   const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr; | ||||||
|  |                 U32 offset; | ||||||
|  |                 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4; | ||||||
|  |                 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */ | ||||||
|  |                 offset = current - matchIndex; | ||||||
|  |                 offset_2 = offset_1; | ||||||
|  |                 offset_1 = offset; | ||||||
|  |                 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); | ||||||
|  |         }   } | ||||||
|  |  | ||||||
|  |         /* found a match : store it */ | ||||||
|  |         ip += mLength; | ||||||
|  |         anchor = ip; | ||||||
|  |  | ||||||
|  |         if (ip <= ilimit) { | ||||||
|  |             /* Fill Table */ | ||||||
|  |             hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; | ||||||
|  |             hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base); | ||||||
|  |             /* check immediate repcode */ | ||||||
|  |             while (ip <= ilimit) { | ||||||
|  |                 U32 const current2 = (U32)(ip-base); | ||||||
|  |                 U32 const repIndex2 = current2 - offset_2; | ||||||
|  |                 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2; | ||||||
|  |                 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex))  /* intentional overflow */ | ||||||
|  |                    && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { | ||||||
|  |                     const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend; | ||||||
|  |                     size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4; | ||||||
|  |                     U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */ | ||||||
|  |                     ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH); | ||||||
|  |                     hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2; | ||||||
|  |                     ip += repLength2; | ||||||
|  |                     anchor = ip; | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |     }   }   } | ||||||
|  |  | ||||||
|  |     /* save reps for next block */ | ||||||
|  |     seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2; | ||||||
|  |  | ||||||
|  |     /* Last Literals */ | ||||||
|  |     {   size_t const lastLLSize = iend - anchor; | ||||||
|  |         memcpy(seqStorePtr->lit, anchor, lastLLSize); | ||||||
|  |         seqStorePtr->lit += lastLLSize; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, | ||||||
|  |                          const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     U32 const mls = ctx->appliedParams.cParams.searchLength; | ||||||
|  |     switch(mls) | ||||||
|  |     { | ||||||
|  |     default: /* includes case 3 */ | ||||||
|  |     case 4 : | ||||||
|  |         ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return; | ||||||
|  |     case 5 : | ||||||
|  |         ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return; | ||||||
|  |     case 6 : | ||||||
|  |         ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return; | ||||||
|  |     case 7 : | ||||||
|  |         ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								lib/compress/zstd_fast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								lib/compress/zstd_fast.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * This source code is licensed under both the BSD-style license (found in the | ||||||
|  |  * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||||||
|  |  * in the COPYING file in the root directory of this source tree). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef ZSTD_FAST_H | ||||||
|  | #define ZSTD_FAST_H | ||||||
|  |  | ||||||
|  | #include "zstd_compress.h" | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | void ZSTD_fillHashTable(ZSTD_CCtx* zc, const void* end, const U32 mls); | ||||||
|  | void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, | ||||||
|  |                        const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, | ||||||
|  |                          const void* src, size_t srcSize); | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* ZSTD_FAST_H */ | ||||||
							
								
								
									
										752
									
								
								lib/compress/zstd_lazy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										752
									
								
								lib/compress/zstd_lazy.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,752 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * This source code is licensed under both the BSD-style license (found in the | ||||||
|  |  * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||||||
|  |  * in the COPYING file in the root directory of this source tree). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "zstd_lazy.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /*-************************************* | ||||||
|  | *  Binary Tree search | ||||||
|  | ***************************************/ | ||||||
|  | /** ZSTD_insertBt1() : add one or multiple positions to tree. | ||||||
|  | *   ip : assumed <= iend-8 . | ||||||
|  | *   @return : nb of positions added */ | ||||||
|  | static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares, | ||||||
|  |                           U32 extDict) | ||||||
|  | { | ||||||
|  |     U32*   const hashTable = zc->hashTable; | ||||||
|  |     U32    const hashLog = zc->appliedParams.cParams.hashLog; | ||||||
|  |     size_t const h  = ZSTD_hashPtr(ip, hashLog, mls); | ||||||
|  |     U32*   const bt = zc->chainTable; | ||||||
|  |     U32    const btLog  = zc->appliedParams.cParams.chainLog - 1; | ||||||
|  |     U32    const btMask = (1 << btLog) - 1; | ||||||
|  |     U32 matchIndex = hashTable[h]; | ||||||
|  |     size_t commonLengthSmaller=0, commonLengthLarger=0; | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     const BYTE* const dictBase = zc->dictBase; | ||||||
|  |     const U32 dictLimit = zc->dictLimit; | ||||||
|  |     const BYTE* const dictEnd = dictBase + dictLimit; | ||||||
|  |     const BYTE* const prefixStart = base + dictLimit; | ||||||
|  |     const BYTE* match; | ||||||
|  |     const U32 current = (U32)(ip-base); | ||||||
|  |     const U32 btLow = btMask >= current ? 0 : current - btMask; | ||||||
|  |     U32* smallerPtr = bt + 2*(current&btMask); | ||||||
|  |     U32* largerPtr  = smallerPtr + 1; | ||||||
|  |     U32 dummy32;   /* to be nullified at the end */ | ||||||
|  |     U32 const windowLow = zc->lowLimit; | ||||||
|  |     U32 matchEndIdx = current+8; | ||||||
|  |     size_t bestLength = 8; | ||||||
|  | #ifdef ZSTD_C_PREDICT | ||||||
|  |     U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0); | ||||||
|  |     U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1); | ||||||
|  |     predictedSmall += (predictedSmall>0); | ||||||
|  |     predictedLarge += (predictedLarge>0); | ||||||
|  | #endif /* ZSTD_C_PREDICT */ | ||||||
|  |  | ||||||
|  |     hashTable[h] = current;   /* Update Hash Table */ | ||||||
|  |  | ||||||
|  |     while (nbCompares-- && (matchIndex > windowLow)) { | ||||||
|  |         U32* const nextPtr = bt + 2*(matchIndex & btMask); | ||||||
|  |         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */ | ||||||
|  |  | ||||||
|  | #ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */ | ||||||
|  |         const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */ | ||||||
|  |         if (matchIndex == predictedSmall) { | ||||||
|  |             /* no need to check length, result known */ | ||||||
|  |             *smallerPtr = matchIndex; | ||||||
|  |             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ | ||||||
|  |             smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */ | ||||||
|  |             matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */ | ||||||
|  |             predictedSmall = predictPtr[1] + (predictPtr[1]>0); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         if (matchIndex == predictedLarge) { | ||||||
|  |             *largerPtr = matchIndex; | ||||||
|  |             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ | ||||||
|  |             largerPtr = nextPtr; | ||||||
|  |             matchIndex = nextPtr[0]; | ||||||
|  |             predictedLarge = predictPtr[0] + (predictPtr[0]>0); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |         if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { | ||||||
|  |             match = base + matchIndex; | ||||||
|  |             if (match[matchLength] == ip[matchLength]) | ||||||
|  |                 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1; | ||||||
|  |         } else { | ||||||
|  |             match = dictBase + matchIndex; | ||||||
|  |             matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart); | ||||||
|  |             if (matchIndex+matchLength >= dictLimit) | ||||||
|  |                 match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */ | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (matchLength > bestLength) { | ||||||
|  |             bestLength = matchLength; | ||||||
|  |             if (matchLength > matchEndIdx - matchIndex) | ||||||
|  |                 matchEndIdx = matchIndex + (U32)matchLength; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (ip+matchLength == iend)   /* equal : no way to know if inf or sup */ | ||||||
|  |             break;   /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */ | ||||||
|  |  | ||||||
|  |         if (match[matchLength] < ip[matchLength]) {  /* necessarily within correct buffer */ | ||||||
|  |             /* match is smaller than current */ | ||||||
|  |             *smallerPtr = matchIndex;             /* update smaller idx */ | ||||||
|  |             commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */ | ||||||
|  |             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ | ||||||
|  |             smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */ | ||||||
|  |             matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */ | ||||||
|  |         } else { | ||||||
|  |             /* match is larger than current */ | ||||||
|  |             *largerPtr = matchIndex; | ||||||
|  |             commonLengthLarger = matchLength; | ||||||
|  |             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ | ||||||
|  |             largerPtr = nextPtr; | ||||||
|  |             matchIndex = nextPtr[0]; | ||||||
|  |     }   } | ||||||
|  |  | ||||||
|  |     *smallerPtr = *largerPtr = 0; | ||||||
|  |     if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));   /* speed optimization */ | ||||||
|  |     if (matchEndIdx > current + 8) return matchEndIdx - current - 8; | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static size_t ZSTD_insertBtAndFindBestMatch ( | ||||||
|  |                         ZSTD_CCtx* zc, | ||||||
|  |                         const BYTE* const ip, const BYTE* const iend, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         U32 nbCompares, const U32 mls, | ||||||
|  |                         U32 extDict) | ||||||
|  | { | ||||||
|  |     U32*   const hashTable = zc->hashTable; | ||||||
|  |     U32    const hashLog = zc->appliedParams.cParams.hashLog; | ||||||
|  |     size_t const h  = ZSTD_hashPtr(ip, hashLog, mls); | ||||||
|  |     U32*   const bt = zc->chainTable; | ||||||
|  |     U32    const btLog  = zc->appliedParams.cParams.chainLog - 1; | ||||||
|  |     U32    const btMask = (1 << btLog) - 1; | ||||||
|  |     U32 matchIndex  = hashTable[h]; | ||||||
|  |     size_t commonLengthSmaller=0, commonLengthLarger=0; | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     const BYTE* const dictBase = zc->dictBase; | ||||||
|  |     const U32 dictLimit = zc->dictLimit; | ||||||
|  |     const BYTE* const dictEnd = dictBase + dictLimit; | ||||||
|  |     const BYTE* const prefixStart = base + dictLimit; | ||||||
|  |     const U32 current = (U32)(ip-base); | ||||||
|  |     const U32 btLow = btMask >= current ? 0 : current - btMask; | ||||||
|  |     const U32 windowLow = zc->lowLimit; | ||||||
|  |     U32* smallerPtr = bt + 2*(current&btMask); | ||||||
|  |     U32* largerPtr  = bt + 2*(current&btMask) + 1; | ||||||
|  |     U32 matchEndIdx = current+8; | ||||||
|  |     U32 dummy32;   /* to be nullified at the end */ | ||||||
|  |     size_t bestLength = 0; | ||||||
|  |  | ||||||
|  |     hashTable[h] = current;   /* Update Hash Table */ | ||||||
|  |  | ||||||
|  |     while (nbCompares-- && (matchIndex > windowLow)) { | ||||||
|  |         U32* const nextPtr = bt + 2*(matchIndex & btMask); | ||||||
|  |         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */ | ||||||
|  |         const BYTE* match; | ||||||
|  |  | ||||||
|  |         if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { | ||||||
|  |             match = base + matchIndex; | ||||||
|  |             if (match[matchLength] == ip[matchLength]) | ||||||
|  |                 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1; | ||||||
|  |         } else { | ||||||
|  |             match = dictBase + matchIndex; | ||||||
|  |             matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart); | ||||||
|  |             if (matchIndex+matchLength >= dictLimit) | ||||||
|  |                 match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */ | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (matchLength > bestLength) { | ||||||
|  |             if (matchLength > matchEndIdx - matchIndex) | ||||||
|  |                 matchEndIdx = matchIndex + (U32)matchLength; | ||||||
|  |             if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) | ||||||
|  |                 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; | ||||||
|  |             if (ip+matchLength == iend)   /* equal : no way to know if inf or sup */ | ||||||
|  |                 break;   /* drop, to guarantee consistency (miss a little bit of compression) */ | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (match[matchLength] < ip[matchLength]) { | ||||||
|  |             /* match is smaller than current */ | ||||||
|  |             *smallerPtr = matchIndex;             /* update smaller idx */ | ||||||
|  |             commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */ | ||||||
|  |             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ | ||||||
|  |             smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */ | ||||||
|  |             matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */ | ||||||
|  |         } else { | ||||||
|  |             /* match is larger than current */ | ||||||
|  |             *largerPtr = matchIndex; | ||||||
|  |             commonLengthLarger = matchLength; | ||||||
|  |             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ | ||||||
|  |             largerPtr = nextPtr; | ||||||
|  |             matchIndex = nextPtr[0]; | ||||||
|  |     }   } | ||||||
|  |  | ||||||
|  |     *smallerPtr = *largerPtr = 0; | ||||||
|  |  | ||||||
|  |     zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1; | ||||||
|  |     return bestLength; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls) | ||||||
|  | { | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     const U32 target = (U32)(ip - base); | ||||||
|  |     U32 idx = zc->nextToUpdate; | ||||||
|  |  | ||||||
|  |     while(idx < target) | ||||||
|  |         idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */ | ||||||
|  | static size_t ZSTD_BtFindBestMatch ( | ||||||
|  |                         ZSTD_CCtx* zc, | ||||||
|  |                         const BYTE* const ip, const BYTE* const iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         const U32 maxNbAttempts, const U32 mls) | ||||||
|  | { | ||||||
|  |     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */ | ||||||
|  |     ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); | ||||||
|  |     return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static size_t ZSTD_BtFindBestMatch_selectMLS ( | ||||||
|  |                         ZSTD_CCtx* zc,   /* Index table will be updated */ | ||||||
|  |                         const BYTE* ip, const BYTE* const iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         const U32 maxNbAttempts, const U32 matchLengthSearch) | ||||||
|  | { | ||||||
|  |     switch(matchLengthSearch) | ||||||
|  |     { | ||||||
|  |     default : /* includes case 3 */ | ||||||
|  |     case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4); | ||||||
|  |     case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5); | ||||||
|  |     case 7 : | ||||||
|  |     case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls) | ||||||
|  | { | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     const U32 target = (U32)(ip - base); | ||||||
|  |     U32 idx = zc->nextToUpdate; | ||||||
|  |  | ||||||
|  |     while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** Tree updater, providing best match */ | ||||||
|  | static size_t ZSTD_BtFindBestMatch_extDict ( | ||||||
|  |                         ZSTD_CCtx* zc, | ||||||
|  |                         const BYTE* const ip, const BYTE* const iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         const U32 maxNbAttempts, const U32 mls) | ||||||
|  | { | ||||||
|  |     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */ | ||||||
|  |     ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); | ||||||
|  |     return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static size_t ZSTD_BtFindBestMatch_selectMLS_extDict ( | ||||||
|  |                         ZSTD_CCtx* zc,   /* Index table will be updated */ | ||||||
|  |                         const BYTE* ip, const BYTE* const iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         const U32 maxNbAttempts, const U32 matchLengthSearch) | ||||||
|  | { | ||||||
|  |     switch(matchLengthSearch) | ||||||
|  |     { | ||||||
|  |     default : /* includes case 3 */ | ||||||
|  |     case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4); | ||||||
|  |     case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5); | ||||||
|  |     case 7 : | ||||||
|  |     case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ********************************* | ||||||
|  | *  Hash Chain | ||||||
|  | ***********************************/ | ||||||
|  | #define NEXT_IN_CHAIN(d, mask)   chainTable[(d) & mask] | ||||||
|  |  | ||||||
|  | /* Update chains up to ip (excluded) | ||||||
|  |    Assumption : always within prefix (i.e. not within extDict) */ | ||||||
|  | U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls) | ||||||
|  | { | ||||||
|  |     U32* const hashTable  = zc->hashTable; | ||||||
|  |     const U32 hashLog = zc->appliedParams.cParams.hashLog; | ||||||
|  |     U32* const chainTable = zc->chainTable; | ||||||
|  |     const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1; | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     const U32 target = (U32)(ip - base); | ||||||
|  |     U32 idx = zc->nextToUpdate; | ||||||
|  |  | ||||||
|  |     while(idx < target) { /* catch up */ | ||||||
|  |         size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls); | ||||||
|  |         NEXT_IN_CHAIN(idx, chainMask) = hashTable[h]; | ||||||
|  |         hashTable[h] = idx; | ||||||
|  |         idx++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     zc->nextToUpdate = target; | ||||||
|  |     return hashTable[ZSTD_hashPtr(ip, hashLog, mls)]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* inlining is important to hardwire a hot branch (template emulation) */ | ||||||
|  | FORCE_INLINE_TEMPLATE | ||||||
|  | size_t ZSTD_HcFindBestMatch_generic ( | ||||||
|  |                         ZSTD_CCtx* zc,   /* Index table will be updated */ | ||||||
|  |                         const BYTE* const ip, const BYTE* const iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         const U32 maxNbAttempts, const U32 mls, const U32 extDict) | ||||||
|  | { | ||||||
|  |     U32* const chainTable = zc->chainTable; | ||||||
|  |     const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog); | ||||||
|  |     const U32 chainMask = chainSize-1; | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     const BYTE* const dictBase = zc->dictBase; | ||||||
|  |     const U32 dictLimit = zc->dictLimit; | ||||||
|  |     const BYTE* const prefixStart = base + dictLimit; | ||||||
|  |     const BYTE* const dictEnd = dictBase + dictLimit; | ||||||
|  |     const U32 lowLimit = zc->lowLimit; | ||||||
|  |     const U32 current = (U32)(ip-base); | ||||||
|  |     const U32 minChain = current > chainSize ? current - chainSize : 0; | ||||||
|  |     int nbAttempts=maxNbAttempts; | ||||||
|  |     size_t ml=4-1; | ||||||
|  |  | ||||||
|  |     /* HC4 match finder */ | ||||||
|  |     U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls); | ||||||
|  |  | ||||||
|  |     for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) { | ||||||
|  |         const BYTE* match; | ||||||
|  |         size_t currentMl=0; | ||||||
|  |         if ((!extDict) || matchIndex >= dictLimit) { | ||||||
|  |             match = base + matchIndex; | ||||||
|  |             if (match[ml] == ip[ml])   /* potentially better */ | ||||||
|  |                 currentMl = ZSTD_count(ip, match, iLimit); | ||||||
|  |         } else { | ||||||
|  |             match = dictBase + matchIndex; | ||||||
|  |             if (MEM_read32(match) == MEM_read32(ip))   /* assumption : matchIndex <= dictLimit-4 (by table construction) */ | ||||||
|  |                 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* save best solution */ | ||||||
|  |         if (currentMl > ml) { | ||||||
|  |             ml = currentMl; | ||||||
|  |             *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; | ||||||
|  |             if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (matchIndex <= minChain) break; | ||||||
|  |         matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ml; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS ( | ||||||
|  |                         ZSTD_CCtx* zc, | ||||||
|  |                         const BYTE* ip, const BYTE* const iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         const U32 maxNbAttempts, const U32 matchLengthSearch) | ||||||
|  | { | ||||||
|  |     switch(matchLengthSearch) | ||||||
|  |     { | ||||||
|  |     default : /* includes case 3 */ | ||||||
|  |     case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0); | ||||||
|  |     case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0); | ||||||
|  |     case 7 : | ||||||
|  |     case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( | ||||||
|  |                         ZSTD_CCtx* zc, | ||||||
|  |                         const BYTE* ip, const BYTE* const iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         const U32 maxNbAttempts, const U32 matchLengthSearch) | ||||||
|  | { | ||||||
|  |     switch(matchLengthSearch) | ||||||
|  |     { | ||||||
|  |     default : /* includes case 3 */ | ||||||
|  |     case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1); | ||||||
|  |     case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1); | ||||||
|  |     case 7 : | ||||||
|  |     case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ******************************* | ||||||
|  | *  Common parser - lazy strategy | ||||||
|  | *********************************/ | ||||||
|  | FORCE_INLINE_TEMPLATE | ||||||
|  | void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, | ||||||
|  |                                      const void* src, size_t srcSize, | ||||||
|  |                                      const U32 searchMethod, const U32 depth) | ||||||
|  | { | ||||||
|  |     seqStore_t* seqStorePtr = &(ctx->seqStore); | ||||||
|  |     const BYTE* const istart = (const BYTE*)src; | ||||||
|  |     const BYTE* ip = istart; | ||||||
|  |     const BYTE* anchor = istart; | ||||||
|  |     const BYTE* const iend = istart + srcSize; | ||||||
|  |     const BYTE* const ilimit = iend - 8; | ||||||
|  |     const BYTE* const base = ctx->base + ctx->dictLimit; | ||||||
|  |  | ||||||
|  |     U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog; | ||||||
|  |     U32 const mls = ctx->appliedParams.cParams.searchLength; | ||||||
|  |  | ||||||
|  |     typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         U32 maxNbAttempts, U32 matchLengthSearch); | ||||||
|  |     searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS; | ||||||
|  |     U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1], savedOffset=0; | ||||||
|  |  | ||||||
|  |     /* init */ | ||||||
|  |     ip += (ip==base); | ||||||
|  |     ctx->nextToUpdate3 = ctx->nextToUpdate; | ||||||
|  |     {   U32 const maxRep = (U32)(ip-base); | ||||||
|  |         if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0; | ||||||
|  |         if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Match Loop */ | ||||||
|  |     while (ip < ilimit) { | ||||||
|  |         size_t matchLength=0; | ||||||
|  |         size_t offset=0; | ||||||
|  |         const BYTE* start=ip+1; | ||||||
|  |  | ||||||
|  |         /* check repCode */ | ||||||
|  |         if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) { | ||||||
|  |             /* repcode : we take it */ | ||||||
|  |             matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; | ||||||
|  |             if (depth==0) goto _storeSequence; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* first search (depth 0) */ | ||||||
|  |         {   size_t offsetFound = 99999999; | ||||||
|  |             size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); | ||||||
|  |             if (ml2 > matchLength) | ||||||
|  |                 matchLength = ml2, start = ip, offset=offsetFound; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (matchLength < 4) { | ||||||
|  |             ip += ((ip-anchor) >> g_searchStrength) + 1;   /* jump faster over incompressible sections */ | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* let's try to find a better solution */ | ||||||
|  |         if (depth>=1) | ||||||
|  |         while (ip<ilimit) { | ||||||
|  |             ip ++; | ||||||
|  |             if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { | ||||||
|  |                 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; | ||||||
|  |                 int const gain2 = (int)(mlRep * 3); | ||||||
|  |                 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); | ||||||
|  |                 if ((mlRep >= 4) && (gain2 > gain1)) | ||||||
|  |                     matchLength = mlRep, offset = 0, start = ip; | ||||||
|  |             } | ||||||
|  |             {   size_t offset2=99999999; | ||||||
|  |                 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); | ||||||
|  |                 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */ | ||||||
|  |                 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); | ||||||
|  |                 if ((ml2 >= 4) && (gain2 > gain1)) { | ||||||
|  |                     matchLength = ml2, offset = offset2, start = ip; | ||||||
|  |                     continue;   /* search a better one */ | ||||||
|  |             }   } | ||||||
|  |  | ||||||
|  |             /* let's find an even better one */ | ||||||
|  |             if ((depth==2) && (ip<ilimit)) { | ||||||
|  |                 ip ++; | ||||||
|  |                 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { | ||||||
|  |                     size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; | ||||||
|  |                     int const gain2 = (int)(ml2 * 4); | ||||||
|  |                     int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); | ||||||
|  |                     if ((ml2 >= 4) && (gain2 > gain1)) | ||||||
|  |                         matchLength = ml2, offset = 0, start = ip; | ||||||
|  |                 } | ||||||
|  |                 {   size_t offset2=99999999; | ||||||
|  |                     size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); | ||||||
|  |                     int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */ | ||||||
|  |                     int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); | ||||||
|  |                     if ((ml2 >= 4) && (gain2 > gain1)) { | ||||||
|  |                         matchLength = ml2, offset = offset2, start = ip; | ||||||
|  |                         continue; | ||||||
|  |             }   }   } | ||||||
|  |             break;  /* nothing found : store previous solution */ | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* NOTE: | ||||||
|  |          * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior. | ||||||
|  |          * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which | ||||||
|  |          * overflows the pointer, which is undefined behavior. | ||||||
|  |          */ | ||||||
|  |         /* catch up */ | ||||||
|  |         if (offset) { | ||||||
|  |             while ( (start > anchor) | ||||||
|  |                  && (start > base+offset-ZSTD_REP_MOVE) | ||||||
|  |                  && (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) )  /* only search for offset within prefix */ | ||||||
|  |                 { start--; matchLength++; } | ||||||
|  |             offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); | ||||||
|  |         } | ||||||
|  |         /* store sequence */ | ||||||
|  | _storeSequence: | ||||||
|  |         {   size_t const litLength = start - anchor; | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH); | ||||||
|  |             anchor = ip = start + matchLength; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* check immediate repcode */ | ||||||
|  |         while ( (ip <= ilimit) | ||||||
|  |              && ((offset_2>0) | ||||||
|  |              & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { | ||||||
|  |             /* store sequence */ | ||||||
|  |             matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; | ||||||
|  |             offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */ | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH); | ||||||
|  |             ip += matchLength; | ||||||
|  |             anchor = ip; | ||||||
|  |             continue;   /* faster when present ... (?) */ | ||||||
|  |     }   } | ||||||
|  |  | ||||||
|  |     /* Save reps for next block */ | ||||||
|  |     seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset; | ||||||
|  |     seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset; | ||||||
|  |  | ||||||
|  |     /* Last Literals */ | ||||||
|  |     {   size_t const lastLLSize = iend - anchor; | ||||||
|  |         memcpy(seqStorePtr->lit, anchor, lastLLSize); | ||||||
|  |         seqStorePtr->lit += lastLLSize; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FORCE_INLINE_TEMPLATE | ||||||
|  | void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, | ||||||
|  |                                      const void* src, size_t srcSize, | ||||||
|  |                                      const U32 searchMethod, const U32 depth) | ||||||
|  | { | ||||||
|  |     seqStore_t* seqStorePtr = &(ctx->seqStore); | ||||||
|  |     const BYTE* const istart = (const BYTE*)src; | ||||||
|  |     const BYTE* ip = istart; | ||||||
|  |     const BYTE* anchor = istart; | ||||||
|  |     const BYTE* const iend = istart + srcSize; | ||||||
|  |     const BYTE* const ilimit = iend - 8; | ||||||
|  |     const BYTE* const base = ctx->base; | ||||||
|  |     const U32 dictLimit = ctx->dictLimit; | ||||||
|  |     const U32 lowestIndex = ctx->lowLimit; | ||||||
|  |     const BYTE* const prefixStart = base + dictLimit; | ||||||
|  |     const BYTE* const dictBase = ctx->dictBase; | ||||||
|  |     const BYTE* const dictEnd  = dictBase + dictLimit; | ||||||
|  |     const BYTE* const dictStart  = dictBase + ctx->lowLimit; | ||||||
|  |  | ||||||
|  |     const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog; | ||||||
|  |     const U32 mls = ctx->appliedParams.cParams.searchLength; | ||||||
|  |  | ||||||
|  |     typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, | ||||||
|  |                         size_t* offsetPtr, | ||||||
|  |                         U32 maxNbAttempts, U32 matchLengthSearch); | ||||||
|  |     searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS; | ||||||
|  |  | ||||||
|  |     U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1]; | ||||||
|  |  | ||||||
|  |     /* init */ | ||||||
|  |     ctx->nextToUpdate3 = ctx->nextToUpdate; | ||||||
|  |     ip += (ip == prefixStart); | ||||||
|  |  | ||||||
|  |     /* Match Loop */ | ||||||
|  |     while (ip < ilimit) { | ||||||
|  |         size_t matchLength=0; | ||||||
|  |         size_t offset=0; | ||||||
|  |         const BYTE* start=ip+1; | ||||||
|  |         U32 current = (U32)(ip-base); | ||||||
|  |  | ||||||
|  |         /* check repCode */ | ||||||
|  |         {   const U32 repIndex = (U32)(current+1 - offset_1); | ||||||
|  |             const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; | ||||||
|  |             const BYTE* const repMatch = repBase + repIndex; | ||||||
|  |             if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))   /* intentional overflow */ | ||||||
|  |             if (MEM_read32(ip+1) == MEM_read32(repMatch)) { | ||||||
|  |                 /* repcode detected we should take it */ | ||||||
|  |                 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4; | ||||||
|  |                 if (depth==0) goto _storeSequence; | ||||||
|  |         }   } | ||||||
|  |  | ||||||
|  |         /* first search (depth 0) */ | ||||||
|  |         {   size_t offsetFound = 99999999; | ||||||
|  |             size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); | ||||||
|  |             if (ml2 > matchLength) | ||||||
|  |                 matchLength = ml2, start = ip, offset=offsetFound; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |          if (matchLength < 4) { | ||||||
|  |             ip += ((ip-anchor) >> g_searchStrength) + 1;   /* jump faster over incompressible sections */ | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* let's try to find a better solution */ | ||||||
|  |         if (depth>=1) | ||||||
|  |         while (ip<ilimit) { | ||||||
|  |             ip ++; | ||||||
|  |             current++; | ||||||
|  |             /* check repCode */ | ||||||
|  |             if (offset) { | ||||||
|  |                 const U32 repIndex = (U32)(current - offset_1); | ||||||
|  |                 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; | ||||||
|  |                 const BYTE* const repMatch = repBase + repIndex; | ||||||
|  |                 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */ | ||||||
|  |                 if (MEM_read32(ip) == MEM_read32(repMatch)) { | ||||||
|  |                     /* repcode detected */ | ||||||
|  |                     const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                     size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; | ||||||
|  |                     int const gain2 = (int)(repLength * 3); | ||||||
|  |                     int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); | ||||||
|  |                     if ((repLength >= 4) && (gain2 > gain1)) | ||||||
|  |                         matchLength = repLength, offset = 0, start = ip; | ||||||
|  |             }   } | ||||||
|  |  | ||||||
|  |             /* search match, depth 1 */ | ||||||
|  |             {   size_t offset2=99999999; | ||||||
|  |                 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); | ||||||
|  |                 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */ | ||||||
|  |                 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); | ||||||
|  |                 if ((ml2 >= 4) && (gain2 > gain1)) { | ||||||
|  |                     matchLength = ml2, offset = offset2, start = ip; | ||||||
|  |                     continue;   /* search a better one */ | ||||||
|  |             }   } | ||||||
|  |  | ||||||
|  |             /* let's find an even better one */ | ||||||
|  |             if ((depth==2) && (ip<ilimit)) { | ||||||
|  |                 ip ++; | ||||||
|  |                 current++; | ||||||
|  |                 /* check repCode */ | ||||||
|  |                 if (offset) { | ||||||
|  |                     const U32 repIndex = (U32)(current - offset_1); | ||||||
|  |                     const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; | ||||||
|  |                     const BYTE* const repMatch = repBase + repIndex; | ||||||
|  |                     if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */ | ||||||
|  |                     if (MEM_read32(ip) == MEM_read32(repMatch)) { | ||||||
|  |                         /* repcode detected */ | ||||||
|  |                         const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                         size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; | ||||||
|  |                         int const gain2 = (int)(repLength * 4); | ||||||
|  |                         int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); | ||||||
|  |                         if ((repLength >= 4) && (gain2 > gain1)) | ||||||
|  |                             matchLength = repLength, offset = 0, start = ip; | ||||||
|  |                 }   } | ||||||
|  |  | ||||||
|  |                 /* search match, depth 2 */ | ||||||
|  |                 {   size_t offset2=99999999; | ||||||
|  |                     size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); | ||||||
|  |                     int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */ | ||||||
|  |                     int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); | ||||||
|  |                     if ((ml2 >= 4) && (gain2 > gain1)) { | ||||||
|  |                         matchLength = ml2, offset = offset2, start = ip; | ||||||
|  |                         continue; | ||||||
|  |             }   }   } | ||||||
|  |             break;  /* nothing found : store previous solution */ | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* catch up */ | ||||||
|  |         if (offset) { | ||||||
|  |             U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); | ||||||
|  |             const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex; | ||||||
|  |             const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart; | ||||||
|  |             while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; }  /* catch up */ | ||||||
|  |             offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* store sequence */ | ||||||
|  | _storeSequence: | ||||||
|  |         {   size_t const litLength = start - anchor; | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH); | ||||||
|  |             anchor = ip = start + matchLength; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* check immediate repcode */ | ||||||
|  |         while (ip <= ilimit) { | ||||||
|  |             const U32 repIndex = (U32)((ip-base) - offset_2); | ||||||
|  |             const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; | ||||||
|  |             const BYTE* const repMatch = repBase + repIndex; | ||||||
|  |             if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */ | ||||||
|  |             if (MEM_read32(ip) == MEM_read32(repMatch)) { | ||||||
|  |                 /* repcode detected we should take it */ | ||||||
|  |                 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; | ||||||
|  |                 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset;   /* swap offset history */ | ||||||
|  |                 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH); | ||||||
|  |                 ip += matchLength; | ||||||
|  |                 anchor = ip; | ||||||
|  |                 continue;   /* faster when present ... (?) */ | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |     }   } | ||||||
|  |  | ||||||
|  |     /* Save reps for next block */ | ||||||
|  |     seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2; | ||||||
|  |  | ||||||
|  |     /* Last Literals */ | ||||||
|  |     {   size_t const lastLLSize = iend - anchor; | ||||||
|  |         memcpy(seqStorePtr->lit, anchor, lastLLSize); | ||||||
|  |         seqStorePtr->lit += lastLLSize; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								lib/compress/zstd_lazy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lib/compress/zstd_lazy.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * This source code is licensed under both the BSD-style license (found in the | ||||||
|  |  * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||||||
|  |  * in the COPYING file in the root directory of this source tree). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef ZSTD_LAZY_H | ||||||
|  | #define ZSTD_LAZY_H | ||||||
|  |  | ||||||
|  | #include "zstd_compress.h" | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls); | ||||||
|  | void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls); | ||||||
|  | void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls); | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* ZSTD_LAZY_H */ | ||||||
							
								
								
									
										954
									
								
								lib/compress/zstd_opt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										954
									
								
								lib/compress/zstd_opt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,954 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * This source code is licensed under both the BSD-style license (found in the | ||||||
|  |  * LICENSE file in the root directory of this source tree) and the GPLv2 (found | ||||||
|  |  * in the COPYING file in the root directory of this source tree). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "zstd_opt.h" | ||||||
|  | #include "zstd_lazy.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #define ZSTD_LITFREQ_ADD    2 | ||||||
|  | #define ZSTD_FREQ_DIV       4 | ||||||
|  | #define ZSTD_MAX_PRICE      (1<<30) | ||||||
|  |  | ||||||
|  | /*-************************************* | ||||||
|  | *  Price functions for optimal parser | ||||||
|  | ***************************************/ | ||||||
|  | static void ZSTD_setLog2Prices(optState_t* optPtr) | ||||||
|  | { | ||||||
|  |     optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1); | ||||||
|  |     optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1); | ||||||
|  |     optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1); | ||||||
|  |     optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1); | ||||||
|  |     optPtr->factor = 1 + ((optPtr->litSum>>5) / optPtr->litLengthSum) + ((optPtr->litSum<<1) / (optPtr->litSum + optPtr->matchSum)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void ZSTD_rescaleFreqs(optState_t* optPtr, const BYTE* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     unsigned u; | ||||||
|  |  | ||||||
|  |     optPtr->cachedLiterals = NULL; | ||||||
|  |     optPtr->cachedPrice = optPtr->cachedLitLength = 0; | ||||||
|  |     optPtr->staticPrices = 0; | ||||||
|  |  | ||||||
|  |     if (optPtr->litLengthSum == 0) { | ||||||
|  |         if (srcSize <= 1024) optPtr->staticPrices = 1; | ||||||
|  |  | ||||||
|  |         assert(optPtr->litFreq!=NULL); | ||||||
|  |         for (u=0; u<=MaxLit; u++) | ||||||
|  |             optPtr->litFreq[u] = 0; | ||||||
|  |         for (u=0; u<srcSize; u++) | ||||||
|  |             optPtr->litFreq[src[u]]++; | ||||||
|  |  | ||||||
|  |         optPtr->litSum = 0; | ||||||
|  |         optPtr->litLengthSum = MaxLL+1; | ||||||
|  |         optPtr->matchLengthSum = MaxML+1; | ||||||
|  |         optPtr->offCodeSum = (MaxOff+1); | ||||||
|  |         optPtr->matchSum = (ZSTD_LITFREQ_ADD<<Litbits); | ||||||
|  |  | ||||||
|  |         for (u=0; u<=MaxLit; u++) { | ||||||
|  |             optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>ZSTD_FREQ_DIV); | ||||||
|  |             optPtr->litSum += optPtr->litFreq[u]; | ||||||
|  |         } | ||||||
|  |         for (u=0; u<=MaxLL; u++) | ||||||
|  |             optPtr->litLengthFreq[u] = 1; | ||||||
|  |         for (u=0; u<=MaxML; u++) | ||||||
|  |             optPtr->matchLengthFreq[u] = 1; | ||||||
|  |         for (u=0; u<=MaxOff; u++) | ||||||
|  |             optPtr->offCodeFreq[u] = 1; | ||||||
|  |     } else { | ||||||
|  |         optPtr->matchLengthSum = 0; | ||||||
|  |         optPtr->litLengthSum = 0; | ||||||
|  |         optPtr->offCodeSum = 0; | ||||||
|  |         optPtr->matchSum = 0; | ||||||
|  |         optPtr->litSum = 0; | ||||||
|  |  | ||||||
|  |         for (u=0; u<=MaxLit; u++) { | ||||||
|  |             optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1)); | ||||||
|  |             optPtr->litSum += optPtr->litFreq[u]; | ||||||
|  |         } | ||||||
|  |         for (u=0; u<=MaxLL; u++) { | ||||||
|  |             optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1)); | ||||||
|  |             optPtr->litLengthSum += optPtr->litLengthFreq[u]; | ||||||
|  |         } | ||||||
|  |         for (u=0; u<=MaxML; u++) { | ||||||
|  |             optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV); | ||||||
|  |             optPtr->matchLengthSum += optPtr->matchLengthFreq[u]; | ||||||
|  |             optPtr->matchSum += optPtr->matchLengthFreq[u] * (u + 3); | ||||||
|  |         } | ||||||
|  |         optPtr->matchSum *= ZSTD_LITFREQ_ADD; | ||||||
|  |         for (u=0; u<=MaxOff; u++) { | ||||||
|  |             optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV); | ||||||
|  |             optPtr->offCodeSum += optPtr->offCodeFreq[u]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ZSTD_setLog2Prices(optPtr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static U32 ZSTD_getLiteralPrice(optState_t* optPtr, U32 litLength, const BYTE* literals) | ||||||
|  | { | ||||||
|  |     U32 price, u; | ||||||
|  |  | ||||||
|  |     if (optPtr->staticPrices) | ||||||
|  |         return ZSTD_highbit32((U32)litLength+1) + (litLength*6); | ||||||
|  |  | ||||||
|  |     if (litLength == 0) | ||||||
|  |         return optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[0]+1); | ||||||
|  |  | ||||||
|  |     /* literals */ | ||||||
|  |     if (optPtr->cachedLiterals == literals) { | ||||||
|  |         U32 const additional = litLength - optPtr->cachedLitLength; | ||||||
|  |         const BYTE* literals2 = optPtr->cachedLiterals + optPtr->cachedLitLength; | ||||||
|  |         price = optPtr->cachedPrice + additional * optPtr->log2litSum; | ||||||
|  |         for (u=0; u < additional; u++) | ||||||
|  |             price -= ZSTD_highbit32(optPtr->litFreq[literals2[u]]+1); | ||||||
|  |         optPtr->cachedPrice = price; | ||||||
|  |         optPtr->cachedLitLength = litLength; | ||||||
|  |     } else { | ||||||
|  |         price = litLength * optPtr->log2litSum; | ||||||
|  |         for (u=0; u < litLength; u++) | ||||||
|  |             price -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1); | ||||||
|  |  | ||||||
|  |         if (litLength >= 12) { | ||||||
|  |             optPtr->cachedLiterals = literals; | ||||||
|  |             optPtr->cachedPrice = price; | ||||||
|  |             optPtr->cachedLitLength = litLength; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* literal Length */ | ||||||
|  |     {   const BYTE LL_deltaCode = 19; | ||||||
|  |         const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength]; | ||||||
|  |         price += LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return price; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra) | ||||||
|  | { | ||||||
|  |     /* offset */ | ||||||
|  |     U32 price; | ||||||
|  |     BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1); | ||||||
|  |  | ||||||
|  |     if (optPtr->staticPrices) | ||||||
|  |         return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode; | ||||||
|  |  | ||||||
|  |     price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1); | ||||||
|  |     if (!ultra && offCode >= 20) price += (offCode-19)*2; | ||||||
|  |  | ||||||
|  |     /* match Length */ | ||||||
|  |     {   const BYTE ML_deltaCode = 36; | ||||||
|  |         const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength]; | ||||||
|  |         price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return price + ZSTD_getLiteralPrice(optPtr, litLength, literals) + optPtr->factor; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void ZSTD_updatePrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength) | ||||||
|  | { | ||||||
|  |     U32 u; | ||||||
|  |  | ||||||
|  |     /* literals */ | ||||||
|  |     optPtr->litSum += litLength*ZSTD_LITFREQ_ADD; | ||||||
|  |     for (u=0; u < litLength; u++) | ||||||
|  |         optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD; | ||||||
|  |  | ||||||
|  |     /* literal Length */ | ||||||
|  |     {   const BYTE LL_deltaCode = 19; | ||||||
|  |         const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength]; | ||||||
|  |         optPtr->litLengthFreq[llCode]++; | ||||||
|  |         optPtr->litLengthSum++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* match offset */ | ||||||
|  |     {   BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1); | ||||||
|  |         optPtr->offCodeSum++; | ||||||
|  |         optPtr->offCodeFreq[offCode]++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* match Length */ | ||||||
|  |     {   const BYTE ML_deltaCode = 36; | ||||||
|  |         const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength]; | ||||||
|  |         optPtr->matchLengthFreq[mlCode]++; | ||||||
|  |         optPtr->matchLengthSum++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ZSTD_setLog2Prices(optPtr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #define SET_PRICE(pos, mlen_, offset_, litlen_, price_)   \ | ||||||
|  |     {                                                 \ | ||||||
|  |         while (last_pos < pos)  { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \ | ||||||
|  |         opt[pos].mlen = mlen_;                         \ | ||||||
|  |         opt[pos].off = offset_;                        \ | ||||||
|  |         opt[pos].litlen = litlen_;                     \ | ||||||
|  |         opt[pos].price = price_;                       \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* function safe only for comparisons */ | ||||||
|  | static U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) | ||||||
|  | { | ||||||
|  |     switch (length) | ||||||
|  |     { | ||||||
|  |     default : | ||||||
|  |     case 4 : return MEM_read32(memPtr); | ||||||
|  |     case 3 : if (MEM_isLittleEndian()) | ||||||
|  |                 return MEM_read32(memPtr)<<8; | ||||||
|  |              else | ||||||
|  |                 return MEM_read32(memPtr)>>8; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Update hashTable3 up to ip (excluded) | ||||||
|  |    Assumption : always within prefix (i.e. not within extDict) */ | ||||||
|  | static | ||||||
|  | U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip) | ||||||
|  | { | ||||||
|  |     U32* const hashTable3  = zc->hashTable3; | ||||||
|  |     U32 const hashLog3  = zc->hashLog3; | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     U32 idx = zc->nextToUpdate3; | ||||||
|  |     const U32 target = zc->nextToUpdate3 = (U32)(ip - base); | ||||||
|  |     const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3); | ||||||
|  |  | ||||||
|  |     while(idx < target) { | ||||||
|  |         hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx; | ||||||
|  |         idx++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return hashTable3[hash3]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /*-************************************* | ||||||
|  | *  Binary Tree search | ||||||
|  | ***************************************/ | ||||||
|  | static U32 ZSTD_insertBtAndGetAllMatches ( | ||||||
|  |                         ZSTD_CCtx* zc, | ||||||
|  |                         const BYTE* const ip, const BYTE* const iLimit, | ||||||
|  |                         U32 nbCompares, const U32 mls, | ||||||
|  |                         U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen) | ||||||
|  | { | ||||||
|  |     const BYTE* const base = zc->base; | ||||||
|  |     const U32 current = (U32)(ip-base); | ||||||
|  |     const U32 hashLog = zc->appliedParams.cParams.hashLog; | ||||||
|  |     const size_t h  = ZSTD_hashPtr(ip, hashLog, mls); | ||||||
|  |     U32* const hashTable = zc->hashTable; | ||||||
|  |     U32 matchIndex  = hashTable[h]; | ||||||
|  |     U32* const bt   = zc->chainTable; | ||||||
|  |     const U32 btLog = zc->appliedParams.cParams.chainLog - 1; | ||||||
|  |     const U32 btMask= (1U << btLog) - 1; | ||||||
|  |     size_t commonLengthSmaller=0, commonLengthLarger=0; | ||||||
|  |     const BYTE* const dictBase = zc->dictBase; | ||||||
|  |     const U32 dictLimit = zc->dictLimit; | ||||||
|  |     const BYTE* const dictEnd = dictBase + dictLimit; | ||||||
|  |     const BYTE* const prefixStart = base + dictLimit; | ||||||
|  |     const U32 btLow = btMask >= current ? 0 : current - btMask; | ||||||
|  |     const U32 windowLow = zc->lowLimit; | ||||||
|  |     U32* smallerPtr = bt + 2*(current&btMask); | ||||||
|  |     U32* largerPtr  = bt + 2*(current&btMask) + 1; | ||||||
|  |     U32 matchEndIdx = current+8; | ||||||
|  |     U32 dummy32;   /* to be nullified at the end */ | ||||||
|  |     U32 mnum = 0; | ||||||
|  |  | ||||||
|  |     const U32 minMatch = (mls == 3) ? 3 : 4; | ||||||
|  |     size_t bestLength = minMatchLen-1; | ||||||
|  |  | ||||||
|  |     if (minMatch == 3) { /* HC3 match finder */ | ||||||
|  |         U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip); | ||||||
|  |         if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) { | ||||||
|  |             const BYTE* match; | ||||||
|  |             size_t currentMl=0; | ||||||
|  |             if ((!extDict) || matchIndex3 >= dictLimit) { | ||||||
|  |                 match = base + matchIndex3; | ||||||
|  |                 if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit); | ||||||
|  |             } else { | ||||||
|  |                 match = dictBase + matchIndex3; | ||||||
|  |                 if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH))    /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */ | ||||||
|  |                     currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             /* save best solution */ | ||||||
|  |             if (currentMl > bestLength) { | ||||||
|  |                 bestLength = currentMl; | ||||||
|  |                 matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3; | ||||||
|  |                 matches[mnum].len = (U32)currentMl; | ||||||
|  |                 mnum++; | ||||||
|  |                 if (currentMl > ZSTD_OPT_NUM) goto update; | ||||||
|  |                 if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/ | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     hashTable[h] = current;   /* Update Hash Table */ | ||||||
|  |  | ||||||
|  |     while (nbCompares-- && (matchIndex > windowLow)) { | ||||||
|  |         U32* nextPtr = bt + 2*(matchIndex & btMask); | ||||||
|  |         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */ | ||||||
|  |         const BYTE* match; | ||||||
|  |  | ||||||
|  |         if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { | ||||||
|  |             match = base + matchIndex; | ||||||
|  |             if (match[matchLength] == ip[matchLength]) { | ||||||
|  |                 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             match = dictBase + matchIndex; | ||||||
|  |             matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart); | ||||||
|  |             if (matchIndex+matchLength >= dictLimit) | ||||||
|  |                 match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */ | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (matchLength > bestLength) { | ||||||
|  |             if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; | ||||||
|  |             bestLength = matchLength; | ||||||
|  |             matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex; | ||||||
|  |             matches[mnum].len = (U32)matchLength; | ||||||
|  |             mnum++; | ||||||
|  |             if (matchLength > ZSTD_OPT_NUM) break; | ||||||
|  |             if (ip+matchLength == iLimit)   /* equal : no way to know if inf or sup */ | ||||||
|  |                 break;   /* drop, to guarantee consistency (miss a little bit of compression) */ | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (match[matchLength] < ip[matchLength]) { | ||||||
|  |             /* match is smaller than current */ | ||||||
|  |             *smallerPtr = matchIndex;             /* update smaller idx */ | ||||||
|  |             commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */ | ||||||
|  |             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ | ||||||
|  |             smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */ | ||||||
|  |             matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */ | ||||||
|  |         } else { | ||||||
|  |             /* match is larger than current */ | ||||||
|  |             *largerPtr = matchIndex; | ||||||
|  |             commonLengthLarger = matchLength; | ||||||
|  |             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ | ||||||
|  |             largerPtr = nextPtr; | ||||||
|  |             matchIndex = nextPtr[0]; | ||||||
|  |     }   } | ||||||
|  |  | ||||||
|  |     *smallerPtr = *largerPtr = 0; | ||||||
|  |  | ||||||
|  | update: | ||||||
|  |     zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1; | ||||||
|  |     return mnum; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** Tree updater, providing best match */ | ||||||
|  | static U32 ZSTD_BtGetAllMatches ( | ||||||
|  |                         ZSTD_CCtx* zc, | ||||||
|  |                         const BYTE* const ip, const BYTE* const iLimit, | ||||||
|  |                         const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen) | ||||||
|  | { | ||||||
|  |     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */ | ||||||
|  |     ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); | ||||||
|  |     return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static U32 ZSTD_BtGetAllMatches_selectMLS ( | ||||||
|  |                         ZSTD_CCtx* zc,   /* Index table will be updated */ | ||||||
|  |                         const BYTE* ip, const BYTE* const iHighLimit, | ||||||
|  |                         const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen) | ||||||
|  | { | ||||||
|  |     switch(matchLengthSearch) | ||||||
|  |     { | ||||||
|  |     case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen); | ||||||
|  |     default : | ||||||
|  |     case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen); | ||||||
|  |     case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen); | ||||||
|  |     case 7 : | ||||||
|  |     case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Tree updater, providing best match */ | ||||||
|  | static U32 ZSTD_BtGetAllMatches_extDict ( | ||||||
|  |                         ZSTD_CCtx* zc, | ||||||
|  |                         const BYTE* const ip, const BYTE* const iLimit, | ||||||
|  |                         const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen) | ||||||
|  | { | ||||||
|  |     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */ | ||||||
|  |     ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); | ||||||
|  |     return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( | ||||||
|  |                         ZSTD_CCtx* zc,   /* Index table will be updated */ | ||||||
|  |                         const BYTE* ip, const BYTE* const iHighLimit, | ||||||
|  |                         const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen) | ||||||
|  | { | ||||||
|  |     switch(matchLengthSearch) | ||||||
|  |     { | ||||||
|  |     case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen); | ||||||
|  |     default : | ||||||
|  |     case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen); | ||||||
|  |     case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen); | ||||||
|  |     case 7 : | ||||||
|  |     case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /*-******************************* | ||||||
|  | *  Optimal parser | ||||||
|  | *********************************/ | ||||||
|  | FORCE_INLINE_TEMPLATE | ||||||
|  | void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, | ||||||
|  |                                     const void* src, size_t srcSize, const int ultra) | ||||||
|  | { | ||||||
|  |     seqStore_t* seqStorePtr = &(ctx->seqStore); | ||||||
|  |     optState_t* optStatePtr = &(ctx->optState); | ||||||
|  |     const BYTE* const istart = (const BYTE*)src; | ||||||
|  |     const BYTE* ip = istart; | ||||||
|  |     const BYTE* anchor = istart; | ||||||
|  |     const BYTE* const iend = istart + srcSize; | ||||||
|  |     const BYTE* const ilimit = iend - 8; | ||||||
|  |     const BYTE* const base = ctx->base; | ||||||
|  |     const BYTE* const prefixStart = base + ctx->dictLimit; | ||||||
|  |  | ||||||
|  |     const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog; | ||||||
|  |     const U32 sufficient_len = ctx->appliedParams.cParams.targetLength; | ||||||
|  |     const U32 mls = ctx->appliedParams.cParams.searchLength; | ||||||
|  |     const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4; | ||||||
|  |  | ||||||
|  |     ZSTD_optimal_t* opt = optStatePtr->priceTable; | ||||||
|  |     ZSTD_match_t* matches = optStatePtr->matchTable; | ||||||
|  |     const BYTE* inr; | ||||||
|  |     U32 offset, rep[ZSTD_REP_NUM]; | ||||||
|  |  | ||||||
|  |     /* init */ | ||||||
|  |     ctx->nextToUpdate3 = ctx->nextToUpdate; | ||||||
|  |     ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize); | ||||||
|  |     ip += (ip==prefixStart); | ||||||
|  |     { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; } | ||||||
|  |  | ||||||
|  |     /* Match Loop */ | ||||||
|  |     while (ip < ilimit) { | ||||||
|  |         U32 cur, match_num, last_pos, litlen, price; | ||||||
|  |         U32 u, mlen, best_mlen, best_off, litLength; | ||||||
|  |         memset(opt, 0, sizeof(ZSTD_optimal_t)); | ||||||
|  |         last_pos = 0; | ||||||
|  |         litlen = (U32)(ip - anchor); | ||||||
|  |  | ||||||
|  |         /* check repCode */ | ||||||
|  |         {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor); | ||||||
|  |             for (i=(ip == anchor); i<last_i; i++) { | ||||||
|  |                 const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i]; | ||||||
|  |                 if ( (repCur > 0) && (repCur < (S32)(ip-prefixStart)) | ||||||
|  |                     && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) { | ||||||
|  |                     mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch; | ||||||
|  |                     if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { | ||||||
|  |                         best_mlen = mlen; best_off = i; cur = 0; last_pos = 1; | ||||||
|  |                         goto _storeSequence; | ||||||
|  |                     } | ||||||
|  |                     best_off = i - (ip == anchor); | ||||||
|  |                     do { | ||||||
|  |                         price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra); | ||||||
|  |                         if (mlen > last_pos || price < opt[mlen].price) | ||||||
|  |                             SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */ | ||||||
|  |                         mlen--; | ||||||
|  |                     } while (mlen >= minMatch); | ||||||
|  |         }   }   } | ||||||
|  |  | ||||||
|  |         match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch); | ||||||
|  |  | ||||||
|  |         if (!last_pos && !match_num) { ip++; continue; } | ||||||
|  |  | ||||||
|  |         if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) { | ||||||
|  |             best_mlen = matches[match_num-1].len; | ||||||
|  |             best_off = matches[match_num-1].off; | ||||||
|  |             cur = 0; | ||||||
|  |             last_pos = 1; | ||||||
|  |             goto _storeSequence; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* set prices using matches at position = 0 */ | ||||||
|  |         best_mlen = (last_pos) ? last_pos : minMatch; | ||||||
|  |         for (u = 0; u < match_num; u++) { | ||||||
|  |             mlen = (u>0) ? matches[u-1].len+1 : best_mlen; | ||||||
|  |             best_mlen = matches[u].len; | ||||||
|  |             while (mlen <= best_mlen) { | ||||||
|  |                 price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra); | ||||||
|  |                 if (mlen > last_pos || price < opt[mlen].price) | ||||||
|  |                     SET_PRICE(mlen, mlen, matches[u].off, litlen, price);   /* note : macro modifies last_pos */ | ||||||
|  |                 mlen++; | ||||||
|  |         }   } | ||||||
|  |  | ||||||
|  |         if (last_pos < minMatch) { ip++; continue; } | ||||||
|  |  | ||||||
|  |         /* initialize opt[0] */ | ||||||
|  |         { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; } | ||||||
|  |         opt[0].mlen = 1; | ||||||
|  |         opt[0].litlen = litlen; | ||||||
|  |  | ||||||
|  |          /* check further positions */ | ||||||
|  |         for (cur = 1; cur <= last_pos; cur++) { | ||||||
|  |            inr = ip + cur; | ||||||
|  |  | ||||||
|  |            if (opt[cur-1].mlen == 1) { | ||||||
|  |                 litlen = opt[cur-1].litlen + 1; | ||||||
|  |                 if (cur > litlen) { | ||||||
|  |                     price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen); | ||||||
|  |                 } else | ||||||
|  |                     price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor); | ||||||
|  |            } else { | ||||||
|  |                 litlen = 1; | ||||||
|  |                 price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1); | ||||||
|  |            } | ||||||
|  |  | ||||||
|  |            if (cur > last_pos || price <= opt[cur].price) | ||||||
|  |                 SET_PRICE(cur, 1, 0, litlen, price); | ||||||
|  |  | ||||||
|  |            if (cur == last_pos) break; | ||||||
|  |  | ||||||
|  |            if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */ | ||||||
|  |                continue; | ||||||
|  |  | ||||||
|  |            mlen = opt[cur].mlen; | ||||||
|  |            if (opt[cur].off > ZSTD_REP_MOVE_OPT) { | ||||||
|  |                 opt[cur].rep[2] = opt[cur-mlen].rep[1]; | ||||||
|  |                 opt[cur].rep[1] = opt[cur-mlen].rep[0]; | ||||||
|  |                 opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT; | ||||||
|  |            } else { | ||||||
|  |                 opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2]; | ||||||
|  |                 opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1]; | ||||||
|  |                 opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]); | ||||||
|  |            } | ||||||
|  |  | ||||||
|  |             best_mlen = minMatch; | ||||||
|  |             {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1); | ||||||
|  |                 for (i=(opt[cur].mlen != 1); i<last_i; i++) {  /* check rep */ | ||||||
|  |                     const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i]; | ||||||
|  |                     if ( (repCur > 0) && (repCur < (S32)(inr-prefixStart)) | ||||||
|  |                        && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) { | ||||||
|  |                        mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch; | ||||||
|  |  | ||||||
|  |                        if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { | ||||||
|  |                             best_mlen = mlen; best_off = i; last_pos = cur + 1; | ||||||
|  |                             goto _storeSequence; | ||||||
|  |                        } | ||||||
|  |  | ||||||
|  |                        best_off = i - (opt[cur].mlen != 1); | ||||||
|  |                        if (mlen > best_mlen) best_mlen = mlen; | ||||||
|  |  | ||||||
|  |                        do { | ||||||
|  |                            if (opt[cur].mlen == 1) { | ||||||
|  |                                 litlen = opt[cur].litlen; | ||||||
|  |                                 if (cur > litlen) { | ||||||
|  |                                     price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra); | ||||||
|  |                                 } else | ||||||
|  |                                     price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra); | ||||||
|  |                             } else { | ||||||
|  |                                 litlen = 0; | ||||||
|  |                                 price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra); | ||||||
|  |                             } | ||||||
|  |  | ||||||
|  |                             if (cur + mlen > last_pos || price <= opt[cur + mlen].price) | ||||||
|  |                                 SET_PRICE(cur + mlen, mlen, i, litlen, price); | ||||||
|  |                             mlen--; | ||||||
|  |                         } while (mlen >= minMatch); | ||||||
|  |             }   }   } | ||||||
|  |  | ||||||
|  |             match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen); | ||||||
|  |  | ||||||
|  |             if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) { | ||||||
|  |                 best_mlen = matches[match_num-1].len; | ||||||
|  |                 best_off = matches[match_num-1].off; | ||||||
|  |                 last_pos = cur + 1; | ||||||
|  |                 goto _storeSequence; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             /* set prices using matches at position = cur */ | ||||||
|  |             for (u = 0; u < match_num; u++) { | ||||||
|  |                 mlen = (u>0) ? matches[u-1].len+1 : best_mlen; | ||||||
|  |                 best_mlen = matches[u].len; | ||||||
|  |  | ||||||
|  |                 while (mlen <= best_mlen) { | ||||||
|  |                     if (opt[cur].mlen == 1) { | ||||||
|  |                         litlen = opt[cur].litlen; | ||||||
|  |                         if (cur > litlen) | ||||||
|  |                             price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra); | ||||||
|  |                         else | ||||||
|  |                             price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra); | ||||||
|  |                     } else { | ||||||
|  |                         litlen = 0; | ||||||
|  |                         price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if (cur + mlen > last_pos || (price < opt[cur + mlen].price)) | ||||||
|  |                         SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price); | ||||||
|  |  | ||||||
|  |                     mlen++; | ||||||
|  |         }   }   } | ||||||
|  |  | ||||||
|  |         best_mlen = opt[last_pos].mlen; | ||||||
|  |         best_off = opt[last_pos].off; | ||||||
|  |         cur = last_pos - best_mlen; | ||||||
|  |  | ||||||
|  |         /* store sequence */ | ||||||
|  | _storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */ | ||||||
|  |         opt[0].mlen = 1; | ||||||
|  |  | ||||||
|  |         while (1) { | ||||||
|  |             mlen = opt[cur].mlen; | ||||||
|  |             offset = opt[cur].off; | ||||||
|  |             opt[cur].mlen = best_mlen; | ||||||
|  |             opt[cur].off = best_off; | ||||||
|  |             best_mlen = mlen; | ||||||
|  |             best_off = offset; | ||||||
|  |             if (mlen > cur) break; | ||||||
|  |             cur -= mlen; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (u = 0; u <= last_pos;) { | ||||||
|  |             u += opt[u].mlen; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (cur=0; cur < last_pos; ) { | ||||||
|  |             mlen = opt[cur].mlen; | ||||||
|  |             if (mlen == 1) { ip++; cur++; continue; } | ||||||
|  |             offset = opt[cur].off; | ||||||
|  |             cur += mlen; | ||||||
|  |             litLength = (U32)(ip - anchor); | ||||||
|  |  | ||||||
|  |             if (offset > ZSTD_REP_MOVE_OPT) { | ||||||
|  |                 rep[2] = rep[1]; | ||||||
|  |                 rep[1] = rep[0]; | ||||||
|  |                 rep[0] = offset - ZSTD_REP_MOVE_OPT; | ||||||
|  |                 offset--; | ||||||
|  |             } else { | ||||||
|  |                 if (offset != 0) { | ||||||
|  |                     best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]); | ||||||
|  |                     if (offset != 1) rep[2] = rep[1]; | ||||||
|  |                     rep[1] = rep[0]; | ||||||
|  |                     rep[0] = best_off; | ||||||
|  |                 } | ||||||
|  |                 if (litLength==0) offset--; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH); | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); | ||||||
|  |             anchor = ip = ip + mlen; | ||||||
|  |     }    }   /* for (cur=0; cur < last_pos; ) */ | ||||||
|  |  | ||||||
|  |     /* Save reps for next block */ | ||||||
|  |     { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; } | ||||||
|  |  | ||||||
|  |     /* Last Literals */ | ||||||
|  |     {   size_t const lastLLSize = iend - anchor; | ||||||
|  |         memcpy(seqStorePtr->lit, anchor, lastLLSize); | ||||||
|  |         seqStorePtr->lit += lastLLSize; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FORCE_INLINE_TEMPLATE | ||||||
|  | void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, | ||||||
|  |                                      const void* src, size_t srcSize, const int ultra) | ||||||
|  | { | ||||||
|  |     seqStore_t* seqStorePtr = &(ctx->seqStore); | ||||||
|  |     optState_t* optStatePtr = &(ctx->optState); | ||||||
|  |     const BYTE* const istart = (const BYTE*)src; | ||||||
|  |     const BYTE* ip = istart; | ||||||
|  |     const BYTE* anchor = istart; | ||||||
|  |     const BYTE* const iend = istart + srcSize; | ||||||
|  |     const BYTE* const ilimit = iend - 8; | ||||||
|  |     const BYTE* const base = ctx->base; | ||||||
|  |     const U32 lowestIndex = ctx->lowLimit; | ||||||
|  |     const U32 dictLimit = ctx->dictLimit; | ||||||
|  |     const BYTE* const prefixStart = base + dictLimit; | ||||||
|  |     const BYTE* const dictBase = ctx->dictBase; | ||||||
|  |     const BYTE* const dictEnd  = dictBase + dictLimit; | ||||||
|  |  | ||||||
|  |     const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog; | ||||||
|  |     const U32 sufficient_len = ctx->appliedParams.cParams.targetLength; | ||||||
|  |     const U32 mls = ctx->appliedParams.cParams.searchLength; | ||||||
|  |     const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4; | ||||||
|  |  | ||||||
|  |     ZSTD_optimal_t* opt = optStatePtr->priceTable; | ||||||
|  |     ZSTD_match_t* matches = optStatePtr->matchTable; | ||||||
|  |     const BYTE* inr; | ||||||
|  |  | ||||||
|  |     /* init */ | ||||||
|  |     U32 offset, rep[ZSTD_REP_NUM]; | ||||||
|  |     { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; } | ||||||
|  |  | ||||||
|  |     ctx->nextToUpdate3 = ctx->nextToUpdate; | ||||||
|  |     ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize); | ||||||
|  |     ip += (ip==prefixStart); | ||||||
|  |  | ||||||
|  |     /* Match Loop */ | ||||||
|  |     while (ip < ilimit) { | ||||||
|  |         U32 cur, match_num, last_pos, litlen, price; | ||||||
|  |         U32 u, mlen, best_mlen, best_off, litLength; | ||||||
|  |         U32 current = (U32)(ip-base); | ||||||
|  |         memset(opt, 0, sizeof(ZSTD_optimal_t)); | ||||||
|  |         last_pos = 0; | ||||||
|  |         opt[0].litlen = (U32)(ip - anchor); | ||||||
|  |  | ||||||
|  |         /* check repCode */ | ||||||
|  |         {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor); | ||||||
|  |             for (i = (ip==anchor); i<last_i; i++) { | ||||||
|  |                 const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i]; | ||||||
|  |                 const U32 repIndex = (U32)(current - repCur); | ||||||
|  |                 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; | ||||||
|  |                 const BYTE* const repMatch = repBase + repIndex; | ||||||
|  |                 if ( (repCur > 0 && repCur <= (S32)current) | ||||||
|  |                    && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */ | ||||||
|  |                    && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { | ||||||
|  |                     /* repcode detected we should take it */ | ||||||
|  |                     const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                     mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch; | ||||||
|  |  | ||||||
|  |                     if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { | ||||||
|  |                         best_mlen = mlen; best_off = i; cur = 0; last_pos = 1; | ||||||
|  |                         goto _storeSequence; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     best_off = i - (ip==anchor); | ||||||
|  |                     litlen = opt[0].litlen; | ||||||
|  |                     do { | ||||||
|  |                         price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra); | ||||||
|  |                         if (mlen > last_pos || price < opt[mlen].price) | ||||||
|  |                             SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */ | ||||||
|  |                         mlen--; | ||||||
|  |                     } while (mlen >= minMatch); | ||||||
|  |         }   }   } | ||||||
|  |  | ||||||
|  |         match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch);  /* first search (depth 0) */ | ||||||
|  |  | ||||||
|  |         if (!last_pos && !match_num) { ip++; continue; } | ||||||
|  |  | ||||||
|  |         { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; } | ||||||
|  |         opt[0].mlen = 1; | ||||||
|  |  | ||||||
|  |         if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) { | ||||||
|  |             best_mlen = matches[match_num-1].len; | ||||||
|  |             best_off = matches[match_num-1].off; | ||||||
|  |             cur = 0; | ||||||
|  |             last_pos = 1; | ||||||
|  |             goto _storeSequence; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         best_mlen = (last_pos) ? last_pos : minMatch; | ||||||
|  |  | ||||||
|  |         /* set prices using matches at position = 0 */ | ||||||
|  |         for (u = 0; u < match_num; u++) { | ||||||
|  |             mlen = (u>0) ? matches[u-1].len+1 : best_mlen; | ||||||
|  |             best_mlen = matches[u].len; | ||||||
|  |             litlen = opt[0].litlen; | ||||||
|  |             while (mlen <= best_mlen) { | ||||||
|  |                 price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra); | ||||||
|  |                 if (mlen > last_pos || price < opt[mlen].price) | ||||||
|  |                     SET_PRICE(mlen, mlen, matches[u].off, litlen, price); | ||||||
|  |                 mlen++; | ||||||
|  |         }   } | ||||||
|  |  | ||||||
|  |         if (last_pos < minMatch) { | ||||||
|  |             ip++; continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* check further positions */ | ||||||
|  |         for (cur = 1; cur <= last_pos; cur++) { | ||||||
|  |             inr = ip + cur; | ||||||
|  |  | ||||||
|  |             if (opt[cur-1].mlen == 1) { | ||||||
|  |                 litlen = opt[cur-1].litlen + 1; | ||||||
|  |                 if (cur > litlen) { | ||||||
|  |                     price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen); | ||||||
|  |                 } else | ||||||
|  |                     price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor); | ||||||
|  |             } else { | ||||||
|  |                 litlen = 1; | ||||||
|  |                 price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (cur > last_pos || price <= opt[cur].price) | ||||||
|  |                 SET_PRICE(cur, 1, 0, litlen, price); | ||||||
|  |  | ||||||
|  |             if (cur == last_pos) break; | ||||||
|  |  | ||||||
|  |             if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */ | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             mlen = opt[cur].mlen; | ||||||
|  |             if (opt[cur].off > ZSTD_REP_MOVE_OPT) { | ||||||
|  |                 opt[cur].rep[2] = opt[cur-mlen].rep[1]; | ||||||
|  |                 opt[cur].rep[1] = opt[cur-mlen].rep[0]; | ||||||
|  |                 opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT; | ||||||
|  |             } else { | ||||||
|  |                 opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2]; | ||||||
|  |                 opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1]; | ||||||
|  |                 opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             best_mlen = minMatch; | ||||||
|  |             {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1); | ||||||
|  |                 for (i = (mlen != 1); i<last_i; i++) { | ||||||
|  |                     const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i]; | ||||||
|  |                     const U32 repIndex = (U32)(current+cur - repCur); | ||||||
|  |                     const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; | ||||||
|  |                     const BYTE* const repMatch = repBase + repIndex; | ||||||
|  |                     if ( (repCur > 0 && repCur <= (S32)(current+cur)) | ||||||
|  |                       && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */ | ||||||
|  |                       && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { | ||||||
|  |                         /* repcode detected */ | ||||||
|  |                         const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; | ||||||
|  |                         mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch; | ||||||
|  |  | ||||||
|  |                         if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { | ||||||
|  |                             best_mlen = mlen; best_off = i; last_pos = cur + 1; | ||||||
|  |                             goto _storeSequence; | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         best_off = i - (opt[cur].mlen != 1); | ||||||
|  |                         if (mlen > best_mlen) best_mlen = mlen; | ||||||
|  |  | ||||||
|  |                         do { | ||||||
|  |                             if (opt[cur].mlen == 1) { | ||||||
|  |                                 litlen = opt[cur].litlen; | ||||||
|  |                                 if (cur > litlen) { | ||||||
|  |                                     price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra); | ||||||
|  |                                 } else | ||||||
|  |                                     price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra); | ||||||
|  |                             } else { | ||||||
|  |                                 litlen = 0; | ||||||
|  |                                 price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra); | ||||||
|  |                             } | ||||||
|  |  | ||||||
|  |                             if (cur + mlen > last_pos || price <= opt[cur + mlen].price) | ||||||
|  |                                 SET_PRICE(cur + mlen, mlen, i, litlen, price); | ||||||
|  |                             mlen--; | ||||||
|  |                         } while (mlen >= minMatch); | ||||||
|  |             }   }   } | ||||||
|  |  | ||||||
|  |             match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch); | ||||||
|  |  | ||||||
|  |             if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) { | ||||||
|  |                 best_mlen = matches[match_num-1].len; | ||||||
|  |                 best_off = matches[match_num-1].off; | ||||||
|  |                 last_pos = cur + 1; | ||||||
|  |                 goto _storeSequence; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             /* set prices using matches at position = cur */ | ||||||
|  |             for (u = 0; u < match_num; u++) { | ||||||
|  |                 mlen = (u>0) ? matches[u-1].len+1 : best_mlen; | ||||||
|  |                 best_mlen = matches[u].len; | ||||||
|  |  | ||||||
|  |                 while (mlen <= best_mlen) { | ||||||
|  |                     if (opt[cur].mlen == 1) { | ||||||
|  |                         litlen = opt[cur].litlen; | ||||||
|  |                         if (cur > litlen) | ||||||
|  |                             price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra); | ||||||
|  |                         else | ||||||
|  |                             price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra); | ||||||
|  |                     } else { | ||||||
|  |                         litlen = 0; | ||||||
|  |                         price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if (cur + mlen > last_pos || (price < opt[cur + mlen].price)) | ||||||
|  |                         SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price); | ||||||
|  |  | ||||||
|  |                     mlen++; | ||||||
|  |         }   }   }   /* for (cur = 1; cur <= last_pos; cur++) */ | ||||||
|  |  | ||||||
|  |         best_mlen = opt[last_pos].mlen; | ||||||
|  |         best_off = opt[last_pos].off; | ||||||
|  |         cur = last_pos - best_mlen; | ||||||
|  |  | ||||||
|  |         /* store sequence */ | ||||||
|  | _storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */ | ||||||
|  |         opt[0].mlen = 1; | ||||||
|  |  | ||||||
|  |         while (1) { | ||||||
|  |             mlen = opt[cur].mlen; | ||||||
|  |             offset = opt[cur].off; | ||||||
|  |             opt[cur].mlen = best_mlen; | ||||||
|  |             opt[cur].off = best_off; | ||||||
|  |             best_mlen = mlen; | ||||||
|  |             best_off = offset; | ||||||
|  |             if (mlen > cur) break; | ||||||
|  |             cur -= mlen; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (u = 0; u <= last_pos; ) { | ||||||
|  |             u += opt[u].mlen; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (cur=0; cur < last_pos; ) { | ||||||
|  |             mlen = opt[cur].mlen; | ||||||
|  |             if (mlen == 1) { ip++; cur++; continue; } | ||||||
|  |             offset = opt[cur].off; | ||||||
|  |             cur += mlen; | ||||||
|  |             litLength = (U32)(ip - anchor); | ||||||
|  |  | ||||||
|  |             if (offset > ZSTD_REP_MOVE_OPT) { | ||||||
|  |                 rep[2] = rep[1]; | ||||||
|  |                 rep[1] = rep[0]; | ||||||
|  |                 rep[0] = offset - ZSTD_REP_MOVE_OPT; | ||||||
|  |                 offset--; | ||||||
|  |             } else { | ||||||
|  |                 if (offset != 0) { | ||||||
|  |                     best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]); | ||||||
|  |                     if (offset != 1) rep[2] = rep[1]; | ||||||
|  |                     rep[1] = rep[0]; | ||||||
|  |                     rep[0] = best_off; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (litLength==0) offset--; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH); | ||||||
|  |             ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); | ||||||
|  |             anchor = ip = ip + mlen; | ||||||
|  |     }    }   /* for (cur=0; cur < last_pos; ) */ | ||||||
|  |  | ||||||
|  |     /* Save reps for next block */ | ||||||
|  |     { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; } | ||||||
|  |  | ||||||
|  |     /* Last Literals */ | ||||||
|  |     {   size_t lastLLSize = iend - anchor; | ||||||
|  |         memcpy(seqStorePtr->lit, anchor, lastLLSize); | ||||||
|  |         seqStorePtr->lit += lastLLSize; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) | ||||||
|  | { | ||||||
|  |     ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1); | ||||||
|  | } | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| /* | /* | ||||||
|  * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. |  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | ||||||
|  * All rights reserved. |  * All rights reserved. | ||||||
|  * |  * | ||||||
|  * This source code is licensed under both the BSD-style license (found in the |  * This source code is licensed under both the BSD-style license (found in the | ||||||
| @@ -7,932 +7,23 @@ | |||||||
|  * in the COPYING file in the root directory of this source tree). |  * in the COPYING file in the root directory of this source tree). | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | #ifndef ZSTD_OPT_H | ||||||
|  | #define ZSTD_OPT_H | ||||||
|  |  | ||||||
| /* Note : this file is intended to be included within zstd_compress.c */ | #include "zstd_compress.h" | ||||||
|  |  | ||||||
|  | #if defined (__cplusplus) | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifndef ZSTD_OPT_H_91842398743 | void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
| #define ZSTD_OPT_H_91842398743 | void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  |  | ||||||
|  | void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  | void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize); | ||||||
|  |  | ||||||
| #define ZSTD_LITFREQ_ADD    2 | #if defined (__cplusplus) | ||||||
| #define ZSTD_FREQ_DIV       4 |  | ||||||
| #define ZSTD_MAX_PRICE      (1<<30) |  | ||||||
|  |  | ||||||
| /*-************************************* |  | ||||||
| *  Price functions for optimal parser |  | ||||||
| ***************************************/ |  | ||||||
| static void ZSTD_setLog2Prices(optState_t* optPtr) |  | ||||||
| { |  | ||||||
|     optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1); |  | ||||||
|     optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1); |  | ||||||
|     optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1); |  | ||||||
|     optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1); |  | ||||||
|     optPtr->factor = 1 + ((optPtr->litSum>>5) / optPtr->litLengthSum) + ((optPtr->litSum<<1) / (optPtr->litSum + optPtr->matchSum)); |  | ||||||
| } | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* ZSTD_OPT_H */ | ||||||
| static void ZSTD_rescaleFreqs(optState_t* optPtr, const BYTE* src, size_t srcSize) |  | ||||||
| { |  | ||||||
|     unsigned u; |  | ||||||
|  |  | ||||||
|     optPtr->cachedLiterals = NULL; |  | ||||||
|     optPtr->cachedPrice = optPtr->cachedLitLength = 0; |  | ||||||
|     optPtr->staticPrices = 0; |  | ||||||
|  |  | ||||||
|     if (optPtr->litLengthSum == 0) { |  | ||||||
|         if (srcSize <= 1024) optPtr->staticPrices = 1; |  | ||||||
|  |  | ||||||
|         assert(optPtr->litFreq!=NULL); |  | ||||||
|         for (u=0; u<=MaxLit; u++) |  | ||||||
|             optPtr->litFreq[u] = 0; |  | ||||||
|         for (u=0; u<srcSize; u++) |  | ||||||
|             optPtr->litFreq[src[u]]++; |  | ||||||
|  |  | ||||||
|         optPtr->litSum = 0; |  | ||||||
|         optPtr->litLengthSum = MaxLL+1; |  | ||||||
|         optPtr->matchLengthSum = MaxML+1; |  | ||||||
|         optPtr->offCodeSum = (MaxOff+1); |  | ||||||
|         optPtr->matchSum = (ZSTD_LITFREQ_ADD<<Litbits); |  | ||||||
|  |  | ||||||
|         for (u=0; u<=MaxLit; u++) { |  | ||||||
|             optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>ZSTD_FREQ_DIV); |  | ||||||
|             optPtr->litSum += optPtr->litFreq[u]; |  | ||||||
|         } |  | ||||||
|         for (u=0; u<=MaxLL; u++) |  | ||||||
|             optPtr->litLengthFreq[u] = 1; |  | ||||||
|         for (u=0; u<=MaxML; u++) |  | ||||||
|             optPtr->matchLengthFreq[u] = 1; |  | ||||||
|         for (u=0; u<=MaxOff; u++) |  | ||||||
|             optPtr->offCodeFreq[u] = 1; |  | ||||||
|     } else { |  | ||||||
|         optPtr->matchLengthSum = 0; |  | ||||||
|         optPtr->litLengthSum = 0; |  | ||||||
|         optPtr->offCodeSum = 0; |  | ||||||
|         optPtr->matchSum = 0; |  | ||||||
|         optPtr->litSum = 0; |  | ||||||
|  |  | ||||||
|         for (u=0; u<=MaxLit; u++) { |  | ||||||
|             optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1)); |  | ||||||
|             optPtr->litSum += optPtr->litFreq[u]; |  | ||||||
|         } |  | ||||||
|         for (u=0; u<=MaxLL; u++) { |  | ||||||
|             optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1)); |  | ||||||
|             optPtr->litLengthSum += optPtr->litLengthFreq[u]; |  | ||||||
|         } |  | ||||||
|         for (u=0; u<=MaxML; u++) { |  | ||||||
|             optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV); |  | ||||||
|             optPtr->matchLengthSum += optPtr->matchLengthFreq[u]; |  | ||||||
|             optPtr->matchSum += optPtr->matchLengthFreq[u] * (u + 3); |  | ||||||
|         } |  | ||||||
|         optPtr->matchSum *= ZSTD_LITFREQ_ADD; |  | ||||||
|         for (u=0; u<=MaxOff; u++) { |  | ||||||
|             optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV); |  | ||||||
|             optPtr->offCodeSum += optPtr->offCodeFreq[u]; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ZSTD_setLog2Prices(optPtr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static U32 ZSTD_getLiteralPrice(optState_t* optPtr, U32 litLength, const BYTE* literals) |  | ||||||
| { |  | ||||||
|     U32 price, u; |  | ||||||
|  |  | ||||||
|     if (optPtr->staticPrices) |  | ||||||
|         return ZSTD_highbit32((U32)litLength+1) + (litLength*6); |  | ||||||
|  |  | ||||||
|     if (litLength == 0) |  | ||||||
|         return optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[0]+1); |  | ||||||
|  |  | ||||||
|     /* literals */ |  | ||||||
|     if (optPtr->cachedLiterals == literals) { |  | ||||||
|         U32 const additional = litLength - optPtr->cachedLitLength; |  | ||||||
|         const BYTE* literals2 = optPtr->cachedLiterals + optPtr->cachedLitLength; |  | ||||||
|         price = optPtr->cachedPrice + additional * optPtr->log2litSum; |  | ||||||
|         for (u=0; u < additional; u++) |  | ||||||
|             price -= ZSTD_highbit32(optPtr->litFreq[literals2[u]]+1); |  | ||||||
|         optPtr->cachedPrice = price; |  | ||||||
|         optPtr->cachedLitLength = litLength; |  | ||||||
|     } else { |  | ||||||
|         price = litLength * optPtr->log2litSum; |  | ||||||
|         for (u=0; u < litLength; u++) |  | ||||||
|             price -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1); |  | ||||||
|  |  | ||||||
|         if (litLength >= 12) { |  | ||||||
|             optPtr->cachedLiterals = literals; |  | ||||||
|             optPtr->cachedPrice = price; |  | ||||||
|             optPtr->cachedLitLength = litLength; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* literal Length */ |  | ||||||
|     {   const BYTE LL_deltaCode = 19; |  | ||||||
|         const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength]; |  | ||||||
|         price += LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return price; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra) |  | ||||||
| { |  | ||||||
|     /* offset */ |  | ||||||
|     U32 price; |  | ||||||
|     BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1); |  | ||||||
|  |  | ||||||
|     if (optPtr->staticPrices) |  | ||||||
|         return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode; |  | ||||||
|  |  | ||||||
|     price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1); |  | ||||||
|     if (!ultra && offCode >= 20) price += (offCode-19)*2; |  | ||||||
|  |  | ||||||
|     /* match Length */ |  | ||||||
|     {   const BYTE ML_deltaCode = 36; |  | ||||||
|         const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength]; |  | ||||||
|         price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return price + ZSTD_getLiteralPrice(optPtr, litLength, literals) + optPtr->factor; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void ZSTD_updatePrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength) |  | ||||||
| { |  | ||||||
|     U32 u; |  | ||||||
|  |  | ||||||
|     /* literals */ |  | ||||||
|     optPtr->litSum += litLength*ZSTD_LITFREQ_ADD; |  | ||||||
|     for (u=0; u < litLength; u++) |  | ||||||
|         optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD; |  | ||||||
|  |  | ||||||
|     /* literal Length */ |  | ||||||
|     {   const BYTE LL_deltaCode = 19; |  | ||||||
|         const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength]; |  | ||||||
|         optPtr->litLengthFreq[llCode]++; |  | ||||||
|         optPtr->litLengthSum++; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* match offset */ |  | ||||||
|     {   BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1); |  | ||||||
|         optPtr->offCodeSum++; |  | ||||||
|         optPtr->offCodeFreq[offCode]++; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* match Length */ |  | ||||||
|     {   const BYTE ML_deltaCode = 36; |  | ||||||
|         const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength]; |  | ||||||
|         optPtr->matchLengthFreq[mlCode]++; |  | ||||||
|         optPtr->matchLengthSum++; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ZSTD_setLog2Prices(optPtr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define SET_PRICE(pos, mlen_, offset_, litlen_, price_)   \ |  | ||||||
|     {                                                 \ |  | ||||||
|         while (last_pos < pos)  { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \ |  | ||||||
|         opt[pos].mlen = mlen_;                         \ |  | ||||||
|         opt[pos].off = offset_;                        \ |  | ||||||
|         opt[pos].litlen = litlen_;                     \ |  | ||||||
|         opt[pos].price = price_;                       \ |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* function safe only for comparisons */ |  | ||||||
| static U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) |  | ||||||
| { |  | ||||||
|     switch (length) |  | ||||||
|     { |  | ||||||
|     default : |  | ||||||
|     case 4 : return MEM_read32(memPtr); |  | ||||||
|     case 3 : if (MEM_isLittleEndian()) |  | ||||||
|                 return MEM_read32(memPtr)<<8; |  | ||||||
|              else |  | ||||||
|                 return MEM_read32(memPtr)>>8; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Update hashTable3 up to ip (excluded) |  | ||||||
|    Assumption : always within prefix (i.e. not within extDict) */ |  | ||||||
| static |  | ||||||
| U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip) |  | ||||||
| { |  | ||||||
|     U32* const hashTable3  = zc->hashTable3; |  | ||||||
|     U32 const hashLog3  = zc->hashLog3; |  | ||||||
|     const BYTE* const base = zc->base; |  | ||||||
|     U32 idx = zc->nextToUpdate3; |  | ||||||
|     const U32 target = zc->nextToUpdate3 = (U32)(ip - base); |  | ||||||
|     const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3); |  | ||||||
|  |  | ||||||
|     while(idx < target) { |  | ||||||
|         hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx; |  | ||||||
|         idx++; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return hashTable3[hash3]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /*-************************************* |  | ||||||
| *  Binary Tree search |  | ||||||
| ***************************************/ |  | ||||||
| static U32 ZSTD_insertBtAndGetAllMatches ( |  | ||||||
|                         ZSTD_CCtx* zc, |  | ||||||
|                         const BYTE* const ip, const BYTE* const iLimit, |  | ||||||
|                         U32 nbCompares, const U32 mls, |  | ||||||
|                         U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen) |  | ||||||
| { |  | ||||||
|     const BYTE* const base = zc->base; |  | ||||||
|     const U32 current = (U32)(ip-base); |  | ||||||
|     const U32 hashLog = zc->appliedParams.cParams.hashLog; |  | ||||||
|     const size_t h  = ZSTD_hashPtr(ip, hashLog, mls); |  | ||||||
|     U32* const hashTable = zc->hashTable; |  | ||||||
|     U32 matchIndex  = hashTable[h]; |  | ||||||
|     U32* const bt   = zc->chainTable; |  | ||||||
|     const U32 btLog = zc->appliedParams.cParams.chainLog - 1; |  | ||||||
|     const U32 btMask= (1U << btLog) - 1; |  | ||||||
|     size_t commonLengthSmaller=0, commonLengthLarger=0; |  | ||||||
|     const BYTE* const dictBase = zc->dictBase; |  | ||||||
|     const U32 dictLimit = zc->dictLimit; |  | ||||||
|     const BYTE* const dictEnd = dictBase + dictLimit; |  | ||||||
|     const BYTE* const prefixStart = base + dictLimit; |  | ||||||
|     const U32 btLow = btMask >= current ? 0 : current - btMask; |  | ||||||
|     const U32 windowLow = zc->lowLimit; |  | ||||||
|     U32* smallerPtr = bt + 2*(current&btMask); |  | ||||||
|     U32* largerPtr  = bt + 2*(current&btMask) + 1; |  | ||||||
|     U32 matchEndIdx = current+8; |  | ||||||
|     U32 dummy32;   /* to be nullified at the end */ |  | ||||||
|     U32 mnum = 0; |  | ||||||
|  |  | ||||||
|     const U32 minMatch = (mls == 3) ? 3 : 4; |  | ||||||
|     size_t bestLength = minMatchLen-1; |  | ||||||
|  |  | ||||||
|     if (minMatch == 3) { /* HC3 match finder */ |  | ||||||
|         U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip); |  | ||||||
|         if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) { |  | ||||||
|             const BYTE* match; |  | ||||||
|             size_t currentMl=0; |  | ||||||
|             if ((!extDict) || matchIndex3 >= dictLimit) { |  | ||||||
|                 match = base + matchIndex3; |  | ||||||
|                 if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit); |  | ||||||
|             } else { |  | ||||||
|                 match = dictBase + matchIndex3; |  | ||||||
|                 if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH))    /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */ |  | ||||||
|                     currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             /* save best solution */ |  | ||||||
|             if (currentMl > bestLength) { |  | ||||||
|                 bestLength = currentMl; |  | ||||||
|                 matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3; |  | ||||||
|                 matches[mnum].len = (U32)currentMl; |  | ||||||
|                 mnum++; |  | ||||||
|                 if (currentMl > ZSTD_OPT_NUM) goto update; |  | ||||||
|                 if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/ |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     hashTable[h] = current;   /* Update Hash Table */ |  | ||||||
|  |  | ||||||
|     while (nbCompares-- && (matchIndex > windowLow)) { |  | ||||||
|         U32* nextPtr = bt + 2*(matchIndex & btMask); |  | ||||||
|         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */ |  | ||||||
|         const BYTE* match; |  | ||||||
|  |  | ||||||
|         if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { |  | ||||||
|             match = base + matchIndex; |  | ||||||
|             if (match[matchLength] == ip[matchLength]) { |  | ||||||
|                 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1; |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             match = dictBase + matchIndex; |  | ||||||
|             matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart); |  | ||||||
|             if (matchIndex+matchLength >= dictLimit) |  | ||||||
|                 match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */ |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (matchLength > bestLength) { |  | ||||||
|             if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; |  | ||||||
|             bestLength = matchLength; |  | ||||||
|             matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex; |  | ||||||
|             matches[mnum].len = (U32)matchLength; |  | ||||||
|             mnum++; |  | ||||||
|             if (matchLength > ZSTD_OPT_NUM) break; |  | ||||||
|             if (ip+matchLength == iLimit)   /* equal : no way to know if inf or sup */ |  | ||||||
|                 break;   /* drop, to guarantee consistency (miss a little bit of compression) */ |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (match[matchLength] < ip[matchLength]) { |  | ||||||
|             /* match is smaller than current */ |  | ||||||
|             *smallerPtr = matchIndex;             /* update smaller idx */ |  | ||||||
|             commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */ |  | ||||||
|             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ |  | ||||||
|             smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */ |  | ||||||
|             matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */ |  | ||||||
|         } else { |  | ||||||
|             /* match is larger than current */ |  | ||||||
|             *largerPtr = matchIndex; |  | ||||||
|             commonLengthLarger = matchLength; |  | ||||||
|             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */ |  | ||||||
|             largerPtr = nextPtr; |  | ||||||
|             matchIndex = nextPtr[0]; |  | ||||||
|     }   } |  | ||||||
|  |  | ||||||
|     *smallerPtr = *largerPtr = 0; |  | ||||||
|  |  | ||||||
| update: |  | ||||||
|     zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1; |  | ||||||
|     return mnum; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /** Tree updater, providing best match */ |  | ||||||
| static U32 ZSTD_BtGetAllMatches ( |  | ||||||
|                         ZSTD_CCtx* zc, |  | ||||||
|                         const BYTE* const ip, const BYTE* const iLimit, |  | ||||||
|                         const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen) |  | ||||||
| { |  | ||||||
|     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */ |  | ||||||
|     ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); |  | ||||||
|     return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static U32 ZSTD_BtGetAllMatches_selectMLS ( |  | ||||||
|                         ZSTD_CCtx* zc,   /* Index table will be updated */ |  | ||||||
|                         const BYTE* ip, const BYTE* const iHighLimit, |  | ||||||
|                         const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen) |  | ||||||
| { |  | ||||||
|     switch(matchLengthSearch) |  | ||||||
|     { |  | ||||||
|     case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen); |  | ||||||
|     default : |  | ||||||
|     case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen); |  | ||||||
|     case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen); |  | ||||||
|     case 7 : |  | ||||||
|     case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** Tree updater, providing best match */ |  | ||||||
| static U32 ZSTD_BtGetAllMatches_extDict ( |  | ||||||
|                         ZSTD_CCtx* zc, |  | ||||||
|                         const BYTE* const ip, const BYTE* const iLimit, |  | ||||||
|                         const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen) |  | ||||||
| { |  | ||||||
|     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */ |  | ||||||
|     ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); |  | ||||||
|     return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( |  | ||||||
|                         ZSTD_CCtx* zc,   /* Index table will be updated */ |  | ||||||
|                         const BYTE* ip, const BYTE* const iHighLimit, |  | ||||||
|                         const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen) |  | ||||||
| { |  | ||||||
|     switch(matchLengthSearch) |  | ||||||
|     { |  | ||||||
|     case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen); |  | ||||||
|     default : |  | ||||||
|     case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen); |  | ||||||
|     case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen); |  | ||||||
|     case 7 : |  | ||||||
|     case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /*-******************************* |  | ||||||
| *  Optimal parser |  | ||||||
| *********************************/ |  | ||||||
| FORCE_INLINE_TEMPLATE |  | ||||||
| void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, |  | ||||||
|                                     const void* src, size_t srcSize, const int ultra) |  | ||||||
| { |  | ||||||
|     seqStore_t* seqStorePtr = &(ctx->seqStore); |  | ||||||
|     optState_t* optStatePtr = &(ctx->optState); |  | ||||||
|     const BYTE* const istart = (const BYTE*)src; |  | ||||||
|     const BYTE* ip = istart; |  | ||||||
|     const BYTE* anchor = istart; |  | ||||||
|     const BYTE* const iend = istart + srcSize; |  | ||||||
|     const BYTE* const ilimit = iend - 8; |  | ||||||
|     const BYTE* const base = ctx->base; |  | ||||||
|     const BYTE* const prefixStart = base + ctx->dictLimit; |  | ||||||
|  |  | ||||||
|     const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog; |  | ||||||
|     const U32 sufficient_len = ctx->appliedParams.cParams.targetLength; |  | ||||||
|     const U32 mls = ctx->appliedParams.cParams.searchLength; |  | ||||||
|     const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4; |  | ||||||
|  |  | ||||||
|     ZSTD_optimal_t* opt = optStatePtr->priceTable; |  | ||||||
|     ZSTD_match_t* matches = optStatePtr->matchTable; |  | ||||||
|     const BYTE* inr; |  | ||||||
|     U32 offset, rep[ZSTD_REP_NUM]; |  | ||||||
|  |  | ||||||
|     /* init */ |  | ||||||
|     ctx->nextToUpdate3 = ctx->nextToUpdate; |  | ||||||
|     ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize); |  | ||||||
|     ip += (ip==prefixStart); |  | ||||||
|     { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; } |  | ||||||
|  |  | ||||||
|     /* Match Loop */ |  | ||||||
|     while (ip < ilimit) { |  | ||||||
|         U32 cur, match_num, last_pos, litlen, price; |  | ||||||
|         U32 u, mlen, best_mlen, best_off, litLength; |  | ||||||
|         memset(opt, 0, sizeof(ZSTD_optimal_t)); |  | ||||||
|         last_pos = 0; |  | ||||||
|         litlen = (U32)(ip - anchor); |  | ||||||
|  |  | ||||||
|         /* check repCode */ |  | ||||||
|         {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor); |  | ||||||
|             for (i=(ip == anchor); i<last_i; i++) { |  | ||||||
|                 const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i]; |  | ||||||
|                 if ( (repCur > 0) && (repCur < (S32)(ip-prefixStart)) |  | ||||||
|                     && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) { |  | ||||||
|                     mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch; |  | ||||||
|                     if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { |  | ||||||
|                         best_mlen = mlen; best_off = i; cur = 0; last_pos = 1; |  | ||||||
|                         goto _storeSequence; |  | ||||||
|                     } |  | ||||||
|                     best_off = i - (ip == anchor); |  | ||||||
|                     do { |  | ||||||
|                         price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra); |  | ||||||
|                         if (mlen > last_pos || price < opt[mlen].price) |  | ||||||
|                             SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */ |  | ||||||
|                         mlen--; |  | ||||||
|                     } while (mlen >= minMatch); |  | ||||||
|         }   }   } |  | ||||||
|  |  | ||||||
|         match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch); |  | ||||||
|  |  | ||||||
|         if (!last_pos && !match_num) { ip++; continue; } |  | ||||||
|  |  | ||||||
|         if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) { |  | ||||||
|             best_mlen = matches[match_num-1].len; |  | ||||||
|             best_off = matches[match_num-1].off; |  | ||||||
|             cur = 0; |  | ||||||
|             last_pos = 1; |  | ||||||
|             goto _storeSequence; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /* set prices using matches at position = 0 */ |  | ||||||
|         best_mlen = (last_pos) ? last_pos : minMatch; |  | ||||||
|         for (u = 0; u < match_num; u++) { |  | ||||||
|             mlen = (u>0) ? matches[u-1].len+1 : best_mlen; |  | ||||||
|             best_mlen = matches[u].len; |  | ||||||
|             while (mlen <= best_mlen) { |  | ||||||
|                 price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra); |  | ||||||
|                 if (mlen > last_pos || price < opt[mlen].price) |  | ||||||
|                     SET_PRICE(mlen, mlen, matches[u].off, litlen, price);   /* note : macro modifies last_pos */ |  | ||||||
|                 mlen++; |  | ||||||
|         }   } |  | ||||||
|  |  | ||||||
|         if (last_pos < minMatch) { ip++; continue; } |  | ||||||
|  |  | ||||||
|         /* initialize opt[0] */ |  | ||||||
|         { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; } |  | ||||||
|         opt[0].mlen = 1; |  | ||||||
|         opt[0].litlen = litlen; |  | ||||||
|  |  | ||||||
|          /* check further positions */ |  | ||||||
|         for (cur = 1; cur <= last_pos; cur++) { |  | ||||||
|            inr = ip + cur; |  | ||||||
|  |  | ||||||
|            if (opt[cur-1].mlen == 1) { |  | ||||||
|                 litlen = opt[cur-1].litlen + 1; |  | ||||||
|                 if (cur > litlen) { |  | ||||||
|                     price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen); |  | ||||||
|                 } else |  | ||||||
|                     price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor); |  | ||||||
|            } else { |  | ||||||
|                 litlen = 1; |  | ||||||
|                 price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1); |  | ||||||
|            } |  | ||||||
|  |  | ||||||
|            if (cur > last_pos || price <= opt[cur].price) |  | ||||||
|                 SET_PRICE(cur, 1, 0, litlen, price); |  | ||||||
|  |  | ||||||
|            if (cur == last_pos) break; |  | ||||||
|  |  | ||||||
|            if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */ |  | ||||||
|                continue; |  | ||||||
|  |  | ||||||
|            mlen = opt[cur].mlen; |  | ||||||
|            if (opt[cur].off > ZSTD_REP_MOVE_OPT) { |  | ||||||
|                 opt[cur].rep[2] = opt[cur-mlen].rep[1]; |  | ||||||
|                 opt[cur].rep[1] = opt[cur-mlen].rep[0]; |  | ||||||
|                 opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT; |  | ||||||
|            } else { |  | ||||||
|                 opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2]; |  | ||||||
|                 opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1]; |  | ||||||
|                 opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]); |  | ||||||
|            } |  | ||||||
|  |  | ||||||
|             best_mlen = minMatch; |  | ||||||
|             {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1); |  | ||||||
|                 for (i=(opt[cur].mlen != 1); i<last_i; i++) {  /* check rep */ |  | ||||||
|                     const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i]; |  | ||||||
|                     if ( (repCur > 0) && (repCur < (S32)(inr-prefixStart)) |  | ||||||
|                        && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) { |  | ||||||
|                        mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch; |  | ||||||
|  |  | ||||||
|                        if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { |  | ||||||
|                             best_mlen = mlen; best_off = i; last_pos = cur + 1; |  | ||||||
|                             goto _storeSequence; |  | ||||||
|                        } |  | ||||||
|  |  | ||||||
|                        best_off = i - (opt[cur].mlen != 1); |  | ||||||
|                        if (mlen > best_mlen) best_mlen = mlen; |  | ||||||
|  |  | ||||||
|                        do { |  | ||||||
|                            if (opt[cur].mlen == 1) { |  | ||||||
|                                 litlen = opt[cur].litlen; |  | ||||||
|                                 if (cur > litlen) { |  | ||||||
|                                     price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra); |  | ||||||
|                                 } else |  | ||||||
|                                     price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra); |  | ||||||
|                             } else { |  | ||||||
|                                 litlen = 0; |  | ||||||
|                                 price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra); |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                             if (cur + mlen > last_pos || price <= opt[cur + mlen].price) |  | ||||||
|                                 SET_PRICE(cur + mlen, mlen, i, litlen, price); |  | ||||||
|                             mlen--; |  | ||||||
|                         } while (mlen >= minMatch); |  | ||||||
|             }   }   } |  | ||||||
|  |  | ||||||
|             match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen); |  | ||||||
|  |  | ||||||
|             if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) { |  | ||||||
|                 best_mlen = matches[match_num-1].len; |  | ||||||
|                 best_off = matches[match_num-1].off; |  | ||||||
|                 last_pos = cur + 1; |  | ||||||
|                 goto _storeSequence; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             /* set prices using matches at position = cur */ |  | ||||||
|             for (u = 0; u < match_num; u++) { |  | ||||||
|                 mlen = (u>0) ? matches[u-1].len+1 : best_mlen; |  | ||||||
|                 best_mlen = matches[u].len; |  | ||||||
|  |  | ||||||
|                 while (mlen <= best_mlen) { |  | ||||||
|                     if (opt[cur].mlen == 1) { |  | ||||||
|                         litlen = opt[cur].litlen; |  | ||||||
|                         if (cur > litlen) |  | ||||||
|                             price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra); |  | ||||||
|                         else |  | ||||||
|                             price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra); |  | ||||||
|                     } else { |  | ||||||
|                         litlen = 0; |  | ||||||
|                         price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     if (cur + mlen > last_pos || (price < opt[cur + mlen].price)) |  | ||||||
|                         SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price); |  | ||||||
|  |  | ||||||
|                     mlen++; |  | ||||||
|         }   }   } |  | ||||||
|  |  | ||||||
|         best_mlen = opt[last_pos].mlen; |  | ||||||
|         best_off = opt[last_pos].off; |  | ||||||
|         cur = last_pos - best_mlen; |  | ||||||
|  |  | ||||||
|         /* store sequence */ |  | ||||||
| _storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */ |  | ||||||
|         opt[0].mlen = 1; |  | ||||||
|  |  | ||||||
|         while (1) { |  | ||||||
|             mlen = opt[cur].mlen; |  | ||||||
|             offset = opt[cur].off; |  | ||||||
|             opt[cur].mlen = best_mlen; |  | ||||||
|             opt[cur].off = best_off; |  | ||||||
|             best_mlen = mlen; |  | ||||||
|             best_off = offset; |  | ||||||
|             if (mlen > cur) break; |  | ||||||
|             cur -= mlen; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (u = 0; u <= last_pos;) { |  | ||||||
|             u += opt[u].mlen; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (cur=0; cur < last_pos; ) { |  | ||||||
|             mlen = opt[cur].mlen; |  | ||||||
|             if (mlen == 1) { ip++; cur++; continue; } |  | ||||||
|             offset = opt[cur].off; |  | ||||||
|             cur += mlen; |  | ||||||
|             litLength = (U32)(ip - anchor); |  | ||||||
|  |  | ||||||
|             if (offset > ZSTD_REP_MOVE_OPT) { |  | ||||||
|                 rep[2] = rep[1]; |  | ||||||
|                 rep[1] = rep[0]; |  | ||||||
|                 rep[0] = offset - ZSTD_REP_MOVE_OPT; |  | ||||||
|                 offset--; |  | ||||||
|             } else { |  | ||||||
|                 if (offset != 0) { |  | ||||||
|                     best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]); |  | ||||||
|                     if (offset != 1) rep[2] = rep[1]; |  | ||||||
|                     rep[1] = rep[0]; |  | ||||||
|                     rep[0] = best_off; |  | ||||||
|                 } |  | ||||||
|                 if (litLength==0) offset--; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH); |  | ||||||
|             ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); |  | ||||||
|             anchor = ip = ip + mlen; |  | ||||||
|     }    }   /* for (cur=0; cur < last_pos; ) */ |  | ||||||
|  |  | ||||||
|     /* Save reps for next block */ |  | ||||||
|     { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; } |  | ||||||
|  |  | ||||||
|     /* Last Literals */ |  | ||||||
|     {   size_t const lastLLSize = iend - anchor; |  | ||||||
|         memcpy(seqStorePtr->lit, anchor, lastLLSize); |  | ||||||
|         seqStorePtr->lit += lastLLSize; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| FORCE_INLINE_TEMPLATE |  | ||||||
| void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, |  | ||||||
|                                      const void* src, size_t srcSize, const int ultra) |  | ||||||
| { |  | ||||||
|     seqStore_t* seqStorePtr = &(ctx->seqStore); |  | ||||||
|     optState_t* optStatePtr = &(ctx->optState); |  | ||||||
|     const BYTE* const istart = (const BYTE*)src; |  | ||||||
|     const BYTE* ip = istart; |  | ||||||
|     const BYTE* anchor = istart; |  | ||||||
|     const BYTE* const iend = istart + srcSize; |  | ||||||
|     const BYTE* const ilimit = iend - 8; |  | ||||||
|     const BYTE* const base = ctx->base; |  | ||||||
|     const U32 lowestIndex = ctx->lowLimit; |  | ||||||
|     const U32 dictLimit = ctx->dictLimit; |  | ||||||
|     const BYTE* const prefixStart = base + dictLimit; |  | ||||||
|     const BYTE* const dictBase = ctx->dictBase; |  | ||||||
|     const BYTE* const dictEnd  = dictBase + dictLimit; |  | ||||||
|  |  | ||||||
|     const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog; |  | ||||||
|     const U32 sufficient_len = ctx->appliedParams.cParams.targetLength; |  | ||||||
|     const U32 mls = ctx->appliedParams.cParams.searchLength; |  | ||||||
|     const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4; |  | ||||||
|  |  | ||||||
|     ZSTD_optimal_t* opt = optStatePtr->priceTable; |  | ||||||
|     ZSTD_match_t* matches = optStatePtr->matchTable; |  | ||||||
|     const BYTE* inr; |  | ||||||
|  |  | ||||||
|     /* init */ |  | ||||||
|     U32 offset, rep[ZSTD_REP_NUM]; |  | ||||||
|     { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; } |  | ||||||
|  |  | ||||||
|     ctx->nextToUpdate3 = ctx->nextToUpdate; |  | ||||||
|     ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize); |  | ||||||
|     ip += (ip==prefixStart); |  | ||||||
|  |  | ||||||
|     /* Match Loop */ |  | ||||||
|     while (ip < ilimit) { |  | ||||||
|         U32 cur, match_num, last_pos, litlen, price; |  | ||||||
|         U32 u, mlen, best_mlen, best_off, litLength; |  | ||||||
|         U32 current = (U32)(ip-base); |  | ||||||
|         memset(opt, 0, sizeof(ZSTD_optimal_t)); |  | ||||||
|         last_pos = 0; |  | ||||||
|         opt[0].litlen = (U32)(ip - anchor); |  | ||||||
|  |  | ||||||
|         /* check repCode */ |  | ||||||
|         {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor); |  | ||||||
|             for (i = (ip==anchor); i<last_i; i++) { |  | ||||||
|                 const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i]; |  | ||||||
|                 const U32 repIndex = (U32)(current - repCur); |  | ||||||
|                 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; |  | ||||||
|                 const BYTE* const repMatch = repBase + repIndex; |  | ||||||
|                 if ( (repCur > 0 && repCur <= (S32)current) |  | ||||||
|                    && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */ |  | ||||||
|                    && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { |  | ||||||
|                     /* repcode detected we should take it */ |  | ||||||
|                     const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; |  | ||||||
|                     mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch; |  | ||||||
|  |  | ||||||
|                     if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { |  | ||||||
|                         best_mlen = mlen; best_off = i; cur = 0; last_pos = 1; |  | ||||||
|                         goto _storeSequence; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     best_off = i - (ip==anchor); |  | ||||||
|                     litlen = opt[0].litlen; |  | ||||||
|                     do { |  | ||||||
|                         price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra); |  | ||||||
|                         if (mlen > last_pos || price < opt[mlen].price) |  | ||||||
|                             SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */ |  | ||||||
|                         mlen--; |  | ||||||
|                     } while (mlen >= minMatch); |  | ||||||
|         }   }   } |  | ||||||
|  |  | ||||||
|         match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch);  /* first search (depth 0) */ |  | ||||||
|  |  | ||||||
|         if (!last_pos && !match_num) { ip++; continue; } |  | ||||||
|  |  | ||||||
|         { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; } |  | ||||||
|         opt[0].mlen = 1; |  | ||||||
|  |  | ||||||
|         if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) { |  | ||||||
|             best_mlen = matches[match_num-1].len; |  | ||||||
|             best_off = matches[match_num-1].off; |  | ||||||
|             cur = 0; |  | ||||||
|             last_pos = 1; |  | ||||||
|             goto _storeSequence; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         best_mlen = (last_pos) ? last_pos : minMatch; |  | ||||||
|  |  | ||||||
|         /* set prices using matches at position = 0 */ |  | ||||||
|         for (u = 0; u < match_num; u++) { |  | ||||||
|             mlen = (u>0) ? matches[u-1].len+1 : best_mlen; |  | ||||||
|             best_mlen = matches[u].len; |  | ||||||
|             litlen = opt[0].litlen; |  | ||||||
|             while (mlen <= best_mlen) { |  | ||||||
|                 price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra); |  | ||||||
|                 if (mlen > last_pos || price < opt[mlen].price) |  | ||||||
|                     SET_PRICE(mlen, mlen, matches[u].off, litlen, price); |  | ||||||
|                 mlen++; |  | ||||||
|         }   } |  | ||||||
|  |  | ||||||
|         if (last_pos < minMatch) { |  | ||||||
|             ip++; continue; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /* check further positions */ |  | ||||||
|         for (cur = 1; cur <= last_pos; cur++) { |  | ||||||
|             inr = ip + cur; |  | ||||||
|  |  | ||||||
|             if (opt[cur-1].mlen == 1) { |  | ||||||
|                 litlen = opt[cur-1].litlen + 1; |  | ||||||
|                 if (cur > litlen) { |  | ||||||
|                     price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen); |  | ||||||
|                 } else |  | ||||||
|                     price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor); |  | ||||||
|             } else { |  | ||||||
|                 litlen = 1; |  | ||||||
|                 price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (cur > last_pos || price <= opt[cur].price) |  | ||||||
|                 SET_PRICE(cur, 1, 0, litlen, price); |  | ||||||
|  |  | ||||||
|             if (cur == last_pos) break; |  | ||||||
|  |  | ||||||
|             if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */ |  | ||||||
|                 continue; |  | ||||||
|  |  | ||||||
|             mlen = opt[cur].mlen; |  | ||||||
|             if (opt[cur].off > ZSTD_REP_MOVE_OPT) { |  | ||||||
|                 opt[cur].rep[2] = opt[cur-mlen].rep[1]; |  | ||||||
|                 opt[cur].rep[1] = opt[cur-mlen].rep[0]; |  | ||||||
|                 opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT; |  | ||||||
|             } else { |  | ||||||
|                 opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2]; |  | ||||||
|                 opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1]; |  | ||||||
|                 opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             best_mlen = minMatch; |  | ||||||
|             {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1); |  | ||||||
|                 for (i = (mlen != 1); i<last_i; i++) { |  | ||||||
|                     const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i]; |  | ||||||
|                     const U32 repIndex = (U32)(current+cur - repCur); |  | ||||||
|                     const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; |  | ||||||
|                     const BYTE* const repMatch = repBase + repIndex; |  | ||||||
|                     if ( (repCur > 0 && repCur <= (S32)(current+cur)) |  | ||||||
|                       && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */ |  | ||||||
|                       && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { |  | ||||||
|                         /* repcode detected */ |  | ||||||
|                         const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; |  | ||||||
|                         mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch; |  | ||||||
|  |  | ||||||
|                         if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { |  | ||||||
|                             best_mlen = mlen; best_off = i; last_pos = cur + 1; |  | ||||||
|                             goto _storeSequence; |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                         best_off = i - (opt[cur].mlen != 1); |  | ||||||
|                         if (mlen > best_mlen) best_mlen = mlen; |  | ||||||
|  |  | ||||||
|                         do { |  | ||||||
|                             if (opt[cur].mlen == 1) { |  | ||||||
|                                 litlen = opt[cur].litlen; |  | ||||||
|                                 if (cur > litlen) { |  | ||||||
|                                     price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra); |  | ||||||
|                                 } else |  | ||||||
|                                     price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra); |  | ||||||
|                             } else { |  | ||||||
|                                 litlen = 0; |  | ||||||
|                                 price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra); |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                             if (cur + mlen > last_pos || price <= opt[cur + mlen].price) |  | ||||||
|                                 SET_PRICE(cur + mlen, mlen, i, litlen, price); |  | ||||||
|                             mlen--; |  | ||||||
|                         } while (mlen >= minMatch); |  | ||||||
|             }   }   } |  | ||||||
|  |  | ||||||
|             match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch); |  | ||||||
|  |  | ||||||
|             if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) { |  | ||||||
|                 best_mlen = matches[match_num-1].len; |  | ||||||
|                 best_off = matches[match_num-1].off; |  | ||||||
|                 last_pos = cur + 1; |  | ||||||
|                 goto _storeSequence; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             /* set prices using matches at position = cur */ |  | ||||||
|             for (u = 0; u < match_num; u++) { |  | ||||||
|                 mlen = (u>0) ? matches[u-1].len+1 : best_mlen; |  | ||||||
|                 best_mlen = matches[u].len; |  | ||||||
|  |  | ||||||
|                 while (mlen <= best_mlen) { |  | ||||||
|                     if (opt[cur].mlen == 1) { |  | ||||||
|                         litlen = opt[cur].litlen; |  | ||||||
|                         if (cur > litlen) |  | ||||||
|                             price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra); |  | ||||||
|                         else |  | ||||||
|                             price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra); |  | ||||||
|                     } else { |  | ||||||
|                         litlen = 0; |  | ||||||
|                         price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     if (cur + mlen > last_pos || (price < opt[cur + mlen].price)) |  | ||||||
|                         SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price); |  | ||||||
|  |  | ||||||
|                     mlen++; |  | ||||||
|         }   }   }   /* for (cur = 1; cur <= last_pos; cur++) */ |  | ||||||
|  |  | ||||||
|         best_mlen = opt[last_pos].mlen; |  | ||||||
|         best_off = opt[last_pos].off; |  | ||||||
|         cur = last_pos - best_mlen; |  | ||||||
|  |  | ||||||
|         /* store sequence */ |  | ||||||
| _storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */ |  | ||||||
|         opt[0].mlen = 1; |  | ||||||
|  |  | ||||||
|         while (1) { |  | ||||||
|             mlen = opt[cur].mlen; |  | ||||||
|             offset = opt[cur].off; |  | ||||||
|             opt[cur].mlen = best_mlen; |  | ||||||
|             opt[cur].off = best_off; |  | ||||||
|             best_mlen = mlen; |  | ||||||
|             best_off = offset; |  | ||||||
|             if (mlen > cur) break; |  | ||||||
|             cur -= mlen; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (u = 0; u <= last_pos; ) { |  | ||||||
|             u += opt[u].mlen; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (cur=0; cur < last_pos; ) { |  | ||||||
|             mlen = opt[cur].mlen; |  | ||||||
|             if (mlen == 1) { ip++; cur++; continue; } |  | ||||||
|             offset = opt[cur].off; |  | ||||||
|             cur += mlen; |  | ||||||
|             litLength = (U32)(ip - anchor); |  | ||||||
|  |  | ||||||
|             if (offset > ZSTD_REP_MOVE_OPT) { |  | ||||||
|                 rep[2] = rep[1]; |  | ||||||
|                 rep[1] = rep[0]; |  | ||||||
|                 rep[0] = offset - ZSTD_REP_MOVE_OPT; |  | ||||||
|                 offset--; |  | ||||||
|             } else { |  | ||||||
|                 if (offset != 0) { |  | ||||||
|                     best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]); |  | ||||||
|                     if (offset != 1) rep[2] = rep[1]; |  | ||||||
|                     rep[1] = rep[0]; |  | ||||||
|                     rep[0] = best_off; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (litLength==0) offset--; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH); |  | ||||||
|             ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); |  | ||||||
|             anchor = ip = ip + mlen; |  | ||||||
|     }    }   /* for (cur=0; cur < last_pos; ) */ |  | ||||||
|  |  | ||||||
|     /* Save reps for next block */ |  | ||||||
|     { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; } |  | ||||||
|  |  | ||||||
|     /* Last Literals */ |  | ||||||
|     {   size_t lastLLSize = iend - anchor; |  | ||||||
|         memcpy(seqStorePtr->lit, anchor, lastLLSize); |  | ||||||
|         seqStorePtr->lit += lastLLSize; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif  /* ZSTD_OPT_H_91842398743 */ |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user