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); }
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); }
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; } } } }