diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9b37eb7..9c86553 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ on: branches: [ "main" ] jobs: - build: + tests: runs-on: ubuntu-22.04 @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v4 - name: Install dependencies - run: sudo apt-get update && sudo apt-get install -y nasm clang-format + run: sudo apt-get update && sudo apt-get install -y nasm clang-format valgrind - name: Check format run: make check-format diff --git a/Makefile b/Makefile index fcac310..e35f469 100644 --- a/Makefile +++ b/Makefile @@ -6,20 +6,29 @@ TEST_NAME = tests_bin # --------------- FILES --------------- # LIST_ASM_SRC = \ - ft_read.s \ - ft_strcmp.s \ - ft_strcpy.s \ - ft_strdup.s \ - ft_strlen.s \ + ft_create_elem.s \ + ft_list.s \ + ft_list_push_front.s \ + ft_list_remove_if.s \ + ft_list_size.s \ + ft_read.s \ + ft_strcmp.s \ + ft_strcpy.s \ + ft_strdup.s \ + ft_strlen.s \ ft_write.s LIST_TEST_SRC = \ - ft_read.c \ - ft_strcmp.c \ - ft_strcpy.c \ - ft_strdup.c \ - ft_strlen.c \ - ft_write.c \ + ft_create_elem.c \ + ft_list_push_front.c \ + ft_list_remove_if.c \ + ft_list_size.c \ + ft_read.c \ + ft_strcmp.c \ + ft_strcpy.c \ + ft_strdup.c \ + ft_strlen.c \ + ft_write.c \ main.c # ------------ DIRECTORIES ------------ # @@ -44,7 +53,7 @@ UTEST_INCLUDE = $(DIR_UTEST) # ------------ COMPILATION ------------ # AS = nasm -ASFLAGS = -f elf64 +ASFLAGS = -f elf64 -I $(DIR_SRC) CFLAGS = -Wall -Wextra -Werror @@ -64,7 +73,7 @@ all: $(NAME) .PHONY: tests tests: $(TEST_NAME) - ./$(TEST_NAME) + valgrind ./$(TEST_NAME) $(TEST_NAME): $(TEST_OBJ) $(NAME) $(CC) $(CFLAGS) $(TEST_OBJ) -L. -l:$(NAME) -o $(TEST_NAME) diff --git a/include/libasm.h b/include/libasm.h index 999d539..eb4ea1b 100644 --- a/include/libasm.h +++ b/include/libasm.h @@ -15,6 +15,13 @@ # include +typedef struct s_list +{ + void *data; + struct s_list *next; +} t_list; + + ssize_t ft_read(int fd, void *buf, size_t count); int ft_strcmp(const char *s1, const char *s2); char *ft_strcpy(char *dst, const char *src); @@ -22,4 +29,9 @@ char *ft_strdup(const char *s1); size_t ft_strlen(const char *str); ssize_t ft_write(int fd, const void *buf, size_t count); +t_list *ft_create_elem(void *data); +void ft_list_push_front(t_list **begin_list, void *data); +int ft_list_size(t_list *begin_list); +void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)(), void (*free_fct)(void *)); + #endif \ No newline at end of file diff --git a/src/ft_create_elem.s b/src/ft_create_elem.s new file mode 100644 index 0000000..00ef175 --- /dev/null +++ b/src/ft_create_elem.s @@ -0,0 +1,30 @@ +bits 64 + +extern malloc + +%include "ft_list.s" + +section .note.GNU-stack + +section .text + global ft_create_elem + +;typedef struct s_list +;{ +; void *data; +; struct s_list *next; +;} t_list; + +; t_list *ft_create_elem(void *data); +ft_create_elem: + push rdi + mov rdi, LIST_SIZE + call malloc wrt ..plt + cmp rax, 0 + jz return + pop rdi + mov [rax + LIST_DATA_OFFSET], rdi + mov qword [rax + LIST_NEXT_OFFSET], 0 + return +return: + ret diff --git a/src/ft_list.s b/src/ft_list.s new file mode 100644 index 0000000..996d270 --- /dev/null +++ b/src/ft_list.s @@ -0,0 +1,16 @@ +bits 64 + +section .note.GNU-stack + +;typedef struct s_list +;{ +; void *data; +; struct s_list *next; +;} t_list; +section .data + LIST_DATA_OFFSET EQU 0 + LIST_NEXT_OFFSET EQU 8 + LIST_SIZE EQU 16 + + + diff --git a/src/ft_list_push_front.s b/src/ft_list_push_front.s new file mode 100644 index 0000000..ccee2f3 --- /dev/null +++ b/src/ft_list_push_front.s @@ -0,0 +1,35 @@ +bits 64 + +extern malloc +extern ft_create_elem + +%include "ft_list.s" + + +section .note.GNU-stack + +section .text + global ft_list_push_front + +;typedef struct s_list +;{ +; void *data; +; struct s_list *next; +;} t_list; + +;void ft_list_push_front(t_list **begin_list, void *data); +ft_list_push_front: + test rdi, rdi + jz .return + push rdi + mov rdi, rsi + call ft_create_elem + cmp rax, 0 + jz .return + pop rdi + mov rsi, [rdi] + mov qword [rax + LIST_NEXT_OFFSET], rsi + mov qword [rdi], rax + .return +.return: + ret diff --git a/src/ft_list_remove_if.s b/src/ft_list_remove_if.s new file mode 100644 index 0000000..c7db79f --- /dev/null +++ b/src/ft_list_remove_if.s @@ -0,0 +1,177 @@ +bits 64 + +%include "ft_list.s" + +extern free + +section .note.GNU-stack + +section .text + global ft_list_remove_if + +;typedef struct s_list +;{ +; void *data; +; struct s_list *next; +;} t_list; + +;void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)(), +; void (*free_fct)(void *)) { +; if (begin_list == NULL || cmp == NULL) { +; return; +; } +; +; t_list *current = *begin_list; +; t_list *previous = NULL; +; while (current) { +; if (cmp(current->data, data_ref) == 0) { +; if (previous) { +; previous->next = current->next; +; } else { +; *begin_list = current->next; +; } +; if (free_fct) { +; free_fct(current->data); +; } +; free(current); +; current = previous ? previous->next : *begin_list; +; } else { +; previous = current; +; current = current->next; +; } +; } + +;void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)(), void (*free_fct)(void *)); +ft_list_remove_if: + ; begin_list + test rdi, rdi + jz end + ; cmp + test rdx, rdx + jz end + ; save r8 and r9 + push r8 + push r9 + ; current_node + mov r8, [rdi] + ; previous_node + xor r9, r9 + jmp loop +loop: + test r8, r8 + jz end_loop + jmp cmp_function + +cmp_function: + push rdi + push rsi + push rdx + push rcx + push r8 + push r9 + mov rdi, [r8 + LIST_DATA_OFFSET] + ; call cmp_fct + call rdx + pop r9 + pop r8 + pop rcx + pop rdx + pop rsi + pop rdi + test rax, rax + jz remove_node + jnz next_node + +remove_node: + ; if previous != NULL + test r9, r9 + jnz link_previous_to_next + jmp link_to_next + +link_previous_to_next: + mov rax, [r8 + LIST_NEXT_OFFSET] + mov [r9 + LIST_NEXT_OFFSET], rax + jmp free_node + +link_to_next: + mov rax, [r8 + LIST_NEXT_OFFSET] + mov [rdi], rax + jmp free_node + +free_node: + ; if free_fct != NULL + test rcx, rcx + jnz call_free_fct + push rdi + push rsi + push rdx + push rcx + push r8 + push r9 + mov rdi, r8 + call free wrt ..plt + pop r9 + pop r8 + pop rcx + pop rdx + pop rsi + pop rdi + jmp update_current_after_free + +call_free_fct: + push rdi + push rsi + push rdx + push rcx + push r8 + push r9 + mov rdi, [r8 + LIST_DATA_OFFSET] + call rcx + pop r9 + pop r8 + pop rcx + pop rdx + pop rsi + pop rdi + + push rdi + push rsi + push rdx + push rcx + push r8 + push r9 + mov rdi, r8 + ;call rcx + call free wrt ..plt + pop r9 + pop r8 + pop rcx + pop rdx + pop rsi + pop rdi + jmp update_current_after_free + +update_current_after_free: + ; if previous != NULL + test r9, r9 + jnz link_current_to_previous_next + mov r8, [rdi] + jmp loop + +link_current_to_previous_next: + mov r8, [r9 + LIST_NEXT_OFFSET] + jmp loop + +next_node: + mov r9, r8 + mov r8, [r8 + LIST_NEXT_OFFSET] + jmp loop + +end_loop: + ; restore r8 and r9 + pop r9 + pop r8 + ret + +end: + ret diff --git a/src/ft_list_size.s b/src/ft_list_size.s new file mode 100644 index 0000000..13a1776 --- /dev/null +++ b/src/ft_list_size.s @@ -0,0 +1,27 @@ +bits 64 + +%include "ft_list.s" + +section .note.GNU-stack + +section .text + global ft_list_size + +;typedef struct s_list +;{ +; void *data; +; struct s_list *next; +;} t_list; + +;int ft_list_size(t_list *begin_list); +ft_list_size: + xor rax, rax + jmp loop +loop: + cmp rdi, 0 + je end + mov rdi, [rdi + LIST_NEXT_OFFSET] + inc rax + jmp loop +end: + ret \ No newline at end of file diff --git a/test/ft_create_elem.c b/test/ft_create_elem.c new file mode 100644 index 0000000..ad50952 --- /dev/null +++ b/test/ft_create_elem.c @@ -0,0 +1,48 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_read.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tdameros +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/04/04 17:28:00 by tdameros #+# #+# */ +/* Updated: 2024/04/04 17:28:00 by tdameros ### ########lyon.fr */ +/* */ +/* ************************************************************************** */ + +#include + +#include "libasm.h" +#include "utest.h" + +UTEST(ft_create_elem, null_data) { + t_list *elem = ft_create_elem(NULL); + ASSERT_EQ(elem->data, NULL); + ASSERT_EQ(elem->next, NULL); + free(elem); +} + +UTEST(ft_create_elem, non_null_data) { + char *data = strdup("Hello, World!"); + t_list *elem = ft_create_elem(data); + ASSERT_EQ(elem->data, data); + ASSERT_EQ(elem->next, NULL); + free(data); + free(elem); +} + +UTEST(ft_create_elem, multiple_elems) { + char *data1 = strdup("Hello, World!"); + char *data2 = strdup("Hello, 42!"); + t_list *elem1 = ft_create_elem(data1); + t_list *elem2 = ft_create_elem(data2); + elem1->next = elem2; + ASSERT_EQ(elem1->data, data1); + ASSERT_EQ(elem1->next, elem2); + ASSERT_EQ(elem2->data, data2); + ASSERT_EQ(elem2->next, NULL); + free(data1); + free(data2); + free(elem1); + free(elem2); +} diff --git a/test/ft_list_push_front.c b/test/ft_list_push_front.c new file mode 100644 index 0000000..3ccf986 --- /dev/null +++ b/test/ft_list_push_front.c @@ -0,0 +1,81 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_read.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tdameros +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/04/04 17:28:00 by tdameros #+# #+# */ +/* Updated: 2024/04/04 17:28:00 by tdameros ### ########lyon.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include + +#include "libasm.h" +#include "utest.h" + +UTEST(ft_list_push_front, null_list) { + t_list *list = NULL; + char *data = strdup("Hello, World!"); + ft_list_push_front(&list, data); + ASSERT_EQ(list->data, data); + ASSERT_EQ(list->next, NULL); + free(data); + free(list); +} + +UTEST(ft_list_push_front, non_null_list) { + char *data1 = strdup("Hello, World!"); + char *data2 = strdup("Hello, 42!"); + t_list *list = ft_create_elem(data1); + ft_list_push_front(&list, data2); + ASSERT_EQ(list->data, data2); + ASSERT_EQ(list->next->data, data1); + ASSERT_EQ(list->next->next, NULL); + free(data1); + free(data2); + free(list->next); + free(list); +} + +UTEST(ft_list_push_front, multiple_elems) { + char *data1 = strdup("Hello, World!"); + char *data2 = strdup("Hello, 42!"); + char *data3 = strdup("Hello, 21!"); + t_list *list = ft_create_elem(data1); + ft_list_push_front(&list, data2); + ft_list_push_front(&list, data3); + ASSERT_EQ(list->data, data3); + ASSERT_EQ(list->next->data, data2); + ASSERT_EQ(list->next->next->data, data1); + ASSERT_EQ(list->next->next->next, NULL); + free(data1); + free(data2); + free(data3); + free(list->next->next); + free(list->next); + free(list); +} + +UTEST(ft_list_push_front, null_data) { + t_list *list = NULL; + ft_list_push_front(&list, NULL); + ASSERT_EQ(list->data, NULL); + ASSERT_EQ(list->next, NULL); + free(list); +} + +UTEST(ft_list_push_front, null_list_null_data) { + t_list *list = NULL; + ft_list_push_front(&list, NULL); + ASSERT_EQ(list->data, NULL); + ASSERT_EQ(list->next, NULL); + free(list); +} + +UTEST(ft_list_push_front, null_list_pointer) { + ft_list_push_front(NULL, NULL); + ASSERT_NE(errno, EFAULT); +} \ No newline at end of file diff --git a/test/ft_list_remove_if.c b/test/ft_list_remove_if.c new file mode 100644 index 0000000..73c0452 --- /dev/null +++ b/test/ft_list_remove_if.c @@ -0,0 +1,133 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_read.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tdameros +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/04/04 17:28:00 by tdameros #+# #+# */ +/* Updated: 2024/04/04 17:28:00 by tdameros ### ########lyon.fr */ +/* */ +/* ************************************************************************** */ + +#include + +#include "libasm.h" +#include "utest.h" + +UTEST(ft_list_remove_if, null_list_ptr) { + t_list **list_ptr = NULL; + ft_list_remove_if(list_ptr, "Hello, World!", strcmp, free); + ASSERT_EQ(list_ptr, NULL); + ASSERT_EQ(errno, 0); +} + +UTEST(ft_list_remove_if, null_list) { + t_list *list = NULL; + ft_list_remove_if(&list, "Hello, World!", strcmp, free); + ASSERT_EQ(list, NULL); + ASSERT_EQ(errno, 0); +} + +static int my_strcmp(const void *s1, const void *s2) { + if (s1 == NULL || s2 == NULL) { + return 1; + } + return strcmp(s1, s2); +} + +UTEST(ft_list_remove_if, null_data_ref) { + t_list *list = NULL; + char *data = strdup("Hello, World!"); + ft_list_push_front(&list, data); + ft_list_remove_if(&list, NULL, my_strcmp, free); + ASSERT_NE(list, NULL); + ASSERT_NE(list->data, NULL); + ASSERT_EQ(list->next, NULL); + free(list); + free(data); + ASSERT_EQ(errno, 0); +} + +UTEST(ft_list_remove_if, null_cmp) { + t_list *list = ft_create_elem(NULL); + ft_list_remove_if(&list, "Hello, World!", NULL, free); + ASSERT_EQ(list->data, NULL); + ASSERT_EQ(list->next, NULL); + free(list); + ASSERT_EQ(errno, 0); +} + +UTEST(ft_list_remove_if, null_free_fct) { + t_list *list = NULL; + char *data = strdup("Hello, World!"); + ft_list_push_front(&list, data); + ft_list_remove_if(&list, "Hello!", strcmp, NULL); + ASSERT_NE(list, NULL); + ASSERT_NE(list->data, NULL); + ASSERT_EQ(list->next, NULL); + free(list); + free(data); + ASSERT_EQ(errno, 0); +} + +UTEST(ft_list_remove_if, null_free_fct_with_remove) { + t_list *list = NULL; + char *data = strdup("Hello, World!"); + ft_list_push_front(&list, data); + ft_list_remove_if(&list, "Hello, World!", strcmp, NULL); + ASSERT_EQ(list, NULL); + free(data); + ASSERT_EQ(errno, 0); +} + +UTEST(ft_list_remove_if, single_node) { + char *data = strdup("42"); + t_list *list = ft_create_elem(data); + ft_list_remove_if(&list, "Hello, World!", strcmp, free); + ASSERT_STREQ(list->data, "42"); + ASSERT_EQ(list->next, NULL); + free(data); + free(list); + ASSERT_EQ(errno, 0); +} + +UTEST(ft_list_remove_if, single_node_remove) { + char *data = strdup("Hello, World!"); + t_list *list = ft_create_elem(data); + ft_list_remove_if(&list, "Hello, World!", strcmp, free); + ASSERT_EQ(list, NULL); + ASSERT_EQ(errno, 0); +} + +UTEST(ft_list_remove_if, multiple_nodes) { + char *data1 = strdup("Hello, World!"); + char *data2 = strdup("Hello, 42!"); + char *data3 = strdup("Hello, 21!"); + t_list *list = NULL; + ft_list_push_front(&list, data1); + ft_list_push_front(&list, data2); + ft_list_push_front(&list, data3); + ft_list_remove_if(&list, "Hello, 42!", strcmp, free); + ASSERT_STREQ(list->data, "Hello, 21!"); + ASSERT_STREQ(list->next->data, "Hello, World!"); + ASSERT_EQ(list->next->next, NULL); + free(data1); + free(data3); + free(list->next); + free(list); + ASSERT_EQ(errno, 0); +} + +UTEST(ft_list_remove_if, full_remove_with_multiple_nodes) { + char *data1 = strdup("Hello, World!"); + char *data2 = strdup("Hello, World!"); + char *data3 = strdup("Hello, World!"); + t_list *list = NULL; + ft_list_push_front(&list, data1); + ft_list_push_front(&list, data2); + ft_list_push_front(&list, data3); + ft_list_remove_if(&list, "Hello, World!", strcmp, free); + ASSERT_EQ(list, NULL); + ASSERT_EQ(errno, 0); +} \ No newline at end of file diff --git a/test/ft_list_size.c b/test/ft_list_size.c new file mode 100644 index 0000000..9f43955 --- /dev/null +++ b/test/ft_list_size.c @@ -0,0 +1,60 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_read.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tdameros +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/04/04 17:28:00 by tdameros #+# #+# */ +/* Updated: 2024/04/04 17:28:00 by tdameros ### ########lyon.fr */ +/* */ +/* ************************************************************************** */ + +#include + +#include "libasm.h" +#include "utest.h" + +UTEST(ft_list_size, null_list) { + t_list *list = NULL; + ASSERT_EQ(ft_list_size(list), 0); +} + +UTEST(ft_list_size, one_elem) { + char *data = strdup("Hello, World!"); + t_list *list = ft_create_elem(data); + ASSERT_EQ(ft_list_size(list), 1); + free(data); + free(list); +} + +UTEST(ft_list_size, multiple_elems) { + char *data1 = strdup("Hello, World!"); + char *data2 = strdup("Hello, 42!"); + char *data3 = strdup("Hello, 21!"); + t_list *list = ft_create_elem(data1); + ft_list_push_front(&list, data2); + ft_list_push_front(&list, data3); + ASSERT_EQ(ft_list_size(list), 3); + free(data1); + free(data2); + free(data3); + free(list->next->next); + free(list->next); + free(list); +} + +UTEST(ft_list_size, multiple_elems_with_null_data) { + char *data1 = strdup("Hello, World!"); + char *data2 = NULL; + char *data3 = strdup("Hello, 21!"); + t_list *list = ft_create_elem(data1); + ft_list_push_front(&list, data2); + ft_list_push_front(&list, data3); + ASSERT_EQ(ft_list_size(list), 3); + free(data1); + free(data3); + free(list->next->next); + free(list->next); + free(list); +}