Commit 43d42731 authored by Brice Videau's avatar Brice Videau

Initial commit with sources from aml/tree/wip/videau/ndcopy.

parent 586f0644
#include <errno.h>
#include <stdlib.h>
#include <citerators.h>
struct citerator_func_table_s {
int (*alloc)(citerator_t data);
void (*free)(citerator_t data);
int (*copy)(citerator_t dst, const citerator_t src);
int (*next)(citerator_t data, citerator_index_t *indexes);
int (*peek)(const citerator_t data, citerator_index_t *indexes);
int (*size)(const citerator_t data, citerator_index_t *size);
int (*rewind)(citerator_t data);
int (*split)(const citerator_t data, citerator_index_t n,
citerator_t *results);
int (*nth)(const citerator_t data, citerator_index_t n,
citerator_index_t *indexes);
int (*n)(const citerator_t data, const citerator_index_t *indexes,
citerator_index_t *n);
int (*pos)(const citerator_t iterator, citerator_index_t *n);
};
struct citerator_s {
const struct citerator_func_table_s *functions;
citerator_index_t dimension;
enum citerator_type_e type;
void *data;
};
/*--------------------------------------------------------------------*/
struct slice_iterator_s {
citerator_t src;
citerator_t indexer;
};
static int slice_iterator_alloc(citerator_t data)
{
data->data = malloc(sizeof(struct slice_iterator_s));
if (!data->data)
return -ENOMEM;
struct slice_iterator_s *iterator =
(struct slice_iterator_s *) data->data;
iterator->src = NULL;
iterator->indexer = NULL;
return 0;
}
static void slice_iterator_free(citerator_t data)
{
struct slice_iterator_s *iterator =
(struct slice_iterator_s *) data->data;
citerator_free(iterator->src);
citerator_free(iterator->indexer);
free(data->data);
}
static int slice_iterator_copy(citerator_t dst, const citerator_t src)
{
const struct slice_iterator_s *iterator =
(const struct slice_iterator_s *) src->data;
struct slice_iterator_s *result = (struct slice_iterator_s *) dst->data;
result->src = citerator_dup(iterator->src);
if (!result->src)
return -ENOMEM;
result->indexer = citerator_dup(iterator->indexer);
if (!result->indexer) {
citerator_free(iterator->src);
return -ENOMEM;
}
return 0;
}
static int slice_iterator_next(citerator_t data, citerator_index_t *indexes)
{
struct slice_iterator_s *iterator =
(struct slice_iterator_s *) data->data;
citerator_index_t n;
int err = citerator_next(iterator->indexer, &n);
if (err)
return err;
return citerator_nth(iterator->src, n, indexes);
}
static int slice_iterator_peek(const citerator_t data,
citerator_index_t *indexes)
{
const struct slice_iterator_s *iterator =
(const struct slice_iterator_s *)data->data;
citerator_index_t n;
int err = citerator_peek(iterator->indexer, &n);
if (err)
return err;
return citerator_nth(iterator->src, n, indexes);
}
static int slice_iterator_size(const citerator_t data, citerator_index_t *size)
{
const struct slice_iterator_s *iterator =
(const struct slice_iterator_s *)data->data;
return citerator_size(iterator->indexer, size);
}
static int slice_iterator_rewind(citerator_t data)
{
struct slice_iterator_s *iterator =
(struct slice_iterator_s *) data->data;
return citerator_rewind(iterator->indexer);
}
static int slice_iterator_nth(const citerator_t data, citerator_index_t n,
citerator_index_t *indexes)
{
const struct slice_iterator_s *iterator =
(const struct slice_iterator_s *)data->data;
citerator_index_t p;
int err = citerator_nth(iterator->indexer, n, &p);
if (err)
return err;
return citerator_nth(iterator->src, p, indexes);
}
static int slice_iterator_n(const citerator_t data,
const citerator_index_t *indexes,
citerator_index_t *n)
{
const struct slice_iterator_s *iterator =
(const struct slice_iterator_s *)data->data;
citerator_index_t inner_n;
int err = citerator_n(iterator->src, indexes, &inner_n);
if (err)
return err;
return citerator_n(iterator->indexer, &inner_n, n);
}
static int slice_iterator_pos(const citerator_t data, citerator_index_t *n)
{
const struct slice_iterator_s *iterator =
(const struct slice_iterator_s *)data->data;
return citerator_pos(iterator->indexer, n);
}
static int slice_iterator_split(const citerator_t data, citerator_index_t n,
citerator_t *results)
{
const struct slice_iterator_s *iterator =
(const struct slice_iterator_s *)data->data;
int err = citerator_split(iterator->indexer, n, results);
if (err)
return err;
if (!results)
return 0;
for (int i = 0; i < n; i++) {
citerator_t tmp;
citerator_t tmp2;
tmp = results[i];
results[i] = citerator_alloc(CITERATOR_SLICE);
if (!results[i]) {
citerator_free(tmp);
err = -ENOMEM;
goto error;
}
tmp2 = citerator_dup(iterator->src);
if (!tmp2) {
citerator_free(tmp);
err = -ENOMEM;
goto error;
}
err = citerator_slice_init(results[i], tmp, tmp2);
if (err) {
citerator_free(tmp);
citerator_free(tmp2);
goto error;
}
}
return 0;
error:
for (int i = 0; i < n; i++)
citerator_free(results[i]);
return err;
}
static const struct citerator_func_table_s citerator_slice_func_table = {
slice_iterator_alloc,
slice_iterator_free,
slice_iterator_copy,
slice_iterator_next,
slice_iterator_peek,
slice_iterator_size,
slice_iterator_rewind,
slice_iterator_split,
slice_iterator_nth,
slice_iterator_n,
slice_iterator_pos
};
int citerator_slice_init(citerator_t iterator, citerator_t src,
citerator_t indexer)
{
if (!iterator || iterator->type != CITERATOR_SLICE || !src || !indexer
|| indexer->dimension != 1)
return -EINVAL;
struct slice_iterator_s *it =
(struct slice_iterator_s *) iterator->data;
citerator_index_t size_src;
citerator_index_t size_indexer;
int err = citerator_size(src, &size_src);
if (err)
return err;
err = citerator_size(indexer, &size_indexer);
if (err)
return err;
if (size_indexer > size_src)
return -EDOM;
it->src = src;
it->indexer = indexer;
iterator->dimension = src->dimension;
return 0;
}
/*--------------------------------------------------------------------*/
struct product_iterator_s {
citerator_index_t count;
citerator_t *iterators;
};
static int product_iterator_alloc(citerator_t data)
{
data->data = malloc(sizeof(struct product_iterator_s));
if (!data->data)
return -ENOMEM;
struct product_iterator_s *iterator =
(struct product_iterator_s *) data->data;
iterator->count = 0;
iterator->iterators = NULL;
return 0;
}
static void product_iterator_free(citerator_t data)
{
struct product_iterator_s *iterator =
(struct product_iterator_s *) data->data;
if (iterator->iterators) {
for (int i = 0; i < iterator->count; i++)
citerator_free(iterator->iterators[i]);
free(iterator->iterators);
}
free(data->data);
}
static int product_iterator_copy(citerator_t dst, const citerator_t src)
{
const struct product_iterator_s *iterator =
(const struct product_iterator_s *)src->data;
struct product_iterator_s *result =
(struct product_iterator_s *) dst->data;
result->iterators =
(citerator_t *) malloc(iterator->count * sizeof(citerator_t));
if (!result->iterators)
return -ENOMEM;
int i;
for (i = 0; i < iterator->count; i++) {
result->iterators[i] = citerator_dup(iterator->iterators[i]);
if (!result->iterators[i]) {
i--;
goto error;
}
}
result->count = iterator->count;
return 0;
error:
while (i >= 0) {
free(result->iterators[i]);
i--;
}
free(result->iterators);
return -ENOMEM;
}
static int product_iterator_rewind(citerator_t data)
{
struct product_iterator_s *iterator =
(struct product_iterator_s *) data->data;
for (int i = 0; i < iterator->count; i++) {
int err = citerator_rewind(iterator->iterators[i]);
if (err)
return err;
}
return 0;
}
static int product_iterator_size(const citerator_t data,
citerator_index_t *size)
{
const struct product_iterator_s *iterator =
(const struct product_iterator_s *) data->data;
citerator_index_t tmp_size = 0;
if (!size)
return -EINVAL;
if (iterator->count == 0)
*size = 0;
else {
*size = 1;
for (int i = 0; i < iterator->count; i++) {
int err =
citerator_size(iterator->iterators[i], &tmp_size);
if (err) {
*size = 0;
return err;
}
*size *= tmp_size;
}
}
return 0;
}
static int product_iterator_nth(const citerator_t data, citerator_index_t n,
citerator_index_t *indexes)
{
int size;
int err = product_iterator_size(data, &size);
if (err)
return err;
if (n < 0 || n >= size)
return -EDOM;
const struct product_iterator_s *iterator =
(const struct product_iterator_s *) data->data;
if (indexes) {
citerator_index_t subsize = 0;
citerator_index_t offset = data->dimension;
for (int i = iterator->count - 1; i >= 0; i--) {
offset -= iterator->iterators[i]->dimension;
err = citerator_size(iterator->iterators[i], &subsize);
if (err)
return err;
err =
citerator_nth(iterator->iterators[i], n % subsize,
indexes + offset);
if (err)
return err;
n /= subsize;
}
}
return 0;
}
static int product_iterator_n(const citerator_t data,
const citerator_index_t *indexes,
citerator_index_t *n)
{
const struct product_iterator_s *iterator =
(const struct product_iterator_s *) data->data;
if (iterator->count == 0)
return -EINVAL;
citerator_index_t offset = 0;
citerator_index_t product = 0;
citerator_index_t inner_n;
citerator_index_t subsize;
for (int i = 0; i < iterator->count; i++) {
int err =
citerator_n(iterator->iterators[i], indexes + offset,
&inner_n);
if (err)
return err;
err = citerator_size(iterator->iterators[i], &subsize);
if (err)
return err;
product *= subsize;
product += inner_n;
offset += iterator->iterators[i]->dimension;
}
if (n)
*n = product;
return 0;
}
static int product_iterator_pos(const citerator_t data, citerator_index_t *n)
{
const struct product_iterator_s *iterator =
(const struct product_iterator_s *) data->data;
if (iterator->count == 0)
return -EINVAL;
citerator_index_t product = 0;
citerator_index_t inner_n;
citerator_index_t subsize;
for (int i = 0; i < iterator->count; i++) {
int err = citerator_pos(iterator->iterators[i], &inner_n);
if (err)
return err;
err = citerator_size(iterator->iterators[i], &subsize);
if (err)
return err;
product *= subsize;
product += inner_n;
}
if (n)
*n = product;
return 0;
}
static inline int product_iterator_peeknext_helper(citerator_t data,
citerator_index_t *indexes,
int next)
{
struct product_iterator_s *iterator =
(struct product_iterator_s *) data->data;
int err;
int looped;
int i;
citerator_index_t *next_indexes;
citerator_index_t offset = data->dimension;
if (iterator->count == 0)
return -EINVAL;
looped = next;
for (i = iterator->count - 1; i > 0; i--) {
if (indexes) {
offset -= iterator->iterators[i]->dimension;
next_indexes = indexes + offset;
} else
next_indexes = NULL;
if (looped)
err =
citerator_cyclic_next(iterator->iterators[i],
next_indexes, &looped);
else
err =
citerator_peek(iterator->iterators[i],
next_indexes);
if (err)
return err;
}
if (indexes) {
offset -= iterator->iterators[i]->dimension;
next_indexes = indexes + offset;
} else
next_indexes = NULL;
if (looped)
err = citerator_next(iterator->iterators[0], next_indexes);
else
err = citerator_peek(iterator->iterators[0], next_indexes);
if (err)
return err;
return 0;
}
static int product_iterator_peek(const citerator_t data,
citerator_index_t *indexes)
{
return product_iterator_peeknext_helper(data, indexes, 0);
}
static int product_iterator_next(citerator_t data, citerator_index_t *indexes)
{
return product_iterator_peeknext_helper(data, indexes, 1);
}
static int product_iterator_split(const citerator_t data, citerator_index_t n,
citerator_t *results)
{
int size;
int err = product_iterator_size(data, &size);
if (err)
return err;
if (size < n)
return -EDOM;
if (!results)
return 0;
citerator_t range = citerator_alloc(CITERATOR_RANGE);
if (!range)
return -ENOMEM;
err = citerator_range_init(range, 0, size - 1, 1);
if (err)
goto error1;
err = citerator_split(range, n, results);
if (err)
goto error1;
for (int i = 0; i < n; i++) {
citerator_t tmp, tmp2;
tmp = citerator_dup(data);
if (!tmp)
goto error2;
tmp2 = results[i];
results[i] = citerator_alloc(CITERATOR_SLICE);
if (!results[i]) {
citerator_free(tmp2);
goto error2;
}
err = citerator_slice_init(results[i], tmp, tmp2);
if (err) {
citerator_free(tmp2);
goto error2;
}
}
citerator_free(range);
return 0;
error2:
for (int i = 0; i < n; i++)
citerator_free(results[i]);
error1:
citerator_free(range);
return err;
}
int citerator_product_count(const citerator_t iterator,
citerator_index_t *count)
{
if (!iterator || iterator->type != CITERATOR_PRODUCT || !count)
return -EINVAL;
*count = ((struct product_iterator_s *) iterator->data)->count;
return 0;
}
int citerator_product_split_dim(const citerator_t iterator,
citerator_index_t dim, citerator_index_t n,
citerator_t *results)
{
if (!iterator || iterator->type != CITERATOR_PRODUCT)
return -EINVAL;
if (n <= 0)
return -EDOM;
int count;
int err = citerator_product_count(iterator, &count);
if (err)
return err;
if (dim >= count)
return -EDOM;
struct product_iterator_s *product_iterator =
(struct product_iterator_s *) iterator->data;
err = citerator_split(product_iterator->iterators[dim], n, results);
if (err)
return err;
if (!results)
return 0;
for (int i = 0; i < n; i++) {
citerator_t tmp = results[i];
results[i] = citerator_dup(iterator);
if (!tmp) {
citerator_free(tmp);
err = -ENOMEM;
goto error;
}
struct product_iterator_s *new_product_iterator =
(struct product_iterator_s *) results[i]->data;
citerator_free(new_product_iterator->iterators[dim]);
new_product_iterator->iterators[dim] = tmp;
}
return 0;
error:
for (int i = 0; i < n; i++)
citerator_free(results[i]);
return err;
}
int citerator_product_add_copy(citerator_t iterator, citerator_t added_iterator)
{
int err = 0;
citerator_t copy = citerator_dup(added_iterator);
if (!copy)
return -EINVAL;
err = citerator_product_add(iterator, copy);
if (err) {
citerator_free(added_iterator);
return err;
}
return 0;
}
int citerator_product_add(citerator_t iterator, citerator_t added_iterator)
{
if (!iterator || iterator->type != CITERATOR_PRODUCT || !iterator->data
|| !added_iterator)
return -EINVAL;
struct product_iterator_s *product_iterator =
(struct product_iterator_s *) iterator->data;
int mew_count = product_iterator->count + 1;
citerator_t *new_its =
(citerator_t *) realloc(product_iterator->iterators,
mew_count * sizeof(citerator_t));
if (!new_its)
return -ENOMEM;
product_iterator->iterators = new_its;
product_iterator->iterators[product_iterator->count] = added_iterator;
product_iterator->count = mew_count;
iterator->dimension += added_iterator->dimension;
return 0;
}
static const struct citerator_func_table_s citerator_product_func_table = {
product_iterator_alloc,
product_iterator_free,
product_iterator_copy,
product_iterator_next,
product_iterator_peek,
product_iterator_size,
product_iterator_rewind,
product_iterator_split,
product_iterator_nth,
product_iterator_n,
product_iterator_pos
};
/*--------------------------------------------------------------------*/
struct circular_fifo_s {
citerator_index_t length;
citerator_index_t start;
citerator_index_t end;
citerator_index_t size;
citerator_index_t *buffer;
};
static void circular_fifo_add(struct circular_fifo_s *fifo,
citerator_index_t elem)
{
if (fifo->size == fifo->length) {
fifo->start = (fifo->start + 1) % fifo->length;
fifo->end = (fifo->end + 1) % fifo->length;
} else {
fifo->end = (fifo->end + 1) % fifo->length;
fifo->size++;
}
fifo->buffer[fifo->end] = elem;
}
static void circular_fifo_dump(const struct circular_fifo_s *fifo,
citerator_index_t *vals)
{
citerator_index_t i;
citerator_index_t j;
for (i = 0, j = fifo->start; i < fifo->size; i++) {
vals[i] = fifo->buffer[j];
j = (j + 1) % fifo->length;
}
}
struct cons_iterator_s {
citerator_t iterator;
citerator_index_t n;
struct circular_fifo_s fifo;
};
static int cons_iterator_alloc(citerator_t data)
{
data->data = malloc(sizeof(struct cons_iterator_s));
if (!data->data)
return -ENOMEM;
struct cons_iterator_s *iterator =
(struct cons_iterator_s *) data->data;
iterator->iterator = NULL;
iterator->n = 0;
iterator->fifo.length = 0;
iterator->fifo.start = 0;
iterator->fifo.end = -1;
iterator->fifo.size = 0;
iterator->fifo.buffer = NULL;
return 0;
}
static void cons_iterator_free(citerator_t data)
{
struct cons_iterator_s *iterator =
(struct cons_iterator_s *) data->data;
citerator_free(iterator->iterator);
free(iterator->fifo.buffer);
free(data->data);
}
static int cons_iterator_copy(citerator_t ddst, const citerator_t dsrc)
{
struct cons_iterator_s *dst = (struct cons_iterator_s *) ddst->data;
const struct cons_iterator_s *src =
(const struct cons_iterator_s *)dsrc->data;
citerator_t copy = citerator_dup(src->iterator);
if (!copy)
return -EINVAL;
dst->iterator = copy;
dst->n = src->n;
dst->fifo.length = src->fifo.length;
dst->fifo.start = src->fifo.start;
dst->fifo.end = src->fifo.end;
dst->fifo.size = src->fifo.size;
dst->fifo.buffer =
(citerator_index_t *) malloc(src->fifo.length *