Fake Rayon (#162)
Dummy implementation of Rayon's traits to avoid `#[cfg()]` and duplicated non-parallel code.
This commit is contained in:
parent
0d4a9e06d6
commit
33890cf0fd
4 changed files with 61 additions and 38 deletions
|
|
@ -9,7 +9,6 @@ use png::STD_COMPRESSION;
|
||||||
use png::STD_FILTERS;
|
use png::STD_FILTERS;
|
||||||
use png::STD_STRATEGY;
|
use png::STD_STRATEGY;
|
||||||
use png::STD_WINDOW;
|
use png::STD_WINDOW;
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::sync::mpsc::*;
|
use std::sync::mpsc::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -63,10 +62,7 @@ impl Evaluator {
|
||||||
let best_result: Mutex<Option<(PngData, _, _)>> = Mutex::new(None);
|
let best_result: Mutex<Option<(PngData, _, _)>> = Mutex::new(None);
|
||||||
// ends when sender is dropped
|
// ends when sender is dropped
|
||||||
for (nth, (image, bias, is_reduction)) in from_channel.iter().enumerate() {
|
for (nth, (image, bias, is_reduction)) in from_channel.iter().enumerate() {
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
let filters_iter = STD_FILTERS.par_iter().with_max_len(1);
|
let filters_iter = STD_FILTERS.par_iter().with_max_len(1);
|
||||||
#[cfg(not(feature = "parallel"))]
|
|
||||||
let filters_iter = STD_FILTERS.iter();
|
|
||||||
|
|
||||||
filters_iter.for_each(|&f| {
|
filters_iter.for_each(|&f| {
|
||||||
if let Ok(idat_data) = deflate::deflate(
|
if let Ok(idat_data) = deflate::deflate(
|
||||||
|
|
|
||||||
38
src/lib.rs
38
src/lib.rs
|
|
@ -9,6 +9,8 @@ extern crate miniz_oxide;
|
||||||
extern crate num_cpus;
|
extern crate num_cpus;
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
extern crate rayon;
|
extern crate rayon;
|
||||||
|
#[cfg(not(feature = "parallel"))]
|
||||||
|
mod rayon;
|
||||||
extern crate rgb;
|
extern crate rgb;
|
||||||
extern crate zopfli;
|
extern crate zopfli;
|
||||||
|
|
||||||
|
|
@ -21,7 +23,6 @@ use image::{DynamicImage, GenericImageView, ImageFormat, Pixel};
|
||||||
use png::PngImage;
|
use png::PngImage;
|
||||||
use png::PngData;
|
use png::PngData;
|
||||||
use colors::BitDepth;
|
use colors::BitDepth;
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
@ -569,10 +570,7 @@ fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options) -> PngR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
let filter_iter = filter.par_iter().with_max_len(1);
|
let filter_iter = filter.par_iter().with_max_len(1);
|
||||||
#[cfg(not(feature = "parallel"))]
|
|
||||||
let filter_iter = filter.iter();
|
|
||||||
let filters: HashMap<u8, Vec<u8>> = filter_iter
|
let filters: HashMap<u8, Vec<u8>> = filter_iter
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
let png = png.clone();
|
let png = png.clone();
|
||||||
|
|
@ -583,10 +581,7 @@ fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options) -> PngR
|
||||||
let added_interlacing = opts.interlace == Some(1) && original_png.raw.ihdr.interlaced == 0;
|
let added_interlacing = opts.interlace == Some(1) && original_png.raw.ihdr.interlaced == 0;
|
||||||
|
|
||||||
let best_size = AtomicMin::new(if opts.force { None } else { Some(original_len) });
|
let best_size = AtomicMin::new(if opts.force { None } else { Some(original_len) });
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
let results_iter = results.into_par_iter().with_max_len(1);
|
let results_iter = results.into_par_iter().with_max_len(1);
|
||||||
#[cfg(not(feature = "parallel"))]
|
|
||||||
let results_iter = results.into_iter();
|
|
||||||
let best = results_iter.filter_map(|trial| {
|
let best = results_iter.filter_map(|trial| {
|
||||||
if deadline.passed() {
|
if deadline.passed() {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -635,20 +630,8 @@ fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options) -> PngR
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#[cfg(feature = "parallel")]
|
let best: Option<TrialWithData> = best.reduce_with(|i, j| {
|
||||||
let best: Option<TrialWithData> =
|
if i.1.len() <= j.1.len() { i } else { j }
|
||||||
best.reduce_with(|i, j| if i.1.len() <= j.1.len() { i } else { j });
|
|
||||||
#[cfg(not(feature = "parallel"))]
|
|
||||||
let best: Option<TrialWithData> = best.fold(None, |i, j| {
|
|
||||||
if let Some(i) = i {
|
|
||||||
if i.1.len() <= j.1.len() {
|
|
||||||
Some(i)
|
|
||||||
} else {
|
|
||||||
Some(j)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Some(j)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(better) = best {
|
if let Some(better) = best {
|
||||||
|
|
@ -704,15 +687,10 @@ fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options) -> PngR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (old_png, new_png) = {
|
let (old_png, new_png) = rayon::join(
|
||||||
let old_png = || image::load_from_memory_with_format(original_data, ImageFormat::PNG);
|
|| image::load_from_memory_with_format(original_data, ImageFormat::PNG),
|
||||||
let new_png = || image::load_from_memory_with_format(&output, ImageFormat::PNG);
|
|| image::load_from_memory_with_format(&output, ImageFormat::PNG)
|
||||||
#[cfg(feature = "parallel")]
|
);
|
||||||
let res = rayon::join(old_png, new_png);
|
|
||||||
#[cfg(not(feature = "parallel"))]
|
|
||||||
let res = (old_png(), new_png());
|
|
||||||
res
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(new_png) = new_png {
|
if let Ok(new_png) = new_png {
|
||||||
if let Ok(old_png) = old_png {
|
if let Ok(old_png) = old_png {
|
||||||
|
|
|
||||||
53
src/rayon.rs
Normal file
53
src/rayon.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
pub mod prelude {
|
||||||
|
pub use super::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ParallelIterator: Iterator + Sized {
|
||||||
|
fn with_max_len(self, _l: usize) -> Self {self}
|
||||||
|
fn reduce_with<OP>(mut self, op: OP) -> Option<Self::Item> where OP: Fn(Self::Item, Self::Item) -> Self::Item + Sync {
|
||||||
|
if let Some(a) = self.next() {
|
||||||
|
Some(self.fold(a, op))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoParallelIterator {
|
||||||
|
type Iter: Iterator<Item=Self::Item>;
|
||||||
|
type Item: Send;
|
||||||
|
fn into_par_iter(self) -> Self::Iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoParallelRefIterator<'data> {
|
||||||
|
type Iter: Iterator<Item=Self::Item>;
|
||||||
|
type Item: Send + 'data;
|
||||||
|
fn par_iter(&'data self) -> Self::Iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: IntoIterator> IntoParallelIterator for I where I::Item: Send {
|
||||||
|
type Iter = I::IntoIter;
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn into_par_iter(self) -> Self::Iter {
|
||||||
|
self.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, I: 'data + ?Sized> IntoParallelRefIterator<'data> for I
|
||||||
|
where &'data I: IntoParallelIterator
|
||||||
|
{
|
||||||
|
type Iter = <&'data I as IntoParallelIterator>::Iter;
|
||||||
|
type Item = <&'data I as IntoParallelIterator>::Item;
|
||||||
|
|
||||||
|
fn par_iter(&'data self) -> Self::Iter {
|
||||||
|
self.into_par_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator> ParallelIterator for I {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn join<A, B>(a: impl FnOnce() -> A, b: impl FnOnce() -> B) -> (A, B) {
|
||||||
|
(a(), b())
|
||||||
|
}
|
||||||
|
|
@ -7,16 +7,12 @@ use colors::AlphaOptim;
|
||||||
use headers::IhdrData;
|
use headers::IhdrData;
|
||||||
use png::PngImage;
|
use png::PngImage;
|
||||||
use colors::ColorType;
|
use colors::ColorType;
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
pub fn try_alpha_reductions(png: Arc<PngImage>, alphas: &HashSet<AlphaOptim>, eval: &Evaluator) {
|
pub fn try_alpha_reductions(png: Arc<PngImage>, alphas: &HashSet<AlphaOptim>, eval: &Evaluator) {
|
||||||
assert!(!alphas.is_empty());
|
assert!(!alphas.is_empty());
|
||||||
let alphas = alphas.iter().collect::<Vec<_>>();
|
let alphas = alphas.iter().collect::<Vec<_>>();
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
let alphas_iter = alphas.par_iter().with_max_len(1);
|
let alphas_iter = alphas.par_iter().with_max_len(1);
|
||||||
#[cfg(not(feature = "parallel"))]
|
|
||||||
let alphas_iter = alphas.iter();
|
|
||||||
alphas_iter
|
alphas_iter
|
||||||
.filter_map(|&alpha| filtered_alpha_channel(&png, *alpha))
|
.filter_map(|&alpha| filtered_alpha_channel(&png, *alpha))
|
||||||
.for_each(|image| eval.try_image(Arc::new(image), 0.99));
|
.for_each(|image| eval.try_image(Arc::new(image), 0.99));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue