///|
pub(all) struct BrotliDistanceRing {
distances : FixedArray[Int]
mut index : Int
mut last_distance_context : Int
}
///|
pub fn BrotliDistanceRing::new() -> BrotliDistanceRing {
{ distances: [16, 15, 11, 4], index: 0, last_distance_context: 0 }
}
///|
/// Return an independent copy of the ring, including its backing slots, so the
/// copy can be mutated without affecting the original. Used by the streaming
/// decoder to speculatively decode a meta-block and roll back on short input.
pub fn BrotliDistanceRing::clone(
self : BrotliDistanceRing,
) -> BrotliDistanceRing {
let distances = FixedArray::make(self.distances.length(), 0)
for i in 0.. Int {
// The ring has four slots, so a bit mask gives the same wraparound as
// modulo 4, including negative indices used by short-distance codes.
index & 3
}
///|
pub fn BrotliDistanceRing::take_short_code(
self : BrotliDistanceRing,
code : Int,
) -> Int raise FbrError {
if code < 0 || code >= brotli_num_distance_short_codes {
raise fbr_err(BrotliInvalidDistance, msg="invalid Brotli short distance")
}
self.last_distance_context = 0
if code <= 3 {
let offset = code - 3
let distance_context = 1 >> code
let distance = self.distances[brotli_distance_ring_slot(self.index - offset)]
self.index -= distance_context
self.last_distance_context = distance_context
return distance
}
let mut index_delta = 3
let mut base = code - 10
if code < 10 {
base = code - 4
} else {
index_delta = 2
}
let delta = ((0x605142 >> (4 * base)) & 0xf) - 3
let distance = self.distances[brotli_distance_ring_slot(
self.index + index_delta,
)] +
delta
if distance <= 0 {
raise fbr_err(BrotliInvalidDistance, msg="invalid Brotli short distance")
}
distance
}
///|
pub fn BrotliDistanceRing::compensate_dictionary_copy(
self : BrotliDistanceRing,
) -> Unit {
self.index += self.last_distance_context
self.last_distance_context = 0
}
///|
pub fn BrotliDistanceRing::record(
self : BrotliDistanceRing,
distance : Int,
) -> Unit raise FbrError {
if distance <= 0 {
raise fbr_err(BrotliInvalidDistance, msg="invalid Brotli distance")
}
self.distances[brotli_distance_ring_slot(self.index)] = distance
self.index += 1
self.last_distance_context = 0
}
///|
pub fn brotli_distance_extra_bits(
code : Int,
npostfix : Int,
ndirect : Int,
) -> Int raise FbrError {
if code < 0 {
raise fbr_err(BrotliInvalidDistance, msg="negative Brotli distance code")
}
if code < brotli_num_distance_short_codes + ndirect {
0
} else {
let xcode = code - ndirect - brotli_num_distance_short_codes
1 + (xcode >> (npostfix + 1))
}
}
///|
pub fn brotli_distance_offset(
code : Int,
npostfix : Int,
ndirect : Int,
) -> Int raise FbrError {
if code < brotli_num_distance_short_codes {
raise fbr_err(BrotliInvalidDistance, msg="short code has no direct offset")
}
if code < brotli_num_distance_short_codes + ndirect {
code - brotli_num_distance_short_codes + 1
} else {
let xcode = code - ndirect - brotli_num_distance_short_codes
let bits = 1 + (xcode >> (npostfix + 1))
let half = (xcode >> npostfix) & 1
let postfix = xcode & ((1 << npostfix) - 1)
ndirect + ((((2 + half) << bits) - 4) << npostfix) + postfix + 1
}
}
///|