memmove, vec_insert, vec_binary_search_by working and tested

This commit is contained in:
janis 2025-10-29 00:39:23 +01:00
parent af19946dc4
commit 1a4055a69a
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
3 changed files with 134 additions and 27 deletions

View file

@ -16,6 +16,7 @@ global strcmp
global strchr global strchr
global streq global streq
global memcpy global memcpy
global memmove
global memswap global memswap
global eprint_str global eprint_str
global exit global exit
@ -162,6 +163,7 @@ strcmp:
mov rax, 1 mov rax, 1
ret ret
;; a and b may be overlapping
;; Copy bytes from one memory location to another ;; Copy bytes from one memory location to another
;; rdi: destination pointer ;; rdi: destination pointer
;; rsi: source pointer ;; rsi: source pointer
@ -182,7 +184,42 @@ memcpy:
.done: .done:
ret ret
;; rdi: destination pointer
;; rsi: source pointer
;; rdx: number of bytes to move
memmove:
; if dest < src {
cmp rdi, rsi
jb .forward
; reverse
; for i in (0..n).rev() {
mov r8, rdx
.rev_loop:
cmp r8, 0
je .done
dec r8
; dest[i] = src[i];
mov al, [rsi + r8]
mov [rdi + r8], al
jmp .rev_loop
; }
.forward:
; for i in 0..n {
xor r8, r8
.fwd_loop:
cmp r8, rdx
jge .done
; dest[i] = src[i];
mov al, [rsi + r8]
mov [rdi + r8], al
inc r8
jmp .fwd_loop
; }
.done:
mov rax, rdi
ret
;; a and b must not be overlapping
;; Swap bytes between two memory locations ;; Swap bytes between two memory locations
;; rdi: pointer to first memory location ;; rdi: pointer to first memory location
;; rsi: pointer to second memory location ;; rsi: pointer to second memory location

View file

@ -3,6 +3,7 @@ section .rdata
section .text section .text
extern memcpy extern memcpy
extern memmove
extern memswap extern memswap
extern oom extern oom
extern panic extern panic
@ -127,21 +128,17 @@ vec_get:
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; rsi: pointer to data to push ;; rsi: pointer to data to push
;; rdx: size of data to push
;; fn vec_push(vec: *mut Vec, data: &[u8]) ;; fn vec_push(vec: *mut Vec, data: &[u8])
vec_push: vec_push:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
; if data.len() != vec.item_size panic();
mov rax, [rdi + 24]
cmp rdx, rax
jne .panic
; let vec, ptr, size; ; let vec, ptr, size;
sub rsp, 24 sub rsp, 24
mov [rsp], rdi ; save vec mov [rsp], rdi ; save vec
mov [rsp + 8], rsi ; save data ptr mov [rsp + 8], rsi ; save data ptr
mov [rsp + 16], rdx ; save data size
; vec_try_grow(vec, size); ; vec_try_grow(vec, size);
mov rsi, [rdi + 8]
inc rsi
call vec_try_grow call vec_try_grow
; memcpy(&vec.data[vec.len], data, size); ; memcpy(&vec.data[vec.len], data, size);
mov rax, [rsp] ; vec mov rax, [rsp] ; vec
@ -152,7 +149,8 @@ vec_push:
add rax, rcx ; data + len * item_size add rax, rcx ; data + len * item_size
mov rdi, rax ; dest ptr mov rdi, rax ; dest ptr
mov rsi, [rsp + 8] ; data ptr mov rsi, [rsp + 8] ; data ptr
mov rdx, [rsp + 16] ; data size mov rax, [rsp] ; vec
mov rdx, [rax + 24] ; item_size
call memcpy call memcpy
; vec.len += 1; ; vec.len += 1;
mov rax, [rsp] ; vec mov rax, [rsp] ; vec
@ -160,10 +158,6 @@ vec_push:
add rsp, 24 add rsp, 24
pop rbp pop rbp
ret ret
.panic:
call panic
pop rbp
ret
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
@ -239,11 +233,14 @@ vec_swap:
jge .panic jge .panic
; a = a * item_size; ; a = a * item_size;
mov rax, [rdi + 24] ; item_size mov rbx, [rdi + 24] ; item_size
mov rax, rdx
xor rdx, rdx
mul rbx ; b * item_size mul rbx ; b * item_size
mov [rsp + 16], rax mov [rsp + 16], rax
; b = b * item_size; ; b = b * item_size;
mov rax, rsi mov rax, rsi
xor rdx, rdx
mul rbx ; a * item_size mul rbx ; a * item_size
mov [rsp + 8], rax mov [rsp + 8], rax
@ -308,16 +305,18 @@ vec_remove:
.panic: .panic:
call panic call panic
;; essentially a reserve() function
;; rdi: pointer to Vec struct ;; rdi: pointer to Vec struct
;; fn vec_try_grow(vec: *mut Vec, push_size: usize) -> bool ;; rsi: desired size
;; fn vec_try_grow(vec: *mut Vec, new_size: usize) -> bool
vec_try_grow: vec_try_grow:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
push rbx push rbx
mov rax, [rdi + 16] ; capacity mov rax, [rdi + 16] ; capacity
mov rbx, [rdi + 8] ; len mov rbx, [rdi + 8] ; len
cmp rbx, rax cmp rsi, rax
jg .grow jge .grow ; grow if new_size >= capacity
pop rbx pop rbx
xor rax, rax xor rax, rax
pop rbp pop rbp
@ -459,20 +458,47 @@ vec_find:
vec_insert: vec_insert:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
sub rsp, 32 push r12
push rbx
sub rsp, 0x20
mov [rsp], rdi ; save vec mov [rsp], rdi ; save vec
mov [rsp + 8], rsi ; save index mov [rsp + 8], rsi ; save index
mov [rsp + 16], rdx ; save data ptr mov [rsp + 0x10], rdx ; save data ptr
mov rsi, rdx
mov rdx, rcx
call vec_push
mov rdi, [rsp]
mov rsi, [rdi + 8] mov rsi, [rdi + 8]
sub rsi, 1 inc rsi
mov rdx, [rsp + 8] call vec_try_grow
call vec_swap
mov rbx, [rsp] ; vec
mov rdi, [rbx] ; vec.data
mov rcx, [rbx + 24] ; item_size
mov rdx, [rbx + 8] ; len
sub rdx, [rsp + 8] ; len - index
mov rax, rdx
mul rcx ; (len - index) * item_size
mov r12, rax ; number of bytes to move
mov rsi, [rbx] ; vec.data
mov rax, [rsp + 8] ; index
mov rcx, [rbx + 24] ; item_size
mul rcx ; index * item_size
add rsi, rax ; src ptr
mov rdi, rsi
add rdi, rcx ; dst ptr
mov rdx, r12 ; number of bytes to move
call memmove
mov rdi, rsi
mov rsi, [rsp + 0x10]
mov rdx, [rbx + 24] ; item_size
call memcpy
mov rax, [rbx + 8] ; len
inc rax
mov [rbx + 8], rax
add rsp, 32 add rsp, 32
pop rbx
pop r12
pop rbp pop rbp
ret ret
@ -502,7 +528,7 @@ vec_binary_search_by:
mov rax, [rsp + 0x20] ; low mov rax, [rsp + 0x20] ; low
mov rcx, [rsp + 0x30] ; high mov rcx, [rsp + 0x30] ; high
cmp rax, rcx cmp rax, rcx
jge .not_found jg .not_found
; mid = (low + high) / 2 ; mid = (low + high) / 2
sub rcx, rax sub rcx, rax
shr rcx, 1 shr rcx, 1
@ -515,8 +541,8 @@ vec_binary_search_by:
mul rdx ; mid * item_size mul rdx ; mid * item_size
add rax, rcx ; vec.data + mid * item_size add rax, rcx ; vec.data + mid * item_size
mov rdi, [rsp + 0x18] ; compare ctx mov rdi, [rsp + 0x18] ; compare ctx
mov rsi, rax mov rsi, [rsp + 0x8] ; key
mov rdx, [rsp + 0x8] ; key mov rdx, rax
mov rax, [rsp + 0x10] ; compare fn mov rax, [rsp + 0x10] ; compare fn
call rax call rax
cmp eax, 0 cmp eax, 0

View file

@ -155,6 +155,36 @@ impl<T> VecT<T> {
} }
} }
} }
fn binary_search_by<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)
}
unsafe {
let index = vec_binary_search_by(
&raw const self.vec as *mut _,
elem as *const T as *const u8,
cmp_trampoline::<T, F>,
&raw mut cmp as *mut F as *mut (),
);
if (index as isize) < 0 {
Err(!index)
} else {
Ok(index)
}
}
}
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
@ -282,4 +312,18 @@ fn main() {
}), }),
Some(1) Some(1)
); );
assert_eq!(vec.as_slice(), &[20, 40, 50]);
vec.insert(30, 1);
assert_eq!(vec.as_slice(), &[20, 30, 40, 50]);
let cmp = |a: &u32, b: &u32| match a.cmp(b) {
core::cmp::Ordering::Less => -1,
core::cmp::Ordering::Equal => 0,
core::cmp::Ordering::Greater => 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(&5, cmp), Err(0));
assert_eq!(vec.binary_search_by(&55, cmp), Err(5));
} }