Skip to content

Instantly share code, notes, and snippets.

@zelark
Last active April 5, 2020 16:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zelark/e40be0d4de9f852328d34aa9e0ceaa5a to your computer and use it in GitHub Desktop.
Save zelark/e40be0d4de9f852328d34aa9e0ceaa5a to your computer and use it in GitHub Desktop.
You can find the original example here https://youtu.be/wg8hZxMRwcw
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASHMAP_SIZE 16
typedef struct entry_t {
char *key;
char *value;
struct entry_t *next;
} entry_t, *entry_p;
typedef struct {
entry_t **entries;
} hmap_t, *hmap_p;
unsigned int hash(char *key) {
unsigned long int value = 0;
unsigned int key_len = strlen(key);
/* Do several rounds of multiplication. */
for (int i = 0; i < key_len; ++i) {
value = value * 37 + key[i];
}
/* Make sure value is 0 <= value < HASHMAP_SIZE. */
value = value % HASHMAP_SIZE;
return value;
}
entry_p hmap_create_entry(char *key, char *value) {
/* Allocate the entry. */
entry_t *entry = malloc(sizeof(entry_t));
entry->key = malloc(strlen(key) + 1);
entry->value = malloc(strlen(value) + 1);
/* Copy the key and value in place. */
strcpy(entry->key, key);
strcpy(entry->value, value);
/* Next starts out null but may be set later on. */
entry->next = NULL;
return entry;
}
void hmap_delete_entry(entry_t *entry) {
free(entry->key);
free(entry->value);
free(entry);
}
hmap_p hmap_create(void) {
hmap_t *hmap = malloc(sizeof(hmap_t));
hmap->entries = malloc(sizeof(entry_p) * HASHMAP_SIZE);
/* Set each entry to null (needed for proper operation). */
for (int i = 0; i < HASHMAP_SIZE; ++i) {
hmap->entries[i] = NULL;
}
return hmap;
}
void hmap_delete(hmap_t *hmap) {
for (int i = 0; i < HASHMAP_SIZE; ++i) {
entry_t *entry = hmap->entries[i];
while (entry) {
entry_t *next = entry->next;
hmap_delete_entry(entry);
entry = next;
}
}
free(hmap->entries);
free(hmap);
}
void hmap_put(hmap_t *hmap, char *key, char *value) {
unsigned int slot = hash(key);
/* Try to look up an entry set. */
entry_t *entry = hmap->entries[slot];
/* No entry means slot empty, insert immediately. */
if (entry == NULL) {
hmap->entries[slot] = hmap_create_entry(key, value);
return;
}
entry_t *prev;
/* Walk through each entry until either the end is */
/* reached or a matching key is found. */
while (entry != NULL) {
/* Check key. */
if (strcmp(entry->key, key) == 0) {
/* Match found, replace value. */
free(entry->value);
entry->value = malloc(strlen(value) + 1);
strcpy(entry->value, value);
return;
}
/* Walk to next. */
prev = entry;
entry = prev->next;
}
// End of chain reached without a match, add new.
prev->next = hmap_create_entry(key, value);
}
char* hmap_get(hmap_t *hmap, char *key) {
unsigned int slot = hash(key);
/* Try to find a valid slot. */
entry_t *entry = hmap->entries[slot];
/* No slot means no entry. */
if (entry == NULL) {
return NULL;
}
/* Walk through each entry in the slot, */
/* which could just be a single thing. */
while (entry != NULL) {
/* Return value if found. */
if (strcmp(entry->key, key) == 0) {
return entry->value;
}
/* Proceed to next key if available. */
entry = entry->next;
}
/* Reaching here means there were >= 1 entries but no key match. */
return NULL;
}
void hmap_del(hmap_t *hmap, char *key) {
unsigned int slot = hash(key);
/* Try to find a valid slot. */
entry_t *entry = hmap->entries[slot];
/* No bucket means no entry. */
if (entry == NULL) {
return;
}
entry_t *prev;
int idx = 0;
/* Walk through each entry until either the end is reached */
/* or a matching key is found. */
while (entry != NULL) {
if (strcmp(entry->key, key) == 0) {
/* If first item and no next entry. */
if (entry->next == NULL && idx == 0) {
hmap->entries[slot] = NULL;
}
/* If first item with a next entry. */
if (entry->next != NULL && idx == 0) {
hmap->entries[slot] = entry->next;
}
/* If last item. */
if (entry->next == NULL && idx != 0) {
prev->next = NULL;
}
/* If middle item. */
if (entry->next != NULL && idx != 0) {
prev->next = entry->next;
}
/* Free the deleted entry. */
hmap_delete_entry(entry);
return;
}
/* Walk to next. */
prev = entry;
entry = prev->next;
++idx;
}
}
void hmap_dump(hmap_t *hmap) {
for (int i = 0; i < HASHMAP_SIZE; ++i) {
entry_t *entry = hmap->entries[i];
if (entry == NULL) {
continue;
}
printf("slot[%04d]: ", i);
while (1) {
printf("%s=%s ", entry->key, entry->value);
if (entry->next == NULL) {
break;
}
entry = entry->next;
}
printf("\n");
}
}
int main(int argc, char **argv) {
hmap_t *hmap = hmap_create();
hmap_put(hmap, "name1", "em");
hmap_put(hmap, "name2", "russian");
hmap_put(hmap, "name3", "pizza");
hmap_put(hmap, "name4", "doge");
hmap_put(hmap, "name5", "pyro");
hmap_put(hmap, "name6", "joost");
hmap_put(hmap, "name7", "kalix");
hmap_dump(hmap);
hmap_delete(hmap);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment