Implement name to part reference change (ugly)
authorLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Sat, 16 Aug 2025 10:36:41 +0000 (12:36 +0200)
committerLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Sat, 16 Aug 2025 11:02:50 +0000 (13:02 +0200)
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

index 99c85b3c056a1df25022138709142c6436bd7365..3d19937899a4cc28fd5589a1c92842c0a87f2326 100644 (file)
@@ -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);