Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hash #50

Merged
merged 11 commits into from
Aug 5, 2024
Merged

Hash #50

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
Loading