mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 02:32:06 +00:00
Rewrite RGBLINK entirely
The goal was to improve readability, but along the way a few things were gained. - Sorted sym and map files - Infrastructure for supporting multiple .o versions - Valgrind-proof, as far as my testing goes anyways - Improved verbosity messages - Added error checking - Performance improvements, see end of commit message The readability improvement was spurred while trying to make sense of the old code while trying to implement features such as sorted sym and map files. I also did my best to remove hardcoded logic, such that modifications should be doable; for example, "RAM loading" sections, which are linked against a different location than the one they're stored at. Some work remains to be done, see the "TODO:" and "FIXME:" comments. Further, while regression tests pass, this new linker should be tested on different codebases (ideally while instrumented with `make develop` and under valgrind). The few errors spotted in the man pages (alignment) need to be corrected. Finally, documentation comments need to be written, I have written a lot of them but not all. This also provides a significant performance boost (benchmarked with a 51994-symbol project): Current master RGBLINK: 2.02user 0.03system 0:02.06elapsed 99%CPU (0avgtext+0avgdata 84336maxresident)k 0inputs+11584outputs (0major+20729minor)pagefaults 0swaps Rewritten RGBLINK: 0.19user 0.06system 0:00.63elapsed 40%CPU (0avgtext+0avgdata 32460maxresident)k 23784inputs+11576outputs (0major+7672minor)pagefaults 0swaps
This commit is contained in:
118
src/hashmap.c
Normal file
118
src/hashmap.c
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "extern/err.h"
|
||||
|
||||
/*
|
||||
* The lower half of the hash is used to index the "master" table,
|
||||
* the upper half is used to help resolve collisions more quickly
|
||||
*/
|
||||
#define UINT_BITS_(NB_BITS) uint##NB_BITS##_t
|
||||
#define UINT_BITS(NB_BITS) UINT_BITS_(NB_BITS)
|
||||
typedef UINT_BITS(HASH_NB_BITS) HashType;
|
||||
typedef UINT_BITS(HALF_HASH_NB_BITS) HalfHashType;
|
||||
|
||||
struct HashMapEntry {
|
||||
HalfHashType hash;
|
||||
char const *key;
|
||||
void *content;
|
||||
struct HashMapEntry *next;
|
||||
};
|
||||
|
||||
#define FNV_OFFSET_BASIS 0x811c9dc5
|
||||
#define FNV_PRIME 16777619
|
||||
|
||||
/* FNV-1a hash */
|
||||
static HashType hash(char const *str)
|
||||
{
|
||||
HashType hash = FNV_OFFSET_BASIS;
|
||||
|
||||
while (*str) {
|
||||
hash ^= (uint8_t)*str++;
|
||||
hash *= FNV_PRIME;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool hash_AddElement(HashMap map, char const *key, void *element)
|
||||
{
|
||||
HashType hashedKey = hash(key);
|
||||
HalfHashType index = hashedKey;
|
||||
struct HashMapEntry *newEntry = malloc(sizeof(*newEntry));
|
||||
|
||||
if (!newEntry)
|
||||
err(1, "%s: Failed to allocate new entry", __func__);
|
||||
|
||||
newEntry->hash = hashedKey >> HALF_HASH_NB_BITS;
|
||||
newEntry->key = key;
|
||||
newEntry->content = element;
|
||||
newEntry->next = map[index];
|
||||
map[index] = newEntry;
|
||||
|
||||
return newEntry->next != NULL;
|
||||
}
|
||||
|
||||
bool hash_DeleteElement(HashMap map, char const *key)
|
||||
{
|
||||
HashType hashedKey = hash(key);
|
||||
struct HashMapEntry **ptr = &map[(HalfHashType)hashedKey];
|
||||
|
||||
while (*ptr) {
|
||||
if (hashedKey >> HALF_HASH_NB_BITS == (*ptr)->hash
|
||||
&& !strcmp((*ptr)->key, key)) {
|
||||
struct HashMapEntry *next = (*ptr)->next;
|
||||
|
||||
free(*ptr);
|
||||
*ptr = next;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void *hash_GetElement(HashMap const map, char const *key)
|
||||
{
|
||||
HashType hashedKey = hash(key);
|
||||
struct HashMapEntry *ptr = map[(HalfHashType)hashedKey];
|
||||
|
||||
while (ptr) {
|
||||
if (hashedKey >> HALF_HASH_NB_BITS == ptr->hash
|
||||
&& !strcmp(ptr->key, key)) {
|
||||
return ptr->content;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg)
|
||||
{
|
||||
for (size_t i = 0; i < HASHMAP_NB_BUCKETS; i++) {
|
||||
struct HashMapEntry *ptr = map[i];
|
||||
|
||||
while (ptr) {
|
||||
func(ptr->content, arg);
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hash_EmptyMap(HashMap map)
|
||||
{
|
||||
for (size_t i = 0; i < HASHMAP_NB_BUCKETS; i++) {
|
||||
struct HashMapEntry *ptr = map[i];
|
||||
|
||||
while (ptr) {
|
||||
struct HashMapEntry *next = ptr->next;
|
||||
|
||||
free(ptr);
|
||||
ptr = next;
|
||||
}
|
||||
map[i] = NULL;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user