Files
obitools3/src/hashtable.c
2018-10-21 17:35:18 +02:00

198 lines
3.8 KiB
C
Executable File

/****************************************************************************
* Hash table source file *
****************************************************************************/
/**
* @file hashtable.c
* @author Celine Mercier
* @date July 26th 2016
* @brief Source file for hash table functions.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "string.h"
#include "murmurhash2.h"
#include "hashtable.h"
// Create a new hashtable
hashtable_p ht_create(size_t size)
{
hashtable_p hashtable = NULL;
size_t i;
// Allocate the table
hashtable = malloc(sizeof(hashtable_t));
if (hashtable == NULL)
return NULL;
// Allocate the head nodes
hashtable->table = malloc(size * sizeof(entry_p));
if (hashtable->table == NULL)
return NULL;
// Initialize the head nodes
for (i=0; i<size; i++)
hashtable->table[i] = NULL;
hashtable->size = size;
return hashtable;
}
// Create an entry
entry_p ht_new_entry(const char* key, void* value)
{
entry_p new_entry;
new_entry = malloc(sizeof(entry_t));
if (new_entry == NULL)
return NULL;
new_entry->key = strdup(key);
if (new_entry->key == NULL)
return NULL;
new_entry->value = value;
new_entry->next = NULL;
return new_entry;
}
// Delete an entry
int ht_delete_entry(hashtable_p hashtable, const char* key)
{
entry_p last = NULL;
entry_p entry = NULL;
size_t bin = 0;
bin = murmurhash2(key, strlen(key), SEED);
bin = bin % hashtable->size;
// Step through the bin looking for the value
entry = hashtable->table[bin];
while ((entry != NULL) && (strcmp(key, entry->key ) != 0))
{
last = entry;
entry = entry->next;
}
if (entry == NULL) // key not found
return -1;
// Link the entries before and after the entry
if (last != NULL) // If not head node
last->next = entry->next;
else // If head node
hashtable->table[bin] = entry->next;
// Free the entry
free(entry->key);
free(entry->value);
free(entry);
return 0;
}
// Set a new entry in the hash table. If the key is already in the table, the value is replaced by the new one
int ht_set(hashtable_p hashtable, const char* key, void* value)
{
size_t bin = 0;
entry_p new_entry = NULL;
entry_p next = NULL;
entry_p last = NULL;
if ((key == NULL) || (value == NULL))
return -1;
bin = murmurhash2(key, strlen(key), SEED);
bin = bin % hashtable->size;
next = hashtable->table[bin];
while ((next != NULL) && (strcmp(key, next->key) != 0))
{
last = next;
next = next->next;
}
// If the key is already in the table, the value is replaced
if ((next != NULL) && (strcmp(key, next->key) == 0))
new_entry->value = value;
// Else, create the new entry and link it at the end of the list
else
{
// Create the new entry
new_entry = ht_new_entry(key, value);
if (new_entry == NULL)
return -1;
// If it is the first entry of that bin, we're at the head node of the list, and we replace it with the new entry
if (last == NULL)
hashtable->table[bin] = new_entry;
// Else link the new entry at the end of the list
else
last->next = new_entry;
}
return 0;
}
// Retrieve a value from a hash table
void* ht_get(hashtable_p hashtable, const char* key)
{
size_t bin = 0;
entry_p entry;
bin = murmurhash2(key, strlen(key), SEED);
bin = bin % hashtable->size;
// Step through the bin looking for the value
entry = hashtable->table[bin];
while ((entry != NULL) && (strcmp(key, entry->key ) != 0))
entry = entry->next;
if (entry == NULL)
return NULL;
else
return entry->value;
}
// Free the hash table
void ht_free(hashtable_p hashtable)
{
size_t i;
entry_p entry;
entry_p next;
for (i=0; i < hashtable->size; i++)
{
next = hashtable->table[i];
while (next != NULL)
{
entry = next;
free(entry->key);
next = entry->next;
free(entry);
}
}
free(hashtable->table);
free(hashtable);
}