private static int LZ4HC_CommonLength_32(LZ4HC_Data_Structure ctx, int p1, int p2) { int[] debruijn32 = DEBRUIJN_TABLE_32; byte[] src = ctx.src; int src_LASTLITERALS = ctx.src_LASTLITERALS; int p1t = p1; while (p1t < src_LASTLITERALS - (STEPSIZE_32 - 1)) { var diff = (int) Xor4(src, p2, p1t); if (diff == 0) { p1t += STEPSIZE_32; p2 += STEPSIZE_32; continue; } p1t += debruijn32[((uint) ((diff) & -(diff)) * 0x077CB531u) >> 27]; return (p1t - p1); } if ((p1t < (src_LASTLITERALS - 1)) && (Equal2(src, p2, p1t))) { p1t += 2; p2 += 2; } if ((p1t < src_LASTLITERALS) && (src[p2] == src[p1t])) { p1t++; } return (p1t - p1); }
private static int LZ4HC_CommonLength_32(LZ4HC_Data_Structure ctx, int p1, int p2) { var debruijn32 = DEBRUIJN_TABLE_32; var src = ctx.src; var src_LASTLITERALS = ctx.src_LASTLITERALS; var p1t = p1; while (p1t < src_LASTLITERALS - (STEPSIZE_32 - 1)) { var diff = (int)Xor4(src, p2, p1t); if (diff == 0) { p1t += STEPSIZE_32; p2 += STEPSIZE_32; continue; } p1t += debruijn32[((uint)((diff) & -(diff)) * 0x077CB531u) >> 27]; return(p1t - p1); } if ((p1t < (src_LASTLITERALS - 1)) && (Equal2(src, p2, p1t))) { p1t += 2; p2 += 2; } if ((p1t < src_LASTLITERALS) && (src[p2] == src[p1t])) { p1t++; } return(p1t - p1); }
private static int LZ4HC_CommonLength_64(LZ4HC_Data_Structure ctx, int p1, int p2) { int[] debruijn64 = DEBRUIJN_TABLE_64; byte[] src = ctx.src; int src_LASTLITERALS = ctx.src_LASTLITERALS; int p1t = p1; while (p1t < src_LASTLITERALS - (STEPSIZE_64 - 1)) { var diff = (long) Xor8(src, p2, p1t); if (diff == 0) { p1t += STEPSIZE_64; p2 += STEPSIZE_64; continue; } p1t += debruijn64[((ulong) ((diff) & -(diff)) * 0x0218A392CDABBD3FL) >> 58]; return (p1t - p1); } if ((p1t < (src_LASTLITERALS - 3)) && (Equal4(src, p2, p1t))) { p1t += 4; p2 += 4; } if ((p1t < (src_LASTLITERALS - 1)) && (Equal2(src, p2, p1t))) { p1t += 2; p2 += 2; } if ((p1t < src_LASTLITERALS) && (src[p2] == src[p1t])) { p1t++; } return (p1t - p1); }
// ReSharper restore InconsistentNaming private static LZ4HC_Data_Structure LZ4HC_Create(byte[] src, int src_0, int src_len, byte[] dst, int dst_0, int dst_len) { var hc4 = new LZ4HC_Data_Structure { src = src, src_base = src_0, src_end = src_0 + src_len, src_LASTLITERALS = (src_0 + src_len - LASTLITERALS), dst = dst, dst_base = dst_0, dst_len = dst_len, dst_end = dst_0 + dst_len, hashTable = new int[HASHHC_TABLESIZE], chainTable = new ushort[MAXD], nextToUpdate = src_0 + 1, }; var ct = hc4.chainTable; for (var i = ct.Length - 1; i >= 0; i--) { ct[i] = unchecked ((ushort)-1); } return(hc4); }
private static int LZ4HC_CommonLength_64(LZ4HC_Data_Structure ctx, int p1, int p2) { int[] debruijn64 = DEBRUIJN_TABLE_64; byte[] src = ctx.src; int src_LASTLITERALS = ctx.src_LASTLITERALS; int p1t = p1; while (p1t < src_LASTLITERALS - (STEPSIZE_64 - 1)) { var diff = (long)Xor8(src, p2, p1t); if (diff == 0) { p1t += STEPSIZE_64; p2 += STEPSIZE_64; continue; } p1t += debruijn64[((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL) >> 58]; return(p1t - p1); } if ((p1t < (src_LASTLITERALS - 3)) && (Equal4(src, p2, p1t))) { p1t += 4; p2 += 4; } if ((p1t < (src_LASTLITERALS - 1)) && (Equal2(src, p2, p1t))) { p1t += 2; p2 += 2; } if ((p1t < src_LASTLITERALS) && (src[p2] == src[p1t])) { p1t++; } return(p1t - p1); }
// Update chains up to ip (excluded) private static unsafe void LZ4HC_Insert_64(LZ4HC_Data_Structure hc4, byte* src_p) { fixed (ushort* chainTable = hc4.chainTable) fixed (int* hashTable = hc4.hashTable) { var src_base = hc4.src_base; while (hc4.nextToUpdate < src_p) { var p = hc4.nextToUpdate; var delta = (int)((p) - (hashTable[((((*(uint*)(p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base)); if (delta > MAX_DISTANCE) delta = MAX_DISTANCE; chainTable[((int)p) & MAXD_MASK] = (ushort)delta; hashTable[((((*(uint*)(p))) * 2654435761u) >> HASHHC_ADJUST)] = (int)(p - src_base); hc4.nextToUpdate++; } } }
// ReSharper restore InconsistentNaming private static unsafe LZ4HC_Data_Structure LZ4HC_Create(byte *src) { var hc4 = new LZ4HC_Data_Structure { hashTable = new int[HASHHC_TABLESIZE], chainTable = new ushort[MAXD] }; fixed(ushort *ct = &hc4.chainTable[0]) { BlockFill((byte *)ct, MAXD * sizeof(ushort), 0xFF); } hc4.src_base = src; hc4.nextToUpdate = src + 1; return(hc4); }
// Update chains up to ip (excluded) private static void LZ4HC_Insert_32(LZ4HC_Data_Structure ctx, int src_p) { var chainTable = ctx.chainTable; var hashTable = ctx.hashTable; var nextToUpdate = ctx.nextToUpdate; var src = ctx.src; var src_base = ctx.src_base; while (nextToUpdate < src_p) { var p = nextToUpdate; var delta = (p) - (hashTable[(((Peek4(src, p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); if (delta > MAX_DISTANCE) delta = MAX_DISTANCE; chainTable[(p) & MAXD_MASK] = (ushort)delta; hashTable[(((Peek4(src, p)) * 2654435761u) >> HASHHC_ADJUST)] = ((p) - src_base); nextToUpdate++; } ctx.nextToUpdate = nextToUpdate; }
// Update chains up to ip (excluded) private static unsafe void LZ4HC_Insert_64(LZ4HC_Data_Structure hc4, byte *src_p) { fixed(ushort *chainTable = hc4.chainTable) fixed(int *hashTable = hc4.hashTable) { var src_base = hc4.src_base; while (hc4.nextToUpdate < src_p) { var p = hc4.nextToUpdate; var delta = (int)((p) - (hashTable[((((*(uint *)(p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base)); if (delta > MAX_DISTANCE) { delta = MAX_DISTANCE; } chainTable[((int)p) & MAXD_MASK] = (ushort)delta; hashTable[((((*(uint *)(p))) * 2654435761u) >> HASHHC_ADJUST)] = (int)(p - src_base); hc4.nextToUpdate++; } } }
// Update chains up to ip (excluded) private static void LZ4HC_Insert_32(LZ4HC_Data_Structure ctx, int src_p) { var chainTable = ctx.chainTable; var hashTable = ctx.hashTable; var nextToUpdate = ctx.nextToUpdate; var src = ctx.src; var src_base = ctx.src_base; while (nextToUpdate < src_p) { var p = nextToUpdate; var delta = (p) - (hashTable[(((Peek4(src, p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); if (delta > MAX_DISTANCE) { delta = MAX_DISTANCE; } chainTable[(p) & MAXD_MASK] = (ushort)delta; hashTable[(((Peek4(src, p)) * 2654435761u) >> HASHHC_ADJUST)] = ((p) - src_base); nextToUpdate++; } ctx.nextToUpdate = nextToUpdate; }
private static int LZ4_compressHCCtx_32(LZ4HC_Data_Structure ctx) { var src = ctx.src; var dst = ctx.dst; var src_0 = ctx.src_base; var src_end = ctx.src_end; var dst_0 = ctx.dst_base; var dst_len = ctx.dst_len; var dst_end = ctx.dst_end; var src_p = src_0; var src_anchor = src_p; var src_mflimit = src_end - MFLIMIT; var dst_p = dst_0; var src_ref = 0; var start2 = 0; var ref2 = 0; var start3 = 0; var ref3 = 0; src_p++; // Main Loop while (src_p < src_mflimit) { var ml = LZ4HC_InsertAndFindBestMatch_32(ctx, src_p, ref src_ref); if (ml == 0) { src_p++; continue; } // saved, in case we would skip too much var start0 = src_p; var ref0 = src_ref; var ml0 = ml; _Search2: var ml2 = src_p + ml < src_mflimit ? LZ4HC_InsertAndGetWiderMatch_32(ctx, src_p + ml - 2, src_p + 1, ml, ref ref2, ref start2) : ml; if (ml2 == ml) // No better match { if (LZ4_encodeSequence_32(ctx, ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) { return(0); } continue; } if (start0 < src_p) { if (start2 < src_p + ml0) // empirical { src_p = start0; src_ref = ref0; ml = ml0; } } // Here, start0==ip if ((start2 - src_p) < 3) // First Match too small : removed { ml = ml2; src_p = start2; src_ref = ref2; goto _Search2; } _Search3: // Currently we have : // ml2 > ml1, and // ip1+3 <= ip2 (usually < ip1+ml1) if ((start2 - src_p) < OPTIMAL_ML) { var new_ml = ml; if (new_ml > OPTIMAL_ML) { new_ml = OPTIMAL_ML; } if (src_p + new_ml > start2 + ml2 - MINMATCH) { new_ml = (start2 - src_p) + ml2 - MINMATCH; } var correction = new_ml - (start2 - src_p); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } // Now, we have start2 = ip+new_ml, with new_ml=min(ml, OPTIMAL_ML=18) var ml3 = start2 + ml2 < src_mflimit ? LZ4HC_InsertAndGetWiderMatch_32(ctx, start2 + ml2 - 3, start2, ml2, ref ref3, ref start3) : ml2; if (ml3 == ml2) // No better match : 2 sequences to encode { // ip & ref are known; Now for ml if (start2 < src_p + ml) { ml = (start2 - src_p); } // Now, encode 2 sequences if (LZ4_encodeSequence_32(ctx, ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) { return(0); } src_p = start2; if (LZ4_encodeSequence_32(ctx, ref src_p, ref dst_p, ref src_anchor, ml2, ref2, dst_end) != 0) { return(0); } continue; } if (start3 < src_p + ml + 3) // Not enough space for match 2 : remove it { if (start3 >= (src_p + ml)) // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 { if (start2 < src_p + ml) { var correction = (src_p + ml - start2); start2 += correction; ref2 += correction; ml2 -= correction; if (ml2 < MINMATCH) { start2 = start3; ref2 = ref3; ml2 = ml3; } } if (LZ4_encodeSequence_32(ctx, ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) { return(0); } src_p = start3; src_ref = ref3; ml = ml3; start0 = start2; ref0 = ref2; ml0 = ml2; goto _Search2; } start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // OK, now we have 3 ascending matches; let's write at least the first one // ip & ref are known; Now for ml if (start2 < src_p + ml) { if ((start2 - src_p) < ML_MASK) { if (ml > OPTIMAL_ML) { ml = OPTIMAL_ML; } if (src_p + ml > start2 + ml2 - MINMATCH) { ml = (start2 - src_p) + ml2 - MINMATCH; } var correction = ml - (start2 - src_p); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } else { ml = (start2 - src_p); } } if (LZ4_encodeSequence_32(ctx, ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) { return(0); } src_p = start2; src_ref = ref2; ml = ml2; start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // Encode Last Literals { var lastRun = (src_end - src_anchor); if ((dst_p - dst_0) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (uint)dst_len) { return(0); // Check output limit } if (lastRun >= RUN_MASK) { dst[dst_p++] = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) { dst[dst_p++] = 255; } dst[dst_p++] = (byte)lastRun; } else { dst[dst_p++] = (byte)(lastRun << ML_BITS); } BlockCopy(src, src_anchor, dst, dst_p, src_end - src_anchor); dst_p += src_end - src_anchor; } // End return(dst_p - dst_0); }
private static unsafe int LZ4_compressHCCtx_64( LZ4HC_Data_Structure ctx, byte* src, byte* dst, int src_len, int dst_maxlen) { var src_p = src; var src_anchor = src_p; var src_end = src_p + src_len; var src_mflimit = src_end - MFLIMIT; var src_LASTLITERALS = (src_end - LASTLITERALS); var dst_p = dst; var dst_end = dst_p + dst_maxlen; byte* src_ref = null; byte* start2 = null; byte* ref2 = null; byte* start3 = null; byte* ref3 = null; src_p++; // Main Loop while (src_p < src_mflimit) { var ml = LZ4HC_InsertAndFindBestMatch_64(ctx, src_p, src_LASTLITERALS, ref src_ref); if (ml == 0) { src_p++; continue; } // saved, in case we would skip too much var start0 = src_p; var ref0 = src_ref; var ml0 = ml; _Search2: var ml2 = src_p + ml < src_mflimit ? LZ4HC_InsertAndGetWiderMatch_64(ctx, src_p + ml - 2, src_p + 1, src_LASTLITERALS, ml, ref ref2, ref start2) : ml; if (ml2 == ml) // No better match { if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) return 0; continue; } if (start0 < src_p && start2 < src_p + ml0) { src_p = start0; src_ref = ref0; ml = ml0; } // Here, start0==ip if ((start2 - src_p) < 3) // First Match too small : removed { ml = ml2; src_p = start2; src_ref = ref2; goto _Search2; } _Search3: // Currently we have : // ml2 > ml1, and // ip1+3 <= ip2 (usually < ip1+ml1) if ((start2 - src_p) < OPTIMAL_ML) { var new_ml = ml; if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML; if (src_p + new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - src_p) + ml2 - MINMATCH; var correction = new_ml - (int)(start2 - src_p); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } // Now, we have start2 = ip+new_ml, with new_ml=min(ml, OPTIMAL_ML=18) var ml3 = start2 + ml2 < src_mflimit ? LZ4HC_InsertAndGetWiderMatch_64(ctx, start2 + ml2 - 3, start2, src_LASTLITERALS, ml2, ref ref3, ref start3) : ml2; if (ml3 == ml2) // No better match : 2 sequences to encode { // ip & ref are known; Now for ml if (start2 < src_p + ml) ml = (int)(start2 - src_p); // Now, encode 2 sequences if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) return 0; src_p = start2; if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml2, ref2, dst_end) != 0) return 0; continue; } if (start3 < src_p + ml + 3) // Not enough space for match 2 : remove it { if (start3 >= src_p + ml) // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 { if (start2 < src_p + ml) { var correction = (int)(src_p + ml - start2); start2 += correction; ref2 += correction; ml2 -= correction; if (ml2 < MINMATCH) { start2 = start3; ref2 = ref3; ml2 = ml3; } } if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) return 0; src_p = start3; src_ref = ref3; ml = ml3; start0 = start2; ref0 = ref2; ml0 = ml2; goto _Search2; } start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // OK, now we have 3 ascending matches; let's write at least the first one // ip & ref are known; Now for ml if (start2 < src_p + ml) { if (start2 - src_p < ML_MASK) { if (ml > OPTIMAL_ML) ml = OPTIMAL_ML; if (src_p + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - src_p) + ml2 - MINMATCH; var correction = ml - (int)(start2 - src_p); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } else { ml = (int)(start2 - src_p); } } if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) return 0; src_p = start2; src_ref = ref2; ml = ml2; start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // Encode Last Literals var lastRun = (int)(src_end - src_anchor); if ((dst_p - dst) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (uint)dst_maxlen) return 0; // Check output limit if (lastRun >= RUN_MASK) { *dst_p++ = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) *dst_p++ = 255; *dst_p++ = (byte)lastRun; } else { *dst_p++ = (byte)(lastRun << ML_BITS); } BlockCopy(src_anchor, dst_p, (int)(src_end - src_anchor)); dst_p += src_end - src_anchor; // End return (int)((dst_p) - dst); }
private static int LZ4HC_InsertAndGetWiderMatch_64(LZ4HC_Data_Structure ctx, int src_p, int startLimit, int longest, ref int matchpos, ref int startpos) { int[] debruijn64 = DEBRUIJN_TABLE_64; ushort[] chainTable = ctx.chainTable; int[] hashTable = ctx.hashTable; byte[] src = ctx.src; int src_base = ctx.src_base; int src_LASTLITERALS = ctx.src_LASTLITERALS; int nbAttempts = MAX_NB_ATTEMPTS; int delta = (src_p - startLimit); // First Match LZ4HC_Insert_64(ctx, src_p); int src_ref = (hashTable[(((Peek4(src, src_p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (src[startLimit + longest] == src[src_ref - delta + longest]) { if (Equal4(src, src_ref, src_p)) { int reft = src_ref + MINMATCH; int ipt = src_p + MINMATCH; int startt = src_p; while (ipt < src_LASTLITERALS - (STEPSIZE_64 - 1)) { var diff = (long) Xor8(src, reft, ipt); if (diff == 0) { ipt += STEPSIZE_64; reft += STEPSIZE_64; continue; } ipt += debruijn64[((ulong) ((diff) & -(diff)) * 0x0218A392CDABBD3FL) >> 58]; goto _endCount; } if ((ipt < (src_LASTLITERALS - 3)) && (Equal4(src, reft, ipt))) { ipt += 4; reft += 4; } if ((ipt < (src_LASTLITERALS - 1)) && (Equal2(src, reft, ipt))) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (src[reft] == src[ipt])) { ipt++; } _endCount: reft = src_ref; while ((startt > startLimit) && (reft > src_base) && (src[startt - 1] == src[reft - 1])) { startt--; reft--; } if ((ipt - startt) > longest) { longest = (ipt - startt); matchpos = reft; startpos = startt; } } } src_ref = ((src_ref) - chainTable[(src_ref) & MAXD_MASK]); } return longest; }
// ReSharper disable InconsistentNaming // ReSharper restore InconsistentNaming private static unsafe LZ4HC_Data_Structure LZ4HC_Create(byte* src) { var hc4 = new LZ4HC_Data_Structure { hashTable = new int[HASHHC_TABLESIZE], chainTable = new ushort[MAXD] }; fixed (ushort* ct = &hc4.chainTable[0]) { BlockFill((byte*) ct, MAXD * sizeof (ushort), 0xFF); } hc4.src_base = src; hc4.nextToUpdate = src + 1; return hc4; }
private static unsafe int LZ4HC_InsertAndFindBestMatch_64( LZ4HC_Data_Structure hc4, byte* src_p, byte* src_LASTLITERALS, ref byte* matchpos) { fixed (ushort* chainTable = hc4.chainTable) fixed (int* hashTable = hc4.hashTable) { var src_base = hc4.src_base; var nbAttempts = MAX_NB_ATTEMPTS; int repl = 0, ml = 0; ushort delta = 0; // HC4 match finder LZ4HC_Insert_64(hc4, src_p); var src_ref = (hashTable[((((*(uint*)(src_p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base); // Detect repetitive sequences of length <= 4 if (src_ref >= src_p - 4) // potential repetition { if ((*(uint*)(src_ref)) == (*(uint*)(src_p))) // confirmed { delta = (ushort)(src_p - src_ref); repl = ml = LZ4HC_CommonLength_64(src_p + MINMATCH, src_ref + MINMATCH, src_LASTLITERALS) + MINMATCH; matchpos = src_ref; } src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]); } while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (*(src_ref + ml) == *(src_p + ml)) if ((*(uint*)(src_ref)) == (*(uint*)(src_p))) { var mlt = LZ4HC_CommonLength_64(src_p + MINMATCH, src_ref + MINMATCH, src_LASTLITERALS) + MINMATCH; if (mlt > ml) { ml = mlt; matchpos = src_ref; } } src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]); } // Complete table if (repl != 0) { var ptr = src_p; var end = src_p + repl - (MINMATCH - 1); while (ptr < end - delta) { chainTable[((int)ptr) & MAXD_MASK] = delta; // Pre-Load ptr++; } do { chainTable[((int)ptr) & MAXD_MASK] = delta; hashTable[((((*(uint*)(ptr))) * 2654435761u) >> HASHHC_ADJUST)] = (int)(ptr - src_base); // Head of chain ptr++; } while (ptr < end); hc4.nextToUpdate = end; } return ml; } }
private static unsafe int LZ4HC_InsertAndGetWiderMatch_32( LZ4HC_Data_Structure hc4, byte* src_p, byte* startLimit, byte* src_LASTLITERALS, int longest, ref byte* matchpos, ref byte* startpos) { fixed (ushort* chainTable = hc4.chainTable) fixed (int* hashTable = hc4.hashTable) fixed (int* debruijn32 = DEBRUIJN_TABLE_32) { var src_base = hc4.src_base; var nbAttempts = MAX_NB_ATTEMPTS; var delta = (int) (src_p - startLimit); // First Match LZ4HC_Insert_32(hc4, src_p); var xxx_ref = hashTable[(*(uint*) src_p*2654435761u) >> HASHHC_ADJUST] + src_base; while ((xxx_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (*(startLimit + longest) == *(xxx_ref - delta + longest)) { if (*(uint*) xxx_ref == *(uint*) src_p) { var reft = xxx_ref + MINMATCH; var ipt = src_p + MINMATCH; var startt = src_p; while (ipt < src_LASTLITERALS - (STEPSIZE_32 - 1)) { var diff = *(int*) reft ^ *(int*) ipt; if (diff == 0) { ipt += STEPSIZE_32; reft += STEPSIZE_32; continue; } ipt += debruijn32[(uint) (diff & -diff)*0x077CB531u >> 27]; goto _endCount; } if ((ipt < src_LASTLITERALS - 1) && (*(ushort*) reft == *(ushort*) ipt)) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (*reft == *ipt)) ipt++; _endCount: reft = xxx_ref; while ((startt > startLimit) && (reft > hc4.src_base) && (startt[-1] == reft[-1])) { startt--; reft--; } if (ipt - startt > longest) { longest = (int) (ipt - startt); matchpos = reft; startpos = startt; } } } xxx_ref = xxx_ref - chainTable[(int) xxx_ref & MAXD_MASK]; } return longest; } }
private static int LZ4HC_InsertAndFindBestMatch( LZ4HC_Data_Structure hc4, byte* src_p, byte* src_LASTLITERALS, ref byte* matchpos) { fixed (ushort* chainTable = hc4.chainTable) { fixed (int* hashTable = hc4.hashTable) { var src_base = hc4.src_base; var nbAttempts = MaxAttempts; int repl = 0, ml = 0; ushort delta = 0; // HC4 match finder LZ4HC_Insert(hc4, src_p); var src_ref = (hashTable[((((*(uint*)(src_p))) * 2654435761u) >> HashHCAdjust)] + src_base); // Detect repetitive sequences of length <= 4 if (src_ref >= src_p - 4) // potential repetition { if ((*(uint*)(src_ref)) == (*(uint*)(src_p))) // confirmed { delta = (ushort)(src_p - src_ref); repl = ml = LZ4HC_CommonLength(src_p + MinMatch, src_ref + MinMatch, src_LASTLITERALS) + MinMatch; matchpos = src_ref; } src_ref = ((src_ref) - chainTable[((int)src_ref) & MaxDMask]); } while ((src_ref >= src_p - MaxDistance) && (nbAttempts != 0)) { nbAttempts--; if (*(src_ref + ml) == *(src_p + ml)) { if ((*(uint*)(src_ref)) == (*(uint*)(src_p))) { var mlt = LZ4HC_CommonLength(src_p + MinMatch, src_ref + MinMatch, src_LASTLITERALS) + MinMatch; if (mlt > ml) { ml = mlt; matchpos = src_ref; } } } src_ref = ((src_ref) - chainTable[((int)src_ref) & MaxDMask]); } // Complete table if (repl != 0) { var ptr = src_p; var end = src_p + repl - (MinMatch - 1); while (ptr < end - delta) { chainTable[((int)ptr) & MaxDMask] = delta; // Pre-Load ptr++; } do { chainTable[((int)ptr) & MaxDMask] = delta; hashTable[((((*(uint*)(ptr))) * 2654435761u) >> HashHCAdjust)] = (int)(ptr - src_base); // Head of chain ptr++; } while (ptr < end); hc4.nextToUpdate = end; } return ml; } } }
private static void LZ4HC_Insert_64(LZ4HC_Data_Structure ctx, int src_p) { ushort[] chainTable = ctx.chainTable; int[] hashTable = ctx.hashTable; byte[] src = ctx.src; int src_base = ctx.src_base; int nextToUpdate = ctx.nextToUpdate; while (nextToUpdate < src_p) { int p = nextToUpdate; int delta = (p) - (hashTable[(((Peek4(src, p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); if (delta > MAX_DISTANCE) { delta = MAX_DISTANCE; } chainTable[(p) & MAXD_MASK] = (ushort) delta; hashTable[(((Peek4(src, p)) * 2654435761u) >> HASHHC_ADJUST)] = ((p) - src_base); nextToUpdate++; } ctx.nextToUpdate = nextToUpdate; }
private static unsafe int LZ4HC_InsertAndFindBestMatch_32( LZ4HC_Data_Structure hc4, byte *src_p, byte *src_LASTLITERALS, ref byte *matchpos) { fixed(ushort *chainTable = hc4.chainTable) fixed(int *hashTable = hc4.hashTable) { var src_base = hc4.src_base; var nbAttempts = MAX_NB_ATTEMPTS; int repl = 0, ml = 0; ushort delta = 0; // HC4 match finder LZ4HC_Insert_32(hc4, src_p); var xxx_ref = hashTable[(*(uint *)src_p * 2654435761u) >> HASHHC_ADJUST] + src_base; // Detect repetitive sequences of length <= 4 if (xxx_ref >= src_p - 4) // potential repetition { if (*(uint *)xxx_ref == *(uint *)src_p) // confirmed { delta = (ushort)(src_p - xxx_ref); repl = ml = LZ4HC_CommonLength_32(src_p + MINMATCH, xxx_ref + MINMATCH, src_LASTLITERALS) + MINMATCH; matchpos = xxx_ref; } xxx_ref = xxx_ref - chainTable[(int)xxx_ref & MAXD_MASK]; } while ((xxx_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (*(xxx_ref + ml) == *(src_p + ml)) { if (*(uint *)xxx_ref == *(uint *)src_p) { var mlt = LZ4HC_CommonLength_32(src_p + MINMATCH, xxx_ref + MINMATCH, src_LASTLITERALS) + MINMATCH; if (mlt > ml) { ml = mlt; matchpos = xxx_ref; } } } xxx_ref = xxx_ref - chainTable[(int)xxx_ref & MAXD_MASK]; } // Complete table if (repl != 0) { var src_ptr = src_p; var src_end = src_p + repl - (MINMATCH - 1); while (src_ptr < src_end - delta) { chainTable[(int)src_ptr & MAXD_MASK] = delta; // Pre-Load src_ptr++; } do { chainTable[(int)src_ptr & MAXD_MASK] = delta; hashTable[(*(uint *)src_ptr * 2654435761u) >> HASHHC_ADJUST] = (int)(src_ptr - src_base); // Head of chain src_ptr++; } while (src_ptr < src_end); hc4.nextToUpdate = src_end; } return(ml); } }
private static int LZ4_encodeSequence_32( LZ4HC_Data_Structure ctx, ref int src_p, ref int dst_p, ref int src_anchor, int matchLength, int src_ref, int dst_end) { int len; var src = ctx.src; var dst = ctx.dst; // Encode Literal length var length = src_p - src_anchor; var dst_token = dst_p++; if ((dst_p + length + (2 + 1 + LASTLITERALS) + (length >> 8)) > dst_end) return 1; // Check output limit if (length >= RUN_MASK) { dst[dst_token] = (RUN_MASK << ML_BITS); len = length - RUN_MASK; for (; len > 254; len -= 255) dst[dst_p++] = 255; dst[dst_p++] = (byte)len; } else { dst[dst_token] = (byte)(length << ML_BITS); } // Copy Literals if (length > 0) { var _i = dst_p + length; src_anchor += WildCopy(src, src_anchor, dst, dst_p, _i); dst_p = _i; } // Encode Offset Poke2(dst, dst_p, (ushort)(src_p - src_ref)); dst_p += 2; // Encode MatchLength len = (matchLength - MINMATCH); if (dst_p + (1 + LASTLITERALS) + (length >> 8) > dst_end) return 1; // Check output limit if (len >= ML_MASK) { dst[dst_token] += ML_MASK; len -= ML_MASK; for (; len > 509; len -= 510) { dst[(dst_p)++] = 255; dst[(dst_p)++] = 255; } if (len > 254) { len -= 255; dst[(dst_p)++] = 255; } dst[(dst_p)++] = (byte)len; } else { dst[dst_token] += (byte)len; } // Prepare next loop src_p += matchLength; src_anchor = src_p; return 0; }
private static int LZ4HC_InsertAndGetWiderMatch_32( LZ4HC_Data_Structure ctx, int src_p, int startLimit, int longest, ref int matchpos, ref int startpos) { var chainTable = ctx.chainTable; var hashTable = ctx.hashTable; var src = ctx.src; var src_base = ctx.src_base; var src_LASTLITERALS = ctx.src_LASTLITERALS; var debruijn32 = DEBRUIJN_TABLE_32; var nbAttempts = MAX_NB_ATTEMPTS; var delta = (src_p - startLimit); // First Match LZ4HC_Insert_32(ctx, src_p); var src_ref = (hashTable[(((Peek4(src, src_p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (src[(startLimit + longest)] == src[(src_ref - delta + longest)]) { if (Equal4(src, src_ref, src_p)) { var reft = src_ref + MINMATCH; var ipt = src_p + MINMATCH; var startt = src_p; while (ipt < src_LASTLITERALS - (STEPSIZE_32 - 1)) { var diff = (int)Xor4(src, reft, ipt); if (diff == 0) { ipt += STEPSIZE_32; reft += STEPSIZE_32; continue; } ipt += debruijn32[((uint)((diff) & -(diff)) * 0x077CB531u) >> 27]; goto _endCount; } if ((ipt < (src_LASTLITERALS - 1)) && (Equal2(src, reft, ipt))) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (src[reft] == src[ipt])) ipt++; _endCount: reft = src_ref; while ((startt > startLimit) && (reft > src_base) && (src[startt - 1] == src[reft - 1])) { startt--; reft--; } if ((ipt - startt) > longest) { longest = (ipt - startt); matchpos = reft; startpos = startt; } } } src_ref = ((src_ref) - chainTable[(src_ref) & MAXD_MASK]); } return longest; }
private static int LZ4HC_InsertAndFindBestMatch_32(LZ4HC_Data_Structure ctx, int src_p, ref int src_match) { var chainTable = ctx.chainTable; var hashTable = ctx.hashTable; var src = ctx.src; var src_base = ctx.src_base; var nbAttempts = MAX_NB_ATTEMPTS; int repl = 0, ml = 0; ushort delta = 0; // HC4 match finder LZ4HC_Insert_32(ctx, src_p); var src_ref = (hashTable[(((Peek4(src, src_p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); // Detect repetitive sequences of length <= 4 if (src_ref >= src_p - 4) // potential repetition { if (Equal4(src, src_ref, src_p)) // confirmed { delta = (ushort)(src_p - src_ref); repl = ml = LZ4HC_CommonLength_32(ctx, src_p + MINMATCH, src_ref + MINMATCH) + MINMATCH; src_match = src_ref; } src_ref = ((src_ref) - chainTable[(src_ref) & MAXD_MASK]); } while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (src[(src_ref + ml)] == src[(src_p + ml)]) { if (Equal4(src, src_ref, src_p)) { var mlt = LZ4HC_CommonLength_32(ctx, src_p + MINMATCH, src_ref + MINMATCH) + MINMATCH; if (mlt > ml) { ml = mlt; src_match = src_ref; } } } src_ref = ((src_ref) - chainTable[(src_ref) & MAXD_MASK]); } // Complete table if (repl != 0) { var src_ptr = src_p; var end = src_p + repl - (MINMATCH - 1); while (src_ptr < end - delta) { chainTable[(src_ptr) & MAXD_MASK] = delta; // Pre-Load src_ptr++; } do { chainTable[(src_ptr) & MAXD_MASK] = delta; hashTable[(((Peek4(src, src_ptr)) * 2654435761u) >> HASHHC_ADJUST)] = ((src_ptr) - src_base); // Head of chain src_ptr++; } while (src_ptr < end); ctx.nextToUpdate = end; } return ml; }
private static LZ4HC_Data_Structure LZ4HC_Create(byte* src) { var hc4 = new LZ4HC_Data_Structure { hashTable = new int[HashHCTableSize], chainTable = new ushort[MaxD] }; fixed (ushort* ct = &hc4.chainTable[0]) { BufferFill((byte*)ct, MaxD * sizeof(ushort), 0xFF); } hc4.src_base = src; hc4.nextToUpdate = src + 1; return hc4; }
private static unsafe int LZ4HC_InsertAndGetWiderMatch_64( LZ4HC_Data_Structure hc4, byte *src_p, byte *startLimit, byte *src_LASTLITERALS, int longest, ref byte *matchpos, ref byte *startpos) { fixed(ushort *chainTable = hc4.chainTable) { fixed(int *hashTable = hc4.hashTable) { fixed(int *debruijn64 = DEBRUIJN_TABLE_64) { byte *src_base = hc4.src_base; int nbAttempts = MAX_NB_ATTEMPTS; var delta = (int)(src_p - startLimit); // First Match LZ4HC_Insert_64(hc4, src_p); byte *src_ref = (hashTable[((((*(uint *)(src_p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base); while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (*(startLimit + longest) == *(src_ref - delta + longest)) { if ((*(uint *)(src_ref)) == (*(uint *)(src_p))) { byte *reft = src_ref + MINMATCH; byte *ipt = src_p + MINMATCH; byte *startt = src_p; while (ipt < src_LASTLITERALS - (STEPSIZE_64 - 1)) { long diff = (*(long *)(reft)) ^ (*(long *)(ipt)); if (diff == 0) { ipt += STEPSIZE_64; reft += STEPSIZE_64; continue; } ipt += debruijn64[(((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL)) >> 58]; goto _endCount; } if ((ipt < (src_LASTLITERALS - 3)) && ((*(uint *)(reft)) == (*(uint *)(ipt)))) { ipt += 4; reft += 4; } if ((ipt < (src_LASTLITERALS - 1)) && ((*(ushort *)(reft)) == (*(ushort *)(ipt)))) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (*reft == *ipt)) { ipt++; } _endCount: reft = src_ref; while ((startt > startLimit) && (reft > hc4.src_base) && (startt[-1] == reft[-1])) { startt--; reft--; } if ((ipt - startt) > longest) { longest = (int)(ipt - startt); matchpos = reft; startpos = startt; } } } src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]); } return(longest); } } } }
private static unsafe int LZ4HC_InsertAndGetWiderMatch_32( LZ4HC_Data_Structure hc4, byte *src_p, byte *startLimit, byte *src_LASTLITERALS, int longest, ref byte *matchpos, ref byte *startpos) { fixed(ushort *chainTable = hc4.chainTable) fixed(int *hashTable = hc4.hashTable) fixed(int *debruijn32 = DEBRUIJN_TABLE_32) { var src_base = hc4.src_base; var nbAttempts = MAX_NB_ATTEMPTS; var delta = (int)(src_p - startLimit); // First Match LZ4HC_Insert_32(hc4, src_p); var xxx_ref = hashTable[(*(uint *)src_p * 2654435761u) >> HASHHC_ADJUST] + src_base; while ((xxx_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (*(startLimit + longest) == *(xxx_ref - delta + longest)) { if (*(uint *)xxx_ref == *(uint *)src_p) { var reft = xxx_ref + MINMATCH; var ipt = src_p + MINMATCH; var startt = src_p; while (ipt < src_LASTLITERALS - (STEPSIZE_32 - 1)) { var diff = *(int *)reft ^ *(int *)ipt; if (diff == 0) { ipt += STEPSIZE_32; reft += STEPSIZE_32; continue; } ipt += debruijn32[(uint)(diff & -diff) * 0x077CB531u >> 27]; goto _endCount; } if ((ipt < src_LASTLITERALS - 1) && (*(ushort *)reft == *(ushort *)ipt)) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (*reft == *ipt)) { ipt++; } _endCount: reft = xxx_ref; while ((startt > startLimit) && (reft > hc4.src_base) && (startt[-1] == reft[-1])) { startt--; reft--; } if (ipt - startt > longest) { longest = (int)(ipt - startt); matchpos = reft; startpos = startt; } } } xxx_ref = xxx_ref - chainTable[(int)xxx_ref & MAXD_MASK]; } return(longest); } }
private static int LZ4_compressHCCtx_64(LZ4HC_Data_Structure ctx) { byte[] src = ctx.src; int src_p = ctx.src_base; int src_end = ctx.src_end; int dst_0 = ctx.dst_base; int src_anchor = src_p; int src_mflimit = src_end - MFLIMIT; byte[] dst = ctx.dst; int dst_len = ctx.dst_len; int dst_p = ctx.dst_base; int xxx_ref = 0; int start2 = 0; int ref2 = 0; int start3 = 0; int ref3 = 0; src_p++; // Main Loop while (src_p < src_mflimit) { int ml = LZ4HC_InsertAndFindBestMatch_64(ctx, src_p, ref xxx_ref); if (ml == 0) { src_p++; continue; } // saved, in case we would skip too much int start0 = src_p; int ref0 = xxx_ref; int ml0 = ml; _Search2: int ml2 = src_p + ml < src_mflimit ? LZ4HC_InsertAndGetWiderMatch_64(ctx, src_p + ml - 2, src_p + 1, ml, ref ref2, ref start2) : ml; if (ml2 == ml) // No better match { if (LZ4_encodeSequence_64(ctx, ref src_p, ref dst_p, ref src_anchor, ml, xxx_ref) != 0) { return 0; } continue; } if (start0 < src_p) { if (start2 < src_p + ml0) // empirical { src_p = start0; xxx_ref = ref0; ml = ml0; } } // Here, start0==ip if ((start2 - src_p) < 3) // First Match too small : removed { ml = ml2; src_p = start2; xxx_ref = ref2; goto _Search2; } _Search3: // Currently we have : // ml2 > ml1, and // ip1+3 <= ip2 (usually < ip1+ml1) if ((start2 - src_p) < OPTIMAL_ML) { int new_ml = ml; if (new_ml > OPTIMAL_ML) { new_ml = OPTIMAL_ML; } if (src_p + new_ml > start2 + ml2 - MINMATCH) { new_ml = (start2 - src_p) + ml2 - MINMATCH; } int correction = new_ml - (start2 - src_p); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } // Now, we have start2 = ip+new_ml, with new_ml=min(ml, OPTIMAL_ML=18) int ml3 = start2 + ml2 < src_mflimit ? LZ4HC_InsertAndGetWiderMatch_64(ctx, start2 + ml2 - 3, start2, ml2, ref ref3, ref start3) : ml2; if (ml3 == ml2) // No better match : 2 sequences to encode { // ip & ref are known; Now for ml if (start2 < src_p + ml) { ml = (start2 - src_p); } // Now, encode 2 sequences if (LZ4_encodeSequence_64(ctx, ref src_p, ref dst_p, ref src_anchor, ml, xxx_ref) != 0) { return 0; } src_p = start2; if (LZ4_encodeSequence_64(ctx, ref src_p, ref dst_p, ref src_anchor, ml2, ref2) != 0) { return 0; } continue; } if (start3 < src_p + ml + 3) // Not enough space for match 2 : remove it { if (start3 >= (src_p + ml)) // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 { if (start2 < src_p + ml) { int correction = (src_p + ml - start2); start2 += correction; ref2 += correction; ml2 -= correction; if (ml2 < MINMATCH) { start2 = start3; ref2 = ref3; ml2 = ml3; } } if (LZ4_encodeSequence_64(ctx, ref src_p, ref dst_p, ref src_anchor, ml, xxx_ref) != 0) { return 0; } src_p = start3; xxx_ref = ref3; ml = ml3; start0 = start2; ref0 = ref2; ml0 = ml2; goto _Search2; } start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // OK, now we have 3 ascending matches; let's write at least the first one // ip & ref are known; Now for ml if (start2 < src_p + ml) { if ((start2 - src_p) < ML_MASK) { if (ml > OPTIMAL_ML) { ml = OPTIMAL_ML; } if (src_p + ml > start2 + ml2 - MINMATCH) { ml = (start2 - src_p) + ml2 - MINMATCH; } int correction = ml - (start2 - src_p); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } else { ml = (start2 - src_p); } } if (LZ4_encodeSequence_64(ctx, ref src_p, ref dst_p, ref src_anchor, ml, xxx_ref) != 0) { return 0; } src_p = start2; xxx_ref = ref2; ml = ml2; start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // Encode Last Literals { int lastRun = (src_end - src_anchor); if ((dst_p - dst_0) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (uint) dst_len) { return 0; // Check output limit } if (lastRun >= RUN_MASK) { dst[dst_p++] = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) { dst[dst_p++] = 255; } dst[dst_p++] = (byte) lastRun; } else { dst[dst_p++] = (byte) (lastRun << ML_BITS); } BlockCopy(src, src_anchor, dst, dst_p, src_end - src_anchor); dst_p += src_end - src_anchor; } // End return (dst_p - dst_0); }
private static unsafe int LZ4HC_InsertAndFindBestMatch_64( LZ4HC_Data_Structure hc4, byte *src_p, byte *src_LASTLITERALS, ref byte *matchpos) { fixed(ushort *chainTable = hc4.chainTable) { fixed(int *hashTable = hc4.hashTable) { byte * src_base = hc4.src_base; int nbAttempts = MAX_NB_ATTEMPTS; int repl = 0, ml = 0; ushort delta = 0; // HC4 match finder LZ4HC_Insert_64(hc4, src_p); byte *src_ref = (hashTable[((((*(uint *)(src_p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base); // Detect repetitive sequences of length <= 4 if (src_ref >= src_p - 4) // potential repetition { if ((*(uint *)(src_ref)) == (*(uint *)(src_p))) // confirmed { delta = (ushort)(src_p - src_ref); repl = ml = LZ4HC_CommonLength_64(src_p + MINMATCH, src_ref + MINMATCH, src_LASTLITERALS) + MINMATCH; matchpos = src_ref; } src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]); } while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (*(src_ref + ml) == *(src_p + ml)) { if ((*(uint *)(src_ref)) == (*(uint *)(src_p))) { int mlt = LZ4HC_CommonLength_64(src_p + MINMATCH, src_ref + MINMATCH, src_LASTLITERALS) + MINMATCH; if (mlt > ml) { ml = mlt; matchpos = src_ref; } } } src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]); } // Complete table if (repl != 0) { byte *ptr = src_p; byte *end = src_p + repl - (MINMATCH - 1); while (ptr < end - delta) { chainTable[((int)ptr) & MAXD_MASK] = delta; // Pre-Load ptr++; } do { chainTable[((int)ptr) & MAXD_MASK] = delta; hashTable[((((*(uint *)(ptr))) * 2654435761u) >> HASHHC_ADJUST)] = (int)(ptr - src_base); // Head of chain ptr++; } while (ptr < end); hc4.nextToUpdate = end; } return(ml); } } }
private static int LZ4HC_InsertAndGetWiderMatch_64(LZ4HC_Data_Structure ctx, int src_p, int startLimit, int longest, ref int matchpos, ref int startpos) { int[] debruijn64 = DEBRUIJN_TABLE_64; ushort[] chainTable = ctx.chainTable; int[] hashTable = ctx.hashTable; byte[] src = ctx.src; int src_base = ctx.src_base; int src_LASTLITERALS = ctx.src_LASTLITERALS; int nbAttempts = MAX_NB_ATTEMPTS; int delta = (src_p - startLimit); // First Match LZ4HC_Insert_64(ctx, src_p); int src_ref = (hashTable[(((Peek4(src, src_p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (src[startLimit + longest] == src[src_ref - delta + longest]) { if (Equal4(src, src_ref, src_p)) { int reft = src_ref + MINMATCH; int ipt = src_p + MINMATCH; int startt = src_p; while (ipt < src_LASTLITERALS - (STEPSIZE_64 - 1)) { var diff = (long)Xor8(src, reft, ipt); if (diff == 0) { ipt += STEPSIZE_64; reft += STEPSIZE_64; continue; } ipt += debruijn64[((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL) >> 58]; goto _endCount; } if ((ipt < (src_LASTLITERALS - 3)) && (Equal4(src, reft, ipt))) { ipt += 4; reft += 4; } if ((ipt < (src_LASTLITERALS - 1)) && (Equal2(src, reft, ipt))) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (src[reft] == src[ipt])) { ipt++; } _endCount: reft = src_ref; while ((startt > startLimit) && (reft > src_base) && (src[startt - 1] == src[reft - 1])) { startt--; reft--; } if ((ipt - startt) > longest) { longest = (ipt - startt); matchpos = reft; startpos = startt; } } } src_ref = ((src_ref) - chainTable[(src_ref) & MAXD_MASK]); } return(longest); }
private static unsafe int LZ4_compressHCCtx_64( LZ4HC_Data_Structure ctx, byte *src, byte *dst, int src_len, int dst_maxlen) { byte *src_p = src; byte *src_anchor = src_p; byte *src_end = src_p + src_len; byte *src_mflimit = src_end - MFLIMIT; byte *src_LASTLITERALS = (src_end - LASTLITERALS); byte *dst_p = dst; byte *dst_end = dst_p + dst_maxlen; byte *src_ref = null; byte *start2 = null; byte *ref2 = null; byte *start3 = null; byte *ref3 = null; src_p++; // Main Loop while (src_p < src_mflimit) { int ml = LZ4HC_InsertAndFindBestMatch_64(ctx, src_p, src_LASTLITERALS, ref src_ref); if (ml == 0) { src_p++; continue; } // saved, in case we would skip too much byte *start0 = src_p; byte *ref0 = src_ref; int ml0 = ml; _Search2: int ml2 = src_p + ml < src_mflimit ? LZ4HC_InsertAndGetWiderMatch_64(ctx, src_p + ml - 2, src_p + 1, src_LASTLITERALS, ml, ref ref2, ref start2) : ml; if (ml2 == ml) // No better match { if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) { return(0); } continue; } if (start0 < src_p && start2 < src_p + ml0) { src_p = start0; src_ref = ref0; ml = ml0; } // Here, start0==ip if ((start2 - src_p) < 3) // First Match too small : removed { ml = ml2; src_p = start2; src_ref = ref2; goto _Search2; } _Search3: // Currently we have : // ml2 > ml1, and // ip1+3 <= ip2 (usually < ip1+ml1) if ((start2 - src_p) < OPTIMAL_ML) { int new_ml = ml; if (new_ml > OPTIMAL_ML) { new_ml = OPTIMAL_ML; } if (src_p + new_ml > start2 + ml2 - MINMATCH) { new_ml = (int)(start2 - src_p) + ml2 - MINMATCH; } int correction = new_ml - (int)(start2 - src_p); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } // Now, we have start2 = ip+new_ml, with new_ml=min(ml, OPTIMAL_ML=18) int ml3 = start2 + ml2 < src_mflimit ? LZ4HC_InsertAndGetWiderMatch_64(ctx, start2 + ml2 - 3, start2, src_LASTLITERALS, ml2, ref ref3, ref start3) : ml2; if (ml3 == ml2) // No better match : 2 sequences to encode { // ip & ref are known; Now for ml if (start2 < src_p + ml) { ml = (int)(start2 - src_p); } // Now, encode 2 sequences if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) { return(0); } src_p = start2; if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml2, ref2, dst_end) != 0) { return(0); } continue; } if (start3 < src_p + ml + 3) // Not enough space for match 2 : remove it { if (start3 >= src_p + ml) // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 { if (start2 < src_p + ml) { var correction = (int)(src_p + ml - start2); start2 += correction; ref2 += correction; ml2 -= correction; if (ml2 < MINMATCH) { start2 = start3; ref2 = ref3; ml2 = ml3; } } if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) { return(0); } src_p = start3; src_ref = ref3; ml = ml3; start0 = start2; ref0 = ref2; ml0 = ml2; goto _Search2; } start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // OK, now we have 3 ascending matches; let's write at least the first one // ip & ref are known; Now for ml if (start2 < src_p + ml) { if (start2 - src_p < ML_MASK) { if (ml > OPTIMAL_ML) { ml = OPTIMAL_ML; } if (src_p + ml > start2 + ml2 - MINMATCH) { ml = (int)(start2 - src_p) + ml2 - MINMATCH; } int correction = ml - (int)(start2 - src_p); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } else { ml = (int)(start2 - src_p); } } if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) { return(0); } src_p = start2; src_ref = ref2; ml = ml2; start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // Encode Last Literals var lastRun = (int)(src_end - src_anchor); if ((dst_p - dst) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (uint)dst_maxlen) { return(0); // Check output limit } if (lastRun >= RUN_MASK) { *dst_p++ = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) { *dst_p++ = 255; } *dst_p++ = (byte)lastRun; } else { *dst_p++ = (byte)(lastRun << ML_BITS); } BlockCopy(src_anchor, dst_p, (int)(src_end - src_anchor)); dst_p += src_end - src_anchor; // End return((int)((dst_p) - dst)); }
// Update chains up to ip (excluded) private static void LZ4HC_Insert(LZ4HC_Data_Structure hc4, byte* src_p) { fixed (ushort* chainTable = hc4.chainTable) { fixed (int* hashTable = hc4.hashTable) { var src_base = hc4.src_base; while (hc4.nextToUpdate < src_p) { var p = hc4.nextToUpdate; var delta = (int)((p) - (hashTable[((((*(uint*)(p))) * 2654435761u) >> HashHCAdjust)] + src_base)); if (delta > MaxDistance) { delta = MaxDistance; } chainTable[((int)p) & MaxDMask] = (ushort)delta; hashTable[((((*(uint*)(p))) * 2654435761u) >> HashHCAdjust)] = (int)(p - src_base); hc4.nextToUpdate++; } } } }
private static int LZ4HC_InsertAndFindBestMatch_32(LZ4HC_Data_Structure ctx, int src_p, ref int src_match) { var chainTable = ctx.chainTable; var hashTable = ctx.hashTable; var src = ctx.src; var src_base = ctx.src_base; var nbAttempts = MAX_NB_ATTEMPTS; int repl = 0, ml = 0; ushort delta = 0; // HC4 match finder LZ4HC_Insert_32(ctx, src_p); var src_ref = (hashTable[(((Peek4(src, src_p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); // Detect repetitive sequences of length <= 4 if (src_ref >= src_p - 4) // potential repetition { if (Equal4(src, src_ref, src_p)) // confirmed { delta = (ushort)(src_p - src_ref); repl = ml = LZ4HC_CommonLength_32(ctx, src_p + MINMATCH, src_ref + MINMATCH) + MINMATCH; src_match = src_ref; } src_ref = ((src_ref) - chainTable[(src_ref) & MAXD_MASK]); } while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (src[(src_ref + ml)] == src[(src_p + ml)]) { if (Equal4(src, src_ref, src_p)) { var mlt = LZ4HC_CommonLength_32(ctx, src_p + MINMATCH, src_ref + MINMATCH) + MINMATCH; if (mlt > ml) { ml = mlt; src_match = src_ref; } } } src_ref = ((src_ref) - chainTable[(src_ref) & MAXD_MASK]); } // Complete table if (repl != 0) { var src_ptr = src_p; var end = src_p + repl - (MINMATCH - 1); while (src_ptr < end - delta) { chainTable[(src_ptr) & MAXD_MASK] = delta; // Pre-Load src_ptr++; } do { chainTable[(src_ptr) & MAXD_MASK] = delta; hashTable[(((Peek4(src, src_ptr)) * 2654435761u) >> HASHHC_ADJUST)] = ((src_ptr) - src_base); // Head of chain src_ptr++; } while (src_ptr < end); ctx.nextToUpdate = end; } return(ml); }
private static int LZ4HC_InsertAndGetWiderMatch_32( LZ4HC_Data_Structure ctx, int src_p, int startLimit, int longest, ref int matchpos, ref int startpos) { var chainTable = ctx.chainTable; var hashTable = ctx.hashTable; var src = ctx.src; var src_base = ctx.src_base; var src_LASTLITERALS = ctx.src_LASTLITERALS; var debruijn32 = DEBRUIJN_TABLE_32; var nbAttempts = MAX_NB_ATTEMPTS; var delta = (src_p - startLimit); // First Match LZ4HC_Insert_32(ctx, src_p); var src_ref = (hashTable[(((Peek4(src, src_p)) * 2654435761u) >> HASHHC_ADJUST)] + src_base); while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (src[(startLimit + longest)] == src[(src_ref - delta + longest)]) { if (Equal4(src, src_ref, src_p)) { var reft = src_ref + MINMATCH; var ipt = src_p + MINMATCH; var startt = src_p; while (ipt < src_LASTLITERALS - (STEPSIZE_32 - 1)) { var diff = (int)Xor4(src, reft, ipt); if (diff == 0) { ipt += STEPSIZE_32; reft += STEPSIZE_32; continue; } ipt += debruijn32[((uint)((diff) & -(diff)) * 0x077CB531u) >> 27]; goto _endCount; } if ((ipt < (src_LASTLITERALS - 1)) && (Equal2(src, reft, ipt))) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (src[reft] == src[ipt])) { ipt++; } _endCount: reft = src_ref; while ((startt > startLimit) && (reft > src_base) && (src[startt - 1] == src[reft - 1])) { startt--; reft--; } if ((ipt - startt) > longest) { longest = (ipt - startt); matchpos = reft; startpos = startt; } } } src_ref = ((src_ref) - chainTable[(src_ref) & MAXD_MASK]); } return(longest); }
private static unsafe int LZ4HC_InsertAndGetWiderMatch_64( LZ4HC_Data_Structure hc4, byte* src_p, byte* startLimit, byte* src_LASTLITERALS, int longest, ref byte* matchpos, ref byte* startpos) { fixed (ushort* chainTable = hc4.chainTable) fixed (int* hashTable = hc4.hashTable) fixed (int* debruijn64 = DEBRUIJN_TABLE_64) { var src_base = hc4.src_base; var nbAttempts = MAX_NB_ATTEMPTS; var delta = (int)(src_p - startLimit); // First Match LZ4HC_Insert_64(hc4, src_p); var src_ref = (hashTable[((((*(uint*)(src_p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base); while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0)) { nbAttempts--; if (*(startLimit + longest) == *(src_ref - delta + longest)) { if ((*(uint*)(src_ref)) == (*(uint*)(src_p))) { var reft = src_ref + MINMATCH; var ipt = src_p + MINMATCH; var startt = src_p; while (ipt < src_LASTLITERALS - (STEPSIZE_64 - 1)) { var diff = (*(long*)(reft)) ^ (*(long*)(ipt)); if (diff == 0) { ipt += STEPSIZE_64; reft += STEPSIZE_64; continue; } ipt += debruijn64[(((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL)) >> 58]; goto _endCount; } if ((ipt < (src_LASTLITERALS - 3)) && ((*(uint*)(reft)) == (*(uint*)(ipt)))) { ipt += 4; reft += 4; } if ((ipt < (src_LASTLITERALS - 1)) && ((*(ushort*)(reft)) == (*(ushort*)(ipt)))) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (*reft == *ipt)) ipt++; _endCount: reft = src_ref; while ((startt > startLimit) && (reft > hc4.src_base) && (startt[-1] == reft[-1])) { startt--; reft--; } if ((ipt - startt) > longest) { longest = (int)(ipt - startt); matchpos = reft; startpos = startt; } } } src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]); } return longest; } }
private static int LZ4_encodeSequence_32( LZ4HC_Data_Structure ctx, ref int src_p, ref int dst_p, ref int src_anchor, int matchLength, int src_ref, int dst_end) { int len; var src = ctx.src; var dst = ctx.dst; // Encode Literal length var length = src_p - src_anchor; var dst_token = dst_p++; if ((dst_p + length + (2 + 1 + LASTLITERALS) + (length >> 8)) > dst_end) { return(1); // Check output limit } if (length >= RUN_MASK) { dst[dst_token] = (RUN_MASK << ML_BITS); len = length - RUN_MASK; for (; len > 254; len -= 255) { dst[dst_p++] = 255; } dst[dst_p++] = (byte)len; } else { dst[dst_token] = (byte)(length << ML_BITS); } // Copy Literals if (length > 0) { var _i = dst_p + length; src_anchor += WildCopy(src, src_anchor, dst, dst_p, _i); dst_p = _i; } // Encode Offset Poke2(dst, dst_p, (ushort)(src_p - src_ref)); dst_p += 2; // Encode MatchLength len = (matchLength - MINMATCH); if (dst_p + (1 + LASTLITERALS) + (length >> 8) > dst_end) { return(1); // Check output limit } if (len >= ML_MASK) { dst[dst_token] += ML_MASK; len -= ML_MASK; for (; len > 509; len -= 510) { dst[(dst_p)++] = 255; dst[(dst_p)++] = 255; } if (len > 254) { len -= 255; dst[(dst_p)++] = 255; } dst[(dst_p)++] = (byte)len; } else { dst[dst_token] += (byte)len; } // Prepare next loop src_p += matchLength; src_anchor = src_p; return(0); }
// ReSharper restore InconsistentNaming private static LZ4HC_Data_Structure LZ4HC_Create(byte[] src, int src_0, int src_len, byte[] dst, int dst_0, int dst_len) { var hc4 = new LZ4HC_Data_Structure { src = src, src_base = src_0, src_end = src_0 + src_len, src_LASTLITERALS = (src_0 + src_len - LASTLITERALS), dst = dst, dst_base = dst_0, dst_len = dst_len, dst_end = dst_0 + dst_len, hashTable = new int[HASHHC_TABLESIZE], chainTable = new ushort[MAXD], nextToUpdate = src_0 + 1, }; var ct = hc4.chainTable; for (var i = ct.Length - 1; i >= 0; i--) ct[i] = unchecked((ushort)-1); return hc4; }
private static int LZ4HC_InsertAndGetWiderMatch( LZ4HC_Data_Structure hc4, byte* src_p, byte* startLimit, byte* src_LASTLITERALS, int longest, ref byte* matchpos, ref byte* startpos) { fixed (ushort* chainTable = hc4.chainTable) { fixed (int* hashTable = hc4.hashTable) { fixed (int* debruijn64 = DebruijnTable) { var src_base = hc4.src_base; var nbAttempts = MaxAttempts; var delta = (int)(src_p - startLimit); // First Match LZ4HC_Insert(hc4, src_p); var src_ref = (hashTable[((((*(uint*)(src_p))) * 2654435761u) >> HashHCAdjust)] + src_base); while ((src_ref >= src_p - MaxDistance) && (nbAttempts != 0)) { nbAttempts--; if (*(startLimit + longest) == *(src_ref - delta + longest)) { if ((*(uint*)(src_ref)) == (*(uint*)(src_p))) { var reft = src_ref + MinMatch; var ipt = src_p + MinMatch; var startt = src_p; while (ipt < src_LASTLITERALS - (StepSize - 1)) { var diff = (*(long*)(reft)) ^ (*(long*)(ipt)); if (diff == 0) { ipt += StepSize; reft += StepSize; continue; } ipt += debruijn64[(((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL)) >> 58]; goto _endCount; } if ((ipt < (src_LASTLITERALS - 3)) && ((*(uint*)(reft)) == (*(uint*)(ipt)))) { ipt += 4; reft += 4; } if ((ipt < (src_LASTLITERALS - 1)) && ((*(ushort*)(reft)) == (*(ushort*)(ipt)))) { ipt += 2; reft += 2; } if ((ipt < src_LASTLITERALS) && (*reft == *ipt)) { ipt++; } _endCount: reft = src_ref; while ((startt > startLimit) && (reft > hc4.src_base) && (startt[-1] == reft[-1])) { startt--; reft--; } if ((ipt - startt) > longest) { longest = (int)(ipt - startt); matchpos = reft; startpos = startt; } } } src_ref = ((src_ref) - chainTable[((int)src_ref) & MaxDMask]); } return longest; } } } }