2024-11-12 17:07:06 +02:00

135 lines
3.2 KiB
Rust

use core::{
cmp::Ordering,
ffi::{c_int, c_void},
};
struct Array {
base: *mut c_void,
size: usize,
nmemb: usize,
}
impl Array {
unsafe fn new(base: *mut c_void, nmemb: usize, size: usize) -> Option<Self> {
if nmemb == 0 || size == 0 || base.is_null() {
return None;
}
Some(Self { base, nmemb, size })
}
fn element(&mut self, i: usize) -> *mut c_void {
if i >= self.nmemb {
panic!("i = {}, nmemb = {}", i, self.nmemb);
}
unsafe { self.base.add(i * self.size) }
}
fn partition<F: Fn(*mut c_void, *mut c_void) -> Ordering>(
&mut self,
lower: usize,
upper: usize,
cmp: &F,
) -> usize {
if lower >= upper {
panic!()
}
let pivot_ptr = self.element(lower);
let mut i = lower;
let mut j = upper;
while i < j {
while i <= upper - 1 && cmp(self.element(i), pivot_ptr).is_le() {
i += 1;
}
while j >= lower + 1 && cmp(self.element(j), pivot_ptr).is_gt() {
j -= 1;
}
if i < j {
self.swap(i, j);
}
}
self.swap(lower, j);
j
}
fn swap(&mut self, i: usize, j: usize) {
let el_i = self.element(i) as *mut u8;
let el_j = self.element(j) as *mut u8;
unsafe {
for i in 0..self.size {
core::ptr::swap(el_i.add(i), el_j.add(i));
}
}
}
fn sort_inner<F: Fn(*mut c_void, *mut c_void) -> Ordering>(
&mut self,
lower: usize,
upper: usize,
cmp: &F,
) {
if lower < upper {
let partition = self.partition(lower, upper, cmp);
if partition != 0 {
self.sort_inner(lower, partition - 1, cmp);
}
self.sort_inner(partition + 1, upper, cmp);
}
}
fn sort<F: Fn(*mut c_void, *mut c_void) -> Ordering>(&mut self, cmp: &F) {
if self.nmemb != 0 {
self.sort_inner(0, self.nmemb - 1, cmp);
}
}
}
pub type qsort_compar_fn_t = extern "C" fn(*const c_void, *const c_void) -> c_int;
pub type qsort_compar_r_fn_t = extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int;
pub type bsearch_compar_fn_t = extern "C" fn(*const c_void, *const c_void) -> c_int;
#[no_mangle]
unsafe extern "C" fn bsearch(
_key: *const c_void,
_base: *const c_void,
_nmemb: usize,
_size: usize,
_compar: bsearch_compar_fn_t,
) -> *mut c_void {
todo!()
}
#[no_mangle]
unsafe extern "C" fn qsort(
base: *mut c_void,
nmemb: usize,
size: usize,
compar: qsort_compar_fn_t,
) {
let Some(mut array) = Array::new(base, nmemb, size) else {
return;
};
array.sort(&|a, b| compar(a, b).cmp(&0));
}
#[no_mangle]
unsafe extern "C" fn qsort_r(
base: *mut c_void,
nmemb: usize,
size: usize,
compar: qsort_compar_r_fn_t,
arg: *mut c_void,
) {
let Some(mut array) = Array::new(base, nmemb, size) else {
return;
};
array.sort(&|a, b| compar(a, b, arg).cmp(&0));
}
// int getsubopt(char **, char *const *, char **);