Search code examples
cglib

Is there a way of indexing structures as values in Glib Hash Tables?


Currently i am trying to implement a symboltabel with scoping managment for interpreting a custom language as a school project.My problem is that i have few knowledge when it comes to libraries implementing containers.I've studied Glib for some time and i've decided to be the most fit, i am trying to use it for my cause.But i have a question is there a way of using structs as value for keys ?


Solution

  • "using structs as value for keys" is confusing me, do you mean "using structs as keys" or "using structs as values"?

    You can use any pointer as either key or value; gpointer is a typedef to void*. Structs as values would be something like

    YourStruct* your_struct_new(void) {
      YourStruct* val = g_malloc0(sizeof(YourStruct));
      /* Any per-struct initialization goes here */
      return val;
    }
    
    void your_struct_free(YourStruct* val) {
      /* Free any members you need to */
      g_free(val);
    }
    
    void do_stuff(void) {
      GHashTable* ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, your_struct_free);
    
      /* Insert an entry */
      g_hash_table_insert(ht, g_strdup("Key"), your_struct_new());
    
      /* Free the hash table, including all entries */
      g_hash_table_unref(ht);
    }
    

    Structs as keys may require custom hash/equal functions, unless you want to just use g_direct_hash which just uses the memory address. Often that's enough, but if not you basically need to generate an int from the contents of your struct somehow. For example, if your struct has two string members, you may want something like

    typedef struct {
      char* foo;
      char* bar;
    } YourStruct;
    
    guint your_struct_hash(YourStruct* val) {
      guint res = g_str_hash(val->foo);
      res |= g_str_hash(val->bar);
      return res;
    }
    
    /* return TRUE if a and b are equal, FALSE otherwise */
    gboolean your_truct_equals(YourStruct* a, YourStruct* b) {
      if (g_strcmp0(a->foo, b->foo))
        return FALSE;
      if (g_strcmp0(a->bar, b->bar))
        return FALSE;
    
      return TRUE;
    }
    

    Then just pass those to g_hash_table_new_full instead of g_str_hash and g_free and you're done. Of course, exactly how to implement those depends pretty heavily on what your data structure looks like, so without more information that's about all I can tell you.