195 lines
4.1 KiB
C
Executable File
195 lines
4.1 KiB
C
Executable File
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "hashtable.h"
|
|
|
|
static hashtable_ent_t* add_new(hashtable_ent_t** entry, const char* key) {
|
|
if (entry == NULL || key == NULL) return NULL;
|
|
*entry = (hashtable_ent_t*)malloc(sizeof(hashtable_ent_t));
|
|
if (*entry == NULL) return NULL;
|
|
(*entry)->key = strdup(key);
|
|
if ((*entry)->key == NULL) {
|
|
free(*entry);
|
|
return NULL;
|
|
}
|
|
(*entry)->next = NULL;
|
|
return *entry;
|
|
}
|
|
|
|
/*
|
|
* Helper function that does most of the implemention work
|
|
*/
|
|
static hashtable_ent_t* locate(hashtable_t* ht, const char* key, int create_if_missing) {
|
|
if (ht == NULL || key == NULL) return NULL;
|
|
int h = hash(key) % ht->table_len;
|
|
hashtable_ent_t* node = ht->table[h];
|
|
if (node != NULL) {
|
|
/* Search until we find a match or hit the end */
|
|
while (node->next != NULL && strcmp(key, node->key)) node = node->next;
|
|
if (!strcmp(key, node->key)) {
|
|
return node;
|
|
} else if (node->next == NULL && create_if_missing) {
|
|
/* If we failed to find the key, we can create an entry in place */
|
|
return add_new(&node->next, key);
|
|
}
|
|
} else if (create_if_missing) {
|
|
return add_new(&ht->table[h], key);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
hashtable_t *create_hashtable(int max_size) {
|
|
if (max_size <= 0) {
|
|
return NULL;
|
|
}
|
|
|
|
hashtable_t* ht = (hashtable_t *) malloc(sizeof(hashtable_t));
|
|
ht->table = (hashtable_ent_t **) malloc(sizeof(hashtable_ent_t) * max_size);
|
|
ht->table_len = max_size;
|
|
|
|
for (int i = 0; i < max_size; i++) {
|
|
ht->table[i] = NULL;
|
|
}
|
|
|
|
return ht;
|
|
}
|
|
|
|
void free_hashtable(hashtable_t *ht) {
|
|
if (ht == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < ht->table_len; i++) {
|
|
hashtable_ent_t* node = ht->table[i];
|
|
while (node != NULL) {
|
|
hashtable_ent_t* next = node->next;
|
|
|
|
free(node->key);
|
|
node->key = NULL;
|
|
free(node);
|
|
|
|
node = next;
|
|
}
|
|
}
|
|
free(ht->table);
|
|
ht->table = NULL;
|
|
free(ht);
|
|
ht = NULL;
|
|
}
|
|
|
|
int get(hashtable_t *ht, const char *key, double *value) {
|
|
if (ht == NULL || key == NULL || value == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
|
|
hashtable_ent_t* entry = locate(ht, key, 0);
|
|
if (entry != NULL) {
|
|
*value = entry->value;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
|
|
/*hashtable_ent_t* entry = ht->table[hash(key) % ht->table_len];
|
|
while (entry != NULL && entry->key != NULL) {
|
|
if (strcmp(entry->key, key) == 0) {
|
|
*value = entry->value;
|
|
return 0;
|
|
}
|
|
entry = entry->next;
|
|
}
|
|
|
|
return -1;*/
|
|
|
|
}
|
|
|
|
int set(hashtable_t *ht, const char *key, double value) {
|
|
if (ht == NULL || key == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
hashtable_ent_t* entry = locate(ht, key, 1);
|
|
if (entry == NULL)
|
|
return -1;
|
|
entry->value = value;
|
|
return 0;
|
|
|
|
/*hashtable_ent_t* entry = ht->table[hash(key) % ht->table_len];
|
|
while (entry != NULL && entry->key != NULL) {
|
|
if (strcmp(entry->key, key) == 0) {
|
|
entry->value = value;
|
|
return 0;
|
|
}
|
|
entry = entry->next;
|
|
}
|
|
|
|
// Does not exist. Add a new entry.
|
|
hashtable_ent_t* newEntry = (hashtable_ent_t *) malloc(sizeof(hashtable_ent_t));
|
|
if (newEntry == NULL) {
|
|
return -1; // Out of memory.
|
|
}
|
|
|
|
newEntry->key = strdup(key);
|
|
newEntry->value = value;
|
|
entry->next = newEntry;
|
|
newEntry->next = NULL;
|
|
|
|
return 0;*/
|
|
}
|
|
|
|
|
|
int key_exists(hashtable_t *ht, const char *key) {
|
|
if (ht == NULL || key == NULL)
|
|
return -1;
|
|
|
|
hashtable_ent_t* entry = locate(ht, key, 0);
|
|
if (entry != NULL)
|
|
return 1;
|
|
return 0;
|
|
|
|
/*double* val = (double *) malloc(sizeof(double));
|
|
int result = get(ht, key, val);
|
|
free(val);
|
|
if (result == 0)
|
|
return 1;
|
|
else
|
|
return 0;*/
|
|
}
|
|
|
|
int remove_key(hashtable_t *ht, const char *key) {
|
|
if (ht == NULL || key == NULL || !key_exists(ht, key))
|
|
return -1;
|
|
|
|
int i = hash(key) % ht->table_len;
|
|
hashtable_ent_t* entry = ht->table[i];
|
|
hashtable_ent_t* prev = NULL;
|
|
while (entry != NULL && entry->key != NULL) {
|
|
if (strcmp(entry->key, key) == 0) {
|
|
if (prev == NULL) { // First node (head).
|
|
ht->table[i] = entry->next; // If next is null, THAT'S OKAY!
|
|
} else {
|
|
prev->next = entry->next; // Again, it's okay if next is null.
|
|
}
|
|
|
|
free(entry->key);
|
|
entry->key = NULL;
|
|
free(entry);
|
|
entry = NULL;
|
|
return 0;
|
|
}
|
|
prev = entry;
|
|
entry = entry->next;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|