0

I am using glib g_hash_table to create a hash table, with int64 as key and pointer as value.

I tried this code but it fails:

GHashTable* hash = g_hash_table_new(g_int64_hash, g_int64_equal);
uint64_t mer_v = 0;
exist_m = g_hash_table_lookup(hash, mer_v);

It reports error:

(gdb) bt
#0  IA__g_int64_hash (v=0x1d89e81700000) at /build/buildd/glib2.0-2.24.1/glib/gutils.c:3294
#1  0x00007ff2de966ded in g_hash_table_lookup_node (hash_table=0x13a4050, key=0x1d89e81700000) at /build/buildd/glib2.0-2.24.1/glib/ghash.c:309
#2  IA__g_hash_table_lookup (hash_table=0x13a4050, key=0x1d89e81700000) at /build/buildd/glib2.0-2.24.1/glib/ghash.c:898

I used glib data structure quite often, but never tried hash_table with key int64. Cannot find any help from Google. This tutorial does not have any hits as well: http://www.ibm.com/developerworks/linux/tutorials/l-glib/section5.html.

Please help. Thanks.

Joy
  • 9,430
  • 11
  • 44
  • 95

1 Answers1

4

To use g_int64_hash and g_int64_equal you need to store addresses of 64-bit keys in the hash table. So, the correct lookup would be:

exist_m = g_hash_table_lookup(hash, &mer_v);

To use this hasher/comparator, all your keys need to be dynamically allocated, and their addresses passed to both g_hash_table_insert and g_hash_table_lookup:

uint64_t *mer_p = malloc(sizeof(uint64_t));
*mer_p = mer_v;
g_hash_table_insert(hash, (gpointer) mer_p, (gpointer) m);

exists = g_hash_table_lookup(hash, (gpointer) &mer_v);

A common optimization is to store the integer values directly as hash table keys, as opposed to their addresses. The hasher and comparator are then g_direct_hash and g_direct_equal. This requires that all integer keys fit into the size of a pointer (guaranteed if you can use uintptr_t), and that an arbitrary integer can be cast to pointer and back (not guaranteed by ISO C, but respected by major platforms). In that case the insertion and lookup look like this:

g_hash_table_insert(hash, (gpointer) mer_v, (gpointer) m);

exists = g_hash_table_lookup(hash, (gpointer) mer_v);
user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • Thanks, @user4815162342. I need strictly 64-bits. From your comments, the key is a pointer? Is the accessing complexity is `O(1)`? And when I want to insert, does this work: `g_hash_table_insert(hash, GINT_TO_POINTER (mer_v), (gpointer) m);`? – Joy Mar 26 '13 at 07:27
  • @CaiShaojiang If your program is guaranteed to run on a 64-bit platform, it will work fine — but be aware that your program is no longer portable to any 32-bit platform. If you go that route, a simple cast will work. (As a quibble, I would prefer `(gpointer) mer_v` over `GINT_TO_POINTER(mer_v)` because `mer_v` is not a `gint`.) Access complexity is O(1), as with any hash table. – user4815162342 Mar 26 '13 at 07:38
  • 1
    I tried the insertion. Should be `g_hash_table_insert(hash, (gpointer) (&mer_v), (gpointer) m);`. Thanks. – Joy Mar 26 '13 at 08:13
  • 1
    @CaiShaojiang Are you sure that's correct? If you're using `g_int64_hash`, you should be allocating all your numbers on the heap, and passing the dynamic pointer to `g_hash_table_insert`, not the address of an automatic variable. OTOH if you're using `g_direct_hash`, you should be casting `mer_v` itself to `gpointer`, not its address. – user4815162342 Mar 26 '13 at 18:03
  • 1
    Yes you are right. My mistake. My `mer_v` is a pointer got from `malloc`. Thank you so much! – Joy Mar 27 '13 at 02:06
  • @CaiShaojiang If `mer_v` is a pointer, your last `g_hash_table_insert` still looks incorrect — it should be `(gpointer) mer_v`, not `(gpointer) &mer_v`. – user4815162342 Mar 27 '13 at 08:30
  • Yes, that is what I meant, should be `g_hash_table_insert(hash, (gpointer) (mer_v), (gpointer) m);` – Joy Mar 27 '13 at 14:11