Branch data Line data Source code
1 : : /*
2 : : * This file is part of libplacebo.
3 : : *
4 : : * libplacebo is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * libplacebo is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : * GNU Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #ifndef LIBPLACEBO_CACHE_H_
19 : : #define LIBPLACEBO_CACHE_H_
20 : :
21 : : #include <stddef.h>
22 : : #include <stdint.h>
23 : : #include <stdio.h>
24 : :
25 : : #include <libplacebo/config.h>
26 : : #include <libplacebo/common.h>
27 : : #include <libplacebo/log.h>
28 : :
29 : : PL_API_BEGIN
30 : :
31 : : typedef struct pl_cache_obj {
32 : : // Cache object key. This will uniquely identify this cached object.
33 : : uint64_t key;
34 : :
35 : : // Cache data pointer and length. 0-length cached objects are invalid
36 : : // and will be silently dropped. You can explicitly remove a cached
37 : : // object by overwriting it with a length 0 object.
38 : : void *data;
39 : : size_t size;
40 : :
41 : : // Free callback, to free memory associated with `data`. (Optional)
42 : : // Will be called when the object is either explicitly deleted, culled
43 : : // due to hitting size limits, or on pl_cache_destroy().
44 : : void (*free)(void *data);
45 : : } pl_cache_obj;
46 : :
47 : : struct pl_cache_params {
48 : : // Optional `pl_log` that is used for logging internal events related
49 : : // to the cache, such as insertions, saving and loading.
50 : : pl_log log;
51 : :
52 : : // Size limits. If 0, no limit is imposed.
53 : : //
54 : : // Note: libplacebo will never detect or invalidate stale cache entries, so
55 : : // setting an upper size limit is strongly recommended
56 : : size_t max_object_size;
57 : : size_t max_total_size;
58 : :
59 : : // Optional external callback to call after a cached object is modified
60 : : // (including deletion and (re-)insertion). Note that this is not called on
61 : : // objects which are merely pruned from the cache due to `max_total_size`,
62 : : // so users must rely on some external mechanism to prune stale entries or
63 : : // enforce size limits.
64 : : //
65 : : // Note: `pl_cache_load` does not trigger this callback.
66 : : // Note: Ownership of `obj` does *not* pass to the caller.
67 : : // Note: This function must be thread safe.
68 : : void (*set)(void *priv, pl_cache_obj obj);
69 : :
70 : : // Optional external callback to call on a cache miss. Ownership of the
71 : : // returned object passes to the `pl_cache`. Objects returned by this
72 : : // callback *should* have a valid `free` callback, unless lifetime can be
73 : : // externally managed and guaranteed to outlive the `pl_cache`.
74 : : //
75 : : // Note: This function must be thread safe.
76 : : pl_cache_obj (*get)(void *priv, uint64_t key);
77 : :
78 : : // External context for insert/lookup.
79 : : void *priv;
80 : : };
81 : :
82 : : #define pl_cache_params(...) (&(struct pl_cache_params) { __VA_ARGS__ })
83 : : PL_API extern const struct pl_cache_params pl_cache_default_params;
84 : :
85 : : // Thread-safety: Safe
86 : : //
87 : : // Note: In any context in which `pl_cache` is used, users may also pass NULL
88 : : // to disable caching. In other words, NULL is a valid `pl_cache`.
89 : : typedef const struct pl_cache_t {
90 : : struct pl_cache_params params;
91 : : } *pl_cache;
92 : :
93 : : // Create a new cache. This function will never fail.
94 : : PL_API pl_cache pl_cache_create(const struct pl_cache_params *params);
95 : :
96 : : // Destroy a `pl_cache` object, including all underlying objects.
97 : : PL_API void pl_cache_destroy(pl_cache *cache);
98 : :
99 : : // Explicitly clear all objects in the cache without destroying it. This is
100 : : // similar to `pl_cache_destroy`, but the cache remains valid afterwards.
101 : : //
102 : : // Note: Objects destroyed in this way *not* propagated to the `set` callback.
103 : : PL_API void pl_cache_reset(pl_cache cache);
104 : :
105 : : // Return the current internal number of objects and total size (bytes)
106 : : PL_API int pl_cache_objects(pl_cache cache);
107 : : PL_API size_t pl_cache_size(pl_cache cache);
108 : :
109 : : // Return a lightweight, order-independent hash of all objects currently stored
110 : : // in the `pl_cache`. Can be used to avoid re-saving unmodified caches.
111 : : PL_API uint64_t pl_cache_signature(pl_cache cache);
112 : :
113 : : // --- Cache saving and loading APIs
114 : :
115 : : // Serialize the internal state of a `pl_cache` into an abstract cache
116 : : // object that can be e.g. saved to disk and loaded again later. Returns the
117 : : // number of objects saved.
118 : : //
119 : : // Note: Using `save/load` is largely redundant with using `insert/lookup`
120 : : // callbacks, and the user should decide whether to use the explicit API or the
121 : : // callback-based API.
122 : : PL_API int pl_cache_save_ex(pl_cache cache,
123 : : void (*write)(void *priv, size_t size, const void *ptr),
124 : : void *priv);
125 : :
126 : : // Load the result of a previous `pl_cache_save` call. Any duplicate entries in
127 : : // the `pl_cache` will be overwritten. Returns the number of objects loaded, or
128 : : // a negative number on serious error (e.g. corrupt header)
129 : : //
130 : : // Note: This does not trigger the `update` callback.
131 : : PL_API int pl_cache_load_ex(pl_cache cache,
132 : : bool (*read)(void *priv, size_t size, void *ptr),
133 : : void *priv);
134 : :
135 : : // --- Convenience wrappers around pl_cache_save/load_ex
136 : :
137 : : // Writes data directly to a pointer. Returns the number of bytes that *would*
138 : : // have been written, so this can be used on a size 0 buffer to get the required
139 : : // total size.
140 : : PL_API size_t pl_cache_save(pl_cache cache, uint8_t *data, size_t size);
141 : :
142 : : // Reads data directly from a pointer. This still reads from `data`, so it does
143 : : // not avoid a copy.
144 : : PL_API int pl_cache_load(pl_cache cache, const uint8_t *data, size_t size);
145 : :
146 : : // Writes/loads data to/from a FILE stream at the current position.
147 : : #define pl_cache_save_file(c, file) pl_cache_save_ex(c, pl_write_file_cb, file)
148 : : #define pl_cache_load_file(c, file) pl_cache_load_ex(c, pl_read_file_cb, file)
149 : :
150 : : static inline void pl_write_file_cb(void *priv, size_t size, const void *ptr)
151 : : {
152 : : (void) fwrite(ptr, 1, size, (FILE *) priv);
153 : : }
154 : :
155 : : static inline bool pl_read_file_cb(void *priv, size_t size, void *ptr)
156 : : {
157 : : return fread(ptr, 1, size, (FILE *) priv) == size;
158 : : }
159 : :
160 : : // --- Object modification API. Mostly intended for internal use.
161 : :
162 : : // Insert a new cached object into a `pl_cache`. Returns whether successful.
163 : : // Overwrites any existing cached object with that signature, so this can be
164 : : // used to e.g. delete objects as well (set their size to 0). On success,
165 : : // ownership of `obj` passes to the `pl_cache`.
166 : : //
167 : : // Note: If `object.free` is NULL, this will perform an internal memdup. To
168 : : // bypass this (e.g. when directly adding externally managed memory), you can
169 : : // set the `free` callback to an explicit noop function.
170 : : //
171 : : // Note: `obj->data/free` will be reset to NULL on successful insertion.
172 : : PL_API bool pl_cache_try_set(pl_cache cache, pl_cache_obj *obj);
173 : :
174 : : // Variant of `pl_cache_try_set` that simply frees `obj` on failure.
175 : : PL_API void pl_cache_set(pl_cache cache, pl_cache_obj *obj);
176 : :
177 : : // Looks up `obj->key` in the object cache. If successful, `obj->data` is
178 : : // set to memory owned by the caller, which must be either explicitly
179 : : // re-inserted, or explicitly freed (using obj->free).
180 : : //
181 : : // Note: On failure, `obj->data/size/free` are reset to NULL.
182 : : PL_API bool pl_cache_get(pl_cache cache, pl_cache_obj *obj);
183 : :
184 : : // Run a callback on every object currently stored in `cache`.
185 : : //
186 : : // Note: Running any `pl_cache_*` function on `cache` from this callback is
187 : : // undefined behavior.
188 : : PL_API void pl_cache_iterate(pl_cache cache,
189 : : void (*cb)(void *priv, pl_cache_obj obj),
190 : : void *priv);
191 : :
192 : : // Utility wrapper to free a `pl_cache_obj` if necessary (and sanitize it)
193 : : static inline void pl_cache_obj_free(pl_cache_obj *obj)
194 : : {
195 [ + + - + ]: 961 : if (obj->free)
196 : 3 : obj->free(obj->data);
197 : 962 : obj->data = NULL;
198 : 962 : obj->free = NULL;
199 [ + + + - ]: 962 : obj->size = 0;
200 : : }
201 : :
202 : : PL_API_END
203 : :
204 : : #endif // LIBPLACEBO_CACHE_H_
|