insert sorted, return tuple instead of strange signed index from binary search methods

This commit is contained in:
janis 2025-10-29 13:38:39 +01:00
parent 1a4055a69a
commit cd21ecb782
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 85 additions and 25 deletions

View file

@ -21,6 +21,7 @@ global vec_get
global vec_drop global vec_drop
global vec_find global vec_find
global vec_insert global vec_insert
global vec_insert_sorted
global vec_binary_search_by global vec_binary_search_by
global vec_tests global vec_tests
@ -507,7 +508,7 @@ vec_insert:
;; rsi: pointer to key ;; rsi: pointer to key
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32 ;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
;; rcx: compare_fn context ;; rcx: compare_fn context
;;fn vec_binary_search_by(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> isize ;;fn vec_binary_search_by(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> (usize, bool)
vec_binary_search_by: vec_binary_search_by:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@ -518,6 +519,7 @@ vec_binary_search_by:
mov [rsp + 0x18], rcx ; save compare fn context mov [rsp + 0x18], rcx ; save compare fn context
mov rax, [rdi + 8] ; len mov rax, [rdi + 8] ; len
dec rax ; high
mov qword [rsp + 0x20], 0 ; low mov qword [rsp + 0x20], 0 ; low
mov [rsp + 0x28], rax ; mid mov [rsp + 0x28], rax ; mid
mov [rsp + 0x30], rax ; high mov [rsp + 0x30], rax ; high
@ -551,31 +553,55 @@ vec_binary_search_by:
; greater ; greater
mov rax, [rsp + 0x28] ; mid mov rax, [rsp + 0x28] ; mid
inc rax inc rax
mov [rsp + 0x28], rax ; mid
mov [rsp + 0x20], rax ; low = mid + 1 mov [rsp + 0x20], rax ; low = mid + 1
jmp .loop jmp .loop
.less: .less:
mov rax, [rsp + 0x28] ; mid mov rax, [rsp + 0x28] ; mid
cmp rax, 0
je .not_found ; if mid == 0, not found
dec rax dec rax
mov [rsp + 0x30], rax ; high = mid - 1 mov [rsp + 0x30], rax ; high = mid - 1
jmp .loop jmp .loop
.found: .found:
mov rax, [rsp + 0x28] mov rax, [rsp + 0x28]
xor rdx, rdx
jmp .epilogue jmp .epilogue
.not_found: .not_found:
mov rax, [rsp + 0x20] mov rax, [rsp + 0x28]
not rax mov rdx, 1
.epilogue: .epilogue:
add rsp, 0x40 add rsp, 0x40
pop rbp pop rbp
ret ret
;; rdi: pointer to Vec struct
;; rsi: pointer to key
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
;; rcx: compare_fn context
;;fn vec_insert_sorted(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> (usize, bool)
vec_insert_sorted:
push rbp
mov rbp, rsp
sub rsp, 0x18
mov [rsp], rdi ; vec
mov [rsp + 8], rsi ; element ptr
call vec_binary_search_by
test rdx, rdx
jnz .insert
; element already exists
jmp .epilogue
.insert:
mov [rsp + 0x10], rax ; index
mov rdi, [rsp] ; vec
mov rsi, rax ; index
mov rdx, [rsp + 8] ; element ptr
call vec_insert
mov rax, [rsp + 0x10] ; index
mov rdx, 1 ; indicate inserted
.epilogue:
add rsp, 0x18
pop rbp
ret

View file

@ -60,11 +60,7 @@ impl<T> VecT<T> {
fn push(&mut self, value: T) { fn push(&mut self, value: T) {
let value = core::mem::ManuallyDrop::new(value); let value = core::mem::ManuallyDrop::new(value);
unsafe { unsafe {
vec_push( vec_push(&mut self.vec, &raw const value as *const T as *const u8);
&mut self.vec,
&raw const value as *const T as *const u8,
core::mem::size_of::<T>(),
);
} }
} }
@ -172,19 +168,47 @@ impl<T> VecT<T> {
} }
unsafe { unsafe {
let index = vec_binary_search_by( let (index, vacant) = vec_binary_search_by(
&raw const self.vec as *mut _, &raw const self.vec as *mut _,
elem as *const T as *const u8, elem as *const T as *const u8,
cmp_trampoline::<T, F>, cmp_trampoline::<T, F>,
&raw mut cmp as *mut F as *mut (), &raw mut cmp as *mut F as *mut (),
); );
if (index as isize) < 0 { if vacant {
Err(!index) Err(index)
} else { } else {
Ok(index) Ok(index)
} }
} }
} }
fn insert_sorted<F>(&self, elem: T, mut cmp: F) -> Result<usize, usize>
where
F: FnMut(&T, &T) -> i32,
{
extern "C" fn cmp_trampoline<T, F: FnMut(&T, &T) -> i32>(
f: *const (),
a: *const u8,
b: *const u8,
) -> i32 {
let f = unsafe { &mut *(f as *mut F) };
let a = unsafe { &*(a as *const T) };
let b = unsafe { &*(b as *const T) };
f(a, b)
}
let mut elem = core::mem::ManuallyDrop::new(elem);
unsafe {
let (index, inserted) = vec_insert_sorted(
&raw const self.vec as *mut _,
&raw const elem as *const u8,
cmp_trampoline::<T, F>,
&raw mut cmp as *mut F as *mut (),
);
Ok(index)
}
}
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
@ -203,7 +227,7 @@ unsafe extern "C" {
drop: Option<extern "C" fn(*mut u8)>, drop: Option<extern "C" fn(*mut u8)>,
cap: usize, cap: usize,
); );
unsafe fn vec_push(vec: *mut BlobVec, elem: *const u8, size: usize); unsafe fn vec_push(vec: *mut BlobVec, elem: *const u8);
unsafe fn vec_insert(vec: *mut BlobVec, index: usize, elem: *const u8); unsafe fn vec_insert(vec: *mut BlobVec, index: usize, elem: *const u8);
unsafe fn vec_pop(vec: *mut BlobVec); unsafe fn vec_pop(vec: *mut BlobVec);
unsafe fn vec_drop_last(vec: *mut BlobVec); unsafe fn vec_drop_last(vec: *mut BlobVec);
@ -226,7 +250,13 @@ unsafe extern "C" {
elem: *const u8, elem: *const u8,
cmp: extern "C" fn(*const (), *const u8, *const u8) -> i32, cmp: extern "C" fn(*const (), *const u8, *const u8) -> i32,
cmp_data: *mut (), cmp_data: *mut (),
) -> usize; ) -> (usize, bool);
unsafe fn vec_insert_sorted(
vec: *mut BlobVec,
elem: *const u8,
cmp: extern "C" fn(*const (), *const u8, *const u8) -> i32,
cmp_data: *mut (),
) -> (usize, bool);
} }
fn main() { fn main() {
@ -266,7 +296,7 @@ fn main() {
vec_init(&mut vec, 4, Some(drop)); vec_init(&mut vec, 4, Some(drop));
let mut value: u32 = 2; let mut value: u32 = 2;
assert_eq!(vec.len, 0); assert_eq!(vec.len, 0);
vec_push(&mut vec, &value as *const u32 as *const u8, 4); vec_push(&mut vec, &value as *const u32 as *const u8);
assert_eq!(vec.len, 1); assert_eq!(vec.len, 1);
assert_eq!(as_slice::<u32>(&vec), &[2]); assert_eq!(as_slice::<u32>(&vec), &[2]);
let retrieved = *(vec_get(&mut vec, 0) as *mut u32); let retrieved = *(vec_get(&mut vec, 0) as *mut u32);
@ -276,10 +306,10 @@ fn main() {
assert_eq!(vec.len, 0); assert_eq!(vec.len, 0);
assert_eq!(get_drops(), 2); assert_eq!(get_drops(), 2);
value = 3; value = 3;
vec_push(&mut vec, &value as *const u32 as *const u8, 4); vec_push(&mut vec, &value as *const u32 as *const u8);
assert_eq!(as_slice::<u32>(&vec), &[3]); assert_eq!(as_slice::<u32>(&vec), &[3]);
value = 5; value = 5;
vec_push(&mut vec, &value as *const u32 as *const u8, 4); vec_push(&mut vec, &value as *const u32 as *const u8);
assert_eq!(as_slice::<u32>(&vec), &[3, 5]); assert_eq!(as_slice::<u32>(&vec), &[3, 5]);
assert_eq!(vec.len, 2); assert_eq!(vec.len, 2);
vec_drop_last(&mut vec); vec_drop_last(&mut vec);
@ -322,8 +352,12 @@ fn main() {
core::cmp::Ordering::Equal => 0, core::cmp::Ordering::Equal => 0,
core::cmp::Ordering::Greater => 1, core::cmp::Ordering::Greater => 1,
}; };
assert_eq!(vec.binary_search_by(&35, cmp), Err(2));
assert_eq!(vec.binary_search_by(&25, cmp), Err(1)); assert_eq!(vec.binary_search_by(&25, cmp), Err(1));
assert_eq!(vec.binary_search_by(&30, cmp), Ok(1)); assert_eq!(vec.binary_search_by(&30, cmp), Ok(1));
assert_eq!(vec.binary_search_by(&5, cmp), Err(0)); assert_eq!(vec.binary_search_by(&5, cmp), Err(0));
assert_eq!(vec.binary_search_by(&55, cmp), Err(5)); assert_eq!(vec.binary_search_by(&55, cmp), Err(4));
vec.insert_sorted(35, cmp);
assert_eq!(vec.as_slice(), &[20, 30, 35, 40, 50]);
} }