diff --git a/lang/src/vec.asm b/lang/src/vec.asm index e30adf0..9ab3e93 100644 --- a/lang/src/vec.asm +++ b/lang/src/vec.asm @@ -21,6 +21,7 @@ global vec_get global vec_drop global vec_find global vec_insert +global vec_insert_sorted global vec_binary_search_by global vec_tests @@ -507,7 +508,7 @@ vec_insert: ;; rsi: pointer to key ;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32 ;; 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: push rbp mov rbp, rsp @@ -518,6 +519,7 @@ vec_binary_search_by: mov [rsp + 0x18], rcx ; save compare fn context mov rax, [rdi + 8] ; len + dec rax ; high mov qword [rsp + 0x20], 0 ; low mov [rsp + 0x28], rax ; mid mov [rsp + 0x30], rax ; high @@ -551,31 +553,55 @@ vec_binary_search_by: ; greater mov rax, [rsp + 0x28] ; mid inc rax + mov [rsp + 0x28], rax ; mid mov [rsp + 0x20], rax ; low = mid + 1 jmp .loop .less: mov rax, [rsp + 0x28] ; mid + cmp rax, 0 + je .not_found ; if mid == 0, not found dec rax mov [rsp + 0x30], rax ; high = mid - 1 jmp .loop .found: mov rax, [rsp + 0x28] + xor rdx, rdx jmp .epilogue .not_found: - mov rax, [rsp + 0x20] - not rax + mov rax, [rsp + 0x28] + mov rdx, 1 .epilogue: add rsp, 0x40 pop rbp 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 diff --git a/lang/tests/vec.rs b/lang/tests/vec.rs index 44aa9bf..282b53f 100644 --- a/lang/tests/vec.rs +++ b/lang/tests/vec.rs @@ -60,11 +60,7 @@ impl VecT { fn push(&mut self, value: T) { let value = core::mem::ManuallyDrop::new(value); unsafe { - vec_push( - &mut self.vec, - &raw const value as *const T as *const u8, - core::mem::size_of::(), - ); + vec_push(&mut self.vec, &raw const value as *const T as *const u8); } } @@ -172,19 +168,47 @@ impl VecT { } unsafe { - let index = vec_binary_search_by( + let (index, vacant) = vec_binary_search_by( &raw const self.vec as *mut _, elem as *const T as *const u8, cmp_trampoline::, &raw mut cmp as *mut F as *mut (), ); - if (index as isize) < 0 { - Err(!index) + if vacant { + Err(index) } else { Ok(index) } } } + + fn insert_sorted(&self, elem: T, mut cmp: F) -> Result + where + F: FnMut(&T, &T) -> i32, + { + extern "C" fn cmp_trampoline 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::, + &raw mut cmp as *mut F as *mut (), + ); + Ok(index) + } + } } #[unsafe(no_mangle)] @@ -203,7 +227,7 @@ unsafe extern "C" { drop: Option, 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_pop(vec: *mut BlobVec); unsafe fn vec_drop_last(vec: *mut BlobVec); @@ -226,7 +250,13 @@ unsafe extern "C" { elem: *const u8, cmp: extern "C" fn(*const (), *const u8, *const u8) -> i32, 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() { @@ -266,7 +296,7 @@ fn main() { vec_init(&mut vec, 4, Some(drop)); let mut value: u32 = 2; 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!(as_slice::(&vec), &[2]); let retrieved = *(vec_get(&mut vec, 0) as *mut u32); @@ -276,10 +306,10 @@ fn main() { assert_eq!(vec.len, 0); assert_eq!(get_drops(), 2); 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::(&vec), &[3]); 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::(&vec), &[3, 5]); assert_eq!(vec.len, 2); vec_drop_last(&mut vec); @@ -322,8 +352,12 @@ fn main() { core::cmp::Ordering::Equal => 0, 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(&30, cmp), Ok(1)); 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]); }