uthash adding a new entry to a <struct, struct> hashmap

434 views Asked by At

I want to create a hashmap with uthash.

I want the key and the value to be a struct, containing a String and a size_t like this:

typedef struct hash_ptr {
    char* string;
    size_t len;
}hash_ptr;

The hash table itself looks like this:

typedef struct hash_map_entry {
    struct hash_ptr *key;
    struct hash_ptr *value;
    UT_hash_handle hh;
}hash_map_entry;

In order to add new entries to the map I wrote a new function called add_entry():

void add_entry(hash_map_entry *map, hash_ptr *key, hash_ptr *value) {
    hash_map_entry *entry;
    HASH_FIND(hh, map, key, sizeof *key, entry);
    if (entry == NULL) {
        entry = (hash_map_entry*) malloc(sizeof *entry);
        memset(entry, 0, sizeof *entry);
        entry->value = value;
        entry->key = key;
        HASH_ADD(hh, map, key, sizeof *key, entry);
    }
}

However, after initializing and calling add_entry()...

hash_map_entry *map = NULL;

hash_ptr *key = (hash_ptr*) malloc(sizeof *key);
memset(key, 0, sizeof *key);
key->string = "Is this the Krusty Krab?";
key->len = strlen(key->string);

hash_ptr *value = (hash_ptr*) malloc(sizeof *value);
memset(value, 0, sizeof *value);
value->string = "No, this is Patrick!";
value->len = strlen(value->string);

add_entry(map, key, value);

...HASH_FIND doesn't find the added entry:

hash_map_entry *find_me;
HASH_FIND(hh, map, key, sizeof *key, find_me);

and find_me is NULL.

I followed the Instructions for using a struct as a key from the official user guide.

Where am I wrong?

1

There are 1 answers

0
Ian Abbott On BEST ANSWER

This is the simplest modification I can come up with. Changes from the original are:

  1. Change the first parameter of add_entry from hash_map_entry *map to hash_map_entry **map and adjust the code accordingly.

  2. Use HASH_ADD_KEYPTR to hash the contents of the string inside struct hash_ptr instead of hashing the struct hash_ptr itself. NOTE: the code assumes that the len member is the length of the the object pointed to by the string member, in bytes.

  3. Related to 2, change the usage of HASH_FIND to hash the contents of the string inside struct hash_ptr.

Here is the result:

#include <stdio.h>
#include <stdlib.h>
#include "uthash.h"

typedef struct hash_ptr {
    char* string;
    size_t len;
}hash_ptr;

typedef struct hash_map_entry {
    struct hash_ptr *key;
    struct hash_ptr *value;
    UT_hash_handle hh;
}hash_map_entry;

void add_entry(hash_map_entry **map, hash_ptr *key, hash_ptr *value) {
    hash_map_entry *entry;
    HASH_FIND(hh, *map, key->string, key->len, entry);
    if (entry == NULL) {
        entry = (hash_map_entry*) malloc(sizeof *entry);
        memset(entry, 0, sizeof *entry);
        entry->value = value;
        entry->key = key;
        HASH_ADD_KEYPTR(hh, *map, key->string, key->len, entry);
    }
}

int main(void)
{
    hash_map_entry *map = NULL;

    hash_ptr *key = (hash_ptr*) malloc(sizeof *key);
    memset(key, 0, sizeof *key);
    key->string = "Is this the Krusty Krab?";
    key->len = strlen(key->string);

    hash_ptr *value = (hash_ptr*) malloc(sizeof *value);
    memset(value, 0, sizeof *value);
    value->string = "No, this is Patrick!";
    value->len = strlen(value->string);

    add_entry(&map, key, value);

    hash_map_entry *find_me;
    HASH_FIND(hh, map, key->string, key->len, find_me);
    if (find_me)
    {
        printf("found key=\"%s\", val=\"%s\"\n", find_me->key->string, find_me->value->string);
    }
    else
    {
        printf("not found\n");
    }
    return 0;
}