Skip to content

Commit

Permalink
Merge pull request #50 from JakeRoggenbuck/hash
Browse files Browse the repository at this point in the history
Hash
  • Loading branch information
JakeRoggenbuck authored Aug 5, 2024
2 parents bf1e0f8 + 4223904 commit 5cc672c
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/testing/main.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include "codegen/x86/test_x86.h"
#include "lexer/test_lexer.h"
#include <util/test_list.h>
#include <util/test_util.h>

int main() {
test_lexer();
test_x86();
test_list();
test_util();

return 0;
}
174 changes: 174 additions & 0 deletions src/util/hashmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#include "hashmap.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <testing/tassert.h>
#include <testing/test_utils.h>

unsigned fnva1(char *value) {
unsigned long h = 16777619;
long int prime = 2166136261;

while (*value != '\0') {
h ^= *value;
h *= prime;
++value;
}

return h;
}

unsigned equal_key(char *a, char *b) { return strcmp(a, b) == 0; }

struct Hashmap *create_hashmap(int capacity) {
struct Hashmap *h = malloc(sizeof(struct Hashmap));

h->buckets = calloc(capacity, sizeof(struct BucketNode *));

h->size = 0;
h->cap = capacity;

h->hash = fnva1;
h->equals = equal_key;

return h;
}

void destroy_hashmap(struct Hashmap *h) {
free(h->buckets);
free(h);
}

struct BucketNode *create_bucket(char *key, void *value) {
struct BucketNode *b = malloc(sizeof(struct BucketNode));

b->key = key;
b->value = value;
b->next = NULL;

return b;
}

struct BucketNode *hm_get(struct Hashmap *h, char *key) {
unsigned a = h->hash(key) % h->cap;

struct BucketNode *b = h->buckets[a];

if (b == NULL) {
return NULL;
}

if (h->equals(b->key, key)) {
return b;
}

// check for linear probing

return NULL;
}

int hm_set(struct Hashmap *h, char *key, void *value) {
unsigned a = h->hash(key) % h->cap;

struct BucketNode *b = h->buckets[a];

if (b == NULL) {
if (h->size == h->cap) {
double_cap(h);
}

h->size++;

h->buckets[a] = malloc(sizeof(struct BucketNode *));
h->buckets[a]->key = key;
h->buckets[a]->value = value;
h->buckets[a]->next = NULL;

return 0;
} else {
// Handle linear probing
return -1;
}
}

void double_cap(struct Hashmap *h) {
struct BucketNode **new_buckets =
calloc(h->cap * 2, sizeof(struct BucketNode *));

for (int i = 0; i < h->cap; i++) {

if (h->buckets[i] != NULL) {
struct BucketNode *b = h->buckets[i];
unsigned a = h->hash(b->key) % h->cap;
new_buckets[a] = b;
}
}

h->buckets = new_buckets;

h->cap = h->cap * 2;
}

int test_hash_init() {
testing_func_setup();
struct Hashmap *h = create_hashmap(100);

tassert(h->size == 0);
tassert(h->cap == 100);
}

int test_hash_init_and_store() {
testing_func_setup();
struct Hashmap *h = create_hashmap(100);

tassert(h->size == 0);
tassert(h->cap == 100);

char name[5] = "jake";

char key[5] = "test";
int ret = hm_set(h, key, name);
tassert(ret != -1);

uint64_t ind = h->hash(key) % h->cap;
struct BucketNode *b = h->buckets[ind];
tassert(strcmp(b->key, key) == 0);

tassert(h->size == 1);
tassert(h->cap == 100);
}

int test_hash_set_and_get() {
testing_func_setup();
struct Hashmap *h = create_hashmap(100);

char name[100] = "jake";
char key[10] = "test";

int ret = hm_set(h, key, name);
tassert(ret != -1);

struct BucketNode *got = hm_get(h, "test");
tassert(strcmp(got->value, "jake") == 0);

return 0;
}

int test_hash_set_and_double_get() {
testing_func_setup();
struct Hashmap *h = create_hashmap(100);

char name[100] = "jake";
char key[10] = "test";

int ret = hm_set(h, key, name);
tassert(ret != -1);

double_cap(h);

struct BucketNode *got = hm_get(h, "test");
tassert(strcmp(got->value, "jake") == 0);

return 0;
}
32 changes: 32 additions & 0 deletions src/util/hashmap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
struct BucketNode {
char *key;
void *value;
struct BucketNode *next;
};

struct Hashmap {
struct BucketNode **buckets;
int size;
int cap;

unsigned (*hash)(char *);
unsigned (*equals)(char *, char *);
};

struct Hashmap *create_hashmap(int capacity);
void destroy_hashmap(struct Hashmap *h);

struct BucketNode *create_bucket(char *key, void *value);

// Get a value with a key
struct BucketNode *hm_get(struct Hashmap *h, char *key);
// Set a value with a key
int hm_set(struct Hashmap *h, char *key, void *value);
// Double the capacity of the hashmap (happens automatically when size >
// capacity)
void double_cap(struct Hashmap *h);

int test_hash_init();
int test_hash_init_and_store();
int test_hash_set_and_get();
int test_hash_set_and_double_get();
14 changes: 14 additions & 0 deletions src/util/test_util.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "hashmap.h"
#include <testing/test_utils.h>

int test_util() {
testing_module_setup();

test_hash_init();
test_hash_init_and_store();
test_hash_set_and_get();
test_hash_set_and_double_get();

testing_module_cleanup();
return 0;
}
5 changes: 5 additions & 0 deletions src/util/test_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include "hashmap.h"

int test_util();

0 comments on commit 5cc672c

Please sign in to comment.