Change to a different hash table implementation
This commit is contained in:
80
src/lisp.h
80
src/lisp.h
@ -1,6 +1,7 @@
|
||||
#ifndef INCLUDED_LISP_H
|
||||
#define INCLUDED_LISP_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <refcount/refcount.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
@ -125,23 +126,20 @@ typedef struct {
|
||||
LispVal *lexenv;
|
||||
} LispFunction;
|
||||
|
||||
struct HashtableBucket {
|
||||
struct HashtableBucket *next;
|
||||
#define LISP_HASHTABLE_INITIAL_SIZE 32
|
||||
#define LISP_HASHTABLE_GROWTH_FACTOR 2
|
||||
|
||||
struct HashtableEntry {
|
||||
uint64_t hash;
|
||||
LispVal *key;
|
||||
LispVal *value;
|
||||
};
|
||||
|
||||
#define LISP_HASHTABLE_INITIAL_SIZE 32
|
||||
#define LISP_HASHTABLE_GROWTH_FACTOR 2
|
||||
#define LISP_HASHTABLE_GROWTH_THRESHOLD 0.75f
|
||||
#define LISP_HASHTABLE_SHRINK_THRESHOLD 0.25f
|
||||
|
||||
typedef struct {
|
||||
LISP_OBJECT_HEADER;
|
||||
|
||||
struct HashtableBucket **data;
|
||||
size_t table_size;
|
||||
size_t table_size; // number of buckets
|
||||
struct HashtableEntry *key_vals; // array of key, hash, value
|
||||
size_t count;
|
||||
LispVal *eq_fn;
|
||||
LispVal *hash_fn;
|
||||
@ -306,11 +304,13 @@ inline static bool NUMBERP(LispVal *v) {
|
||||
refcount_init_static(Q##sym); \
|
||||
refcount_init_static(((LispSymbol *) Q##sym)->name); \
|
||||
}
|
||||
#define REGISTER_SYMBOL_INTO(sym, pkg) \
|
||||
REGISTER_SYMBOL_NOINTERN(sym) \
|
||||
#define REGISTER_DO_INTERN(sym, pkg) \
|
||||
((LispSymbol *) Q##sym)->package = refcount_ref(pkg); \
|
||||
puthash(((LispPackage *) pkg)->obarray, \
|
||||
LISPVAL(((LispSymbol *) Q##sym)->name), Q##sym);
|
||||
#define REGISTER_SYMBOL_INTO(sym, pkg) \
|
||||
REGISTER_SYMBOL_NOINTERN(sym) \
|
||||
REGISTER_DO_INTERN(sym, pkg)
|
||||
#define REGISTER_SYMBOL(sym) REGISTER_SYMBOL_INTO(sym, system_package)
|
||||
#define REGISTER_STATIC_FUNCTION(name, args, docstr) \
|
||||
REGISTER_SYMBOL_NOINTERN(name); \
|
||||
@ -333,22 +333,11 @@ inline static bool NUMBERP(LispVal *v) {
|
||||
// ###############
|
||||
// # Loop macros #
|
||||
// ###############
|
||||
#define HASHTABLE_FOREACH(key_var, val_var, table) \
|
||||
for (struct { \
|
||||
LispHashtable *ht; \
|
||||
size_t i; \
|
||||
} __l = {.ht = (void *) table, .i = 0}; \
|
||||
__l.i < __l.ht->table_size; ++__l.i) \
|
||||
for (LispVal *__b = (void *) __l.ht->data[__l.i], \
|
||||
*key_var = __b ? ((struct HashtableBucket *) __b)->key \
|
||||
: NULL, \
|
||||
*val_var = __b ? ((struct HashtableBucket *) __b)->value \
|
||||
: NULL; \
|
||||
__b; __b = (void *) ((struct HashtableBucket *) __b)->next, \
|
||||
key_var = __b ? ((struct HashtableBucket *) __b)->key \
|
||||
: NULL, \
|
||||
val_var = __b ? ((struct HashtableBucket *) __b)->value \
|
||||
: NULL)
|
||||
#define HT_FOREACH_VALID_INDEX(table, i_var) \
|
||||
for (size_t i_var = 0; i_var < ((LispHashtable *) (table))->table_size; \
|
||||
++i_var) \
|
||||
if (!HASH_SLOT_UNSET_P((table), i_var))
|
||||
|
||||
#define FOREACH(var, list) \
|
||||
for (LispVal *__foreach_cur = list, *var = HEAD(list); \
|
||||
!NILP(__foreach_cur); \
|
||||
@ -362,6 +351,7 @@ inline static bool NUMBERP(LispVal *v) {
|
||||
#define GC_EVERY_N_BYTES 1024 * 80
|
||||
void *lisp_malloc(size_t size);
|
||||
void *lisp_realloc(void *old_ptr, size_t size);
|
||||
void *lisp_malloc0(size_t size);
|
||||
#define lisp_free free
|
||||
|
||||
void garbage_collect(void);
|
||||
@ -528,7 +518,7 @@ LispVal *intern(const char *name, size_t length, bool take, LispVal *package,
|
||||
bool included_too);
|
||||
|
||||
// #######################
|
||||
// # Hashtable Functions #
|
||||
// # Hash Table Functions #
|
||||
// #######################
|
||||
DECLARE_FUNCTION(hashtablep, (LispVal * val));
|
||||
DECLARE_FUNCTION(make_hashtable, (LispVal * hash_fn, LispVal *eq_fn));
|
||||
@ -537,6 +527,11 @@ DECLARE_FUNCTION(hash_table_count, (LispVal * table));
|
||||
DECLARE_FUNCTION(puthash, (LispVal * table, LispVal *key, LispVal *value));
|
||||
DECLARE_FUNCTION(gethash, (LispVal * table, LispVal *key, LispVal *def));
|
||||
DECLARE_FUNCTION(remhash, (LispVal * table, LispVal *key));
|
||||
struct HashtableDataArray {
|
||||
size_t size;
|
||||
struct HashtableEntry *entries;
|
||||
};
|
||||
void free_hash_table_data_array(void *data);
|
||||
|
||||
// Don't ref their return value
|
||||
LispVal *puthash(LispVal *table, LispVal *key, LispVal *value);
|
||||
@ -760,7 +755,8 @@ static inline void push_to_lexenv(LispVal **lexenv, LispVal *key,
|
||||
refcount_unref(old);
|
||||
}
|
||||
|
||||
// These are like the internal functions, but they don't ref their return value
|
||||
// These are like the internal functions, but they don't ref their
|
||||
// return value
|
||||
static inline LispVal *HEAD(LispVal *list) {
|
||||
if (NILP(list)) {
|
||||
return Qnil;
|
||||
@ -788,6 +784,32 @@ static inline LispVal *TAIL_SAFE(LispVal *list) {
|
||||
return ((LispPair *) list)->tail;
|
||||
}
|
||||
|
||||
static inline double HASH_TABLE_LOAD_FACTOR(void *obj) {
|
||||
assert(HASHTABLEP(obj));
|
||||
LispHashtable *table = obj;
|
||||
return (double) table->count / table->table_size;
|
||||
}
|
||||
static inline bool HASH_SLOT_UNSET_P(void *obj, size_t i) {
|
||||
assert(HASHTABLEP(obj));
|
||||
LispHashtable *table = obj;
|
||||
return !table->key_vals[i].key;
|
||||
}
|
||||
static inline LispVal *HASH_KEY(void *obj, size_t i) {
|
||||
assert(HASHTABLEP(obj));
|
||||
LispHashtable *table = obj;
|
||||
return table->key_vals[i].key;
|
||||
}
|
||||
static inline LispVal *HASH_VALUE(void *obj, size_t i) {
|
||||
assert(HASHTABLEP(obj));
|
||||
LispHashtable *table = obj;
|
||||
return table->key_vals[i].value;
|
||||
}
|
||||
static inline uint64_t HASH_HASH(void *obj, size_t i) {
|
||||
assert(HASHTABLEP(obj));
|
||||
LispHashtable *table = obj;
|
||||
return table->key_vals[i].hash;
|
||||
}
|
||||
|
||||
// ###################
|
||||
// # Debug Functions #
|
||||
// ###################
|
||||
|
Reference in New Issue
Block a user