From 67720402bc8eb39f2f12f4c1cec322591aee1fd5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Luk=C3=A1=C5=A1=20Ji=C5=99i=C5=A1t=C4=9B?= Date: Sat, 16 Aug 2025 12:36:41 +0200 Subject: [PATCH] Implement name to part reference change (ugly) This commit introduces the swap from a part name to a pointer to a part. It also implements the p and n FETs as parts in a way that I consider ugly - there is a lot of stuff that WILL BREAK if Libft changes the implementation of the underlying structures. I explain myself in a comment directly adjacent to the ugly code but will reiterate here. The 42 Norm only allows static constant globals I was not able to define the FETs as such. So I fit them in a static variable of a function. And so that I don't have to release the memory (Norm mandates clear Valgrind output) I try to fit it on the stack. This should be quite easy to refactor if one decides not to comply with the Norm. --- src/c_load.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 240 insertions(+), 26 deletions(-) diff --git a/src/c_load.c b/src/c_load.c index 99c85b3..3d19937 100644 --- a/src/c_load.c +++ b/src/c_load.c @@ -237,31 +237,11 @@ int cmp_parts_void(const void *a_v, const void *b_v) return (ft_strcmp(a->name, b->name)); } -union u_part_spec +typedef union u_part_spec { char *name; const t_part *part; -}; - -typedef struct s_part_spec -{ - int is_string_tag; - union u_part_spec spec; -} t_part_spec; - -const char *get_name_from_spec(t_part_spec spec) -{ - if (spec.is_string_tag) - return (spec.spec.name); - return (spec.spec.part->name); -} - -const t_part *get_part_from_spec(t_part_spec spec) -{ - if (spec.is_string_tag) - return (NULL); - return (spec.spec.part); -} +} t_part_spec; int cmp_strings_void(const void *a_v, const void *b_v) { @@ -312,19 +292,36 @@ void free_part_void(void *part) return ; } +void free_part_with_used_names(t_part *part) +{ + if (!part) + return ; + free(part->name); + ft_vec_free(&part->nodes, free_node); + ft_vec_free(&part->mosfets, NULL); + ft_dict_free(&part->used_parts, free_string_void, free_string_void); + ft_dict_free(&part->io_to_node, free_string_void, NULL); + return ; +} + +void free_part_with_used_names_void(void *part) +{ + free_part_with_used_names(part); + return ; +} + int write_used_part(t_part *part, const t_parse_tree_node *part_reference) { char *specific_name; t_part_spec part_spec; specific_name = ft_strdup(ft_cget_child_deep(part_reference, 3, 0, 0, 0)->token.str); - part_spec.is_string_tag = 1; - part_spec.spec.name = ft_strdup(ft_cget_child_deep(part_reference, 3, 2, 0, 0)->token.str); - if (specific_name && part_spec.spec.name + part_spec.name = ft_strdup(ft_cget_child_deep(part_reference, 3, 2, 0, 0)->token.str); + if (specific_name && part_spec.name && ft_dict_insert(&part->used_parts, &specific_name, &part_spec) == success) return (0); free(specific_name); - free(part_spec.spec.name); + free(part_spec.name); return (1); } typedef t_rbtree t_catalog; @@ -339,6 +336,15 @@ t_ft_stat insert_into_catalog(t_catalog *part_catalog, t_part *part) return (ft_rbtree_insert(part_catalog, part) != success); } +// This works because part name is the first member of a part and there can +// be no padding before the first member of a struct +// +// Thinking about it this is an easy way to use rbtrees as dicts... +t_part *access_catalog(t_catalog *part_catalog, const char *part_name) +{ + return (ft_rbtree_search(part_catalog, &part_name)); +} + void free_catalog(t_catalog *part_catalog) { ft_rbtree_free(part_catalog, free_part_void); @@ -379,12 +385,220 @@ int extract_used_names(t_catalog *part_catalog, t_parse_tree_node *part_spec_lis return (0); } +void free_unchanged_part_of_catalog(t_rbtree_traversal *traversal, t_catalog *part_catalog) +{ + t_part *part; + + part = ft_rbtree_traverse(traversal); + while (part) + { + ft_rbtree_delete(part_catalog, part, free_part_with_used_names_void); + part = ft_rbtree_traverse(traversal); + } + return ; +} + +// The following is exactly what one should not do - using the implementation details +// instead of the interface +// +// I first wanted to create the FETs as static consts (as per the Norm). +// But they are not possible to initialize because the nodes hold pointers to mosfets. +// +// So I had to do static var. But I did not want to allocate any space for that, +// because I would need to clean the memory for Valgrind not to cry. +// +// So I am doing this thing... Because of the challenge of adhering to the Norm (to the interesting part). +static const char *const g_gate_str = "gate"; +static const char *const g_drain_str = "drain"; +static const char *const g_source_str = "source"; +static const char g_p_name[] = "p"; +static const char g_n_name[] = "n"; + +// IO needs to hold node id instead of pointer +#define G_SIZE_OF_IO_NODE (sizeof(t_rbtree_node) + sizeof(char *) + sizeof(t_node *)) +#define G_COMPLETE_SIZE_OF_FET_PART (sizeof(t_part) + 3 * (sizeof(t_node)) + sizeof(t_id) + sizeof(t_mosfet) + 3 * G_SIZE_OF_IO_NODE) + +void init_fet_nodes(t_part *fet, t_node *nodes, t_id *mosfet) +{ + size_t i = 0; + t_node *node; + + fet->nodes.capacity = 3; + fet->nodes.size = 0; + fet->nodes.el_size = sizeof(t_node); + fet->nodes.vec = nodes; + while (i < 3) + { + node = add_node(&fet->nodes, floating); + node->connected_gates.capacity = 1; + node->connected_gates.vec = mosfet; + node->connected.capacity = 1; + node->connected.vec = mosfet; + ++i; + } + return ; +} + +void init_fet_mosfet(t_part *fet, t_mosfet *mosfet, t_type type) +{ + if (type == p) + fet->name = (char *)g_p_name; + else + fet->name = (char *)g_n_name; + fet->mosfets.capacity = 1; + fet->mosfets.size = 0; + fet->mosfets.el_size = sizeof(t_mosfet); + fet->mosfets.vec = mosfet; + add_mosfet(&fet->mosfets, type, (t_position){.x = 0, .y = 0}, RIGHT); + return ; +} + +void init_fet_single_io(t_part *fet, t_rbtree_node *io_node, t_node *node, t_terminal terminal) +{ + t_mosfet *mosfet; + + mosfet = node->connected.vec; + io_node->tree = &fet->io_to_node.tree; + io_node->parent = NULL; + io_node->is_black = 1; + io_node->left = NULL; + io_node->right = NULL; + ft_memcpy((char *)&io_node->data + sizeof(char *), &node, sizeof(t_node *)); + if (terminal == source) + { + bind_fet_node(&fet->nodes, mosfet, node, source); + ft_memcpy(&io_node->data, &g_source_str, sizeof(char *)); + } + else if (terminal == gate) + { + bind_fet_node(&fet->nodes, mosfet, node, gate); + ft_memcpy(&io_node->data, &g_gate_str, sizeof(char *)); + } + else + { + bind_fet_node(&fet->nodes, mosfet, node, drain); + ft_memcpy(&io_node->data, &g_drain_str, sizeof(char *)); + } +} + +void build_tree(t_part *fet, t_rbtree_node *left, t_rbtree_node *root, t_rbtree_node *right) +{ + root->left = left; + root->right = right; + right->parent = root; + left->parent = root; + fet->io_to_node.tree.root = root; + return ; +} + +void init_fet_io(t_part *fet, t_rbtree_node *io_node_source) +{ + t_rbtree_node *const io_node_gate = (t_rbtree_node *)((char *)io_node_source + G_SIZE_OF_IO_NODE); + t_rbtree_node *const io_node_drain = (t_rbtree_node *)((char *)io_node_gate + G_SIZE_OF_IO_NODE); + const int source_gate_cmp = cmp_strings_void(&g_source_str, &g_gate_str); + const int gate_drain_cmp = cmp_strings_void(&g_gate_str, &g_drain_str); + const int drain_source_cmp = cmp_strings_void(&g_drain_str, &g_source_str); + + ft_dict_init(&fet->io_to_node, sizeof(char *), sizeof(t_node *), cmp_strings_void); + init_fet_single_io(fet, io_node_source, ft_vec_access(&fet->nodes, 0), source); + init_fet_single_io(fet, io_node_gate, ft_vec_access(&fet->nodes, 1), gate); + init_fet_single_io(fet, io_node_drain, ft_vec_access(&fet->nodes, 2), drain); + if (drain_source_cmp < 0 && source_gate_cmp < 0) + build_tree(fet, io_node_drain, io_node_source, io_node_gate); + else if (source_gate_cmp < 0 && gate_drain_cmp < 0) + build_tree(fet, io_node_source, io_node_gate, io_node_drain); + else if (gate_drain_cmp < 0 && drain_source_cmp < 0) + build_tree(fet, io_node_gate, io_node_drain, io_node_source); + else if (drain_source_cmp > 0 && source_gate_cmp > 0) + build_tree(fet, io_node_gate, io_node_source, io_node_drain); + else if (source_gate_cmp > 0 && gate_drain_cmp > 0) + build_tree(fet, io_node_drain, io_node_gate, io_node_source); + else if (gate_drain_cmp > 0 && drain_source_cmp > 0) + build_tree(fet, io_node_source, io_node_drain, io_node_gate); + return ; +} + +void initialize_fet_part(t_part *fet, t_type type) +{ + t_node *const nodes = (t_node *)((char *)fet + sizeof(t_part)); + t_id *const mosfet_id = (t_id *)((char *)nodes + 3 * sizeof(t_node)); + t_mosfet *const mosfet = (t_mosfet *)((char *)mosfet_id + sizeof(t_id)); + t_rbtree_node *const io_nodes = (t_rbtree_node *)((char *)mosfet + sizeof(t_mosfet)); + + init_fet_nodes(fet, nodes, mosfet_id); + init_fet_mosfet(fet, mosfet, type); + init_fet_io(fet, io_nodes); +} + +const t_part *get_part_from_name(t_catalog *parts_catalog, const char *part_name) +{ + static char memory_for_fets[2 * G_COMPLETE_SIZE_OF_FET_PART]; + static t_part *nfet_part = NULL; + static t_part *pfet_part = NULL; + + if (nfet_part == NULL) + { + nfet_part = (t_part *)memory_for_fets; + initialize_fet_part(nfet_part, n); + pfet_part = (t_part *)(memory_for_fets + G_COMPLETE_SIZE_OF_FET_PART); + initialize_fet_part(pfet_part, p); + } + if (!ft_strcmp(part_name, "n")) + return (nfet_part); + if (!ft_strcmp(part_name, "p")) + return (pfet_part); + return (access_catalog(parts_catalog, part_name)); +} + +int rebind_names_to_parts(t_catalog *parts_catalog) +{ + t_rbtree_traversal parts_traversal; + t_dict_traversal used_parts_traversal; + t_part *part; + t_part_spec *part_spec; + char *part_name; + + if (ft_rbtree_traversal_init(&parts_traversal, parts_catalog, inorder) != success) + return (1); + part = ft_rbtree_traverse(&parts_traversal); + while (part) + { + if (ft_dict_traversal_init(&used_parts_traversal, &part->used_parts) != success) + { + free_unchanged_part_of_catalog(&parts_traversal, parts_catalog); + return (1); + } + part_spec = ft_dict_traverse(&used_parts_traversal); + while (part_spec) + { + part_name = part_spec->name; + part_spec->part = get_part_from_name(parts_catalog, part_name); + free(part_name); + if (!part_spec->part) + { + free_unchanged_part_of_catalog(&parts_traversal, parts_catalog); + part_spec = ft_dict_traverse(&used_parts_traversal); + while (part_spec) + { + free(part_spec->name); + part_spec = ft_dict_traverse(&used_parts_traversal); + } + return (1); + } + part_spec = ft_dict_traverse(&used_parts_traversal); + } + part = ft_rbtree_traverse(&parts_traversal); + } + return (0); +} + int construct_new_graph(t_parse_tree_node *parse_tree, __attribute__((unused)) t_vec *nodes, __attribute__((unused)) t_vec *mosfets) { t_catalog part_catalog; init_catalog(&part_catalog); extract_used_names(&part_catalog, parse_tree); + rebind_names_to_parts(&part_catalog); //build_graphs(&part_catalog, parse_tree); //transfer_main(&part_catalog, nodes, mosfets); free_catalog(&part_catalog); -- 2.30.2