aboutsummaryrefslogtreecommitdiff
path: root/src/cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cache.c')
-rw-r--r--src/cache.c95
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;
+}