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

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;
}