/* SPDX-License-Identifier: LGPL-2.1-only */ /* Copyright (C) 2020 Gediminas Jakutis */ #include #include #include #include #include #include "defs.h" int cache_create(struct stream * const in, const struct settings * const restrict s) { int ret = 0; 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"); /* yeah... */ in->cache = cache; in->cache_a = cache; in->cache_l = cache; err: return ret; } int cache_populate(struct stream * const in) { int ret = 0; size_t i; struct entry_l *tmp; try(!in->cached, err, EINVAL, "cannot populate cache: stream is uncached"); for (i = 0; i < in->n && !ret; ++i) { errno = 0; tmp = in->get_next_element_direct(in); if (tmp) { /* non-cache reads CAN fail */ put(in, tmp); } else { ret = errno; break; } } err: return ret; } int cache_flush(struct stream * const in) { int ret = 0; struct entry_l *tmp; try(!in->cached, err, EINVAL, "no cache to flush: stream is uncached"); try(in->out != 1, err, EINVAL, "cannot flush a non-output cache"); while((tmp = get(in))) { in->place_next_element_direct(in, tmp); } err: return ret; } int cache_destroy(struct stream * const in) { int ret = 0; try(!in->cached, err, EINVAL, "no cache to destroy: stream uncached"); free(in->cache); in->cache_l = NULL; in->cache_a = NULL; in->cache = NULL; err: return ret; } int cache_transfer(struct stream * const src, struct stream * const dest) { int ret = 0; try(!src->cached || !dest->cached, err, EINVAL, "cannot transfer caches of uncached streams"); try(!src->cache, err, EINVAL, "no cache to transfer"); try(dest->cache, err, EINVAL, "cannot transfer cache: recipient cache already exists"); dest->cache = src->cache; dest->cache_a = (struct entry *) src->cache; dest->cache_l = (struct entry_l *) src->cache; src->cache = NULL; src->cache_a = NULL; src->cache_l = NULL; err: return ret; } int cache_block_copy(struct stream const * const src, struct stream * const dest, const struct settings * const s) { int ret = 0; try(!src->cached || !dest->cached, err, EINVAL, "cannot cache-copy between uncached streams"); try(!src->cache, err, EINVAL, "no cache to transfer"); try(!(src->n < s->to), err, EINVAL, "invalid copy size"); try(!dest->cache, err, EINVAL, "no cache to transfer to"); memcpy(dest->cache, src->cache_a + s->ss, (s->to - s->ss) * s->stride); err: return ret; } int cache_list_copy(struct stream const * const src, struct stream * const dest, const struct settings * const s) { int ret = ENOSYS; (void) src; (void) dest; (void) s; rin_warn("stub!"); return ret; } int cache_block_split(struct stream * const src, struct stream * const A, struct stream * const B) { int ret = 0; try(src->n < 2, err, EINVAL, "cannot split single element stream."); /* copy everything, then change whatever's neccesary */ *A = *B = *src; A->n = A->n / 2 + A->n % 2; B->n = B->n / 2; A->index = B->index = 0; B->cache_a = B->cache_a + A->n; B->cache_l = (struct entry_l *) B->cache_a; B->cache = (char *) B->cache_a; err: return ret; } int cache_list_split(struct stream * const src, struct stream * const A, struct stream * const B) { int ret = ENOSYS; (void) src; (void) A; (void) B; rin_warn("stub!"); return ret; } struct entry_l *cached_get_array(struct stream * const in) { struct entry_l *ret = NULL; if (in->index < in->n) { ret = (struct entry_l *)(in->cache_a + in->index); ++in->index; } return ret; } struct entry_l *cached_get_list(struct stream * const in) { struct entry_l *ret = NULL; if (in->index < in->n) { ret = in->cnode; in->cnode = (struct entry_l *) ret->next; ++in->index; } return ret; } int cached_put_array(struct stream * const in, const struct entry_l * const data) { int ret = EINVAL; if (in->index < in->n) { in->cache_a[in->index].val = data->val; ++in->index; } return ret; } int cached_put_list(struct stream * const restrict in, const struct entry_l * const node) { int ret = ENOSYS; (void) in; (void) node; rin_warn("stub!"); return ret; }