void ZSTD_compressBlock_opt_extDict_generic()

in lib/zstd/zstd_opt.h [690:1002]


void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const int ultra)
{
	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 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->params.cParams.searchLog;
	const U32 sufficient_len = ctx->params.cParams.targetLength;
	const U32 mls = ctx->params.cParams.searchLength;
	const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4;

	ZSTD_optimal_t *opt = seqStorePtr->priceTable;
	ZSTD_match_t *matches = seqStorePtr->matchTable;
	const BYTE *inr;

	/* init */
	U32 offset, rep[ZSTD_REP_NUM];
	{
		U32 i;
		for (i = 0; i < ZSTD_REP_NUM; i++)
			rep[i] = ctx->rep[i];
	}

	ctx->nextToUpdate3 = ctx->nextToUpdate;
	ZSTD_rescaleFreqs(seqStorePtr, (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 curr = (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)(curr - repCur);
				const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
				const BYTE *const repMatch = repBase + repIndex;
				if ((repCur > 0 && repCur <= (S32)curr) &&
				    (((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(seqStorePtr, 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(seqStorePtr, 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(seqStorePtr, litlen, inr - litlen);
				} else
					price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor);
			} else {
				litlen = 1;
				price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, 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)(curr + cur - repCur);
					const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
					const BYTE *const repMatch = repBase + repIndex;
					if ((repCur > 0 && repCur <= (S32)(curr + 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(seqStorePtr, litlen, inr - litlen,
															best_off, mlen - MINMATCH, ultra);
								} else
									price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
							} else {
								litlen = 0;
								price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 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(seqStorePtr, litlen, ip + cur - litlen,
													matches[u].off - 1, mlen - MINMATCH, ultra);
						else
							price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
					} else {
						litlen = 0;
						price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 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(seqStorePtr, 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++)
			ctx->repToConfirm[i] = rep[i];
	}

	/* Last Literals */
	{
		size_t lastLLSize = iend - anchor;
		memcpy(seqStorePtr->lit, anchor, lastLLSize);
		seqStorePtr->lit += lastLLSize;
	}
}