diff options
Diffstat (limited to 'src/cache.c')
| -rw-r--r-- | src/cache.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/cache.c b/src/cache.c new file mode 100644 index 0000000..1ffb31c --- /dev/null +++ b/src/cache.c @@ -0,0 +1,95 @@ +#include <uthash.h> + +#include "compiler.h" +#include "utils.h" +#include "cache.h" + +struct cache_entry { + char *key; + void *value; + UT_hash_handle hh; +}; + +struct cache { + cache_getter_t getter; + cache_free_t free; + void *user_data; + struct cache_entry *entries; +}; + +void cache_set(struct cache *c, const char *key, void *data) { + struct cache_entry *e = NULL; + HASH_FIND_STR(c->entries, key, e); + CHECK(!e); + + e = ccalloc(1, struct cache_entry); + e->key = strdup(key); + e->value = data; + HASH_ADD_STR(c->entries, key, e); +} + +void *cache_get(struct cache *c, const char *key, int *err) { + struct cache_entry *e; + HASH_FIND_STR(c->entries, key, e); + if (e) { + return e->value; + } + + int tmperr; + if (!err) { + err = &tmperr; + } + + *err = 0; + e = ccalloc(1, struct cache_entry); + e->key = strdup(key); + e->value = c->getter(c->user_data, key, err); + if (*err) { + free(e->key); + free(e); + return NULL; + } + + HASH_ADD_STR(c->entries, key, e); + return e->value; +} + +static inline void _cache_invalidate(struct cache *c, struct cache_entry *e) { + if (c->free) { + c->free(c->user_data, e->value); + } + free(e->key); + HASH_DEL(c->entries, e); + free(e); +} + +void cache_invalidate(struct cache *c, const char *key) { + struct cache_entry *e; + HASH_FIND_STR(c->entries, key, e); + + if (e) { + _cache_invalidate(c, e); + } +} + +void cache_invalidate_all(struct cache *c) { + struct cache_entry *e, *tmpe; + HASH_ITER(hh, c->entries, e, tmpe) { + _cache_invalidate(c, e); + } +} + +void *cache_free(struct cache *c) { + void *ret = c->user_data; + cache_invalidate_all(c); + free(c); + return ret; +} + +struct cache *new_cache(void *ud, cache_getter_t getter, cache_free_t f) { + auto c = ccalloc(1, struct cache); + c->user_data = ud; + c->getter = getter; + c->free = f; + return c; +} |