2012-05-17 15:51:19 +02:00
|
|
|
#include "internal.h"
|
|
|
|
|
#include "hammer.h"
|
|
|
|
|
#include "allocator.h"
|
|
|
|
|
#include <assert.h>
|
2012-11-14 14:05:25 -05:00
|
|
|
#include <stdlib.h>
|
2012-10-08 21:12:56 +02:00
|
|
|
#include <string.h>
|
2012-05-17 15:51:19 +02:00
|
|
|
// {{{ counted arrays
|
|
|
|
|
|
|
|
|
|
|
2012-05-26 14:06:52 +02:00
|
|
|
HCountedArray *h_carray_new_sized(HArena * arena, size_t size) {
|
|
|
|
|
HCountedArray *ret = h_arena_malloc(arena, sizeof(HCountedArray));
|
2012-05-17 15:51:19 +02:00
|
|
|
assert(size > 0);
|
|
|
|
|
ret->used = 0;
|
|
|
|
|
ret->capacity = size;
|
|
|
|
|
ret->arena = arena;
|
2012-05-26 14:06:52 +02:00
|
|
|
ret->elements = h_arena_malloc(arena, sizeof(void*) * size);
|
2012-05-17 15:51:19 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
2012-10-08 18:16:18 +02:00
|
|
|
|
2012-05-26 14:06:52 +02:00
|
|
|
HCountedArray *h_carray_new(HArena * arena) {
|
|
|
|
|
return h_carray_new_sized(arena, 4);
|
2012-05-17 15:51:19 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-26 14:06:52 +02:00
|
|
|
void h_carray_append(HCountedArray *array, void* item) {
|
2012-05-17 15:51:19 +02:00
|
|
|
if (array->used >= array->capacity) {
|
2012-05-26 14:06:52 +02:00
|
|
|
HParsedToken **elements = h_arena_malloc(array->arena, (array->capacity *= 2) * sizeof(HCountedArray*));
|
2012-05-17 15:51:19 +02:00
|
|
|
for (size_t i = 0; i < array->used; i++)
|
|
|
|
|
elements[i] = array->elements[i];
|
|
|
|
|
for (size_t i = array->used; i < array->capacity; i++)
|
|
|
|
|
elements[i] = 0;
|
|
|
|
|
array->elements = elements;
|
|
|
|
|
}
|
|
|
|
|
array->elements[array->used++] = item;
|
|
|
|
|
}
|
2012-10-08 17:11:47 +02:00
|
|
|
|
|
|
|
|
// HSlist
|
|
|
|
|
HSlist* h_slist_new(HArena *arena) {
|
|
|
|
|
HSlist *ret = h_arena_malloc(arena, sizeof(HSlist));
|
|
|
|
|
ret->head = NULL;
|
|
|
|
|
ret->arena = arena;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-10 00:40:19 +01:00
|
|
|
HSlist* h_slist_copy(HSlist *slist) {
|
|
|
|
|
HSlist *ret = h_slist_new(slist->arena);
|
|
|
|
|
HSlistNode *head = slist->head;
|
|
|
|
|
HSlistNode *tail;
|
|
|
|
|
if (head != NULL) {
|
|
|
|
|
h_slist_push(ret, head->elem);
|
|
|
|
|
tail = ret->head;
|
|
|
|
|
head = head->next;
|
|
|
|
|
}
|
|
|
|
|
while (head != NULL) {
|
|
|
|
|
// append head item to tail in a new node
|
|
|
|
|
HSlistNode *node = h_arena_malloc(slist->arena, sizeof(HSlistNode));
|
|
|
|
|
node->elem = head->elem;
|
|
|
|
|
node->next = NULL;
|
|
|
|
|
tail = tail->next = node;
|
|
|
|
|
head = head->next;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-08 17:11:47 +02:00
|
|
|
void* h_slist_pop(HSlist *slist) {
|
|
|
|
|
HSlistNode *head = slist->head;
|
|
|
|
|
if (!head)
|
|
|
|
|
return NULL;
|
|
|
|
|
void* ret = head->elem;
|
|
|
|
|
slist->head = head->next;
|
|
|
|
|
h_arena_free(slist->arena, head);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void h_slist_push(HSlist *slist, void* item) {
|
|
|
|
|
HSlistNode *hnode = h_arena_malloc(slist->arena, sizeof(HSlistNode));
|
|
|
|
|
hnode->elem = item;
|
|
|
|
|
hnode->next = slist->head;
|
|
|
|
|
// write memory barrier here.
|
|
|
|
|
slist->head = hnode;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-08 18:16:18 +02:00
|
|
|
bool h_slist_find(HSlist *slist, const void* item) {
|
|
|
|
|
assert (item != NULL);
|
|
|
|
|
HSlistNode *head = slist->head;
|
|
|
|
|
while (head != NULL) {
|
|
|
|
|
if (head->elem == item)
|
|
|
|
|
return true;
|
|
|
|
|
head = head->next;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HSlist* h_slist_remove_all(HSlist *slist, const void* item) {
|
|
|
|
|
assert (item != NULL);
|
|
|
|
|
HSlistNode *node = slist->head;
|
|
|
|
|
HSlistNode *prev = NULL;
|
|
|
|
|
while (node != NULL) {
|
|
|
|
|
if (node->elem == item) {
|
|
|
|
|
HSlistNode *next = node->next;
|
|
|
|
|
if (prev)
|
|
|
|
|
prev->next = next;
|
|
|
|
|
else
|
|
|
|
|
slist->head = next;
|
|
|
|
|
// FIXME free the removed node! this leaks.
|
|
|
|
|
node = next;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
prev = node;
|
|
|
|
|
node = prev->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return slist;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-08 17:11:47 +02:00
|
|
|
void h_slist_free(HSlist *slist) {
|
|
|
|
|
while (slist->head != NULL)
|
|
|
|
|
h_slist_pop(slist);
|
|
|
|
|
h_arena_free(slist->arena, slist);
|
|
|
|
|
}
|
2012-10-08 18:16:18 +02:00
|
|
|
|
2012-10-08 21:12:56 +02:00
|
|
|
HHashTable* h_hashtable_new(HArena *arena, HEqualFunc equalFunc, HHashFunc hashFunc) {
|
2012-10-08 22:06:33 +02:00
|
|
|
HHashTable *ht = h_arena_malloc(arena, sizeof(HHashTable));
|
2012-10-08 19:20:36 +02:00
|
|
|
ht->hashFunc = hashFunc;
|
|
|
|
|
ht->equalFunc = equalFunc;
|
|
|
|
|
ht->capacity = 64; // to start; should be tuned later...
|
|
|
|
|
ht->used = 0;
|
2012-10-08 22:06:33 +02:00
|
|
|
ht->arena = arena;
|
2012-10-08 19:20:36 +02:00
|
|
|
ht->contents = h_arena_malloc(arena, sizeof(HHashTableEntry) * ht->capacity);
|
2012-10-08 22:06:33 +02:00
|
|
|
for (size_t i = 0; i < ht->capacity; i++) {
|
|
|
|
|
ht->contents[i].key = NULL;
|
|
|
|
|
ht->contents[i].value = NULL;
|
|
|
|
|
ht->contents[i].next = NULL;
|
|
|
|
|
ht->contents[i].hashval = 0;
|
|
|
|
|
}
|
|
|
|
|
//memset(ht->contents, 0, sizeof(HHashTableEntry) * ht->capacity);
|
2012-10-08 19:20:36 +02:00
|
|
|
return ht;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-08 17:01:23 +02:00
|
|
|
void* h_hashtable_get(const HHashTable* ht, const void* key) {
|
2012-10-08 19:20:36 +02:00
|
|
|
HHashValue hashval = ht->hashFunc(key);
|
|
|
|
|
#ifdef CONSISTENCY_CHECK
|
|
|
|
|
assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-10-08 22:06:33 +02:00
|
|
|
HHashTableEntry *hte = NULL;
|
|
|
|
|
for (hte = &ht->contents[hashval & (ht->capacity - 1)];
|
2012-10-08 19:20:36 +02:00
|
|
|
hte != NULL;
|
|
|
|
|
hte = hte->next) {
|
|
|
|
|
if (hte->hashval != hashval)
|
|
|
|
|
continue;
|
|
|
|
|
if (ht->equalFunc(key, hte->key))
|
|
|
|
|
return hte->value;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-30 17:44:54 +02:00
|
|
|
void h_hashtable_put(HHashTable* ht, const void* key, void* value) {
|
2012-10-08 19:20:36 +02:00
|
|
|
// # Start with a rebalancing
|
2012-10-08 21:12:56 +02:00
|
|
|
//h_hashtable_ensure_capacity(ht, ht->used + 1);
|
2012-10-08 19:20:36 +02:00
|
|
|
|
|
|
|
|
HHashValue hashval = ht->hashFunc(key);
|
|
|
|
|
#ifdef CONSISTENCY_CHECK
|
|
|
|
|
assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-10-08 21:12:56 +02:00
|
|
|
HHashTableEntry *hte = &ht->contents[hashval & (ht->capacity - 1)];
|
2012-10-08 19:20:36 +02:00
|
|
|
if (hte->key != NULL) {
|
2013-05-05 22:12:05 +02:00
|
|
|
for(;;) {
|
|
|
|
|
// check each link, stay on last if not found
|
2012-10-08 19:20:36 +02:00
|
|
|
if (hte->hashval == hashval && ht->equalFunc(key, hte->key))
|
|
|
|
|
goto insert_here;
|
2013-05-05 22:12:05 +02:00
|
|
|
if (hte->next == NULL)
|
|
|
|
|
break;
|
|
|
|
|
hte = hte->next;
|
|
|
|
|
}
|
2012-10-08 19:20:36 +02:00
|
|
|
// Add a new link...
|
|
|
|
|
assert (hte->next == NULL);
|
|
|
|
|
hte->next = h_arena_malloc(ht->arena, sizeof(HHashTableEntry));
|
|
|
|
|
hte = hte->next;
|
|
|
|
|
hte->next = NULL;
|
2012-10-08 22:06:33 +02:00
|
|
|
ht->used++;
|
|
|
|
|
} else
|
|
|
|
|
ht->used++;
|
2012-10-08 19:20:36 +02:00
|
|
|
|
|
|
|
|
insert_here:
|
|
|
|
|
hte->key = key;
|
|
|
|
|
hte->value = value;
|
|
|
|
|
hte->hashval = hashval;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-30 17:45:33 +02:00
|
|
|
void h_hashtable_update(HHashTable *dst, const HHashTable *src) {
|
2013-04-30 17:49:07 +02:00
|
|
|
size_t i;
|
|
|
|
|
HHashTableEntry *hte;
|
|
|
|
|
for(i=0; i < src->capacity; i++) {
|
|
|
|
|
for(hte = &src->contents[i]; hte; hte = hte->next) {
|
2013-05-05 19:32:23 +02:00
|
|
|
if(hte->key == NULL)
|
|
|
|
|
continue;
|
2013-04-30 17:49:07 +02:00
|
|
|
h_hashtable_put(dst, hte->key, hte->value);
|
2013-04-30 17:45:33 +02:00
|
|
|
}
|
2013-04-30 17:49:07 +02:00
|
|
|
}
|
2013-04-30 17:45:33 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-24 22:29:33 +02:00
|
|
|
void h_hashtable_merge(void *(*combine)(void *v1, const void *v2),
|
2013-05-22 21:57:46 +02:00
|
|
|
HHashTable *dst, const HHashTable *src) {
|
|
|
|
|
size_t i;
|
|
|
|
|
HHashTableEntry *hte;
|
|
|
|
|
for(i=0; i < src->capacity; i++) {
|
|
|
|
|
for(hte = &src->contents[i]; hte; hte = hte->next) {
|
|
|
|
|
if(hte->key == NULL)
|
|
|
|
|
continue;
|
2013-05-24 22:29:33 +02:00
|
|
|
void *dstvalue = h_hashtable_get(dst, hte->key);
|
|
|
|
|
void *srcvalue = hte->value;
|
|
|
|
|
h_hashtable_put(dst, hte->key, combine(dstvalue, srcvalue));
|
2013-05-22 21:57:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-08 17:01:23 +02:00
|
|
|
int h_hashtable_present(const HHashTable* ht, const void* key) {
|
2012-10-08 19:20:36 +02:00
|
|
|
HHashValue hashval = ht->hashFunc(key);
|
|
|
|
|
#ifdef CONSISTENCY_CHECK
|
|
|
|
|
assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (HHashTableEntry *hte = &ht->contents[hashval & (ht->capacity - 1)];
|
|
|
|
|
hte != NULL;
|
|
|
|
|
hte = hte->next) {
|
|
|
|
|
if (hte->hashval != hashval)
|
|
|
|
|
continue;
|
|
|
|
|
if (ht->equalFunc(key, hte->key))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2013-04-30 17:44:54 +02:00
|
|
|
void h_hashtable_del(HHashTable* ht, const void* key) {
|
2012-10-08 19:20:36 +02:00
|
|
|
HHashValue hashval = ht->hashFunc(key);
|
|
|
|
|
#ifdef CONSISTENCY_CHECK
|
|
|
|
|
assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (HHashTableEntry *hte = &ht->contents[hashval & (ht->capacity - 1)];
|
|
|
|
|
hte != NULL;
|
|
|
|
|
hte = hte->next) {
|
|
|
|
|
if (hte->hashval != hashval)
|
|
|
|
|
continue;
|
|
|
|
|
if (ht->equalFunc(key, hte->key)) {
|
|
|
|
|
// FIXME: Leaks keys and values.
|
|
|
|
|
HHashTableEntry* hten = hte->next;
|
|
|
|
|
if (hten != NULL) {
|
|
|
|
|
*hte = *hten;
|
|
|
|
|
h_arena_free(ht->arena, hten);
|
|
|
|
|
} else {
|
|
|
|
|
hte->key = hte->value = NULL;
|
|
|
|
|
hte->hashval = 0;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void h_hashtable_free(HHashTable* ht) {
|
2012-10-08 21:12:56 +02:00
|
|
|
for (size_t i = 0; i < ht->capacity; i++) {
|
2012-10-08 19:20:36 +02:00
|
|
|
HHashTableEntry *hten, *hte = &ht->contents[i];
|
|
|
|
|
// FIXME: Free key and value
|
|
|
|
|
hte = hte->next;
|
|
|
|
|
while (hte != NULL) {
|
|
|
|
|
// FIXME: leaks keys and values.
|
|
|
|
|
hten = hte->next;
|
|
|
|
|
h_arena_free(ht->arena, hte);
|
|
|
|
|
hte = hten;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
h_arena_free(ht->arena, ht->contents);
|
|
|
|
|
}
|
2012-10-08 19:21:56 +02:00
|
|
|
|
2013-05-08 15:54:29 +02:00
|
|
|
bool h_eq_ptr(const void *p, const void *q) {
|
|
|
|
|
return (p==q);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HHashValue h_hash_ptr(const void *p) {
|
2013-05-22 20:38:36 +02:00
|
|
|
// XXX just djbhash it
|
2013-05-08 16:07:51 +02:00
|
|
|
return (uintptr_t)p >> 4;
|
2013-05-08 15:54:29 +02:00
|
|
|
}
|