transpose out of place for rot_90 cloner

This commit is contained in:
bendn 2023-10-02 04:19:15 +07:00
parent ed92acb021
commit f863d295d6
No known key found for this signature in database
GPG key ID: 0D9D3A2A3B2A93D6
4 changed files with 54 additions and 13 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "fimg" name = "fimg"
version = "0.4.12" version = "0.4.13"
authors = ["bend-n <bend.n@outlook.com>"] authors = ["bend-n <bend.n@outlook.com>"]
license = "MIT" license = "MIT"
edition = "2021" edition = "2021"
@ -9,6 +9,7 @@ repository = "https://github.com/bend-n/fimg"
exclude = ["tdata", "benches/", ".gitignore"] exclude = ["tdata", "benches/", ".gitignore"]
[dependencies] [dependencies]
mattr = "0.0.2"
png = { version = "0.17", features = ["unstable"], optional = true } png = { version = "0.17", features = ["unstable"], optional = true }
[dev-dependencies] [dev-dependencies]

View file

@ -1,7 +1,7 @@
use fimg::*; use fimg::*;
macro_rules! bench { macro_rules! bench {
(fn $name: ident() { run $fn: ident() }) => { (fn $name: ident() { run $fn: ident() } $($namec:ident)?) => {
fn $name() { fn $name() {
let mut img: Image<_, 4> = let mut img: Image<_, 4> =
Image::build(128, 128).buf(include_bytes!("4_128x128.imgbuf").to_vec()); Image::build(128, 128).buf(include_bytes!("4_128x128.imgbuf").to_vec());
@ -12,12 +12,24 @@ macro_rules! bench {
}; };
} }
} }
$(fn $namec() {
let img: Image<&[u8], 4> =
Image::build(128, 128).buf(include_bytes!("4_128x128.imgbuf"));
#[allow(unused_unsafe)]
unsafe {
std::hint::black_box(img.cloner().$fn())
};
})?
}; };
} }
bench!(fn flip_h() { run flip_h() }); bench!(fn flip_h() { run flip_h() } flip_hc);
bench!(fn flip_v() { run flip_v() }); bench!(fn flip_v() { run flip_v() } flip_vc);
bench!(fn rotate_90() { run rot_90() }); bench!(fn rotate_90() { run rot_90() } rot_90c);
bench!(fn rotate_180() { run rot_180() }); bench!(fn rotate_180() { run rot_180() } rot_180c);
bench!(fn rotate_270() { run rot_270() }); bench!(fn rotate_270() { run rot_270() } rot_280c);
iai::main!(flip_h, flip_v, rotate_90, rotate_180, rotate_270); iai::main!(
flip_h, flip_v, rotate_90, rotate_180, rotate_270, flip_hc, flip_vc, rot_90c, rot_180c,
rot_280c
);

View file

@ -107,9 +107,18 @@ impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
/// UB if the image is not square /// UB if the image is not square
#[must_use = "function does not modify the original image"] #[must_use = "function does not modify the original image"]
pub unsafe fn rot_90(&self) -> Image<Vec<u8>, CHANNELS> { pub unsafe fn rot_90(&self) -> Image<Vec<u8>, CHANNELS> {
let mut out = self.flip_v(); let mut out = self.alloc();
// SAFETY: yep
unsafe {
mattr::transpose(
self.flatten(),
out.flatten_mut(),
self.height() as usize,
self.width() as usize,
)
};
// SAFETY: sqar // SAFETY: sqar
unsafe { transpose(&mut out.as_mut()) }; unsafe { crev(out.as_mut()) };
out out
} }
@ -157,6 +166,26 @@ impl<const CHANNELS: usize, T: DerefMut<Target = [u8]>> Image<T, CHANNELS> {
} }
} }
/// Reverse columns of square image
/// # Safety
///
/// UB if supplied image not square
unsafe fn crev<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(mut img: Image<T, CHANNELS>) {
debug_assert_eq!(img.width(), img.height());
let size = img.width() as usize;
let b = img.flatten_mut();
for i in 0..size {
let mut start = 0;
let mut end = size - 1;
while start < end {
// SAFETY: hmm
unsafe { b.swap_unchecked(i * size + start, i * size + end) };
start += 1;
end -= 1;
}
}
}
/// Transpose a square image /// Transpose a square image
/// # Safety /// # Safety
/// ///

View file

@ -10,8 +10,7 @@
portable_simd, portable_simd,
array_windows, array_windows,
const_option, const_option,
array_chunks, array_chunks
test
)] )]
#![warn( #![warn(
clippy::missing_docs_in_private_items, clippy::missing_docs_in_private_items,
@ -300,7 +299,7 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
#[inline] #[inline]
/// Flatten the chunks of this image into a slice of slices. /// Flatten the chunks of this image into a slice of slices.
pub fn flatten(&mut self) -> &[[u8; CHANNELS]] { pub fn flatten(&self) -> &[[u8; CHANNELS]] {
// SAFETY: buffer cannot have half pixels // SAFETY: buffer cannot have half pixels
unsafe { self.buffer.as_chunks_unchecked::<CHANNELS>() } unsafe { self.buffer.as_chunks_unchecked::<CHANNELS>() }
} }