FORCE_INLINE int LZ4_compress_generic()

in lib/lz4/lz4.cc [485:695]


FORCE_INLINE int LZ4_compress_generic(void *const ctx, const char *const source, char *const dest,
                                      const int inputSize, const int maxOutputSize,
                                      const limitedOutput_directive outputLimited,
                                      const tableType_t tableType, const dict_directive dict,
                                      const dictIssue_directive dictIssue, const U32 acceleration) {
    LZ4_stream_t_internal *const dictPtr = (LZ4_stream_t_internal *)ctx;

    const BYTE *ip = (const BYTE *)source;
    const BYTE *base;
    const BYTE *lowLimit;
    const BYTE *const lowRefLimit = ip - dictPtr->dictSize;
    const BYTE *const dictionary = dictPtr->dictionary;
    const BYTE *const dictEnd = dictionary + dictPtr->dictSize;
    const size_t dictDelta = dictEnd - (const BYTE *)source;
    const BYTE *anchor = (const BYTE *)source;
    const BYTE *const iend = ip + inputSize;
    const BYTE *const mflimit = iend - MFLIMIT;
    const BYTE *const matchlimit = iend - LASTLITERALS;

    BYTE *op = (BYTE *)dest;
    BYTE *const olimit = op + maxOutputSize;

    U32 forwardH;
    size_t refDelta = 0;

    /* Init conditions */
    if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE)
        return 0; /* Unsupported input size, too large (or negative) */
    switch (dict) {
        case noDict:
        default:
            base = (const BYTE *)source;
            lowLimit = (const BYTE *)source;
            break;
        case withPrefix64k:
            base = (const BYTE *)source - dictPtr->currentOffset;
            lowLimit = (const BYTE *)source - dictPtr->dictSize;
            break;
        case usingExtDict:
            base = (const BYTE *)source - dictPtr->currentOffset;
            lowLimit = (const BYTE *)source;
            break;
    }
    if ((tableType == byU16) && (inputSize >= LZ4_64Klimit))
        return 0;                                       /* Size too large (not within 64K limit) */
    if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */

    /* First Byte */
    LZ4_putPosition(ip, ctx, tableType, base);
    ip++;
    forwardH = LZ4_hashPosition(ip, tableType);

    /* Main Loop */
    for (;;) {
        const BYTE *match;
        BYTE *token;
        {
            const BYTE *forwardIp = ip;
            unsigned step = 1;
            unsigned searchMatchNb = acceleration << LZ4_skipTrigger;

            /* Find a match */
            do {
                U32 h = forwardH;
                ip = forwardIp;
                forwardIp += step;
                step = (searchMatchNb++ >> LZ4_skipTrigger);

                if (unlikely(forwardIp > mflimit)) goto _last_literals;

                match = LZ4_getPositionOnHash(h, ctx, tableType, base);
                if (dict == usingExtDict) {
                    if (match < (const BYTE *)source) {
                        refDelta = dictDelta;
                        lowLimit = dictionary;
                    } else {
                        refDelta = 0;
                        lowLimit = (const BYTE *)source;
                    }
                }
                forwardH = LZ4_hashPosition(forwardIp, tableType);
                LZ4_putPositionOnHash(ip, h, ctx, tableType, base);

            } while (((dictIssue == dictSmall) ? (match < lowRefLimit) : 0) ||
                     ((tableType == byU16) ? 0 : (match + MAX_DISTANCE < ip)) ||
                     (LZ4_read32(match + refDelta) != LZ4_read32(ip)));
        }

        /* Catch up */
        while ((ip > anchor) && (match + refDelta > lowLimit) && (unlikely(ip[-1] == match[refDelta - 1]))) {
            ip--;
            match--;
        }

        {
            /* Encode Literal length */
            unsigned litLength = (unsigned)(ip - anchor);
            token = op++;
            if ((outputLimited) &&
                (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength / 255) > olimit)))
                return 0; /* Check output limit */
            if (litLength >= RUN_MASK) {
                int len = (int)litLength - RUN_MASK;
                *token = (RUN_MASK << ML_BITS);
                for (; len >= 255; len -= 255) *op++ = 255;
                *op++ = (BYTE)len;
            } else
                *token = (BYTE)(litLength << ML_BITS);

            /* Copy Literals */
            LZ4_wildCopy(op, anchor, op + litLength);
            op += litLength;
        }

    _next_match:
        /* Encode Offset */
        LZ4_writeLE16(op, (U16)(ip - match));
        op += 2;

        /* Encode MatchLength */
        {
            unsigned matchLength;

            if ((dict == usingExtDict) && (lowLimit == dictionary)) {
                const BYTE *limit;
                match += refDelta;
                limit = ip + (dictEnd - match);
                if (limit > matchlimit) limit = matchlimit;
                matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, limit);
                ip += MINMATCH + matchLength;
                if (ip == limit) {
                    unsigned more = LZ4_count(ip, (const BYTE *)source, matchlimit);
                    matchLength += more;
                    ip += more;
                }
            } else {
                matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit);
                ip += MINMATCH + matchLength;
            }

            if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength >> 8) > olimit)))
                return 0; /* Check output limit */
            if (matchLength >= ML_MASK) {
                *token += ML_MASK;
                matchLength -= ML_MASK;
                for (; matchLength >= 510; matchLength -= 510) {
                    *op++ = 255;
                    *op++ = 255;
                }
                if (matchLength >= 255) {
                    matchLength -= 255;
                    *op++ = 255;
                }
                *op++ = (BYTE)matchLength;
            } else
                *token += (BYTE)(matchLength);
        }

        anchor = ip;

        /* Test end of chunk */
        if (ip > mflimit) break;

        /* Fill table */
        LZ4_putPosition(ip - 2, ctx, tableType, base);

        /* Test next position */
        match = LZ4_getPosition(ip, ctx, tableType, base);
        if (dict == usingExtDict) {
            if (match < (const BYTE *)source) {
                refDelta = dictDelta;
                lowLimit = dictionary;
            } else {
                refDelta = 0;
                lowLimit = (const BYTE *)source;
            }
        }
        LZ4_putPosition(ip, ctx, tableType, base);
        if (((dictIssue == dictSmall) ? (match >= lowRefLimit) : 1) && (match + MAX_DISTANCE >= ip) &&
            (LZ4_read32(match + refDelta) == LZ4_read32(ip))) {
            token = op++;
            *token = 0;
            goto _next_match;
        }

        /* Prepare next loop */
        forwardH = LZ4_hashPosition(++ip, tableType);
    }

_last_literals:
    /* Encode Last Literals */
    {
        const size_t lastRun = (size_t)(iend - anchor);
        if ((outputLimited) &&
            ((op - (BYTE *)dest) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (U32)maxOutputSize))
            return 0; /* Check output limit */
        if (lastRun >= RUN_MASK) {
            size_t accumulator = lastRun - RUN_MASK;
            *op++ = RUN_MASK << ML_BITS;
            for (; accumulator >= 255; accumulator -= 255) *op++ = 255;
            *op++ = (BYTE)accumulator;
        } else {
            *op++ = (BYTE)(lastRun << ML_BITS);
        }
        memcpy(op, anchor, lastRun);
        op += lastRun;
    }

    /* End */
    return (int)(((char *)op) - dest);
}