Example #1
0
        private static int FindMatchLength(Pointer p1, Pointer p2, int length)
        {
            int matched = 0;

            while (p2 <= length - 4 && p2.ToUInt32() == (p1 + matched).ToUInt32())
            {
                p2      += 4;
                matched += 4;
            }

            if (p2 <= length - 4)
            {
                var x            = p2.ToUInt32() ^ (p1 + matched).ToUInt32();
                var matchingBits = FindLSBSetNonZero(x);
                matched += matchingBits >> 3;
            }
            else
            {
                while ((p2 < length) && (p1[matched] == p2[0]))
                {
                    p2 += 1;
                    ++matched;
                }
            }

            return(matched);
        }
Example #2
0
        private static int CompressFragment(byte[] source, int length, HashTable hashTable, byte[] scratchOutput)
        {
            const int inputMarginBytes = 15;

            int shift    = 32 - Log2Floor(hashTable.Size);
            var op       = new Pointer(scratchOutput);
            var ip       = new Pointer(source);
            var nextEmit = new Pointer(source);
            var baseIp   = new Pointer(ip);

            Func <Pointer, int, uint> hashPtr = (value, offset) => (value.ToUInt32(offset) * 0x1e35a7bd) >> shift;

            if (length >= inputMarginBytes)
            {
                var ipLimit = length - inputMarginBytes;

                ip = ip + 1;
                var nextHash = hashPtr(ip, 0);
                while (true)
                {
                    uint skip = 32;

                    var     nextIp = new Pointer(ip);
                    Pointer candidate;
                    do
                    {
                        ip = nextIp;
                        uint hash = nextHash;
                        Debug.Assert(hash == hashPtr(ip, 0));

                        uint bytesBetweenHashLookups = skip++ >> 5;
                        nextIp = ip + bytesBetweenHashLookups;

                        if (nextIp > ipLimit)
                        {
                            goto emit_remainder;
                        }

                        nextHash  = hashPtr(nextIp, 0);
                        candidate = baseIp + hashTable[hash];

                        Debug.Assert(candidate >= baseIp);
                        Debug.Assert(candidate < ip);

                        hashTable[hash] = ip - baseIp;
                    } while (ip.ToUInt32() != candidate.ToUInt32());

                    Debug.Assert(nextEmit + 16 <= length);

                    op = EmitLiteral(op, nextEmit, ip - nextEmit, allowFastPath: true);

                    Pointer inputBytes;
                    uint    candidateBytes;

                    do
                    {
                        Pointer b       = ip;
                        int     matched = 4 + FindMatchLength(candidate + 4, ip + 4, length);
                        ip += matched;
                        var offset = b - candidate;

                        op = EmitCopy(op, offset, matched);

                        Pointer insertTail = ip - 1;
                        nextEmit = ip;

                        if (ip >= ipLimit)
                        {
                            goto emit_remainder;
                        }

                        inputBytes = insertTail;

                        var prevHash = hashPtr(inputBytes, 0);
                        hashTable[prevHash] = ip - baseIp - 1;

                        var curHash = hashPtr(inputBytes, 1);
                        candidate = baseIp + hashTable[curHash];

                        candidateBytes     = candidate.ToUInt32();
                        hashTable[curHash] = ip - baseIp;
                    } while (inputBytes.ToUInt32(1) == candidateBytes);

                    nextHash = hashPtr(inputBytes, 2);
                    ip       = ip + 1;
                }
            }

emit_remainder:
            if (nextEmit < length)
            {
                op = EmitLiteral(op, nextEmit, length - nextEmit, false);
            }

            return(op);
        }
Example #3
0
        private void DecompressAllTags()
        {
            Pointer ip = _ip;

            // We could have put this refill fragment only at the beginning of the loop.
            // However, duplicating it at the end of each branch gives the compiler more
            // scope to optimize the <ip_limit_ - ip> expression based on the local
            // context, which overall increases speed.
            Func <bool> maybeRefill = () =>
            {
                if (_ipLimit - ip < 5)
                {
                    _ip = ip;
                    if (!RefillTag())
                    {
                        return(false);
                    }

                    ip = _ip;
                }

                return(true);
            };

            if (!maybeRefill())
            {
                return;
            }

            for (; ;)
            {
                byte c = ip[0];
                ip = ip + 1;

                if ((c & 0x3) == CompressorTag.Literal)
                {
                    int literalLength = ((c >> 2) + 1);
                    if (_output.TryFastAppend(ip, _ipLimit - ip, literalLength))
                    {
                        Debug.Assert(literalLength < 61);
                        ip += literalLength;
                        if (!maybeRefill())
                        {
                            return;
                        }

                        continue;
                    }

                    if (literalLength >= 61)
                    {
                        int longLiteral = literalLength - 60;
                        literalLength = (int)((ip.ToUInt32() & Wordmask[longLiteral]) + 1);
                        ip           += longLiteral;
                    }

                    int avail = _ipLimit - ip;
                    while (avail < literalLength)
                    {
                        if (!_output.Append(ip, avail))
                        {
                            return;
                        }
                        literalLength -= avail;

                        Skip(_peeked);
                        int n;
                        ip      = Peek(out n);
                        avail   = n;
                        _peeked = avail;
                        if (avail == 0)
                        {
                            return; // Premature end of input
                        }
                        _ipLimit = ip + avail;
                    }
                    if (!_output.Append(ip, literalLength))
                    {
                        return;
                    }
                    ip += literalLength;
                    if (!maybeRefill())
                    {
                        return;
                    }
                }
                else
                {
                    int entry   = CharTable[c];
                    int trailer = (int)(ip.ToUInt32() & Wordmask[entry >> 11]);
                    int length  = entry & 0xff;
                    ip += entry >> 11;

                    // copy_offset/256 is encoded in bits 8..10.  By just fetching
                    // those bits, we get copy_offset (since the bit-field starts at
                    // bit 8).
                    int copyOffset = entry & 0x700;
                    if (!_output.AppendFromSelf(copyOffset + trailer, length))
                    {
                        return;
                    }
                    if (!maybeRefill())
                    {
                        return;
                    }
                }
            }
        }