mirror of
https://github.com/exoticorn/upkr.git
synced 2026-01-20 11:36:42 +01:00
speed optimizations + progress bar
This commit is contained in:
90
Cargo.lock
generated
90
Cargo.lock
generated
@@ -30,6 +30,44 @@ dependencies = [
|
|||||||
"sacabase",
|
"sacabase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.108"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@@ -39,6 +77,18 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pbr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff5751d87f7c00ae6403eb1fcbba229b9c76c9a30de8c1cf87182177b168cea2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
|
"libc",
|
||||||
|
"time",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pico-args"
|
name = "pico-args"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -54,11 +104,51 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "upkr"
|
name = "upkr"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cdivsufsort",
|
"cdivsufsort",
|
||||||
|
"pbr",
|
||||||
"pico-args",
|
"pico-args",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ edition = "2021"
|
|||||||
cdivsufsort = "2"
|
cdivsufsort = "2"
|
||||||
pico-args = "0.4"
|
pico-args = "0.4"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
pbr = "1"
|
||||||
@@ -3,7 +3,7 @@ use crate::match_finder::MatchFinder;
|
|||||||
use crate::rans::RansCoder;
|
use crate::rans::RansCoder;
|
||||||
|
|
||||||
pub fn pack(data: &[u8]) -> Vec<u8> {
|
pub fn pack(data: &[u8]) -> Vec<u8> {
|
||||||
let match_finder = MatchFinder::new(data);
|
let mut match_finder = MatchFinder::new(data);
|
||||||
let mut rans_coder = RansCoder::new();
|
let mut rans_coder = RansCoder::new();
|
||||||
let mut state = lz::CoderState::new();
|
let mut state = lz::CoderState::new();
|
||||||
|
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ mod parsing_packer;
|
|||||||
pub use greedy_packer::pack as pack_fast;
|
pub use greedy_packer::pack as pack_fast;
|
||||||
pub use parsing_packer::pack;
|
pub use parsing_packer::pack;
|
||||||
pub use lz::unpack;
|
pub use lz::unpack;
|
||||||
|
|
||||||
|
pub type ProgressCallback<'a> = &'a mut dyn FnMut(usize);
|
||||||
12
src/main.rs
12
src/main.rs
@@ -18,8 +18,18 @@ fn main() -> Result<()> {
|
|||||||
let packed_data = if fast {
|
let packed_data = if fast {
|
||||||
upkr::pack_fast(&data)
|
upkr::pack_fast(&data)
|
||||||
} else {
|
} else {
|
||||||
upkr::pack(&data)
|
let mut pb = pbr::ProgressBar::new(data.len() as u64);
|
||||||
|
pb.set_units(pbr::Units::Bytes);
|
||||||
|
let packed_data = upkr::pack(
|
||||||
|
&data,
|
||||||
|
Some(&mut |pos| {
|
||||||
|
pb.set(pos as u64);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
pb.finish();
|
||||||
|
packed_data
|
||||||
};
|
};
|
||||||
|
println!("Compressed {} bytes to {} bytes ({}%)", data.len(), packed_data.len(), packed_data.len() as f32 * 100. / data.len() as f32);
|
||||||
File::create(outfile)?.write_all(&packed_data)?;
|
File::create(outfile)?.write_all(&packed_data)?;
|
||||||
}
|
}
|
||||||
Some("unpack") => {
|
Some("unpack") => {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ pub struct MatchFinder {
|
|||||||
max_matches_per_length: usize,
|
max_matches_per_length: usize,
|
||||||
patience: usize,
|
patience: usize,
|
||||||
max_length_diff: usize,
|
max_length_diff: usize,
|
||||||
|
|
||||||
|
queue: BinaryHeap<usize>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchFinder {
|
impl MatchFinder {
|
||||||
@@ -43,15 +45,17 @@ impl MatchFinder {
|
|||||||
suffixes,
|
suffixes,
|
||||||
rev_suffixes,
|
rev_suffixes,
|
||||||
lcp,
|
lcp,
|
||||||
max_queue_size: 100,
|
max_queue_size: 1000,
|
||||||
max_matches_per_length: 5,
|
max_matches_per_length: 10,
|
||||||
patience: 100,
|
patience: 1000,
|
||||||
max_length_diff: 2,
|
max_length_diff: 4,
|
||||||
|
queue: BinaryHeap::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches(&self, pos: usize) -> Matches {
|
pub fn matches(&mut self, pos: usize) -> Matches {
|
||||||
let index = self.rev_suffixes[pos] as usize;
|
let index = self.rev_suffixes[pos] as usize;
|
||||||
|
self.queue.clear();
|
||||||
let mut matches = Matches {
|
let mut matches = Matches {
|
||||||
finder: self,
|
finder: self,
|
||||||
pos_range: 0..pos,
|
pos_range: 0..pos,
|
||||||
@@ -62,7 +66,6 @@ impl MatchFinder {
|
|||||||
current_length: usize::MAX,
|
current_length: usize::MAX,
|
||||||
matches_left: 0,
|
matches_left: 0,
|
||||||
max_length: 0,
|
max_length: 0,
|
||||||
queue: BinaryHeap::new(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
matches.move_left();
|
matches.move_left();
|
||||||
@@ -73,7 +76,7 @@ impl MatchFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Matches<'a> {
|
pub struct Matches<'a> {
|
||||||
finder: &'a MatchFinder,
|
finder: &'a mut MatchFinder,
|
||||||
pos_range: Range<usize>,
|
pos_range: Range<usize>,
|
||||||
left_index: usize,
|
left_index: usize,
|
||||||
left_length: usize,
|
left_length: usize,
|
||||||
@@ -82,7 +85,6 @@ pub struct Matches<'a> {
|
|||||||
current_length: usize,
|
current_length: usize,
|
||||||
matches_left: usize,
|
matches_left: usize,
|
||||||
max_length: usize,
|
max_length: usize,
|
||||||
queue: BinaryHeap<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -95,8 +97,8 @@ impl<'a> Iterator for Matches<'a> {
|
|||||||
type Item = Match;
|
type Item = Match;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Match> {
|
fn next(&mut self) -> Option<Match> {
|
||||||
if self.queue.is_empty() || self.matches_left == 0 {
|
if self.finder.queue.is_empty() || self.matches_left == 0 {
|
||||||
self.queue.clear();
|
self.finder.queue.clear();
|
||||||
self.current_length = self.current_length.saturating_sub(1).min(self.left_length.max(self.right_length));
|
self.current_length = self.current_length.saturating_sub(1).min(self.left_length.max(self.right_length));
|
||||||
self.max_length = self.max_length.max(self.current_length);
|
self.max_length = self.max_length.max(self.current_length);
|
||||||
if self.current_length < 2
|
if self.current_length < 2
|
||||||
@@ -104,16 +106,16 @@ impl<'a> Iterator for Matches<'a> {
|
|||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
while self.queue.len() < self.finder.max_queue_size
|
while self.finder.queue.len() < self.finder.max_queue_size
|
||||||
&& (self.left_length == self.current_length
|
&& (self.left_length == self.current_length
|
||||||
|| self.right_length == self.current_length)
|
|| self.right_length == self.current_length)
|
||||||
{
|
{
|
||||||
if self.left_length == self.current_length {
|
if self.left_length == self.current_length {
|
||||||
self.add_to_queue(self.finder.suffixes[self.left_index]);
|
self.finder.queue.push(self.finder.suffixes[self.left_index] as usize);
|
||||||
self.move_left();
|
self.move_left();
|
||||||
}
|
}
|
||||||
if self.right_length == self.current_length {
|
if self.right_length == self.current_length {
|
||||||
self.add_to_queue(self.finder.suffixes[self.right_index]);
|
self.finder.queue.push(self.finder.suffixes[self.right_index] as usize);
|
||||||
self.move_right();
|
self.move_right();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +124,7 @@ impl<'a> Iterator for Matches<'a> {
|
|||||||
|
|
||||||
self.matches_left = self.matches_left.saturating_sub(1);
|
self.matches_left = self.matches_left.saturating_sub(1);
|
||||||
|
|
||||||
self.queue.pop().map(|pos| Match {
|
self.finder.queue.pop().map(|pos| Match {
|
||||||
pos,
|
pos,
|
||||||
length: self.current_length,
|
length: self.current_length,
|
||||||
})
|
})
|
||||||
@@ -168,8 +170,4 @@ impl<'a> Matches<'a> {
|
|||||||
}
|
}
|
||||||
self.right_length = 0;
|
self.right_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_to_queue(&mut self, pos: i32) {
|
|
||||||
self.queue.push(pos as usize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::lz;
|
use crate::{ProgressCallback, lz};
|
||||||
use crate::match_finder::MatchFinder;
|
use crate::match_finder::MatchFinder;
|
||||||
use crate::rans::{CostCounter, RansCoder};
|
use crate::rans::{CostCounter, RansCoder};
|
||||||
|
|
||||||
pub fn pack(data: &[u8]) -> Vec<u8> {
|
pub fn pack(data: &[u8], progress_cb: Option<ProgressCallback>) -> Vec<u8> {
|
||||||
let mut parse = parse(data);
|
let mut parse = parse(data, progress_cb);
|
||||||
let mut ops = vec![];
|
let mut ops = vec![];
|
||||||
while let Some(link) = parse {
|
while let Some(link) = parse {
|
||||||
ops.push(link.op);
|
ops.push(link.op);
|
||||||
@@ -34,10 +34,10 @@ struct Arrival {
|
|||||||
|
|
||||||
type Arrivals = HashMap<usize, Vec<Arrival>>;
|
type Arrivals = HashMap<usize, Vec<Arrival>>;
|
||||||
|
|
||||||
const MAX_ARRIVALS: usize = 4;
|
const MAX_ARRIVALS: usize = 256;
|
||||||
|
|
||||||
fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
fn parse(data: &[u8], mut progress_cb: Option<ProgressCallback>) -> Option<Rc<Parse>> {
|
||||||
let match_finder = MatchFinder::new(data);
|
let mut match_finder = MatchFinder::new(data);
|
||||||
let mut near_matches = [usize::MAX; 1024];
|
let mut near_matches = [usize::MAX; 1024];
|
||||||
let mut last_seen = [usize::MAX; 256];
|
let mut last_seen = [usize::MAX; 256];
|
||||||
|
|
||||||
@@ -58,18 +58,19 @@ fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
|||||||
}
|
}
|
||||||
fn add_match(
|
fn add_match(
|
||||||
arrivals: &mut Arrivals,
|
arrivals: &mut Arrivals,
|
||||||
|
cost_counter: &mut CostCounter,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
length: usize,
|
length: usize,
|
||||||
arrival: &Arrival,
|
arrival: &Arrival,
|
||||||
) {
|
) {
|
||||||
let mut cost_counter = CostCounter(0.);
|
cost_counter.reset();
|
||||||
let mut state = arrival.state.clone();
|
let mut state = arrival.state.clone();
|
||||||
let op = lz::Op::Match {
|
let op = lz::Op::Match {
|
||||||
offset: offset as u32,
|
offset: offset as u32,
|
||||||
len: length as u32,
|
len: length as u32,
|
||||||
};
|
};
|
||||||
op.encode(&mut cost_counter, &mut state);
|
op.encode(cost_counter, &mut state);
|
||||||
add_arrival(
|
add_arrival(
|
||||||
arrivals,
|
arrivals,
|
||||||
pos + length,
|
pos + length,
|
||||||
@@ -79,7 +80,7 @@ fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
|||||||
op,
|
op,
|
||||||
})),
|
})),
|
||||||
state,
|
state,
|
||||||
cost: arrival.cost + cost_counter.0,
|
cost: arrival.cost + cost_counter.cost(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -92,6 +93,8 @@ fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
|||||||
cost: 0.0,
|
cost: 0.0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let cost_counter = &mut CostCounter::new();
|
||||||
let mut best_per_offset = HashMap::new();
|
let mut best_per_offset = HashMap::new();
|
||||||
for pos in 0..data.len() {
|
for pos in 0..data.len() {
|
||||||
let match_length = |offset: usize| {
|
let match_length = |offset: usize| {
|
||||||
@@ -117,8 +120,8 @@ fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
|||||||
*per_offset = per_offset.min(arrival.cost);
|
*per_offset = per_offset.min(arrival.cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
for arrival in here_arrivals {
|
'arrival_loop: for arrival in here_arrivals {
|
||||||
if arrival.cost > (best_cost + 32.0).min(*best_per_offset.get(&arrival.state.last_offset()).unwrap()) {
|
if arrival.cost > (best_cost + 16.0).min(*best_per_offset.get(&arrival.state.last_offset()).unwrap()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut found_last_offset = false;
|
let mut found_last_offset = false;
|
||||||
@@ -127,10 +130,13 @@ fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
|||||||
closest_match = Some(closest_match.unwrap_or(0).max(m.pos));
|
closest_match = Some(closest_match.unwrap_or(0).max(m.pos));
|
||||||
let offset = pos - m.pos;
|
let offset = pos - m.pos;
|
||||||
found_last_offset |= offset as u32 == arrival.state.last_offset();
|
found_last_offset |= offset as u32 == arrival.state.last_offset();
|
||||||
add_match(&mut arrivals, pos, offset, m.length, &arrival);
|
add_match(&mut arrivals, cost_counter, pos, offset, m.length, &arrival);
|
||||||
|
if m.length > 64 {
|
||||||
|
break 'arrival_loop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut near_matches_left = 4;
|
let mut near_matches_left = 8;
|
||||||
let mut match_pos = last_seen[data[pos] as usize];
|
let mut match_pos = last_seen[data[pos] as usize];
|
||||||
while near_matches_left > 0
|
while near_matches_left > 0
|
||||||
&& match_pos != usize::MAX
|
&& match_pos != usize::MAX
|
||||||
@@ -139,7 +145,7 @@ fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
|||||||
let offset = pos - match_pos;
|
let offset = pos - match_pos;
|
||||||
let length = match_length(offset);
|
let length = match_length(offset);
|
||||||
assert!(length > 0);
|
assert!(length > 0);
|
||||||
add_match(&mut arrivals, pos, offset, length, &arrival);
|
add_match(&mut arrivals, cost_counter, pos, offset, length, &arrival);
|
||||||
found_last_offset |= offset as u32 == arrival.state.last_offset();
|
found_last_offset |= offset as u32 == arrival.state.last_offset();
|
||||||
if offset < near_matches.len() {
|
if offset < near_matches.len() {
|
||||||
match_pos = near_matches[match_pos % near_matches.len()];
|
match_pos = near_matches[match_pos % near_matches.len()];
|
||||||
@@ -151,14 +157,14 @@ fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
|||||||
let offset = arrival.state.last_offset() as usize;
|
let offset = arrival.state.last_offset() as usize;
|
||||||
let length = match_length(offset);
|
let length = match_length(offset);
|
||||||
if length > 0 {
|
if length > 0 {
|
||||||
add_match(&mut arrivals, pos, offset, length, &arrival);
|
add_match(&mut arrivals, cost_counter, pos, offset, length, &arrival);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cost_counter = CostCounter(0.);
|
cost_counter.reset();
|
||||||
let mut state = arrival.state;
|
let mut state = arrival.state;
|
||||||
let op = lz::Op::Literal(data[pos]);
|
let op = lz::Op::Literal(data[pos]);
|
||||||
op.encode(&mut cost_counter, &mut state);
|
op.encode(cost_counter, &mut state);
|
||||||
add_arrival(
|
add_arrival(
|
||||||
&mut arrivals,
|
&mut arrivals,
|
||||||
pos + 1,
|
pos + 1,
|
||||||
@@ -168,12 +174,15 @@ fn parse(data: &[u8]) -> Option<Rc<Parse>> {
|
|||||||
op,
|
op,
|
||||||
})),
|
})),
|
||||||
state,
|
state,
|
||||||
cost: arrival.cost + cost_counter.0,
|
cost: arrival.cost + cost_counter.cost(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
near_matches[pos % near_matches.len()] = last_seen[data[pos] as usize];
|
near_matches[pos % near_matches.len()] = last_seen[data[pos] as usize];
|
||||||
last_seen[data[pos] as usize] = pos;
|
last_seen[data[pos] as usize] = pos;
|
||||||
|
if let Some(ref mut cb) = progress_cb {
|
||||||
|
cb(pos + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
arrivals.remove(&data.len()).unwrap()[0].parse.clone()
|
arrivals.remove(&data.len()).unwrap()[0].parse.clone()
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/rans.rs
37
src/rans.rs
@@ -57,13 +57,42 @@ impl RansCoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CostCounter(pub f64);
|
pub struct CostCounter {
|
||||||
|
cost: f64,
|
||||||
|
log2_table: Vec<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CostCounter {
|
||||||
|
pub fn new() -> CostCounter {
|
||||||
|
let log2_table = (0..ONE_PROB)
|
||||||
|
.map(|prob| {
|
||||||
|
let inv_prob = ONE_PROB as f64 / prob as f64;
|
||||||
|
inv_prob.log2()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
CostCounter {
|
||||||
|
cost: 0.0,
|
||||||
|
log2_table,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cost(&self) -> f64 {
|
||||||
|
self.cost
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.cost = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EntropyCoder for CostCounter {
|
impl EntropyCoder for CostCounter {
|
||||||
fn encode_bit(&mut self, bit: bool, prob: u16) {
|
fn encode_bit(&mut self, bit: bool, prob: u16) {
|
||||||
let prob = if bit { prob as u32 } else { ONE_PROB - prob as u32 };
|
let prob = if bit {
|
||||||
let inv_prob = ONE_PROB as f64 / prob as f64;
|
prob as u32
|
||||||
self.0 += inv_prob.log2();
|
} else {
|
||||||
|
ONE_PROB - prob as u32
|
||||||
|
};
|
||||||
|
self.cost += self.log2_table[prob as usize];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user