use fearless_simd::{Level, Simd, dispatch};
use super::fast::{FastCore, encode_fragment};
use super::greedy::backward_references::{ReferenceState, create_backward_references};
use super::greedy::hashers::{MatchFinder, with_matcher};
use super::greedy::params::GreedyParams;
use super::hq::h10::BinaryTreeMatcher;
use super::hq::params::{HqParams, HqQuality};
use super::hq::zopfli::{
ZopfliState, ZopfliWorkspace, create_hq_zopfli_backward_references,
create_zopfli_backward_references,
};
use super::rfc9841::context::SharedContextInner;
use super::shared::bits::BitWriter;
use super::shared::command::{Command, CommandExtension, extend_last_command};
use super::shared::ringbuffer::{BlockSpan, Window};
pub(crate) struct GreedyInput<'a> {
pub(crate) matcher: &'a mut MatchFinder,
pub(crate) params: &'a GreedyParams,
pub(crate) window: Window<'a>,
pub(crate) span: BlockSpan,
pub(crate) attached: Option<&'a SharedContextInner>,
pub(crate) references: &'a mut ReferenceState,
pub(crate) commands: &'a mut Vec<Command>,
}
pub(crate) struct HqInput<'a> {
pub(crate) matcher: &'a mut BinaryTreeMatcher,
pub(crate) params: &'a HqParams,
pub(crate) window: Window<'a>,
pub(crate) span: BlockSpan,
pub(crate) attached: Option<&'a SharedContextInner>,
pub(crate) references: &'a mut ZopfliState,
pub(crate) workspace: &'a mut ZopfliWorkspace,
pub(crate) commands: &'a mut Vec<Command>,
}
pub(crate) trait Kernels: Send + Sync {
fn fast(
&self,
core: &mut FastCore,
input: &[u8],
is_last: bool,
table: &mut [i32],
writer: &mut BitWriter<'_>,
);
fn extend(&self, input: CommandExtension<'_>);
fn fast_append(
&self,
core: &mut FastCore,
input: &[u8],
is_last: bool,
table: &mut [i32],
writer: &mut BitWriter<'_, Vec<u8>>,
);
fn greedy(&self, input: GreedyInput<'_>);
fn hq(&self, input: HqInput<'_>);
fn stitch(
&self,
matcher: &mut BinaryTreeMatcher,
input_size: usize,
position: usize,
window: Window<'_>,
);
}
struct Selected<S, G, const INDEPENDENT: bool> {
simd: S,
greedy: G,
}
fn boxed<S: Simd, const INDEPENDENT: bool>(simd: S) -> Box<dyn Kernels> {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
if let Some(sse2) = simd.level().as_sse2() {
return Box::new(Selected::<S, fearless_simd::Sse2, INDEPENDENT> {
simd,
greedy: sse2,
});
}
Box::new(Selected::<S, fearless_simd::Fallback, INDEPENDENT> {
simd,
greedy: fearless_simd::Fallback::new(),
})
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
{
Box::new(Selected::<S, S, INDEPENDENT> { simd, greedy: simd })
}
}
pub(crate) fn select(level: Level) -> Box<dyn Kernels> {
dispatch!(level, simd => boxed::<_, false>(simd))
}
pub(crate) fn select_independent(level: Level) -> Box<dyn Kernels> {
dispatch!(level, simd => boxed::<_, true>(simd))
}
impl<S: Simd, G: Simd, const INDEPENDENT: bool> Kernels for Selected<S, G, INDEPENDENT> {
fn fast(
&self,
core: &mut FastCore,
input: &[u8],
is_last: bool,
table: &mut [i32],
writer: &mut BitWriter<'_>,
) {
self.simd.vectorize(
#[inline(always)]
|| encode_fragment::<_, INDEPENDENT>(self.simd, core, input, is_last, table, writer),
);
}
fn extend(&self, input: CommandExtension<'_>) {
self.simd.vectorize(
#[inline(always)]
|| extend_last_command(self.simd, input),
);
}
fn fast_append(
&self,
core: &mut FastCore,
input: &[u8],
is_last: bool,
table: &mut [i32],
writer: &mut BitWriter<'_, Vec<u8>>,
) {
self.simd.vectorize(
#[inline(always)]
|| encode_fragment::<_, INDEPENDENT>(self.simd, core, input, is_last, table, writer),
);
}
fn greedy(&self, input: GreedyInput<'_>) {
let GreedyInput {
matcher,
params,
window,
span,
attached,
references,
commands,
} = input;
self.greedy.vectorize(
#[inline(always)]
|| match attached {
None => with_matcher!(matcher, |finder| create_backward_references::<
_,
_,
false,
INDEPENDENT,
>(
self.greedy,
finder,
params,
window,
span,
None,
references,
commands
)),
Some(_) => {
with_matcher!(matcher, |finder| create_backward_references::<
_,
_,
true,
INDEPENDENT,
>(
self.greedy,
finder,
params,
window,
span,
attached,
references,
commands
))
}
},
);
}
fn hq(&self, input: HqInput<'_>) {
let HqInput {
matcher,
params,
window,
span,
attached,
references,
workspace,
commands,
} = input;
self.simd.vectorize(
#[inline(always)]
|| match params.quality {
HqQuality::Q10 => create_zopfli_backward_references::<_, INDEPENDENT>(
self.simd,
span.bytes as usize,
span.position as usize,
window.data,
window.mask,
params,
attached,
matcher,
workspace,
references,
commands,
),
HqQuality::Q11 => create_hq_zopfli_backward_references::<_, INDEPENDENT>(
self.simd,
span.bytes as usize,
span.position as usize,
window.data,
window.mask,
params,
attached,
matcher,
workspace,
references,
commands,
),
},
);
}
fn stitch(
&self,
matcher: &mut BinaryTreeMatcher,
input_size: usize,
position: usize,
window: Window<'_>,
) {
self.simd.vectorize(
#[inline(always)]
|| {
matcher.stitch_to_previous_block(
self.simd,
input_size,
position,
window.data,
window.mask,
)
},
);
}
}