Compare commits
5 commits
edc4f4e576
...
cd21ecb782
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd21ecb782 | ||
|
|
1a4055a69a | ||
|
|
af19946dc4 | ||
|
|
8ac409c677 | ||
|
|
fd52df1307 |
|
|
@ -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
|
||||||
|
|
|
||||||
325
lang/src/vec.asm
325
lang/src/vec.asm
|
|
@ -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
|
||||||
|
|
@ -10,12 +11,18 @@ extern eprint_str
|
||||||
extern allocate
|
extern allocate
|
||||||
|
|
||||||
global vec_init
|
global vec_init
|
||||||
|
global vec_init_with
|
||||||
global vec_push
|
global vec_push
|
||||||
global vec_pop
|
global vec_pop
|
||||||
|
global vec_drop_last
|
||||||
global vec_swap
|
global vec_swap
|
||||||
global vec_remove
|
global vec_remove
|
||||||
global vec_get
|
global vec_get
|
||||||
global vec_drop
|
global vec_drop
|
||||||
|
global vec_find
|
||||||
|
global vec_insert
|
||||||
|
global vec_insert_sorted
|
||||||
|
global vec_binary_search_by
|
||||||
|
|
||||||
global vec_tests
|
global vec_tests
|
||||||
|
|
||||||
|
|
@ -62,6 +69,41 @@ vec_init:
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; Initialize a new vector
|
||||||
|
;; rdi: pointer to Vec struct
|
||||||
|
;; rsi: item_size
|
||||||
|
;; rdx: drop function pointer
|
||||||
|
;; rcx: capacity
|
||||||
|
;; fn vec_init_with(vec: *mut Vec, item_size: usize, drop: Option<fn(*mut u8)>, capacity: usize)
|
||||||
|
vec_init_with:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
sub rsp, 0x20
|
||||||
|
mov [rsp], rdx ; save drop
|
||||||
|
mov [rsp + 8], rsi ; save item_size
|
||||||
|
mov [rsp + 16], rcx ; save capacity
|
||||||
|
push rdi
|
||||||
|
; (*vec).data = allocate(INIT_CAPACITY);
|
||||||
|
|
||||||
|
xor rdx, rdx
|
||||||
|
mov rax, rcx
|
||||||
|
mul rsi ; capacity * item_size
|
||||||
|
mov rdi, rax
|
||||||
|
call allocate
|
||||||
|
pop r15
|
||||||
|
mov [r15], rax
|
||||||
|
; (*vec).len = 0;
|
||||||
|
mov qword [r15 + 8], 0
|
||||||
|
mov rax, [rsp + 8]
|
||||||
|
mov qword [r15 + 24], rax ; item_size
|
||||||
|
mov rax, [rsp + 16]
|
||||||
|
mov qword [r15 + 16], rax ; capacity
|
||||||
|
mov rax, [rsp]
|
||||||
|
mov qword [r15 + 32], rax ; drop
|
||||||
|
add rsp, 0x20
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
;; rsi: index
|
;; rsi: index
|
||||||
;; fn vec_get(vec: *mut Vec, index: usize) -> *mut u8
|
;; fn vec_get(vec: *mut Vec, index: usize) -> *mut u8
|
||||||
|
|
@ -87,21 +129,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
|
||||||
|
|
@ -112,7 +150,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
|
||||||
|
|
@ -120,15 +159,31 @@ 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
|
||||||
;; fn vec_pop(vec: *mut Vec)
|
;; fn vec_pop(vec: *mut Vec)
|
||||||
vec_pop:
|
vec_pop:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
; if vec.len == 0 panic();
|
||||||
|
mov rax, [rdi + 8] ; len
|
||||||
|
test rax, rax
|
||||||
|
je .underflow
|
||||||
|
; vec.len -= 1;
|
||||||
|
sub rax, 1
|
||||||
|
mov [rdi + 8], rax
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
; }
|
||||||
|
.underflow:
|
||||||
|
call panic
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
;; rdi: pointer to Vec struct
|
||||||
|
;; fn vec_pop(vec: *mut Vec)
|
||||||
|
vec_drop_last:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
; if vec.len == 0 panic();
|
; if vec.len == 0 panic();
|
||||||
|
|
@ -143,10 +198,10 @@ vec_pop:
|
||||||
test r8, r8
|
test r8, r8
|
||||||
je .ret
|
je .ret
|
||||||
; drop(&mut vec.data[vec.len..vec.len + vec.item_size]);
|
; drop(&mut vec.data[vec.len..vec.len + vec.item_size]);
|
||||||
|
xor rdx, rdx
|
||||||
mul qword [rdi + 24] ; len * item_size
|
mul qword [rdi + 24] ; len * item_size
|
||||||
mov rsi, [rdi] ; data
|
mov rdi, [rdi] ; data
|
||||||
add rax, rsi ; data + len * item_size
|
add rdi, rax ; data + len * item_size
|
||||||
mov rdi, rax
|
|
||||||
call r8
|
call r8
|
||||||
.ret:
|
.ret:
|
||||||
pop rbp
|
pop rbp
|
||||||
|
|
@ -168,32 +223,35 @@ vec_swap:
|
||||||
push rbx
|
push rbx
|
||||||
; let vec, a, b;
|
; let vec, a, b;
|
||||||
sub rsp, 24
|
sub rsp, 24
|
||||||
mov [rsp], rdi
|
mov [rsp], rdi ; save vec
|
||||||
; let max_index = max(a, b);
|
; let max_index = max(a, b);
|
||||||
mov rbx, rsi
|
mov rbx, rsi
|
||||||
cmp rbx, rdx
|
cmp rbx, rdx
|
||||||
cmovl rbx, rdx
|
cmovl rbx, rdx
|
||||||
; if (max_index >= vec.len) panic();
|
; if (max_index >= vec.len) panic();
|
||||||
mov rax, [rdi + 8] ; len
|
mov rax, [rdi + 8] ; vec.len
|
||||||
cmp rbx, rax
|
cmp rbx, rax
|
||||||
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
|
||||||
|
|
||||||
; // SAFETY: a and b must not overlap
|
; // SAFETY: a and b must not overlap
|
||||||
; memswap(&mut vec.data.add(a), &mut vec.data.add(b), vec.item_size);
|
; memswap(&mut vec.data.add(a), &mut vec.data.add(b), vec.item_size);
|
||||||
mov rcx, [rdi + 24] ; item_size
|
mov rdx, [rdi + 24] ; item_size
|
||||||
lea rdi, [rdi] ; vec.data
|
mov rdi, [rdi] ; vec.data
|
||||||
mov rsi, rdi
|
mov rsi, rdi
|
||||||
add rdi, [rsp + 16] ; data + a
|
add rdi, [rsp + 16] ; data + a
|
||||||
add rsi, [rsp + 24] ; data + b
|
add rsi, [rsp + 8] ; data + b
|
||||||
call memswap
|
call memswap
|
||||||
add rsp, 24
|
add rsp, 24
|
||||||
pop rbx
|
pop rbx
|
||||||
|
|
@ -201,8 +259,6 @@ vec_swap:
|
||||||
ret
|
ret
|
||||||
.panic:
|
.panic:
|
||||||
call panic
|
call panic
|
||||||
pop rbx
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
;; rdi: pointer to Vec struct
|
;; rdi: pointer to Vec struct
|
||||||
|
|
@ -211,6 +267,10 @@ vec_swap:
|
||||||
vec_remove:
|
vec_remove:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
sub rsp, 0x10
|
||||||
|
mov [rsp], rdi ; save vec
|
||||||
|
mov [rsp + 8], rsi ; save index
|
||||||
|
|
||||||
; if (index >= vec.len) panic();
|
; if (index >= vec.len) panic();
|
||||||
mov rax, [rdi + 8] ; len
|
mov rax, [rdi + 8] ; len
|
||||||
cmp rsi, rax
|
cmp rsi, rax
|
||||||
|
|
@ -225,6 +285,7 @@ vec_remove:
|
||||||
; }
|
; }
|
||||||
; vec.len -= 1;
|
; vec.len -= 1;
|
||||||
.remove_last:
|
.remove_last:
|
||||||
|
mov rdi, [rsp] ; vec
|
||||||
mov rax, [rdi + 8] ; len
|
mov rax, [rdi + 8] ; len
|
||||||
sub rax, 1
|
sub rax, 1
|
||||||
mov [rdi + 8], rax
|
mov [rdi + 8], rax
|
||||||
|
|
@ -234,28 +295,29 @@ vec_remove:
|
||||||
je .ret
|
je .ret
|
||||||
; drop(&mut vec.data[vec.len..vec.len + vec.item_size]);
|
; drop(&mut vec.data[vec.len..vec.len + vec.item_size]);
|
||||||
mul qword [rdi + 24] ; len * item_size
|
mul qword [rdi + 24] ; len * item_size
|
||||||
lea rdi, [rdi] ; data
|
mov rdi, [rdi] ; data
|
||||||
add rdi, rax ; data + len * item_size
|
add rdi, rax ; data + len * item_size
|
||||||
call r8
|
call r8
|
||||||
; }
|
; }
|
||||||
.ret:
|
.ret:
|
||||||
|
add rsp, 0x10
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
.panic:
|
.panic:
|
||||||
call panic
|
call panic
|
||||||
pop rbp
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
;; 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
|
||||||
|
|
@ -336,3 +398,210 @@ vec_drop:
|
||||||
pop r12
|
pop r12
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;; rdi: pointer to Vec struct
|
||||||
|
;; rsi: poiter to object to find
|
||||||
|
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> bool
|
||||||
|
;; rcx: compare_fn context
|
||||||
|
vec_find:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
push r12
|
||||||
|
sub rsp, 0x28
|
||||||
|
mov [rsp], rdi ; save vec
|
||||||
|
mov [rsp + 8], rsi ; save object ptr
|
||||||
|
mov [rsp + 0x10], rdx ; save compare fn
|
||||||
|
mov rax, [rdi + 24] ; item_size
|
||||||
|
mov [rsp + 0x18], rax ; save size
|
||||||
|
mov [rsp + 0x20], rcx ; save compare fn context
|
||||||
|
|
||||||
|
xor r12, r12
|
||||||
|
.loop:
|
||||||
|
mov rcx, [rsp]
|
||||||
|
mov rcx, [rcx + 8]
|
||||||
|
cmp r12, rcx
|
||||||
|
jge .not_found
|
||||||
|
; if compare(&vec.data[i], object) {
|
||||||
|
mov rdi, [rsp + 0x20] ; compare fn context
|
||||||
|
mov rsi, [rsp + 0x8]
|
||||||
|
mov rax, [rsp + 0x18] ; size
|
||||||
|
xor rdx, rdx
|
||||||
|
mul r12 ; i * item_size
|
||||||
|
mov rdx, [rsp] ; vec
|
||||||
|
mov rdx, [rdx] ; vec.data
|
||||||
|
add rdx, rax ; vec.data + i * item_size
|
||||||
|
mov rax, [rsp + 0x10] ; compare fn
|
||||||
|
call rax
|
||||||
|
test rax, rax
|
||||||
|
jne .found
|
||||||
|
; }
|
||||||
|
inc r12
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.not_found:
|
||||||
|
mov rax, -1
|
||||||
|
jmp .epilogue
|
||||||
|
.found:
|
||||||
|
mov rax, r12
|
||||||
|
|
||||||
|
.epilogue:
|
||||||
|
add rsp, 0x28
|
||||||
|
pop r12
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;; rdi: pointer to Vec struct
|
||||||
|
;; rsi : index
|
||||||
|
;; rdx: pointer to data to insert
|
||||||
|
;; fn vec_insert(vec: *mut Vec, index: usize, data: *const T, size: usize)
|
||||||
|
vec_insert:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
push r12
|
||||||
|
push rbx
|
||||||
|
sub rsp, 0x20
|
||||||
|
mov [rsp], rdi ; save vec
|
||||||
|
mov [rsp + 8], rsi ; save index
|
||||||
|
mov [rsp + 0x10], rdx ; save data ptr
|
||||||
|
|
||||||
|
mov rsi, [rdi + 8]
|
||||||
|
inc rsi
|
||||||
|
call vec_try_grow
|
||||||
|
|
||||||
|
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
|
||||||
|
pop rbx
|
||||||
|
pop r12
|
||||||
|
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_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
|
||||||
|
sub rsp, 0x40
|
||||||
|
mov [rsp], rdi ; save vec
|
||||||
|
mov [rsp + 0x8], rsi ; save key
|
||||||
|
mov [rsp + 0x10], rdx ; save compare fn
|
||||||
|
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
|
||||||
|
mov rax, [rdi + 24] ; item_size
|
||||||
|
mov [rsp + 0x38], rax ; item_size
|
||||||
|
|
||||||
|
.loop:
|
||||||
|
mov rax, [rsp + 0x20] ; low
|
||||||
|
mov rcx, [rsp + 0x30] ; high
|
||||||
|
cmp rax, rcx
|
||||||
|
jg .not_found
|
||||||
|
; mid = (low + high) / 2
|
||||||
|
sub rcx, rax
|
||||||
|
shr rcx, 1
|
||||||
|
add rax, rcx
|
||||||
|
mov [rsp + 0x28], rax ; mid
|
||||||
|
|
||||||
|
mov rcx, [rsp] ; vec
|
||||||
|
mov rcx, [rcx] ; vec.data
|
||||||
|
mov rdx, [rsp + 0x38] ; item_size
|
||||||
|
mul rdx ; mid * item_size
|
||||||
|
add rax, rcx ; vec.data + mid * item_size
|
||||||
|
mov rdi, [rsp + 0x18] ; compare ctx
|
||||||
|
mov rsi, [rsp + 0x8] ; key
|
||||||
|
mov rdx, rax
|
||||||
|
mov rax, [rsp + 0x10] ; compare fn
|
||||||
|
call rax
|
||||||
|
cmp eax, 0
|
||||||
|
je .found
|
||||||
|
jl .less
|
||||||
|
; 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 + 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
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,210 @@ pub struct BlobVec {
|
||||||
pub drop: Option<extern "C" fn(*mut u8)>,
|
pub drop: Option<extern "C" fn(*mut u8)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VecT<T> {
|
||||||
|
vec: BlobVec,
|
||||||
|
_marker: core::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> VecT<T> {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self::new_with(32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with(capacity: usize) -> Self {
|
||||||
|
let mut vec = BlobVec {
|
||||||
|
data: core::ptr::null_mut(),
|
||||||
|
len: 0,
|
||||||
|
cap: 0,
|
||||||
|
elem_size: 0,
|
||||||
|
drop: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" fn drop_fn<T>(ptr: *mut u8) {
|
||||||
|
unsafe {
|
||||||
|
core::ptr::drop_in_place::<T>(ptr as *mut T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
vec_init_with(
|
||||||
|
&mut vec,
|
||||||
|
core::mem::size_of::<T>(),
|
||||||
|
Some(drop_fn::<T>),
|
||||||
|
capacity,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
vec,
|
||||||
|
_marker: core::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_slice(&self) -> &[T] {
|
||||||
|
assert_eq!(self.vec.elem_size, core::mem::size_of::<T>());
|
||||||
|
unsafe { core::slice::from_raw_parts(self.vec.data as *const T, self.vec.len) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_slice_mut(&mut self) -> &mut [T] {
|
||||||
|
assert_eq!(self.vec.elem_size, core::mem::size_of::<T>());
|
||||||
|
unsafe { core::slice::from_raw_parts_mut(self.vec.data as *mut T, self.vec.len) }
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, value: T, index: usize) {
|
||||||
|
if index > self.vec.len {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let value = core::mem::ManuallyDrop::new(value);
|
||||||
|
unsafe {
|
||||||
|
vec_insert(
|
||||||
|
&mut self.vec,
|
||||||
|
index,
|
||||||
|
&raw const value as *const T as *const u8,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self) -> Option<T> {
|
||||||
|
if self.vec.len == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let ptr = vec_get(&mut self.vec, self.vec.len - 1) as *mut T;
|
||||||
|
let value = ptr.read();
|
||||||
|
vec_pop(&mut self.vec);
|
||||||
|
Some(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, index: usize) -> Option<&T> {
|
||||||
|
if index >= self.vec.len {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let ptr = vec_get(&raw const self.vec as *mut _, index) as *mut T;
|
||||||
|
Some(&*ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_mut(&mut self, index: usize) -> Option<&mut T> {
|
||||||
|
if index >= self.vec.len {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let ptr = vec_get(&raw mut self.vec, index) as *mut T;
|
||||||
|
Some(&mut *ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, index: usize) {
|
||||||
|
if index >= self.vec.len {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
vec_remove(&mut self.vec, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.vec.len
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position<F>(&self, elem: &T, mut cmp: F) -> Option<usize>
|
||||||
|
where
|
||||||
|
F: FnMut(&T, &T) -> bool,
|
||||||
|
{
|
||||||
|
extern "C" fn cmp_trampoline<T, F: FnMut(&T, &T) -> bool>(
|
||||||
|
f: *const (),
|
||||||
|
a: *const u8,
|
||||||
|
b: *const u8,
|
||||||
|
) -> bool {
|
||||||
|
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_find(
|
||||||
|
&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 == usize::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, vacant) = 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 vacant {
|
||||||
|
Err(index)
|
||||||
|
} else {
|
||||||
|
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)]
|
||||||
extern "C" fn panic() -> ! {
|
extern "C" fn panic() -> ! {
|
||||||
panic!("Called panic from external code.");
|
panic!("Called panic from external code.");
|
||||||
|
|
@ -17,14 +221,42 @@ unsafe impl Sync for BlobVec {}
|
||||||
|
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
unsafe fn vec_init(vec: *mut BlobVec, elem_size: usize, drop: Option<extern "C" fn(*mut u8)>);
|
unsafe fn vec_init(vec: *mut BlobVec, elem_size: usize, drop: Option<extern "C" fn(*mut u8)>);
|
||||||
unsafe fn vec_push(vec: *mut BlobVec, elem: *const u8, size: usize);
|
unsafe fn vec_init_with(
|
||||||
|
vec: *mut BlobVec,
|
||||||
|
elem_size: usize,
|
||||||
|
drop: Option<extern "C" fn(*mut u8)>,
|
||||||
|
cap: 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_pop(vec: *mut BlobVec);
|
||||||
|
unsafe fn vec_drop_last(vec: *mut BlobVec);
|
||||||
unsafe fn vec_get(vec: *mut BlobVec, index: usize) -> *mut u8;
|
unsafe fn vec_get(vec: *mut BlobVec, index: usize) -> *mut u8;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
unsafe fn vec_remove(vec: *mut BlobVec, index: usize);
|
unsafe fn vec_remove(vec: *mut BlobVec, index: usize);
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
unsafe fn vec_drop(vec: *mut BlobVec);
|
unsafe fn vec_drop(vec: *mut BlobVec);
|
||||||
|
|
||||||
|
unsafe fn vec_find(
|
||||||
|
vec: *mut BlobVec,
|
||||||
|
elem: *const u8,
|
||||||
|
cmp: extern "C" fn(*const (), *const u8, *const u8) -> bool,
|
||||||
|
cmp_data: *mut (),
|
||||||
|
) -> usize;
|
||||||
|
|
||||||
|
unsafe fn vec_binary_search_by(
|
||||||
|
vec: *mut BlobVec,
|
||||||
|
elem: *const u8,
|
||||||
|
cmp: extern "C" fn(*const (), *const u8, *const u8) -> i32,
|
||||||
|
cmp_data: *mut (),
|
||||||
|
) -> (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() {
|
||||||
|
|
@ -64,25 +296,68 @@ 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);
|
||||||
assert_eq!(retrieved, 2);
|
assert_eq!(retrieved, 2);
|
||||||
assert_eq!(get_drops(), 1);
|
assert_eq!(get_drops(), 1);
|
||||||
vec_pop(&mut vec);
|
vec_drop_last(&mut vec);
|
||||||
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_pop(&mut vec);
|
vec_drop_last(&mut vec);
|
||||||
vec_pop(&mut vec);
|
vec_drop_last(&mut vec);
|
||||||
assert_eq!(get_drops(), 2 * 3 * 5);
|
assert_eq!(get_drops(), 2 * 3 * 5);
|
||||||
eprintln!("Push/pop test passed\n");
|
eprintln!("Push/pop test passed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut vec = VecT::<u32>::new_with(100);
|
||||||
|
assert_eq!(vec.len(), 0);
|
||||||
|
vec.push(10);
|
||||||
|
vec.push(20);
|
||||||
|
vec.push(30);
|
||||||
|
assert_eq!(vec.len(), 3);
|
||||||
|
assert_eq!(vec.get(0), Some(&10));
|
||||||
|
assert_eq!(vec.get(1), Some(&20));
|
||||||
|
assert_eq!(vec.get(2), Some(&30));
|
||||||
|
assert_eq!(vec.pop(), Some(30));
|
||||||
|
assert_eq!(vec.len(), 2);
|
||||||
|
vec.remove(0);
|
||||||
|
assert_eq!(vec.len(), 1);
|
||||||
|
assert_eq!(vec.get(0), Some(&20));
|
||||||
|
vec.push(40);
|
||||||
|
vec.push(50);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
vec.position(&40, |a, b| {
|
||||||
|
eprintln!("Comparing {} and {}", a, b);
|
||||||
|
a == b
|
||||||
|
}),
|
||||||
|
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(&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(4));
|
||||||
|
|
||||||
|
vec.insert_sorted(35, cmp);
|
||||||
|
assert_eq!(vec.as_slice(), &[20, 30, 35, 40, 50]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue