Commit a97d5c7c authored by Nicolas Denoyelle's avatar Nicolas Denoyelle

split files and add tleaf iterator

parent 4e08270a
...@@ -2,6 +2,6 @@ AM_CFLAGS = -Wall -Werror -pedantic ...@@ -2,6 +2,6 @@ AM_CFLAGS = -Wall -Werror -pedantic
lib_LTLIBRARIES = libexcit.la lib_LTLIBRARIES = libexcit.la
libexcit_la_SOURCES = excit.c excit.h libexcit_la_SOURCES = excit.c tleaf.c range.c slice.c repeat.c prod.c cons.c hilbert2d.c
include_HEADERS = excit.h include_HEADERS = excit.h
#include "cons.h"
#define EXCIT_DATA(data, it) \
if(data == NULL) { return EXCIT_EINVAL; } \
do{ \
int err = excit_get_data(data, (void**)(&it)); \
if(err != EXCIT_SUCCESS) { return err; } \
} while(0); \
if(it == NULL){ return EXCIT_EINVAL; }
static void circular_fifo_add(struct circular_fifo_s *fifo, ssize_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,
ssize_t *vals)
{
ssize_t i;
ssize_t j;
for (i = 0, j = fifo->start; i < fifo->size; i++) {
vals[i] = fifo->buffer[j];
j = (j + 1) % fifo->length;
}
}
struct excit_func_table_s excit_cons_func_table = {
cons_it_alloc,
cons_it_free,
cons_it_copy,
cons_it_next,
cons_it_peek,
cons_it_size,
cons_it_rewind,
cons_it_split,
cons_it_nth,
cons_it_rank,
cons_it_pos
};
int cons_it_alloc(excit_t data)
{
struct cons_it_s *it;
EXCIT_DATA(data, it);
it->it = NULL;
it->n = 0;
it->fifo.length = 0;
it->fifo.start = 0;
it->fifo.end = -1;
it->fifo.size = 0;
it->fifo.buffer = NULL;
return EXCIT_SUCCESS;
}
void cons_it_free(excit_t data)
{
struct cons_it_s *it;
if(data == NULL) { return ; }
int err = excit_get_data(data, (void**)(&it));
if(err != EXCIT_SUCCESS) { return; }
if(it == NULL){ return; }
excit_free(it->it);
free(it->fifo.buffer);
}
int cons_it_copy(excit_t ddst, const excit_t dsrc)
{
struct cons_it_s *dst;
EXCIT_DATA(ddst, dst);
const struct cons_it_s *src;
EXCIT_DATA(dsrc, src);
excit_t copy = excit_dup(src->it);
if (!copy)
return -EXCIT_EINVAL;
dst->it = 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 =
(ssize_t *) malloc(src->fifo.length * sizeof(ssize_t));
if (!dst->fifo.buffer) {
excit_free(copy);
return -EXCIT_ENOMEM;
}
for (int i = 0; i < dst->fifo.length; i++)
dst->fifo.buffer[i] = src->fifo.buffer[i];
return EXCIT_SUCCESS;
}
int cons_it_size(const excit_t data, ssize_t *size)
{
const struct cons_it_s *it;
EXCIT_DATA(data, it);
ssize_t tmp_size = 0;
int err = excit_size(it->it, &tmp_size);
if (err)
return err;
*size = tmp_size - (it->n - 1);
return EXCIT_SUCCESS;
}
int cons_it_split(const excit_t data, ssize_t n, excit_t *results)
{
ssize_t size;
int err = cons_it_size(data, &size);
if (err)
return err;
if (size < n)
return -EXCIT_EDOM;
if (!results)
return EXCIT_SUCCESS;
excit_t range = excit_alloc(EXCIT_RANGE);
if (!range)
return -EXCIT_ENOMEM;
err = excit_range_init(range, 0, size - 1, 1);
if (err)
goto error1;
err = excit_split(range, n, results);
if (err)
goto error1;
int i;
for (i = 0; i < n; i++) {
excit_t tmp, tmp2;
tmp = excit_dup(data);
if (!tmp)
goto error2;
tmp2 = results[i];
results[i] = excit_alloc(EXCIT_SLICE);
if (!results[i]) {
excit_free(tmp2);
goto error2;
}
err = excit_slice_init(results[i], tmp, tmp2);
if (err) {
excit_free(tmp2);
goto error2;
}
}
excit_free(range);
return EXCIT_SUCCESS;
error2:
for (; i >= 0; i--)
excit_free(results[i]);
error1:
excit_free(range);
return err;
}
int cons_it_nth(const excit_t data, ssize_t n, ssize_t *indexes)
{
ssize_t size;
int err = cons_it_size(data, &size);
if (err)
return err;
if (n < 0 || n >= size)
return -EXCIT_EDOM;
const struct cons_it_s *it;
EXCIT_DATA(data, it);
int dim = excit_get_dimension(it->it);
if (indexes) {
for (int i = 0; i < it->n; i++) {
err = excit_nth(it->it, n + i, indexes + dim * i);
if (err)
return err;
}
}
return EXCIT_SUCCESS;
}
int cons_it_rank(const excit_t data, const ssize_t *indexes, ssize_t *n)
{
const struct cons_it_s *it;
EXCIT_DATA(data, it);
ssize_t inner_n, inner_n_tmp;
int err = excit_rank(it->it, indexes, &inner_n);
if (err)
return err;
int dim = excit_get_dimension(it->it);
for (int i = 1; i < it->n; i++) {
err = excit_rank(it->it, indexes + dim * i, &inner_n_tmp);
if (err)
return err;
if (inner_n_tmp != inner_n + 1)
return -EXCIT_EINVAL;
inner_n = inner_n_tmp;
}
if (n)
*n = inner_n - (it->n - 1);
return EXCIT_SUCCESS;
}
int cons_it_pos(const excit_t data, ssize_t *n)
{
ssize_t inner_n;
const struct cons_it_s *it;
EXCIT_DATA(data, it);
int err = excit_pos(it->it, &inner_n);
if (err)
return err;
if (n)
*n = inner_n - (it->n - 1);
return EXCIT_SUCCESS;
}
int cons_it_peek(const excit_t data, ssize_t *indexes)
{
const struct cons_it_s *it;
EXCIT_DATA(data, it);
int err;
int dim = excit_get_dimension(it->it);
int n = it->n;
if (indexes) {
circular_fifo_dump(&it->fifo, indexes);
err = excit_peek(it->it, indexes + dim * (n - 1));
} else
err = excit_peek(it->it, NULL);
if (err)
return err;
return EXCIT_SUCCESS;
}
int cons_it_next(excit_t data, ssize_t *indexes)
{
struct cons_it_s *it;
EXCIT_DATA(data, it);
int err;
int dim = excit_get_dimension(it->it);
int n = it->n;
if (indexes) {
circular_fifo_dump(&it->fifo, indexes);
err = excit_next(it->it, indexes + dim * (n - 1));
} else
err = excit_next(it->it, NULL);
if (err)
return err;
if (indexes)
for (int i = dim * (n - 1); i < dim * n; i++)
circular_fifo_add(&it->fifo, indexes[i]);
return EXCIT_SUCCESS;
}
int cons_it_rewind(excit_t data)
{
struct cons_it_s *it;
EXCIT_DATA(data, it);
int err = excit_rewind(it->it);
if (err)
return err;
it->fifo.start = 0;
it->fifo.end = -1;
it->fifo.size = 0;
for (int i = 0; i < it->n - 1; i++) {
int err;
err =
excit_next(it->it, it->fifo.buffer + excit_get_dimension(it->it) * i);
if (err)
return err;
it->fifo.size += excit_get_dimension(it->it);
it->fifo.end += excit_get_dimension(it->it);
}
return EXCIT_SUCCESS;
}
int excit_cons_init(excit_t it, excit_t src, ssize_t n)
{
ssize_t src_size;
int err;
if (!it || !src || n <= 0)
return -EXCIT_EINVAL;
err = excit_size(src, &src_size);
if (err)
return err;
if (src_size < n)
return -EXCIT_EINVAL;
struct cons_it_s *cons_it;
EXCIT_DATA(it, cons_it);
free(cons_it->fifo.buffer);
excit_free(cons_it->it);
excit_set_dimension(it, excit_get_dimension(src) * n);
cons_it->it = src;
cons_it->n = n;
cons_it->fifo.length = excit_get_dimension(src) * (n - 1);
cons_it->fifo.buffer =
(ssize_t *) malloc(cons_it->fifo.length * sizeof(ssize_t));
if (!cons_it->fifo.buffer)
return -EXCIT_ENOMEM;
err = cons_it_rewind(it);
if (err) {
free(cons_it->fifo.buffer);
return err;
}
return EXCIT_SUCCESS;
}
#ifndef CONS_H
#define CONS_H
#include "excit.h"
struct circular_fifo_s {
ssize_t length;
ssize_t start;
ssize_t end;
ssize_t size;
ssize_t *buffer;
};
struct cons_it_s {
excit_t it;
ssize_t n;
struct circular_fifo_s fifo;
};
int cons_it_alloc(excit_t data);
void cons_it_free(excit_t data);
int cons_it_copy(excit_t ddst, const excit_t dsrc);
int cons_it_size(const excit_t data, ssize_t *size);
int cons_it_split(const excit_t data, ssize_t n, excit_t *results);
int cons_it_nth(const excit_t data, ssize_t n, ssize_t *indexes);
int cons_it_rank(const excit_t data, const ssize_t *indexes, ssize_t *n);
int cons_it_pos(const excit_t data, ssize_t *n);
int cons_it_peek(const excit_t data, ssize_t *indexes);
int cons_it_next(excit_t data, ssize_t *indexes);
int cons_it_rewind(excit_t data);
extern struct excit_func_table_s excit_cons_func_table;
#endif
This diff is collapsed.
#ifndef EXCIT_H #ifndef EXCIT_H
#define EXCIT_H 1 #define EXCIT_H 1
#include <stdlib.h>
/* /*
* The different types of iterator supported. All iterators use the same * The different types of iterator supported. All iterators use the same
* integer type (ssize_t) for values. * integer type (ssize_t) for values.
*/ */
enum excit_type_e { enum excit_type_e {
EXCIT_INVALID, /*!< Tag for invalid iterators */ EXCIT_INVALID, /*!< Tag for invalid iterators */
EXCIT_RANGE, /*!< Iterator over a range of values */ EXCIT_RANGE, /*!< Iterator over a range of values */
EXCIT_CONS, /*!< Sliding window iterator */ EXCIT_CONS, /*!< Sliding window iterator */
EXCIT_REPEAT, /*!< Ierator that stutters a certain amount of times */ EXCIT_REPEAT, /*!< Ierator that stutters a certain amount of times */
EXCIT_HILBERT2D, /*!< Hilbert space filing curve */ EXCIT_HILBERT2D, /*!< Hilbert space filing curve */
EXCIT_PRODUCT, /*!< Iterator over the catesian product of iterators */ EXCIT_PRODUCT, /*!< Iterator over the catesian product of iterators */
EXCIT_SLICE, /*!< Iterator using another iterator to index a third */ EXCIT_SLICE, /*!< Iterator using another iterator to index a third */
EXCIT_USER, /*!< User-defined iterator */ EXCIT_TLEAF, /*!< Iterator on leaves of a balanced tree */
EXCIT_TYPE_MAX /*!< Guard */ EXCIT_USER, /*!< User-defined iterator */
EXCIT_TYPE_MAX /*!< Guard */
}; };
/* /*
...@@ -26,13 +29,13 @@ const char * excit_type_name(enum excit_type_e type); ...@@ -26,13 +29,13 @@ const char * excit_type_name(enum excit_type_e type);
* The different possible return codes of an excit function. * The different possible return codes of an excit function.
*/ */
enum excit_error_e { enum excit_error_e {
EXCIT_SUCCESS, /*!< Sucess */ EXCIT_SUCCESS, /*!< Sucess */
EXCIT_STOPIT, /*!< Iteration space is depleted */ EXCIT_STOPIT, /*!< Iteration space is depleted */
EXCIT_ENOMEM, /*!< Out of memory */ EXCIT_ENOMEM, /*!< Out of memory */
EXCIT_EINVAL, /*!< Parameter has an invalid value */ EXCIT_EINVAL, /*!< Parameter has an invalid value */
EXCIT_EDOM, /*!< Parameter is out of possible domain */ EXCIT_EDOM, /*!< Parameter is out of possible domain */
EXCIT_ENOTSUP, /*!< Operation is not supported */ EXCIT_ENOTSUP, /*!< Operation is not supported */
EXCIT_ERROR_MAX /*!< Guard */ EXCIT_ERROR_MAX /*!< Guard */
}; };
/* /*
...@@ -50,16 +53,23 @@ typedef struct excit_s *excit_t; ...@@ -50,16 +53,23 @@ typedef struct excit_s *excit_t;
******************************************************************************/ ******************************************************************************/
/* /*
* Sets the dimension of a user-defined iterator. * Sets the dimension of a (user-defined) iterator.
* "it": a user-defined iterator. * "it": a (user-defined) iterator.
* "dimension": the new dimension of the iterator. * "dimension": the new dimension of the iterator.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int excit_set_dimension(excit_t it, ssize_t dimension); int excit_set_dimension(excit_t it, ssize_t dimension);
/* /*
* Gets the inner data pointer of a user-defined iterator. * Gets the dimension of an iterator.
* "it": a user-defined iterator. * "it": the iterator.
* Returns the dimension or -1 if it is NULL.
*/
ssize_t excit_get_dimension(excit_t it);
/*
* Gets the inner data pointer of a (user-defined) iterator.
* "it": a (user-defined) iterator.
* "data": a pointer to a pointer variable where the result will be written. * "data": a pointer to a pointer variable where the result will be written.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
...@@ -72,71 +82,71 @@ int excit_get_data(excit_t it, void **data); ...@@ -72,71 +82,71 @@ int excit_get_data(excit_t it, void **data);
* -EXCIT_ENOTSUP. * -EXCIT_ENOTSUP.
*/ */
struct excit_func_table_s { struct excit_func_table_s {
/* /*
* This function is called during excit_alloc, after the memory * This function is called during excit_alloc, after the memory
* allocation, the inner data pointer will already be set. * allocation, the inner data pointer will already be set.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int (*alloc)(excit_t it); int (*alloc)(excit_t it);
/* /*
* This function is called during excit_free. After this function is * This function is called during excit_free. After this function is
* called the iterator and the data will be freed. * called the iterator and the data will be freed.
*/ */
void (*free)(excit_t it); void (*free)(excit_t it);
/* /*
* This funciton is called during excit_dup. It is responsible for * This funciton is called during excit_dup. It is responsible for
* duplicating the content of the inner data between src_it and dst_it. * duplicating the content of the inner data between src_it and dst_it.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int (*copy)(excit_t dst_it, const excit_t src_it); int (*copy)(excit_t dst_it, const excit_t src_it);
/* /*
* This function is responsible for implementing the next functionality * This function is responsible for implementing the next functionality
* of the iterator. * of the iterator.
* Returns EXCIT_SUCCESS, EXCIT_STOPIT or an error code. * Returns EXCIT_SUCCESS, EXCIT_STOPIT or an error code.
*/ */
int (*next)(excit_t it, ssize_t *indexes); int (*next)(excit_t it, ssize_t *indexes);
/* /*
* This function is responsible for implementing the peek functionality * This function is responsible for implementing the peek functionality
* of the iterator. * of the iterator.
* Returns EXCIT_SUCCESS, EXCIT_STOPIT or an error code. * Returns EXCIT_SUCCESS, EXCIT_STOPIT or an error code.
*/ */
int (*peek)(const excit_t it, ssize_t *indexes); int (*peek)(const excit_t it, ssize_t *indexes);
/* /*
* This function is responsible for implementing the size functionality * This function is responsible for implementing the size functionality
* of the iterator. * of the iterator.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int (*size)(const excit_t it, ssize_t *size); int (*size)(const excit_t it, ssize_t *size);
/* /*
* This function is responsible for implementing the rewind * This function is responsible for implementing the rewind
* functionality of the iterator. * functionality of the iterator.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int (*rewind)(excit_t it); int (*rewind)(excit_t it);
/* /*
* This function is responsible for implementing the split * This function is responsible for implementing the split
* functionality of the iterator. * functionality of the iterator.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int (*split)(const excit_t it, ssize_t n, excit_t *results); int (*split)(const excit_t it, ssize_t n, excit_t *results);
/* /*
* This function is responsible for implementing the nth functionality * This function is responsible for implementing the nth functionality
* of the iterator. * of the iterator.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int (*nth)(const excit_t it, ssize_t n, ssize_t *indexes); int (*nth)(const excit_t it, ssize_t n, ssize_t *indexes);
/* /*
* This function is responsible for implementing the rank functionality * This function is responsible for implementing the rank functionality
* of the iterator. * of the iterator.
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int (*rank)(const excit_t it, const ssize_t *indexes, ssize_t *n); int (*rank)(const excit_t it, const ssize_t *indexes, ssize_t *n);
/* /*
* This function is responsible for implementing the pos functionality * This function is responsible for implementing the pos functionality
* of the iterator. * of the iterator.
* Returns EXCIT_SUCCESS, EXCIT_STOPIT or an error code. * Returns EXCIT_SUCCESS, EXCIT_STOPIT or an error code.
*/ */
int (*pos)(const excit_t it, ssize_t *n); int (*pos)(const excit_t it, ssize_t *n);
}; };
/* /*
...@@ -245,7 +255,7 @@ int excit_size(const excit_t it, ssize_t *size); ...@@ -245,7 +255,7 @@ int excit_size(const excit_t it, ssize_t *size);
* "it": an iterator. * "it": an iterator.
* "n": number of iterators desired. * "n": number of iterators desired.
* "results": an array of at least n excit_t, or NULL in which case no iterator * "results": an array of at least n excit_t, or NULL in which case no iterator
* is created. / * is created.
* Returns EXCIT_SUCCESS, -EXCIT_EDOM if the source iterator is too small to be * Returns EXCIT_SUCCESS, -EXCIT_EDOM if the source iterator is too small to be
* subdivised in the wanted number or an error code. * subdivised in the wanted number or an error code.
*/ */
...@@ -383,4 +393,21 @@ int excit_product_split_dim(const excit_t it, ssize_t dim, ssize_t n, ...@@ -383,4 +393,21 @@ int excit_product_split_dim(const excit_t it, ssize_t dim, ssize_t n,
* Returns EXCIT_SUCCESS or an error code. * Returns EXCIT_SUCCESS or an error code.
*/ */
int excit_slice_init(excit_t it, excit_t src, excit_t indexer); int excit_slice_init(excit_t it, excit_t src, excit_t indexer);
enum tleaf_it_policy_e {
ROUND_ROBIN, /* Iterate on tree leaves in a round-robin fashion */
SCATTER /* Iterate on tree leaves such spreading as much as possible */
};
/*
* Initialize a tleaf iterator by giving its depth, levels arity and iteration policy.
* "it": a tleaf iterator
* "depth": the total number of levels of the tree, including leaves
* "arity": For each level, the number of children attached to a node. Leaves have no children, hence last level arity must be 0.
* "iter_policy": A policy for iteration on leaves.
*/
int excit_tleaf_init(excit_t it, const ssize_t depth, const ssize_t* arity, const enum tleaf_it_policy_e iter_policy);
#endif #endif
#include "hilbert2d.h"
struct excit_func_table_s excit_hilbert2d_func_table = {
hilbert2d_it_alloc,
hilbert2d_it_free,
hilbert2d_it_copy,
hilbert2d_it_next,
hilbert2d_it_peek,
hilbert2d_it_size,
hilbert2d_it_rewind,
hilbert2d_it_split,
hilbert2d_it_nth,
hilbert2d_it_rank,
hilbert2d_it_pos
};
#define EXCIT_DATA(data, it) \
if(data == NULL) { return EXCIT_EINVAL; } \
do{ \
int err = excit_get_data(data, (void**)(&it)); \
if(err != EXCIT_SUCCESS) { return err; } \
} while(0); \
if(it == NULL){ return EXCIT_EINVAL; }
/* Helper functions from: https://en.wikipedia.org/wiki/Hilbert_curve */
//rotate/flip a quadrant appropriately
static void rot(ssize_t n, ssize_t *x, ssize_t *y, ssize_t rx, ssize_t ry)
{
if (ry == 0) {
if (rx == 1) {
*x = n - 1 - *x;
*y = n - 1 - *y;
}
//Swap x and y
ssize_t t = *x;
*x = *y;
*y = t;
}
}
//convert (x,y) to d
static ssize_t xy2d(ssize_t n, ssize_t x, ssize_t y)
{
ssize_t rx, ry, s, d = 0;
for (s = n / 2; s > 0; s /= 2) {
rx = (x & s) > 0;
ry = (y & s) > 0;
d += s * s * ((3 * rx) ^ ry);
rot(s, &x, &y, rx, ry);
}
return d;
}
//convert d to (x,y)
static void d2xy(ssize_t n, ssize_t d, ssize_t *x, ssize_t *y)
{
ssize_t rx, ry, s, t = d;
*x = *y = 0;
for (s = 1; s < n; s *= 2) {
rx = 1 & (t / 2);
ry = 1 & (t ^ rx);
rot(s, x, y, rx, ry);
*x += s * rx;
*y += s * ry;
t /= 4;
}
}
/* End helper functions */
int hilbert2d_it_alloc(excit_t data)
{
struct hilbert2d_it_s *it;
EXCIT_DATA(data, it);
it->n = 0;
it->range_it = NULL;
return EXCIT_SUCCESS;
}
void hilbert2d_it_free(excit_t data)
{
struct hilbert2d_it_s *it;
if(data == NULL) { return ; }
int err = excit_get_data(data, (void**)(&it));
if(err != EXCIT_SUCCESS) { return; }
if(it == NULL){ return; }
excit_free(it->range_it);
}
int hilbert2d_it_copy(excit_t ddst, const excit_t dsrc)
{
struct hilbert2d_it_s *dst;
EXCIT_DATA(ddst, dst);
const struct hilbert2d_it_s *src;
EXCIT_DATA(dsrc, src);
excit_t copy = excit_dup(src->range_it);
if (!copy)
return -EXCIT_EINVAL;
dst->range_it = copy;
dst->n = src->n;