summaryrefslogtreecommitdiffstats
path: root/src/cache.c
diff options
context:
space:
mode:
authorGravatar Gediminas Jakutis <gediminas@varciai.lt> 2020-03-27 14:40:33 +0200
committerGravatar Gediminas Jakutis <gediminas@varciai.lt> 2020-03-27 14:40:33 +0200
commit7754455c48c50764ad7291ea508109c53b60517f (patch)
treef8b3f0fe7ad2509ff8c40a998cde91f8f7353f80 /src/cache.c
parent8b4c2c3194dbf9b18ecf475597d257ee7125a1e1 (diff)
downloadalgos-ld1-7754455c48c50764ad7291ea508109c53b60517f.tar.gz
algos-ld1-7754455c48c50764ad7291ea508109c53b60517f.tar.bz2
algos-ld1-7754455c48c50764ad7291ea508109c53b60517f.zip
cache I/O implementation and fixes.
Signed-off-by: Gediminas Jakutis <gediminas@varciai.lt>
Diffstat (limited to 'src/cache.c')
-rw-r--r--src/cache.c92
1 files changed, 89 insertions, 3 deletions
diff --git a/src/cache.c b/src/cache.c
index ebe1047..de182ec 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -6,11 +6,14 @@
#include <stdlib.h>
#include "defs.h"
+static off_t cache_walker(struct stream * const restrict in, ssize_t idx);
+
int cache_create(struct stream * const restrict in, const struct settings * const restrict s)
{
int ret;
void *cache;
+ try(!in->cached, err, EINVAL, "cannot create cache: stream is uncached");
try(!(cache = calloc(in->n, s->stride)), err, ENOMEM, "out of memory");
in->cache = cache;
@@ -21,7 +24,9 @@ err:
int cache_populate(struct stream * const restrict in)
{
int ret = 0;
- ssize_t i;
+ size_t i;
+
+ try(!in->cached, err, EINVAL, "cannot populate cache: stream is uncached");
for (i = 0; i < in->n && !ret; ++i) {
ret = in->get_element(in, i, in->cache + i);
@@ -34,7 +39,10 @@ err:
int cache_flush(struct stream * const in)
{
int ret;
- ssize_t i;
+ size_t i;
+
+ try(!in->cached, err, EINVAL, "no cache to flush: stream is uncached");
+ try(in->out != 1, err, EINVAL, "cannot flush a non-output cache");
for (i = 0; i < in->n && !ret; ++i) {
ret = in->put_element(in, i, in->cache + i);
@@ -48,9 +56,87 @@ int cache_destroy(struct stream * const in)
{
int ret;
- try(!in->cache, err, EINVAL, "trying to destroy cache of uncached streadm");
+ try(!in->cached, err, EINVAL, "no cache to destroy: stream uncached");
free(in->cache);
in->cache = NULL;
err:
return ret;
}
+
+int cache_transfer(struct stream * const from, struct stream * const to)
+{
+ int ret;
+
+ try(!from->cached || !to->cached, err, EINVAL, "cannot transfer caches of uncached streams");
+ try(!from->cache, err, EINVAL, "no cache to transfer");
+ try(!to->cache, err, EINVAL, "cannot transfer cache: recipient cache already exists");
+
+ to->cache = from->cache;
+ from->cache = NULL;
+err:
+ return ret;
+}
+
+int cached_get_array(struct stream * const in, ssize_t idx, struct entry_l * const data)
+{
+ int ret = 0;
+ const struct entry * const cache = in->cache;
+
+ data->val = cache[idx].val;
+
+ return ret;
+}
+
+int cached_get_list(struct stream * const restrict in, ssize_t idx, struct entry_l * const data)
+{
+ int ret = 0;
+ off_t offset;
+
+ offset = cache_walker(in, idx);
+ *data = in->cache[offset];
+
+ return ret;
+}
+
+int cached_put_array(struct stream * const in, ssize_t idx, const struct entry_l * const data)
+{
+ int ret = 0;
+ struct entry * const cache = in->cache;
+
+ cache[idx].val = data->val;
+
+ return ret;
+}
+
+int cached_put_list(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data)
+{
+ int ret = 0;
+ off_t offset;
+
+ offset = cache_walker(in, idx);
+ in->cache[offset] = *data;
+
+ return ret;
+}
+
+static off_t cache_walker(struct stream * const restrict in, ssize_t idx)
+{
+ size_t i;
+ off_t ret = in->prev_off;
+
+ if (in->prev_idx < idx) { /* previous index smaller, walk forward */
+ for (i = labs(idx - in->prev_idx); i; --i) {
+ ret = in->cache[ret].next;
+ }
+
+ } else if (in->prev_idx > idx) { /* previous index larger, walk backwards */
+ for (i = in->prev_idx - idx; i; --i) {
+ ret = in->cache[ret].prev;
+ }
+ } /* ...or we're standing on it already, if neither */
+
+ in->prev_idx = idx;
+ in->prev_off = ret;
+
+ return ret;
+}