///|
fn read_bits(
bit_count : Int,
data_val : Ref[Int],
data_position : Ref[Int],
data_index : Ref[Int],
reset_value : Int,
get_next_value : (Int) -> Int,
) -> Int {
let mut bits = 0
let mut power = 1
let maxpower = 1 << bit_count
while power != maxpower {
let resb = data_val.val & data_position.val
data_position.val = data_position.val >> 1
if data_position.val == 0 {
data_position.val = reset_value
data_val.val = get_next_value(data_index.val)
data_index.val += 1
}
bits = bits | ((if resb > 0 { 1 } else { 0 }) * power)
power = power << 1
}
bits
}
///|
fn read_new_entry(
data_val : Ref[Int],
data_position : Ref[Int],
data_index : Ref[Int],
reset_value : Int,
get_next_value : (Int) -> Int,
) -> String? {
let mode = read_bits(
2, data_val, data_position, data_index, reset_value, get_next_value,
)
match mode {
0 =>
Some(
read_bits(
8, data_val, data_position, data_index, reset_value, get_next_value,
)
|> char_from_code_unit,
)
1 =>
Some(
read_bits(
16, data_val, data_position, data_index, reset_value, get_next_value,
)
|> char_from_code_unit,
)
2 => Some("")
_ => None
}
}
///|
fn _decompress(
length : Int,
reset_value : Int,
get_next_value : (Int) -> Int,
) -> String? {
let dictionary : Array[String] = ["0", "1", "2"]
let result = StringBuilder::new()
let data_val = Ref::new(get_next_value(0))
let data_position = Ref::new(reset_value)
let data_index = Ref::new(1)
let mut enlarge_in = 4
let mut dict_size = 4
let mut num_bits = 3
let first = read_new_entry(
data_val, data_position, data_index, reset_value, get_next_value,
)
let c = match first {
Some(v) => v
None => return Some("")
}
if c == "" {
return Some("")
}
dictionary.push(c)
let mut w = c
result.write_string(c)
while true {
if data_index.val > length {
return Some("")
}
let mut c_idx = read_bits(
num_bits, data_val, data_position, data_index, reset_value, get_next_value,
)
if c_idx == 0 {
let code = read_bits(
8, data_val, data_position, data_index, reset_value, get_next_value,
)
dictionary.push(char_from_code_unit(code))
c_idx = dict_size
dict_size += 1
enlarge_in -= 1
} else if c_idx == 1 {
let code = read_bits(
16, data_val, data_position, data_index, reset_value, get_next_value,
)
dictionary.push(char_from_code_unit(code))
c_idx = dict_size
dict_size += 1
enlarge_in -= 1
} else if c_idx == 2 {
return Some(result.to_string())
}
if enlarge_in == 0 {
enlarge_in = 1 << num_bits
num_bits += 1
}
let entry = if c_idx < dictionary.length() {
dictionary[c_idx]
} else if c_idx == dict_size {
w + single_code_unit(w, 0)
} else {
return None
}
result.write_string(entry)
dictionary.push(w + single_code_unit(entry, 0))
dict_size += 1
enlarge_in -= 1
w = entry
if enlarge_in == 0 {
enlarge_in = 1 << num_bits
num_bits += 1
}
}
None
}