Merge pull request #2483 from mpu/ldmgear
New algorithms for the long distance matcher
This commit is contained in:
commit
8884cb887d
@ -1628,7 +1628,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams);
|
ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams);
|
||||||
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
|
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
|
||||||
assert(params.ldmParams.hashRateLog < 32);
|
assert(params.ldmParams.hashRateLog < 32);
|
||||||
zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
|
{ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
|
||||||
|
@ -184,13 +184,22 @@ typedef struct {
|
|||||||
U32 checksum;
|
U32 checksum;
|
||||||
} ldmEntry_t;
|
} ldmEntry_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BYTE const* split;
|
||||||
|
U32 hash;
|
||||||
|
U32 checksum;
|
||||||
|
ldmEntry_t* bucket;
|
||||||
|
} ldmMatchCandidate_t;
|
||||||
|
|
||||||
|
#define LDM_BATCH_SIZE 64
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ZSTD_window_t window; /* State for the window round buffer management */
|
ZSTD_window_t window; /* State for the window round buffer management */
|
||||||
ldmEntry_t* hashTable;
|
ldmEntry_t* hashTable;
|
||||||
U32 loadedDictEnd;
|
U32 loadedDictEnd;
|
||||||
BYTE* bucketOffsets; /* Next position in bucket to insert entry */
|
BYTE* bucketOffsets; /* Next position in bucket to insert entry */
|
||||||
U64 hashPower; /* Used to compute the rolling hash.
|
size_t splitIndices[LDM_BATCH_SIZE];
|
||||||
* Depends on ldmParams.minMatchLength */
|
ldmMatchCandidate_t matchCandidates[LDM_BATCH_SIZE];
|
||||||
} ldmState_t;
|
} ldmState_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -11,13 +11,100 @@
|
|||||||
#include "zstd_ldm.h"
|
#include "zstd_ldm.h"
|
||||||
|
|
||||||
#include "../common/debug.h"
|
#include "../common/debug.h"
|
||||||
|
#include "../common/xxhash.h"
|
||||||
#include "zstd_fast.h" /* ZSTD_fillHashTable() */
|
#include "zstd_fast.h" /* ZSTD_fillHashTable() */
|
||||||
#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
|
#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
|
||||||
|
#include "zstd_ldm_geartab.h"
|
||||||
|
|
||||||
#define LDM_BUCKET_SIZE_LOG 3
|
#define LDM_BUCKET_SIZE_LOG 3
|
||||||
#define LDM_MIN_MATCH_LENGTH 64
|
#define LDM_MIN_MATCH_LENGTH 64
|
||||||
#define LDM_HASH_RLOG 7
|
#define LDM_HASH_RLOG 7
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U64 rolling;
|
||||||
|
U64 stopMask;
|
||||||
|
} ldmRollingHashState_t;
|
||||||
|
|
||||||
|
/** ZSTD_ldm_gear_init():
|
||||||
|
*
|
||||||
|
* Initializes the rolling hash state such that it will honor the
|
||||||
|
* settings in params. */
|
||||||
|
static void ZSTD_ldm_gear_init(ldmRollingHashState_t* state, ldmParams_t const* params)
|
||||||
|
{
|
||||||
|
unsigned maxBitsInMask = MIN(params->minMatchLength, 64);
|
||||||
|
unsigned hashRateLog = params->hashRateLog;
|
||||||
|
|
||||||
|
state->rolling = ~(U32)0;
|
||||||
|
|
||||||
|
/* The choice of the splitting criterion is subject to two conditions:
|
||||||
|
* 1. it has to trigger on average every 2^(hashRateLog) bytes;
|
||||||
|
* 2. ideally, it has to depend on a window of minMatchLength bytes.
|
||||||
|
*
|
||||||
|
* In the gear hash algorithm, bit n depends on the last n bytes;
|
||||||
|
* so in order to obtain a good quality splitting criterion it is
|
||||||
|
* preferable to use bits with high weight.
|
||||||
|
*
|
||||||
|
* To match condition 1 we use a mask with hashRateLog bits set
|
||||||
|
* and, because of the previous remark, we make sure these bits
|
||||||
|
* have the highest possible weight while still respecting
|
||||||
|
* condition 2.
|
||||||
|
*/
|
||||||
|
if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) {
|
||||||
|
state->stopMask = (((U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog);
|
||||||
|
} else {
|
||||||
|
/* In this degenerate case we simply honor the hash rate. */
|
||||||
|
state->stopMask = ((U64)1 << hashRateLog) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ZSTD_ldm_gear_feed():
|
||||||
|
*
|
||||||
|
* Registers in the splits array all the split points found in the first
|
||||||
|
* size bytes following the data pointer. This function terminates when
|
||||||
|
* either all the data has been processed or LDM_BATCH_SIZE splits are
|
||||||
|
* present in the splits array.
|
||||||
|
*
|
||||||
|
* Precondition: The splits array must not be full.
|
||||||
|
* Returns: The number of bytes processed. */
|
||||||
|
static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state,
|
||||||
|
BYTE const* data, size_t size,
|
||||||
|
size_t* splits, unsigned* numSplits)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
U64 hash, mask;
|
||||||
|
|
||||||
|
hash = state->rolling;
|
||||||
|
mask = state->stopMask;
|
||||||
|
n = 0;
|
||||||
|
|
||||||
|
#define GEAR_ITER_ONCE() do { \
|
||||||
|
hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \
|
||||||
|
n += 1; \
|
||||||
|
if (UNLIKELY((hash & mask) == 0)) { \
|
||||||
|
splits[*numSplits] = n; \
|
||||||
|
*numSplits += 1; \
|
||||||
|
if (*numSplits == LDM_BATCH_SIZE) \
|
||||||
|
goto done; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
while (n + 3 < size) {
|
||||||
|
GEAR_ITER_ONCE();
|
||||||
|
GEAR_ITER_ONCE();
|
||||||
|
GEAR_ITER_ONCE();
|
||||||
|
GEAR_ITER_ONCE();
|
||||||
|
}
|
||||||
|
while (n < size) {
|
||||||
|
GEAR_ITER_ONCE();
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef GEAR_ITER_ONCE
|
||||||
|
|
||||||
|
done:
|
||||||
|
state->rolling = hash;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
||||||
ZSTD_compressionParameters const* cParams)
|
ZSTD_compressionParameters const* cParams)
|
||||||
{
|
{
|
||||||
@ -53,38 +140,6 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
|
|||||||
return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
|
return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ZSTD_ldm_getSmallHash() :
|
|
||||||
* numBits should be <= 32
|
|
||||||
* If numBits==0, returns 0.
|
|
||||||
* @return : the most significant numBits of hash. */
|
|
||||||
static U32 ZSTD_ldm_getSmallHash(U64 hash, U32 numBits)
|
|
||||||
{
|
|
||||||
assert(numBits <= 32);
|
|
||||||
return numBits == 0 ? 0 : (U32)(hash >> (64 - numBits));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ZSTD_ldm_getChecksum() :
|
|
||||||
* numBitsToDiscard should be <= 32
|
|
||||||
* @return : the next most significant 32 bits after numBitsToDiscard */
|
|
||||||
static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
|
|
||||||
{
|
|
||||||
assert(numBitsToDiscard <= 32);
|
|
||||||
return (hash >> (64 - (32 + numBitsToDiscard))) & 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ZSTD_ldm_getTagMask() :
|
|
||||||
* Returns the mask against which the rolling hash must be
|
|
||||||
* checked. */
|
|
||||||
static U64 ZSTD_ldm_getTagMask(U32 hbits, U32 hashRateLog)
|
|
||||||
{
|
|
||||||
assert(hashRateLog < 32 && hbits <= 32);
|
|
||||||
if (32 - hbits < hashRateLog) {
|
|
||||||
return (((U64)1 << hashRateLog) - 1);
|
|
||||||
} else {
|
|
||||||
return (((U64)1 << hashRateLog) - 1) << (32 - hbits - hashRateLog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ZSTD_ldm_getBucket() :
|
/** ZSTD_ldm_getBucket() :
|
||||||
* Returns a pointer to the start of the bucket associated with hash. */
|
* Returns a pointer to the start of the bucket associated with hash. */
|
||||||
static ldmEntry_t* ZSTD_ldm_getBucket(
|
static ldmEntry_t* ZSTD_ldm_getBucket(
|
||||||
@ -107,33 +162,6 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ZSTD_ldm_makeEntryAndInsertByTag() :
|
|
||||||
*
|
|
||||||
* Gets the small hash, checksum, and tag from the rollingHash.
|
|
||||||
*
|
|
||||||
* If the tag matches (1 << ldmParams.hashRateLog)-1, then
|
|
||||||
* creates an ldmEntry from the offset, and inserts it into the hash table.
|
|
||||||
*
|
|
||||||
* hBits is the length of the small hash, which is the most significant hBits
|
|
||||||
* of rollingHash. The checksum is the next 32 most significant bits, followed
|
|
||||||
* by ldmParams.hashRateLog bits that make up the tag. */
|
|
||||||
static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
|
|
||||||
U64 const rollingHash,
|
|
||||||
U32 const hBits,
|
|
||||||
U32 const offset,
|
|
||||||
ldmParams_t const ldmParams)
|
|
||||||
{
|
|
||||||
U64 const tagMask = ZSTD_ldm_getTagMask(hBits, ldmParams.hashRateLog);
|
|
||||||
if ((rollingHash & tagMask) == tagMask) {
|
|
||||||
U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
|
|
||||||
U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
|
|
||||||
ldmEntry_t entry;
|
|
||||||
entry.offset = offset;
|
|
||||||
entry.checksum = checksum;
|
|
||||||
ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ZSTD_ldm_countBackwardsMatch() :
|
/** ZSTD_ldm_countBackwardsMatch() :
|
||||||
* Returns the number of bytes that match backwards before pIn and pMatch.
|
* Returns the number of bytes that match backwards before pIn and pMatch.
|
||||||
*
|
*
|
||||||
@ -209,43 +237,42 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ZSTD_ldm_fillLdmHashTable() :
|
|
||||||
*
|
|
||||||
* Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
|
|
||||||
* lastHash is the rolling hash that corresponds to lastHashed.
|
|
||||||
*
|
|
||||||
* Returns the rolling hash corresponding to position iend-1. */
|
|
||||||
static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
|
|
||||||
U64 lastHash, const BYTE* lastHashed,
|
|
||||||
const BYTE* iend, const BYTE* base,
|
|
||||||
U32 hBits, ldmParams_t const ldmParams)
|
|
||||||
{
|
|
||||||
U64 rollingHash = lastHash;
|
|
||||||
const BYTE* cur = lastHashed + 1;
|
|
||||||
|
|
||||||
while (cur < iend) {
|
|
||||||
rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
|
|
||||||
cur[ldmParams.minMatchLength-1],
|
|
||||||
state->hashPower);
|
|
||||||
ZSTD_ldm_makeEntryAndInsertByTag(state,
|
|
||||||
rollingHash, hBits,
|
|
||||||
(U32)(cur - base), ldmParams);
|
|
||||||
++cur;
|
|
||||||
}
|
|
||||||
return rollingHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZSTD_ldm_fillHashTable(
|
void ZSTD_ldm_fillHashTable(
|
||||||
ldmState_t* state, const BYTE* ip,
|
ldmState_t* ldmState, const BYTE* ip,
|
||||||
const BYTE* iend, ldmParams_t const* params)
|
const BYTE* iend, ldmParams_t const* params)
|
||||||
{
|
{
|
||||||
|
U32 const minMatchLength = params->minMatchLength;
|
||||||
|
U32 const hBits = params->hashLog - params->bucketSizeLog;
|
||||||
|
BYTE const* const base = ldmState->window.base;
|
||||||
|
BYTE const* const istart = ip;
|
||||||
|
ldmRollingHashState_t hashState;
|
||||||
|
size_t* const splits = ldmState->splitIndices;
|
||||||
|
unsigned numSplits;
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTD_ldm_fillHashTable");
|
DEBUGLOG(5, "ZSTD_ldm_fillHashTable");
|
||||||
if ((size_t)(iend - ip) >= params->minMatchLength) {
|
|
||||||
U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength);
|
ZSTD_ldm_gear_init(&hashState, params);
|
||||||
ZSTD_ldm_fillLdmHashTable(
|
while (ip < iend) {
|
||||||
state, startingHash, ip, iend - params->minMatchLength, state->window.base,
|
size_t hashed;
|
||||||
params->hashLog - params->bucketSizeLog,
|
unsigned n;
|
||||||
*params);
|
|
||||||
|
numSplits = 0;
|
||||||
|
hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits);
|
||||||
|
|
||||||
|
for (n = 0; n < numSplits; n++) {
|
||||||
|
if (ip + splits[n] >= istart + minMatchLength) {
|
||||||
|
BYTE const* const split = ip + splits[n] - minMatchLength;
|
||||||
|
U64 const xxhash = XXH64(split, minMatchLength, 0);
|
||||||
|
U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1));
|
||||||
|
ldmEntry_t entry;
|
||||||
|
|
||||||
|
entry.offset = (U32)(split - base);
|
||||||
|
entry.checksum = (U32)(xxhash >> 32);
|
||||||
|
ZSTD_ldm_insertEntry(ldmState, hash, entry, *params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ip += hashed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,10 +298,8 @@ static size_t ZSTD_ldm_generateSequences_internal(
|
|||||||
/* LDM parameters */
|
/* LDM parameters */
|
||||||
int const extDict = ZSTD_window_hasExtDict(ldmState->window);
|
int const extDict = ZSTD_window_hasExtDict(ldmState->window);
|
||||||
U32 const minMatchLength = params->minMatchLength;
|
U32 const minMatchLength = params->minMatchLength;
|
||||||
U64 const hashPower = ldmState->hashPower;
|
|
||||||
U32 const hBits = params->hashLog - params->bucketSizeLog;
|
|
||||||
U32 const entsPerBucket = 1U << params->bucketSizeLog;
|
U32 const entsPerBucket = 1U << params->bucketSizeLog;
|
||||||
U64 const tagMask = ZSTD_ldm_getTagMask(hBits, params->hashRateLog);
|
U32 const hBits = params->hashLog - params->bucketSizeLog;
|
||||||
/* Prefix and extDict parameters */
|
/* Prefix and extDict parameters */
|
||||||
U32 const dictLimit = ldmState->window.dictLimit;
|
U32 const dictLimit = ldmState->window.dictLimit;
|
||||||
U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
|
U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
|
||||||
@ -286,50 +311,76 @@ static size_t ZSTD_ldm_generateSequences_internal(
|
|||||||
/* Input bounds */
|
/* Input bounds */
|
||||||
BYTE const* const istart = (BYTE const*)src;
|
BYTE const* const istart = (BYTE const*)src;
|
||||||
BYTE const* const iend = istart + srcSize;
|
BYTE const* const iend = istart + srcSize;
|
||||||
BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
|
BYTE const* const ilimit = iend - HASH_READ_SIZE;
|
||||||
/* Input positions */
|
/* Input positions */
|
||||||
BYTE const* anchor = istart;
|
BYTE const* anchor = istart;
|
||||||
BYTE const* ip = istart;
|
BYTE const* ip = istart;
|
||||||
/* Rolling hash */
|
/* Rolling hash state */
|
||||||
BYTE const* lastHashed = NULL;
|
ldmRollingHashState_t hashState;
|
||||||
U64 rollingHash = 0;
|
/* Arrays for staged-processing */
|
||||||
|
size_t* const splits = ldmState->splitIndices;
|
||||||
|
ldmMatchCandidate_t* const candidates = ldmState->matchCandidates;
|
||||||
|
unsigned numSplits;
|
||||||
|
|
||||||
while (ip <= ilimit) {
|
if (srcSize < minMatchLength)
|
||||||
U32 const currentIndex = (U32)(ip - base);
|
return iend - anchor;
|
||||||
U32 hash, checksum;
|
|
||||||
size_t mLength;
|
|
||||||
size_t forwardMatchLength = 0, backwardMatchLength = 0;
|
|
||||||
ldmEntry_t const* bestEntry = NULL;
|
|
||||||
ldmEntry_t newEntry;
|
|
||||||
|
|
||||||
if (ip != istart) {
|
/* Initialize the rolling hash state with the first minMatchLength bytes */
|
||||||
rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
|
ZSTD_ldm_gear_init(&hashState, params);
|
||||||
lastHashed[minMatchLength],
|
{
|
||||||
hashPower);
|
size_t n = 0;
|
||||||
} else {
|
|
||||||
rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
|
while (n < minMatchLength) {
|
||||||
|
numSplits = 0;
|
||||||
|
n += ZSTD_ldm_gear_feed(&hashState, ip + n, minMatchLength - n,
|
||||||
|
splits, &numSplits);
|
||||||
}
|
}
|
||||||
lastHashed = ip;
|
ip += minMatchLength;
|
||||||
|
}
|
||||||
|
|
||||||
/* Do not insert and do not look for a match */
|
while (ip < ilimit) {
|
||||||
if ((rollingHash & tagMask) != tagMask) {
|
size_t hashed;
|
||||||
ip++;
|
unsigned n;
|
||||||
continue;
|
|
||||||
|
numSplits = 0;
|
||||||
|
hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip,
|
||||||
|
splits, &numSplits);
|
||||||
|
|
||||||
|
for (n = 0; n < numSplits; n++) {
|
||||||
|
BYTE const* const split = ip + splits[n] - minMatchLength;
|
||||||
|
U64 const xxhash = XXH64(split, minMatchLength, 0);
|
||||||
|
U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1));
|
||||||
|
|
||||||
|
candidates[n].split = split;
|
||||||
|
candidates[n].hash = hash;
|
||||||
|
candidates[n].checksum = (U32)(xxhash >> 32);
|
||||||
|
candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params);
|
||||||
|
PREFETCH_L1(candidates[n].bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
|
for (n = 0; n < numSplits; n++) {
|
||||||
checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
|
size_t forwardMatchLength = 0, backwardMatchLength = 0,
|
||||||
|
bestMatchLength = 0, mLength;
|
||||||
newEntry.offset = currentIndex;
|
BYTE const* const split = candidates[n].split;
|
||||||
newEntry.checksum = checksum;
|
U32 const checksum = candidates[n].checksum;
|
||||||
|
U32 const hash = candidates[n].hash;
|
||||||
/* Get the best entry and compute the match lengths */
|
ldmEntry_t* const bucket = candidates[n].bucket;
|
||||||
{
|
|
||||||
ldmEntry_t* const bucket = ZSTD_ldm_getBucket(ldmState, hash, *params);
|
|
||||||
ldmEntry_t const* cur;
|
ldmEntry_t const* cur;
|
||||||
size_t bestMatchLength = 0;
|
ldmEntry_t const* bestEntry = NULL;
|
||||||
|
ldmEntry_t newEntry;
|
||||||
|
|
||||||
for (cur = bucket; cur < bucket + entsPerBucket; ++cur) {
|
newEntry.offset = (U32)(split - base);
|
||||||
|
newEntry.checksum = checksum;
|
||||||
|
|
||||||
|
/* If a split point would generate a sequence overlapping with
|
||||||
|
* the previous one, we merely register it in the hash table and
|
||||||
|
* move on */
|
||||||
|
if (split < anchor) {
|
||||||
|
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cur = bucket; cur < bucket + entsPerBucket; cur++) {
|
||||||
size_t curForwardMatchLength, curBackwardMatchLength,
|
size_t curForwardMatchLength, curBackwardMatchLength,
|
||||||
curTotalMatchLength;
|
curTotalMatchLength;
|
||||||
if (cur->checksum != checksum || cur->offset <= lowestIndex) {
|
if (cur->checksum != checksum || cur->offset <= lowestIndex) {
|
||||||
@ -343,31 +394,23 @@ static size_t ZSTD_ldm_generateSequences_internal(
|
|||||||
cur->offset < dictLimit ? dictEnd : iend;
|
cur->offset < dictLimit ? dictEnd : iend;
|
||||||
BYTE const* const lowMatchPtr =
|
BYTE const* const lowMatchPtr =
|
||||||
cur->offset < dictLimit ? dictStart : lowPrefixPtr;
|
cur->offset < dictLimit ? dictStart : lowPrefixPtr;
|
||||||
|
curForwardMatchLength =
|
||||||
curForwardMatchLength = ZSTD_count_2segments(
|
ZSTD_count_2segments(split, pMatch, iend, matchEnd, lowPrefixPtr);
|
||||||
ip, pMatch, iend,
|
|
||||||
matchEnd, lowPrefixPtr);
|
|
||||||
if (curForwardMatchLength < minMatchLength) {
|
if (curForwardMatchLength < minMatchLength) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
curBackwardMatchLength =
|
curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments(
|
||||||
ZSTD_ldm_countBackwardsMatch_2segments(ip, anchor,
|
split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd);
|
||||||
pMatch, lowMatchPtr,
|
|
||||||
dictStart, dictEnd);
|
|
||||||
curTotalMatchLength = curForwardMatchLength +
|
|
||||||
curBackwardMatchLength;
|
|
||||||
} else { /* !extDict */
|
} else { /* !extDict */
|
||||||
BYTE const* const pMatch = base + cur->offset;
|
BYTE const* const pMatch = base + cur->offset;
|
||||||
curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
|
curForwardMatchLength = ZSTD_count(split, pMatch, iend);
|
||||||
if (curForwardMatchLength < minMatchLength) {
|
if (curForwardMatchLength < minMatchLength) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
curBackwardMatchLength =
|
curBackwardMatchLength =
|
||||||
ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
|
ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr);
|
||||||
lowPrefixPtr);
|
|
||||||
curTotalMatchLength = curForwardMatchLength +
|
|
||||||
curBackwardMatchLength;
|
|
||||||
}
|
}
|
||||||
|
curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength;
|
||||||
|
|
||||||
if (curTotalMatchLength > bestMatchLength) {
|
if (curTotalMatchLength > bestMatchLength) {
|
||||||
bestMatchLength = curTotalMatchLength;
|
bestMatchLength = curTotalMatchLength;
|
||||||
@ -376,54 +419,39 @@ static size_t ZSTD_ldm_generateSequences_internal(
|
|||||||
bestEntry = cur;
|
bestEntry = cur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* No match found -- continue searching */
|
/* No match found -- insert an entry into the hash table
|
||||||
if (bestEntry == NULL) {
|
* and process the next candidate match */
|
||||||
|
if (bestEntry == NULL) {
|
||||||
|
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Match found */
|
||||||
|
mLength = forwardMatchLength + backwardMatchLength;
|
||||||
|
{
|
||||||
|
U32 const offset = (U32)(split - base) - bestEntry->offset;
|
||||||
|
rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
|
||||||
|
|
||||||
|
/* Out of sequence storage */
|
||||||
|
if (rawSeqStore->size == rawSeqStore->capacity)
|
||||||
|
return ERROR(dstSize_tooSmall);
|
||||||
|
seq->litLength = (U32)(split - backwardMatchLength - anchor);
|
||||||
|
seq->matchLength = (U32)mLength;
|
||||||
|
seq->offset = offset;
|
||||||
|
rawSeqStore->size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert the current entry into the hash table --- it must be
|
||||||
|
* done after the previous block to avoid clobbering bestEntry */
|
||||||
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
|
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
|
||||||
ip++;
|
|
||||||
continue;
|
anchor = split + forwardMatchLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Match found */
|
ip += hashed;
|
||||||
mLength = forwardMatchLength + backwardMatchLength;
|
|
||||||
ip -= backwardMatchLength;
|
|
||||||
|
|
||||||
{
|
|
||||||
/* Store the sequence:
|
|
||||||
* ip = currentIndex - backwardMatchLength
|
|
||||||
* The match is at (bestEntry->offset - backwardMatchLength)
|
|
||||||
*/
|
|
||||||
U32 const matchIndex = bestEntry->offset;
|
|
||||||
U32 const offset = currentIndex - matchIndex;
|
|
||||||
rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
|
|
||||||
|
|
||||||
/* Out of sequence storage */
|
|
||||||
if (rawSeqStore->size == rawSeqStore->capacity)
|
|
||||||
return ERROR(dstSize_tooSmall);
|
|
||||||
seq->litLength = (U32)(ip - anchor);
|
|
||||||
seq->matchLength = (U32)mLength;
|
|
||||||
seq->offset = offset;
|
|
||||||
rawSeqStore->size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert the current entry into the hash table --- it must be
|
|
||||||
* done after the previous block to avoid clobbering bestEntry */
|
|
||||||
ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
|
|
||||||
|
|
||||||
assert(ip + backwardMatchLength == lastHashed);
|
|
||||||
|
|
||||||
/* Fill the hash table from lastHashed+1 to ip+mLength*/
|
|
||||||
/* Heuristic: don't need to fill the entire table at end of block */
|
|
||||||
if (ip + mLength <= ilimit) {
|
|
||||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
|
||||||
ldmState, rollingHash, lastHashed,
|
|
||||||
ip + mLength, base, hBits, *params);
|
|
||||||
lastHashed = ip + mLength - 1;
|
|
||||||
}
|
|
||||||
ip += mLength;
|
|
||||||
anchor = ip;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return iend - anchor;
|
return iend - anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
lib/compress/zstd_ldm_geartab.h
Normal file
103
lib/compress/zstd_ldm_geartab.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2021, 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).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_LDM_GEARTAB_H
|
||||||
|
#define ZSTD_LDM_GEARTAB_H
|
||||||
|
|
||||||
|
static U64 ZSTD_ldm_gearTab[256] = {
|
||||||
|
0xf5b8f72c5f77775c, 0x84935f266b7ac412, 0xb647ada9ca730ccc,
|
||||||
|
0xb065bb4b114fb1de, 0x34584e7e8c3a9fd0, 0x4e97e17c6ae26b05,
|
||||||
|
0x3a03d743bc99a604, 0xcecd042422c4044f, 0x76de76c58524259e,
|
||||||
|
0x9c8528f65badeaca, 0x86563706e2097529, 0x2902475fa375d889,
|
||||||
|
0xafb32a9739a5ebe6, 0xce2714da3883e639, 0x21eaf821722e69e,
|
||||||
|
0x37b628620b628, 0x49a8d455d88caf5, 0x8556d711e6958140,
|
||||||
|
0x4f7ae74fc605c1f, 0x829f0c3468bd3a20, 0x4ffdc885c625179e,
|
||||||
|
0x8473de048a3daf1b, 0x51008822b05646b2, 0x69d75d12b2d1cc5f,
|
||||||
|
0x8c9d4a19159154bc, 0xc3cc10f4abbd4003, 0xd06ddc1cecb97391,
|
||||||
|
0xbe48e6e7ed80302e, 0x3481db31cee03547, 0xacc3f67cdaa1d210,
|
||||||
|
0x65cb771d8c7f96cc, 0x8eb27177055723dd, 0xc789950d44cd94be,
|
||||||
|
0x934feadc3700b12b, 0x5e485f11edbdf182, 0x1e2e2a46fd64767a,
|
||||||
|
0x2969ca71d82efa7c, 0x9d46e9935ebbba2e, 0xe056b67e05e6822b,
|
||||||
|
0x94d73f55739d03a0, 0xcd7010bdb69b5a03, 0x455ef9fcd79b82f4,
|
||||||
|
0x869cb54a8749c161, 0x38d1a4fa6185d225, 0xb475166f94bbe9bb,
|
||||||
|
0xa4143548720959f1, 0x7aed4780ba6b26ba, 0xd0ce264439e02312,
|
||||||
|
0x84366d746078d508, 0xa8ce973c72ed17be, 0x21c323a29a430b01,
|
||||||
|
0x9962d617e3af80ee, 0xab0ce91d9c8cf75b, 0x530e8ee6d19a4dbc,
|
||||||
|
0x2ef68c0cf53f5d72, 0xc03a681640a85506, 0x496e4e9f9c310967,
|
||||||
|
0x78580472b59b14a0, 0x273824c23b388577, 0x66bf923ad45cb553,
|
||||||
|
0x47ae1a5a2492ba86, 0x35e304569e229659, 0x4765182a46870b6f,
|
||||||
|
0x6cbab625e9099412, 0xddac9a2e598522c1, 0x7172086e666624f2,
|
||||||
|
0xdf5003ca503b7837, 0x88c0c1db78563d09, 0x58d51865acfc289d,
|
||||||
|
0x177671aec65224f1, 0xfb79d8a241e967d7, 0x2be1e101cad9a49a,
|
||||||
|
0x6625682f6e29186b, 0x399553457ac06e50, 0x35dffb4c23abb74,
|
||||||
|
0x429db2591f54aade, 0xc52802a8037d1009, 0x6acb27381f0b25f3,
|
||||||
|
0xf45e2551ee4f823b, 0x8b0ea2d99580c2f7, 0x3bed519cbcb4e1e1,
|
||||||
|
0xff452823dbb010a, 0x9d42ed614f3dd267, 0x5b9313c06257c57b,
|
||||||
|
0xa114b8008b5e1442, 0xc1fe311c11c13d4b, 0x66e8763ea34c5568,
|
||||||
|
0x8b982af1c262f05d, 0xee8876faaa75fbb7, 0x8a62a4d0d172bb2a,
|
||||||
|
0xc13d94a3b7449a97, 0x6dbbba9dc15d037c, 0xc786101f1d92e0f1,
|
||||||
|
0xd78681a907a0b79b, 0xf61aaf2962c9abb9, 0x2cfd16fcd3cb7ad9,
|
||||||
|
0x868c5b6744624d21, 0x25e650899c74ddd7, 0xba042af4a7c37463,
|
||||||
|
0x4eb1a539465a3eca, 0xbe09dbf03b05d5ca, 0x774e5a362b5472ba,
|
||||||
|
0x47a1221229d183cd, 0x504b0ca18ef5a2df, 0xdffbdfbde2456eb9,
|
||||||
|
0x46cd2b2fbee34634, 0xf2aef8fe819d98c3, 0x357f5276d4599d61,
|
||||||
|
0x24a5483879c453e3, 0x88026889192b4b9, 0x28da96671782dbec,
|
||||||
|
0x4ef37c40588e9aaa, 0x8837b90651bc9fb3, 0xc164f741d3f0e5d6,
|
||||||
|
0xbc135a0a704b70ba, 0x69cd868f7622ada, 0xbc37ba89e0b9c0ab,
|
||||||
|
0x47c14a01323552f6, 0x4f00794bacee98bb, 0x7107de7d637a69d5,
|
||||||
|
0x88af793bb6f2255e, 0xf3c6466b8799b598, 0xc288c616aa7f3b59,
|
||||||
|
0x81ca63cf42fca3fd, 0x88d85ace36a2674b, 0xd056bd3792389e7,
|
||||||
|
0xe55c396c4e9dd32d, 0xbefb504571e6c0a6, 0x96ab32115e91e8cc,
|
||||||
|
0xbf8acb18de8f38d1, 0x66dae58801672606, 0x833b6017872317fb,
|
||||||
|
0xb87c16f2d1c92864, 0xdb766a74e58b669c, 0x89659f85c61417be,
|
||||||
|
0xc8daad856011ea0c, 0x76a4b565b6fe7eae, 0xa469d085f6237312,
|
||||||
|
0xaaf0365683a3e96c, 0x4dbb746f8424f7b8, 0x638755af4e4acc1,
|
||||||
|
0x3d7807f5bde64486, 0x17be6d8f5bbb7639, 0x903f0cd44dc35dc,
|
||||||
|
0x67b672eafdf1196c, 0xa676ff93ed4c82f1, 0x521d1004c5053d9d,
|
||||||
|
0x37ba9ad09ccc9202, 0x84e54d297aacfb51, 0xa0b4b776a143445,
|
||||||
|
0x820d471e20b348e, 0x1874383cb83d46dc, 0x97edeec7a1efe11c,
|
||||||
|
0xb330e50b1bdc42aa, 0x1dd91955ce70e032, 0xa514cdb88f2939d5,
|
||||||
|
0x2791233fd90db9d3, 0x7b670a4cc50f7a9b, 0x77c07d2a05c6dfa5,
|
||||||
|
0xe3778b6646d0a6fa, 0xb39c8eda47b56749, 0x933ed448addbef28,
|
||||||
|
0xaf846af6ab7d0bf4, 0xe5af208eb666e49, 0x5e6622f73534cd6a,
|
||||||
|
0x297daeca42ef5b6e, 0x862daef3d35539a6, 0xe68722498f8e1ea9,
|
||||||
|
0x981c53093dc0d572, 0xfa09b0bfbf86fbf5, 0x30b1e96166219f15,
|
||||||
|
0x70e7d466bdc4fb83, 0x5a66736e35f2a8e9, 0xcddb59d2b7c1baef,
|
||||||
|
0xd6c7d247d26d8996, 0xea4e39eac8de1ba3, 0x539c8bb19fa3aff2,
|
||||||
|
0x9f90e4c5fd508d8, 0xa34e5956fbaf3385, 0x2e2f8e151d3ef375,
|
||||||
|
0x173691e9b83faec1, 0xb85a8d56bf016379, 0x8382381267408ae3,
|
||||||
|
0xb90f901bbdc0096d, 0x7c6ad32933bcec65, 0x76bb5e2f2c8ad595,
|
||||||
|
0x390f851a6cf46d28, 0xc3e6064da1c2da72, 0xc52a0c101cfa5389,
|
||||||
|
0xd78eaf84a3fbc530, 0x3781b9e2288b997e, 0x73c2f6dea83d05c4,
|
||||||
|
0x4228e364c5b5ed7, 0x9d7a3edf0da43911, 0x8edcfeda24686756,
|
||||||
|
0x5e7667a7b7a9b3a1, 0x4c4f389fa143791d, 0xb08bc1023da7cddc,
|
||||||
|
0x7ab4be3ae529b1cc, 0x754e6132dbe74ff9, 0x71635442a839df45,
|
||||||
|
0x2f6fb1643fbe52de, 0x961e0a42cf7a8177, 0xf3b45d83d89ef2ea,
|
||||||
|
0xee3de4cf4a6e3e9b, 0xcd6848542c3295e7, 0xe4cee1664c78662f,
|
||||||
|
0x9947548b474c68c4, 0x25d73777a5ed8b0b, 0xc915b1d636b7fc,
|
||||||
|
0x21c2ba75d9b0d2da, 0x5f6b5dcf608a64a1, 0xdcf333255ff9570c,
|
||||||
|
0x633b922418ced4ee, 0xc136dde0b004b34a, 0x58cc83b05d4b2f5a,
|
||||||
|
0x5eb424dda28e42d2, 0x62df47369739cd98, 0xb4e0b42485e4ce17,
|
||||||
|
0x16e1f0c1f9a8d1e7, 0x8ec3916707560ebf, 0x62ba6e2df2cc9db3,
|
||||||
|
0xcbf9f4ff77d83a16, 0x78d9d7d07d2bbcc4, 0xef554ce1e02c41f4,
|
||||||
|
0x8d7581127eccf94d, 0xa9b53336cb3c8a05, 0x38c42c0bf45c4f91,
|
||||||
|
0x640893cdf4488863, 0x80ec34bc575ea568, 0x39f324f5b48eaa40,
|
||||||
|
0xe9d9ed1f8eff527f, 0x9224fc058cc5a214, 0xbaba00b04cfe7741,
|
||||||
|
0x309a9f120fcf52af, 0xa558f3ec65626212, 0x424bec8b7adabe2f,
|
||||||
|
0x41622513a6aea433, 0xb88da2d5324ca798, 0xd287733b245528a4,
|
||||||
|
0x9a44697e6d68aec3, 0x7b1093be2f49bb28, 0x50bbec632e3d8aad,
|
||||||
|
0x6cd90723e1ea8283, 0x897b9e7431b02bf3, 0x219efdcb338a7047,
|
||||||
|
0x3b0311f0a27c0656, 0xdb17bf91c0db96e7, 0x8cd4fd6b4e85a5b2,
|
||||||
|
0xfab071054ba6409d, 0x40d6fe831fa9dfd9, 0xaf358debad7d791e,
|
||||||
|
0xeb8d0e25a65e3e58, 0xbbcbd3df14e08580, 0xcf751f27ecdab2b,
|
||||||
|
0x2b4da14f2613d8f4
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ZSTD_LDM_GEARTAB_H */
|
@ -472,8 +472,6 @@ ZSTDMT_serialState_reset(serialState_t* serialState,
|
|||||||
ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams);
|
ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams);
|
||||||
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
|
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
|
||||||
assert(params.ldmParams.hashRateLog < 32);
|
assert(params.ldmParams.hashRateLog < 32);
|
||||||
serialState->ldmState.hashPower =
|
|
||||||
ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
|
|
||||||
} else {
|
} else {
|
||||||
ZSTD_memset(¶ms.ldmParams, 0, sizeof(params.ldmParams));
|
ZSTD_memset(¶ms.ldmParams, 0, sizeof(params.ldmParams));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user