forked from FT-Labs/picom
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cache uses an invasive design now, a la list.h and uthash. This get rid of the ugly integer to pointer cache, and gives us freedom of what we can put into the cache. Signed-off-by: Yuxuan Shui <[email protected]>
- Loading branch information
Showing
6 changed files
with
122 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,94 +1,56 @@ | ||
#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; | ||
}; | ||
|
||
static inline struct cache_entry *cache_get_entry(struct cache *c, const char *key) { | ||
struct cache_entry *e; | ||
struct cache_handle *cache_get(struct cache *c, const char *key) { | ||
struct cache_handle *e; | ||
HASH_FIND_STR(c->entries, key, e); | ||
return e; | ||
} | ||
|
||
void *cache_get(struct cache *c, const char *key) { | ||
struct cache_entry *e = cache_get_entry(c, key); | ||
return e ? e->value : NULL; | ||
} | ||
|
||
void *cache_get_or_fetch(struct cache *c, const char *key, int *err) { | ||
struct cache_entry *e = cache_get_entry(c, key); | ||
if (e) { | ||
return e->value; | ||
int cache_get_or_fetch(struct cache *c, const char *key, struct cache_handle **value) { | ||
*value = cache_get(c, key); | ||
if (*value) { | ||
return 0; | ||
} | ||
|
||
int tmperr; | ||
if (!err) { | ||
err = &tmperr; | ||
int err = c->getter(c, key, value); | ||
assert(err <= 0); | ||
if (err < 0) { | ||
return err; | ||
} | ||
(*value)->key = strdup(key); | ||
|
||
*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; | ||
HASH_ADD_STR(c->entries, key, *value); | ||
return 1; | ||
} | ||
|
||
static inline void cache_invalidate_impl(struct cache *c, struct cache_entry *e) { | ||
if (c->free) { | ||
c->free(c->user_data, e->value); | ||
} | ||
static inline void | ||
cache_invalidate_impl(struct cache *c, struct cache_handle *e, cache_free_t free_fn) { | ||
free(e->key); | ||
HASH_DEL(c->entries, e); | ||
free(e); | ||
if (free_fn) { | ||
free_fn(c, e); | ||
} | ||
} | ||
|
||
void cache_invalidate(struct cache *c, const char *key) { | ||
struct cache_entry *e; | ||
void cache_invalidate(struct cache *c, const char *key, cache_free_t free_fn) { | ||
struct cache_handle *e; | ||
HASH_FIND_STR(c->entries, key, e); | ||
|
||
if (e) { | ||
cache_invalidate_impl(c, e); | ||
cache_invalidate_impl(c, e, free_fn); | ||
} | ||
} | ||
|
||
void cache_invalidate_all(struct cache *c) { | ||
struct cache_entry *e, *tmpe; | ||
void cache_invalidate_all(struct cache *c, cache_free_t free_fn) { | ||
struct cache_handle *e, *tmpe; | ||
HASH_ITER(hh, c->entries, e, tmpe) { | ||
cache_invalidate_impl(c, e); | ||
cache_invalidate_impl(c, e, free_fn); | ||
} | ||
} | ||
|
||
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; | ||
void cache_init(struct cache *cache, cache_getter_t getter) { | ||
cache->getter = getter; | ||
cache->entries = NULL; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,46 @@ | ||
#pragma once | ||
|
||
#include <uthash.h> | ||
#include "utils.h" | ||
|
||
#define cache_entry(ptr, type, member) container_of(ptr, type, member) | ||
|
||
struct cache; | ||
struct cache_handle; | ||
|
||
/// User-provided function to fetch a value for the cache, when it's not present. | ||
/// Should return 0 if the value is fetched successfully, and a negative number if the | ||
/// value cannot be fetched. Getter doesn't need to initialize fields of `struct | ||
/// cache_handle`. | ||
typedef int (*cache_getter_t)(struct cache *, const char *key, struct cache_handle **value); | ||
typedef void (*cache_free_t)(struct cache *, struct cache_handle *value); | ||
|
||
typedef void *(*cache_getter_t)(void *user_data, const char *key, int *err); | ||
typedef void (*cache_free_t)(void *user_data, void *data); | ||
struct cache { | ||
cache_getter_t getter; | ||
struct cache_handle *entries; | ||
}; | ||
|
||
/// Create a cache with `getter`, and a free function `f` which is used to free the cache | ||
/// value when they are invalidated. | ||
/// | ||
/// `user_data` will be passed to `getter` and `f` when they are called. | ||
struct cache *new_cache(void *user_data, cache_getter_t getter, cache_free_t f); | ||
struct cache_handle { | ||
char *key; | ||
UT_hash_handle hh; | ||
}; | ||
|
||
/// Initialize a cache with `getter` | ||
void cache_init(struct cache *cache, cache_getter_t getter); | ||
|
||
/// Get a value from the cache. If the value doesn't present in the cache yet, the | ||
/// getter will be called, and the returned value will be stored into the cache. | ||
void *cache_get_or_fetch(struct cache *, const char *key, int *err); | ||
/// Returns 0 if the value is already present in the cache, 1 if the value is fetched | ||
/// successfully, and a negative number if the value cannot be fetched. | ||
int cache_get_or_fetch(struct cache *, const char *key, struct cache_handle **value); | ||
|
||
/// Get a value from the cache. If the value doesn't present in the cache, NULL will be | ||
/// returned. | ||
void *cache_get(struct cache *, const char *key); | ||
struct cache_handle *cache_get(struct cache *, const char *key); | ||
|
||
/// Invalidate a value in the cache. | ||
void cache_invalidate(struct cache *, const char *key); | ||
|
||
/// Invalidate all values in the cache. | ||
void cache_invalidate_all(struct cache *); | ||
void cache_invalidate(struct cache *, const char *key, cache_free_t free_fn); | ||
|
||
/// Invalidate all values in the cache and free it. Returns the user data passed to | ||
/// `new_cache` | ||
void *cache_free(struct cache *); | ||
/// Invalidate all values in the cache. After this call, `struct cache` holds no allocated | ||
/// memory, and can be discarded. | ||
void cache_invalidate_all(struct cache *, cache_free_t free_fn); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters