// Optional speed/ratio trade-off inspired by fzip's byte-diversity and
// repetition checks. This is a heuristic, not a proof of incompressibility.
// It never changes decompressed bytes, but can miss profitable LZ matches.
///|
fn fast_store_sample(length : Int, byte_at : (Int) -> Byte) -> Bool {
let frequencies = FixedArray::make(256, 0)
if length < 8192 {
let mut distinct = 0
let mut largest = 0
for i in 0.. 240 && largest <= length / 32 else { return false }
for distance in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] {
// The adapters require at least 1024 bytes, so all 64 probes fit.
let matches = for i = 0, matches = 0 {
guard i < 64 else { break matches }
continue i + 1,
matches + (if byte_at(i) == byte_at(i + distance) { 1 } else { 0 })
}
guard matches <= 32 else { return false }
}
return true
}
// Bound work to 2048 samples. Require all four regions to look random,
// rather than allowing a random suffix to dominate a compressible prefix.
let quarter = length / 4
for region in 0..<4 {
frequencies.fill(0)
let start = region * quarter
let end = if region == 3 { length } else { start + quarter }
let stride = (end - start) / 512
let mut distinct = 0
let mut largest = 0
let mut local_matches = 0
for sample in 0..<512 {
let position = start + sample * stride
let byte = byte_at(position)
let value = byte.to_int()
if frequencies[value] == 0 {
distinct += 1
}
frequencies[value] += 1
largest = largest.max(frequencies[value])
if position >= start + 3 &&
(
byte == byte_at(position - 1) ||
(
byte == byte_at(position - 2) &&
byte_at(position - 1) == byte_at(position - 3)
)
) {
local_matches += 1
}
}
guard distinct > 200 && largest <= 16 && local_matches * 10 < 512 else {
return false
}
}
true
}
///|
fn should_fast_store(input : BytesView) -> Bool {
// Avoid classifier/allocation overhead on tiny inputs.
guard input.length() >= 1024 else { return false }
fast_store_sample(input.length(), i => input[i])
}
///|
fn should_fast_store_window(
data : FixedArray[Byte],
start : Int,
end : Int,
) -> Bool {
guard end - start >= 1024 else { return false }
fast_store_sample(end - start, i => data[(start + i) & STREAM_RING_MASK])
}