diff --git a/.cargo/config.toml b/.cargo/config.toml index 709bb3a..d38b22b 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,6 @@ [build] -target = "x86_64-unknown-linux-gnu" +target = "aarch64-linux-android" +rustflags = ["-Ctarget-feature=+neon"] [unstable] build-std = ["std", "panic_abort"] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 85328cc..182628f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,10 +17,11 @@ jobs: - uses: actions/checkout@v3 - name: Setup NDK run: | - wget -nv https://dl.google.com/android/repository/android-ndk-r25b-linux.zip - unzip -qo android-ndk-r25b-linux.zip - chmod -R 777 ./android-ndk-r25b - export NDK_HOME="$(pwd)/android-ndk-r25b" + N="android-ndk-r25c" + wget -nv https://dl.google.com/android/repository/${N}-linux.zip + unzip -qo ${N}-linux.zip + chmod -R 777 ./${N} + export NDK_HOME="$(pwd)/${N}" cargo install cargo-ndk mkdir -p output diff --git a/.gitignore b/.gitignore index 7764d73..88584bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /test +test* Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 1ccb779..3509814 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" [dependencies] libc = "0.2" +[profile.dev] +panic = "abort" + [profile.release] lto = true panic = "abort" diff --git a/src/main.rs b/src/main.rs index c53b9f6..3ccc063 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,43 +1,22 @@ #![no_main] -#![feature(slice_as_chunks)] -#![feature(let_chains)] - -use cmpr::{cprintln, Mmap, RawArgs}; -use std::{fs::File, os::unix::prelude::AsRawFd, path::Path}; - -mod cmperror { - use std::io; - pub enum Error { - FileReadErr(io::Error), - MmapErr, - } - - impl From for Error { - fn from(e: io::Error) -> Self { - Self::FileReadErr(e) - } - } -} +#![feature(array_chunks, portable_simd, let_chains)] #[no_mangle] pub extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 { let mut args = RawArgs::new(argc, argv); let _ = args.next().unwrap(); if args.len() < 2 { - if let Some(arg) = args.next() && arg == "--version" { - cprintln!("cmpr by j-hc (github.com/j-hc)\nLicense GPL-3.0"); - } else { - cprintln!("Usage: cmpr "); - } - return 1; + cprintln!( + "Usage: cmpr \ncmpr by j-hc (github.com/j-hc)\nLicense GPL-3.0" + ); } match run(args.next().unwrap(), args.next().unwrap()) { Ok(true) => 0, Err(e) => { match e { - cmperror::Error::FileReadErr(_) => cprintln!("ERROR: File read failed"), - cmperror::Error::MmapErr => cprintln!("ERROR: Memory mapping failed"), + RunErr::IO => cprintln!("ERROR: could not read file"), + RunErr::MMap => cprintln!("ERROR: could not mmap file"), } 1 } @@ -45,22 +24,43 @@ pub extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 { } } -fn run(f1_path: impl AsRef, f2_path: impl AsRef) -> Result { - const CHUNK_SIZE: usize = 4096; +enum RunErr { + IO, + MMap, +} - let f1 = File::open(f1_path)?; - let f1_size = f1.metadata()?.len(); +impl From for RunErr { + fn from(_: io::Error) -> Self { + Self::IO + } +} - let f2 = File::open(f2_path)?; +fn run(p1: &str, p2: &str) -> Result { + let f1 = File::open(p1)?; + let f1_size = f1.metadata()?.len(); + let f2 = File::open(p2)?; let f2_size = f2.metadata()?.len(); if f1_size != f2_size { return Ok(false); } + let Some(fm1) = Mmap::new(f1.as_raw_fd(), f1_size as _) else { return Err(RunErr::MMap) }; + let Some(fm2) = Mmap::new(f2.as_raw_fd(), f2_size as _) else { return Err(RunErr::MMap) }; - let mmap1 = Mmap::new(f1.as_raw_fd(), f1_size as _).ok_or(cmperror::Error::MmapErr)?; - let mmap2 = Mmap::new(f2.as_raw_fd(), f2_size as _).ok_or(cmperror::Error::MmapErr)?; + Ok(compare(&fm1, &fm2)) +} + +fn compare(fm1: &[u8], fm2: &[u8]) -> bool { + const CHUNK_SIZE: usize = 16; + let mut fm1 = fm1.array_chunks::(); + let mut fm2 = fm2.array_chunks::(); - let (chunks1, r1) = mmap1.as_chunks::(); - let (chunks2, r2) = mmap2.as_chunks::(); - Ok(chunks1.iter().zip(chunks2.iter()).all(|(b1, b2)| b1 == b2) && r1 == r2) + iter::zip(fm1.by_ref(), fm2.by_ref()) + .all(|(m1, m2)| u8x16::from_slice(m1) == u8x16::from_slice(m2)) + && iter::zip(fm1.remainder(), fm2.remainder()).all(|(m1, m2)| m1 == m2) } + +use cmpr::{cprintln, Mmap, RawArgs}; +use std::fs::File; +use std::os::fd::AsRawFd; +use std::simd::u8x16; +use std::{io, iter};