135 lines
3.2 KiB
Rust
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 **);
|