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

Hashmap implementation #46

Closed
wants to merge 4 commits into from
Closed
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: 1 addition & 1 deletion src/codegen/x86/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include "codegen.h"

#include <testing/tassert.h> // tassert
#include "../../testing/tassert.h" // tassert

struct GenState {
// Each bit corresponds with a registers 0-31 where the LSB is 0
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/x86/codegen.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include <testing/test_utils.h>
#include "../../testing/test_utils.h"

char *start_main();

Expand Down
2 changes: 1 addition & 1 deletion src/codegen/x86/test_x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

#include "codegen.h"
#include <testing/test_utils.h>
#include "../../testing/test_utils.h"

int test_x86() {
testing_module_setup();
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/x86/test_x86.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
#pragma once

#include "codegen.h"
#include <testing/test_utils.h>
#include "../../testing/test_utils.h"

int test_x86();
6 changes: 3 additions & 3 deletions src/driver/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
#include <stdio.h>
#include <string.h> // strcmp

#include <lexer/lex.h>
#include <parser/parse.h>
#include <util/out.h>
#include "../lexer/lex.h"
#include "../parser/parse.h"
#include "../util/out.h"

int lexer_dump(const char *filename) {

Expand Down
6 changes: 3 additions & 3 deletions src/lexer/lex.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
#include "token.h"
#include <assert.h>
#include <stdio.h>
#include <testing/tassert.h> // tassert
#include <testing/test_utils.h>
#include "../testing/tassert.h" // tassert
#include "../testing/test_utils.h"

#include <ctype.h>
#include <string.h> // memcpy

#define STREQ(a, b) (!strcmp((a), (b)))

#include <util/out.h> // error reporting
#include "../util/out.h" // error reporting

// Is a character in the given string?
int in_string(char c, char s[]) {
Expand Down
2 changes: 1 addition & 1 deletion src/lexer/test_lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

#include "lex.h"
#include <testing/test_utils.h>
#include "../testing/test_utils.h"

int test_lexer() {
testing_module_setup();
Expand Down
8 changes: 5 additions & 3 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 "../codegen/x86/test_x86.h"
#include "../lexer/test_lexer.h"
#include "../util/test_list.h"
#include "../util/test_hash.h"

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

return 0;
}
2 changes: 1 addition & 1 deletion src/testing/test_utils.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <stdio.h>
#include <util/out.h>
#include "../util/out.h"

void testing_setup_internal(const char *func_name) {
printf("Running tests from ");
Expand Down
115 changes: 115 additions & 0 deletions src/util/hash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include <stdlib.h>
#include <string.h>
#include "hash.h"
#include "out.h"

const uint64_t OFFSET = 14695981039346656037;
const uint64_t FNV_PRIME = 1099511628211;

HashMap* hm_init(int num_buckets) {
HashMap* hm = malloc(sizeof(HashMap));

// bounce if out of memory
if (hm == NULL) {
PRINT_WARNING("out of memory");
return NULL;
}

hm->stored = 0;
hm->capacity = num_buckets;

hm->entries = calloc(hm->capacity, sizeof(HashNode));

// bounce if out of memory
if (hm->entries == NULL) {
PRINT_WARNING("out of memory, could not allocate space for %d entries", hm->capacity);
free(hm->entries);
return NULL;
}

return hm;
}

void hm_free(HashMap *hm) {
for (int i = 0; i<hm->capacity; i++) {
// free all the chars allocated as keys
free(hm->entries[i].key);
}
free(hm->entries);
free(hm);
}

// follows FNV-1a hashing
uint64_t hash(const char* key) {
uint64_t hash = OFFSET;
for (const char *p = key; *p; p++) {
hash ^= (uint64_t)(char)(*p);
hash *= FNV_PRIME;
}
return hash;
}

void* hm_lookup(HashMap *hm, const char* key) {
uint64_t ind = hash(key) % hm->capacity;

for (int i = 0; i < hm->capacity-1; i++) {
// since removed entries aren't actually cleared, if you run
// into a null key, what you're looking for was never added
if (hm->entries[ind].key == NULL) {
return NULL;
} else if (strcmp(key, hm->entries[ind].key) == 0) {
return hm->entries[ind].value;
}

ind++;
if (ind >= hm->capacity) {
ind = 0;
}
}

return NULL;
}

int hm_set(HashMap *hm, const char *key, void *value) {
uint64_t ind = hash(key) % hm->capacity;

for (int i = 0; i < hm->capacity-1; i++) {
// Values are allowed to be overwritten!
if ((hm->entries[ind].key == NULL) || (strcmp(key, hm->entries[ind].key) == 0)) {
hm->entries[ind].value = value;
hm->entries[ind].key = key;
return 1;
}

ind++;
if (ind >= hm->capacity) {
ind = 0;
}
}

PRINT_WARNING("hashmap full!");
return 0;
}

int hm_remove(HashMap *hm, const char *key) {
uint64_t ind = hash(key) % hm->capacity;

for (int i = 0; i < hm->capacity-1; i++) {
if (hm->entries[ind].key == NULL) {
return 0;
} else if (strcmp(key, hm->entries[ind].key) == 0) {
// It just NULL's out the value--this can be written again.
// that makes hm_lookup return the same thing for a removed
// item as a non-existent one, though, which is the goal
hm->entries[ind].value = NULL;
return 1;
}

ind++;
if (ind >= hm->capacity) {
ind = 0;
}
}

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

#include <stdint.h>

typedef struct node {
void* value;
// the key is NULL if the node is empty
const char* key;
} HashNode;

typedef struct {
int stored; // # of items in hashtable
int capacity; // # of entries that can fit in the table
HashNode* entries;// collection of entries
} HashMap;

// initialize. returns pointer to the HashMap
HashMap* hm_init(int num_buckets);

// free memory
void hm_free(HashMap *hm);

// find element
void* hm_lookup(HashMap *hm, const char* key);

// add element. VERY IMPORTANTLY, the hashtable does *not* copy the string
// you give it as a key. If you de-allocate that string, the hashtable gets
// a bunch of undefined behavior (like seg-faulting at free)
int hm_set(HashMap *hm, const char *key, void *value);

// remove element. DOES NOT DEALLOCATE THE SPACE FOR THE REMOVED ELEMENTS
int hm_remove(HashMap *hm, const char* key);

// hashes the keys
uint64_t hash(const char* key);
2 changes: 1 addition & 1 deletion src/util/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <stdlib.h> // memory

#include <util/out.h>
#include "../util/out.h"

typedef struct ListBlock {
void* * array;
Expand Down
13 changes: 8 additions & 5 deletions src/util/list.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@ typedef

// Make and destroy lists.
struct List* create_list(int blocksize);
int destroy_list(List* l);
int destroy_list(List *l);

// Access the n-th element of a list.
void* lget_element(List* l, int index);
void* lget_element(List *l, int index);

// Add new element. Returns success (0) or failure (-1).
int ladd_element(List* l, void* element);
int ladd_element(List *l, void *element);

// Set n-th element.
int lset_element(List* l, int index, void* value);
int lset_element(List *l, int index, void *value);

// Iterate over elements. This takes a highly customizable approach. We pass in
// a function which takes a void* pointer and returns an int, and we pass this
// function over every void* element in the list. We return the sum of all
// return values thus accumulated.
int literate(List* l, int (*fn)(void*));
int literate(List *l, int (*fn)(void*));
Loading
Loading