#ifndef INCLUDED_HASHTABLE_H #define INCLUDED_HASHTABLE_H #include "base.h" struct HashTableBucket { uintptr_t hash; LispVal *key; LispVal *value; }; DEFOBJTYPE(HashTable, HASH_TABLE, HASH_TABLE_P, { LispVal *hash_fn; LispVal *eq_fn; struct HashTableBucket *data; size_t size; size_t count; struct HashTableBucket *cache_bucket; }); // makes no effort to ensure its values are not GCed!!! LispVal *make_hash_table_no_gc(LispVal *hash_fn, LispVal *eq_fn); void release_hash_table_no_gc(LispVal *val); DECLARE_FUNCTION(make_hash_table, (LispVal * hash_fn, LispVal *eq_fn)); DECLARE_FUNCTION(gethash, (LispVal * ht, LispVal *key, LispVal *def)); DECLARE_FUNCTION(puthash, (LispVal * ht, LispVal *key, LispVal *val)); DECLARE_FUNCTION(remhash, (LispVal * ht, LispVal *key)); DECLARE_FUNCTION(hash_table_count, (LispVal * ht)); static ALWAYS_INLINE size_t HASH_TABLE_COUNT(LispVal *ht) { assert(HASH_TABLE_P(ht)); return ((LispHashTable *) ht)->count; } static ALWAYS_INLINE bool HT_BUCKET_EMPTY_P(struct HashTableBucket *b) { return !b->key; } static ALWAYS_INLINE LispVal *HASH_KEY(LispVal *ht, size_t i) { assert(HASH_TABLE_P(ht)); return ((LispHashTable *) ht)->data[i].key; } static ALWAYS_INLINE LispVal *HASH_VALUE(LispVal *ht, size_t i) { assert(HASH_TABLE_P(ht)); return ((LispHashTable *) ht)->data[i].value; } #define HT_FOREACH_INDEX(ht, i) \ for (size_t i = 0; i < ((LispHashTable *) ht)->size; ++i) \ if (!HT_BUCKET_EMPTY_P(&((LispHashTable *) ht)->data[i])) #endif