From: Lukáš Jiřiště Date: Tue, 30 Dec 2025 14:28:47 +0000 (+0100) Subject: Implement graph structure X-Git-Url: https://git.ljiriste.work/?a=commitdiff_plain;h=93f58ca0533371a83c36fd12d3752440fcf51ca3;p=Libft.git Implement graph structure --- diff --git a/Makefile b/Makefile index 91f244c..e31ed43 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,8 @@ SRCstruct:= ft_stack_free.c \ ft_dict_traversal.c \ ft_linked_list.c \ ft_linked_list_helpers.c \ + ft_graph.c \ + ft_graph_helpers.c \ SRCparse:= ft_parse.c \ ft_parsing_table_init.c \ diff --git a/ft_struct/ft_graph.c b/ft_struct/ft_graph.c new file mode 100644 index 0000000..f06bf4e --- /dev/null +++ b/ft_struct/ft_graph.c @@ -0,0 +1,58 @@ +#include "ft_struct.h" + +t_ft_stat ft_graph_init(t_graph *graph, size_t el_size) +{ + if (!graph) + return (invalid_input); + graph->el_size = el_size; + return (ft_linked_list_init(&graph->nodes, sizeof(t_graph_node) + el_size)); +} + +// Static global function pointer would be more elegant +static t_free_fun handle_generic_free(int set, t_free_fun free_el) +{ + static t_free_fun saved_free_el; + + if (set) + saved_free_el = free_el; + return (saved_free_el); +} + +static void generic_free(void *element) +{ + t_graph_node *node; + t_free_fun free_el; + + node = element; + free_el = handle_generic_free(0, NULL); + if (free_el) + free_el(ft_graph_access(node)); + ft_vec_free(&node->connected_nodes, NULL); + return ; +} + +void ft_graph_free(t_graph *graph, t_free_fun free_el) +{ + if (!graph) + return ; + handle_generic_free(1, free_el); + ft_linked_list_free(&graph->nodes, generic_free); + return ; +} + +void ft_graph_delete(t_graph *graph, t_graph_node *node, t_free_fun free_el) +{ + t_graph_node **disconnecting_node; + t_linked_list_node *list_node; + + while (node->connected_nodes.size > 0) + { + disconnecting_node = ft_vec_access(&node->connected_nodes, 0); + ft_graph_disconnect(node, *disconnecting_node); + } + handle_generic_free(1, free_el); + list_node = (t_linked_list_node *) + ((char *)node - offsetof(t_linked_list_node, data)); + ft_linked_list_delete(&graph->nodes, list_node, generic_free); + return ; +} diff --git a/ft_struct/ft_graph_helpers.c b/ft_struct/ft_graph_helpers.c new file mode 100644 index 0000000..30cb8ba --- /dev/null +++ b/ft_struct/ft_graph_helpers.c @@ -0,0 +1,54 @@ +#include "ft_struct.h" +#include "libft.h" + +t_graph_node *ft_graph_insert(t_graph *graph, void *element) +{ + t_graph_node new_node; + + if (!graph || !element) + return (NULL); + if (ft_vec_init(&new_node.connected_nodes, sizeof(t_graph_node *))) + return (NULL); + ft_memcpy(&new_node.data, element, graph->el_size); + return ((t_graph_node *) + &ft_linked_list_insert(&graph->nodes, &new_node)->data); +} + +void *ft_graph_access(t_graph_node *node) +{ + return (&node->data); +} + +t_ft_stat ft_graph_connect(t_graph_node *node1, t_graph_node *node2) +{ + t_ft_stat res; + + res = ft_vec_append(&node1->connected_nodes, &node2); + if (res != success) + return (res); + res = ft_vec_append(&node2->connected_nodes, &node1); + if (res != success) + ft_vec_forget(&node1->connected_nodes, node1->connected_nodes.size - 1); + return (res); +} + +static int cmp_address(const void *v_address1, const void *v_address2) +{ + t_graph_node *const *address1; + t_graph_node *const *address2; + + address1 = v_address1; + address2 = v_address2; + return ((*address1 > *address2) - (*address1 < *address2)); +} + +void ft_graph_disconnect(t_graph_node *node1, t_graph_node *node2) +{ + size_t index; + + ft_vec_find_index(&node1->connected_nodes, node2, &index, cmp_address); + ft_vec_forget(&node1->connected_nodes, index); + ft_vec_find_index(&node2->connected_nodes, node1, &index, cmp_address); + ft_vec_forget(&node2->connected_nodes, index); + return ; +} diff --git a/inc/ft_struct.h b/inc/ft_struct.h index debad50..53e1db7 100644 --- a/inc/ft_struct.h +++ b/inc/ft_struct.h @@ -6,7 +6,7 @@ /* By: ljiriste +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/20 16:59:43 by ljiriste #+# #+# */ -/* Updated: 2025/12/30 09:43:24 by ljiriste ### ########.fr */ +/* Updated: 2025/12/30 15:01:59 by ljiriste ### ########.fr */ /* */ /* ************************************************************************** */ @@ -174,6 +174,28 @@ void ft_linked_list_delete_next( t_linked_list_node *node, t_free_fun free_el); void ft_linked_list_free(t_linked_list *list, t_free_fun free_el); +typedef struct s_graph_node +{ + t_vec connected_nodes; + char data[]; +} t_graph_node; + +// A linked list is used for storage so that node addresses stay constant +typedef struct s_graph +{ + size_t el_size; + t_linked_list nodes; +} t_graph; + +t_ft_stat ft_graph_init(t_graph *graph, size_t el_size); +t_graph_node *ft_graph_insert(t_graph *graph, void *element); +void *ft_graph_access(t_graph_node *node); +t_ft_stat ft_graph_connect(t_graph_node *node1, t_graph_node *node2); +void ft_graph_disconnect(t_graph_node *node1, t_graph_node *node2); +void ft_graph_delete(t_graph *graph, t_graph_node *node, + t_free_fun free_el); +void ft_graph_free(t_graph *graph, t_free_fun free_el); + # ifdef __cplusplus } # endif // __cplusplus