...
 
Commits (21)
......@@ -2,6 +2,6 @@ AM_CFLAGS = -Wall -Werror -pedantic
lib_LTLIBRARIES = libexcit.la
libexcit_la_SOURCES = excit.c slice.c prod.c cons.c repeat.c hilbert2d.c range.c tleaf.c
libexcit_la_SOURCES = excit.c composition.c prod.c cons.c repeat.c hilbert2d.c range.c tleaf.c
include_HEADERS = excit.h
#include "dev/excit.h"
#include "slice.h"
#include "composition.h"
static int slice_it_alloc(excit_t data)
static int composition_it_alloc(excit_t data)
{
struct slice_it_s *it = (struct slice_it_s *)data->data;
struct composition_it_s *it = (struct composition_it_s *)data->data;
it->src = NULL;
it->indexer = NULL;
return EXCIT_SUCCESS;
}
static void slice_it_free(excit_t data)
static void composition_it_free(excit_t data)
{
struct slice_it_s *it = (struct slice_it_s *)data->data;
struct composition_it_s *it = (struct composition_it_s *)data->data;
excit_free(it->src);
excit_free(it->indexer);
}
static int slice_it_copy(excit_t dst, const excit_t src)
static int composition_it_copy(excit_t dst, const excit_t src)
{
const struct slice_it_s *it = (const struct slice_it_s *)src->data;
struct slice_it_s *result = (struct slice_it_s *)dst->data;
const struct composition_it_s *it = (const struct composition_it_s *)src->data;
struct composition_it_s *result = (struct composition_it_s *)dst->data;
result->src = excit_dup(it->src);
if (!result->src)
......@@ -34,9 +34,9 @@ static int slice_it_copy(excit_t dst, const excit_t src)
return EXCIT_SUCCESS;
}
static int slice_it_next(excit_t data, ssize_t *indexes)
static int composition_it_next(excit_t data, ssize_t *indexes)
{
struct slice_it_s *it = (struct slice_it_s *)data->data;
struct composition_it_s *it = (struct composition_it_s *)data->data;
ssize_t n;
int err = excit_next(it->indexer, &n);
......@@ -45,9 +45,9 @@ static int slice_it_next(excit_t data, ssize_t *indexes)
return excit_nth(it->src, n, indexes);
}
static int slice_it_peek(const excit_t data, ssize_t *indexes)
static int composition_it_peek(const excit_t data, ssize_t *indexes)
{
const struct slice_it_s *it = (const struct slice_it_s *)data->data;
const struct composition_it_s *it = (const struct composition_it_s *)data->data;
ssize_t n;
int err = excit_peek(it->indexer, &n);
......@@ -56,23 +56,23 @@ static int slice_it_peek(const excit_t data, ssize_t *indexes)
return excit_nth(it->src, n, indexes);
}
static int slice_it_size(const excit_t data, ssize_t *size)
static int composition_it_size(const excit_t data, ssize_t *size)
{
const struct slice_it_s *it = (const struct slice_it_s *)data->data;
const struct composition_it_s *it = (const struct composition_it_s *)data->data;
return excit_size(it->indexer, size);
}
static int slice_it_rewind(excit_t data)
static int composition_it_rewind(excit_t data)
{
struct slice_it_s *it = (struct slice_it_s *)data->data;
struct composition_it_s *it = (struct composition_it_s *)data->data;
return excit_rewind(it->indexer);
}
static int slice_it_nth(const excit_t data, ssize_t n, ssize_t *indexes)
static int composition_it_nth(const excit_t data, ssize_t n, ssize_t *indexes)
{
const struct slice_it_s *it = (const struct slice_it_s *)data->data;
const struct composition_it_s *it = (const struct composition_it_s *)data->data;
ssize_t p;
int err = excit_nth(it->indexer, n, &p);
......@@ -81,10 +81,10 @@ static int slice_it_nth(const excit_t data, ssize_t n, ssize_t *indexes)
return excit_nth(it->src, p, indexes);
}
static int slice_it_rank(const excit_t data, const ssize_t *indexes,
static int composition_it_rank(const excit_t data, const ssize_t *indexes,
ssize_t *n)
{
const struct slice_it_s *it = (const struct slice_it_s *)data->data;
const struct composition_it_s *it = (const struct composition_it_s *)data->data;
ssize_t inner_n;
int err = excit_rank(it->src, indexes, &inner_n);
......@@ -93,16 +93,16 @@ static int slice_it_rank(const excit_t data, const ssize_t *indexes,
return excit_rank(it->indexer, &inner_n, n);
}
static int slice_it_pos(const excit_t data, ssize_t *n)
static int composition_it_pos(const excit_t data, ssize_t *n)
{
const struct slice_it_s *it = (const struct slice_it_s *)data->data;
const struct composition_it_s *it = (const struct composition_it_s *)data->data;
return excit_pos(it->indexer, n);
}
static int slice_it_split(const excit_t data, ssize_t n, excit_t *results)
static int composition_it_split(const excit_t data, ssize_t n, excit_t *results)
{
const struct slice_it_s *it = (const struct slice_it_s *)data->data;
const struct composition_it_s *it = (const struct composition_it_s *)data->data;
int err = excit_split(it->indexer, n, results);
if (err)
......@@ -114,7 +114,7 @@ static int slice_it_split(const excit_t data, ssize_t n, excit_t *results)
excit_t tmp2;
tmp = results[i];
results[i] = excit_alloc(EXCIT_SLICE);
results[i] = excit_alloc(EXCIT_COMPOSITION);
if (!results[i]) {
excit_free(tmp);
err = -EXCIT_ENOMEM;
......@@ -126,7 +126,7 @@ static int slice_it_split(const excit_t data, ssize_t n, excit_t *results)
err = -EXCIT_ENOMEM;
goto error;
}
err = excit_slice_init(results[i], tmp2, tmp);
err = excit_composition_init(results[i], tmp2, tmp);
if (err) {
excit_free(tmp);
excit_free(tmp2);
......@@ -140,26 +140,26 @@ error:
return err;
}
struct excit_func_table_s excit_slice_func_table = {
slice_it_alloc,
slice_it_free,
slice_it_copy,
slice_it_next,
slice_it_peek,
slice_it_size,
slice_it_rewind,
slice_it_split,
slice_it_nth,
slice_it_rank,
slice_it_pos
struct excit_func_table_s excit_composition_func_table = {
composition_it_alloc,
composition_it_free,
composition_it_copy,
composition_it_next,
composition_it_peek,
composition_it_size,
composition_it_rewind,
composition_it_split,
composition_it_nth,
composition_it_rank,
composition_it_pos
};
int excit_slice_init(excit_t it, excit_t src, excit_t indexer)
int excit_composition_init(excit_t it, excit_t src, excit_t indexer)
{
if (!it || it->type != EXCIT_SLICE || !src || !indexer
if (!it || it->type != EXCIT_COMPOSITION || !src || !indexer
|| indexer->dimension != 1)
return -EXCIT_EINVAL;
struct slice_it_s *slice_it = (struct slice_it_s *)it->data;
struct composition_it_s *composition_it = (struct composition_it_s *)it->data;
ssize_t size_src;
ssize_t size_indexer;
int err = excit_size(src, &size_src);
......@@ -171,8 +171,8 @@ int excit_slice_init(excit_t it, excit_t src, excit_t indexer)
return err;
if (size_indexer > size_src)
return -EXCIT_EDOM;
slice_it->src = src;
slice_it->indexer = indexer;
composition_it->src = src;
composition_it->indexer = indexer;
it->dimension = src->dimension;
return EXCIT_SUCCESS;
}
......
......@@ -4,12 +4,12 @@
#include "excit.h"
#include "dev/excit.h"
struct slice_it_s {
struct composition_it_s {
excit_t src;
excit_t indexer;
};
extern struct excit_func_table_s excit_slice_func_table;
extern struct excit_func_table_s excit_composition_func_table;
#endif //EXCIT_SLICE_H
#include <stdlib.h>
#include "excit.h"
#include "dev/excit.h"
#include "slice.h"
#include "composition.h"
#include "prod.h"
#include "cons.h"
#include "repeat.h"
......@@ -19,7 +19,7 @@ const char *excit_type_name(enum excit_type_e type)
CASE(EXCIT_REPEAT);
CASE(EXCIT_HILBERT2D);
CASE(EXCIT_PRODUCT);
CASE(EXCIT_SLICE);
CASE(EXCIT_COMPOSITION);
CASE(EXCIT_USER);
CASE(EXCIT_TYPE_MAX);
default:
......@@ -115,8 +115,8 @@ excit_t excit_alloc(enum excit_type_e type)
case EXCIT_PRODUCT:
ALLOC_EXCIT(prod);
break;
case EXCIT_SLICE:
ALLOC_EXCIT(slice);
case EXCIT_COMPOSITION:
ALLOC_EXCIT(composition);
break;
case EXCIT_TLEAF:
ALLOC_EXCIT(tleaf);
......@@ -270,12 +270,12 @@ int excit_split(const excit_t it, ssize_t n, excit_t *results)
if (!tmp)
goto error2;
tmp2 = results[i];
results[i] = excit_alloc(EXCIT_SLICE);
results[i] = excit_alloc(EXCIT_COMPOSITION);
if (!results[i]) {
excit_free(tmp2);
goto error2;
}
err = excit_slice_init(results[i], tmp, tmp2);
err = excit_composition_init(results[i], tmp, tmp2);
if (err) {
excit_free(tmp2);
goto error2;
......
......@@ -4,20 +4,87 @@
#include <stdlib.h>
/*
* The different types of iterator supported. All iterators use the same
* integer type (ssize_t) for values.
* excit library provides an interface to build multi-dimensional iterators over
* indexes.
* excit iterators walk an array of n elements indexed from 0 to n-1,
* and returns the aforementionned elements.
* excit return elements which type can only be an index of type ssize_t,
* or an array of indexes (a multi-dimensional index) if the defined iterator
* has several dimensions. ssize_t elements can fit pointers. Thus, it makes
* excit library the ideal tool box for indexing and ealking complex structures.
*
* excit implements its own interface with several iterators (see excit_type_e).
* For instance, excit implementation of product iterators enable to mix iterators
* to create more complex ones. The library balanced tree "tleaf" iterator is built
* on top of product iterator.
*
* excit library uses the concept of "ownership".
* An excit iterator has the ownership of its internal data, i.e it will free
* its owned data upon call to excit_free(). This ownership
* may be transferred to another iterator through a library function such as
* excit_cons_init() or excit_product_add().
* Thus ownership must be carefully watched to avoid memory leaks or double free.
*
* excit library provides a rank function to find the index given an element.
*/
enum excit_type_e {
EXCIT_INVALID, /*!< Tag for invalid iterators */
EXCIT_RANGE, /*!< Iterator over a range of values */
EXCIT_CONS, /*!< Sliding window iterator */
EXCIT_REPEAT, /*!< Ierator that stutters a certain amount of times */
EXCIT_HILBERT2D, /*!< Hilbert space filing curve */
EXCIT_PRODUCT, /*!< Iterator over the catesian product of iterators */
EXCIT_SLICE, /*!< Iterator using another iterator to index a third */
EXCIT_TLEAF, /*!< Iterator on tree leaves with all leaves at same depth */
EXCIT_USER, /*!< User-defined iterator */
EXCIT_TYPE_MAX /*!< Guard */
/*!< Tag for invalid iterators */
EXCIT_INVALID,
/*!<
* Iterator over a range of values.
* See function excit_range_init for further details on iterator
* behaviour.
*/
EXCIT_RANGE,
/*!<
* Sliding window iterator
* See function excit_cons_init for further details on iterator
* behaviour.
*/
EXCIT_CONS,
/*!<
* Iterator that stutters a certain amount of times.
* Builds an iterator on top of another iterator repeating the latter elements.
* See function excit_repeat_init() for further details on iterator
* behaviour.
*/
EXCIT_REPEAT,
/*!< Hilbert space filing curve */
EXCIT_HILBERT2D,
/*!<
* Iterator over the catesian product of iterators.
* The result iterator dimension is the sum of of input iterator dimensions.
*/
EXCIT_PRODUCT,
/*!<
* Iterator composing two iterators,
* i.e using an iterator to index another.
* It is possible to chain composition iterators as long as
* input and output sets are compatible.
* (Only dimension compatibility is not enforced by the library).
* It is straightforward to build a composition iterator by composing two range iterators.
*/
EXCIT_COMPOSITION,
/*!<
* Iterator on balanced tree leaves.
* The iterator walks an index of leaves according to a policy.
* tleaf iterator has a special tleaf_it_split() for splitting the
* tree at a specific level.
* See tleaf_it_policy_e and excit_tleaf_init() for further explaination.
*/
EXCIT_TLEAF,
/*!<
* User-defined iterator
* excit library allow users to define their own iterator.
* To do so, they need to populate the function table excit_func_table_s
* with the routines to manipulate the aforementionned iterator.
* The outcome is that they will enjoy the functionnalities of the library
* for mixing with other iterators.
*/
EXCIT_USER,
/*!< Guard */
EXCIT_TYPE_MAX
};
/*
......@@ -96,6 +163,8 @@ struct excit_func_table_s {
/*
* This funciton is called during excit_dup. It is responsible for
* duplicating the content of the inner data between src_it and dst_it.
* The internal state of the iterator must also be copied, i.e subsequent
* calls to excit_next() must return the same results for both iterators.
* Returns EXCIT_SUCCESS or an error code.
*/
int (*copy)(excit_t dst_it, const excit_t src_it);
......@@ -185,7 +254,7 @@ excit_t excit_alloc_user(struct excit_func_table_s *func_table,
size_t data_size);
/*
* Duplicates an iterator.
* Duplicates an iterator and keep its internal state.
* "it": iterator to duplicate.
* Returns an iterator that will need to be freed unless ownership is
* transfered or NULL if an error occured.
......@@ -262,7 +331,8 @@ int excit_size(const excit_t it, ssize_t *size);
int excit_split(const excit_t it, ssize_t n, excit_t *results);
/*
* Gets the nth element of an iterator.
* Gets the nth element of an iterator. If an iterator has k dimensions,
* then the nth element is an array of k nth elements along each dimension.
* "it": an iterator.
* "rank": rank of the element, comprised between 0 and the size of the
* iterator.
......@@ -273,14 +343,17 @@ int excit_split(const excit_t it, ssize_t n, excit_t *results);
int excit_nth(const excit_t it, ssize_t rank, ssize_t *indexes);
/*
* Gets the rank of an element of an iterator.
* Gets the rank of an element of an iterator. The rank of an element is its
* iteration index, i.e excit_nth(excit_rank(element)) should return element.
* If the iterator has k dimensions, element is an array of the k values
* composing element.
* "it": an iterator.
* "indexes": an array of indexes corresponding to the element of the iterator.
* "rank": a pointer to a variable where the result will be stored, no result is
* returned if NULL.
* Returns EXCIT_SUCCESS or an error code.
*/
int excit_rank(const excit_t it, const ssize_t *indexes, ssize_t *rank);
int excit_rank(const excit_t it, const ssize_t *element, ssize_t *rank);
/*
* Gets the position of the iterator.
......@@ -311,7 +384,7 @@ int excit_skip(excit_t it);
int excit_cyclic_next(excit_t it, ssize_t *indexes, int *looped);
/*
* Initializes a range iterator to iterate from first to last (included) by sep.
* Initializes a range iterator to iterate from first to last (included) by step.
* "it": a range iterator.
* "first": first value of the range.
* "last": last value of the range.
......@@ -398,13 +471,13 @@ int excit_product_split_dim(const excit_t it, ssize_t dim, ssize_t n,
excit_t *results);
/*
* Initializes a slice iterator by giving asrc iterator and an indexer iterator.
* "it": a slice iterator.
* Initializes a composition iterator by giving a src iterator and an indexer iterator.
* "it": a composition iterator.
* "src": the iterator whom elements are to be returned.
* "indexer": the iterator that will provide the rank of the elements to return.
* Returns EXCIT_SUCCESS or an error code.
*/
int excit_slice_init(excit_t it, excit_t src, excit_t indexer);
int excit_composition_init(excit_t it, excit_t src, excit_t indexer);
enum tleaf_it_policy_e {
TLEAF_POLICY_ROUND_ROBIN, /* Iterate on tree leaves in a round-robin fashion */
......@@ -414,28 +487,41 @@ enum tleaf_it_policy_e {
/*
* Initialize a tleaf iterator by giving its depth, levels arity and iteration policy.
* example building a user scatter policy:
* excit_tleaf_init(it, 4, {3, 2, 4}, TLEAF_POLICY_USER, {2, 1, 0});
* gives the output index:
* 0,6,12,18,3,9,15,21,1,7,13,19,4,10,16,22,2,8,14,20,5,11,17,23.
* "it": a tleaf iterator
* "depth": the total number of levels of the tree, including leaves
* "arity": An array of size (depth-1). For each level, the number of children attached to a node. Leaves have no children, hence last level arity is ignored. Arities are organized from root to leaves.
* "arity": An array of size (depth-1). For each level, the number of children attached to a node.
* Leaves have no children. Arities are organized from root to leaves.
* "index": NULL or an array of depth excit_t to re-index levels.
* It is intended to prune node of certain levels while keeping index of the initial structure.
* Ownership of index is not taken. The iterator allocates a copy of index and manage it internally.
* "policy": A policy for iteration on leaves.
* "user_policy": If policy is TLEAF_POLICY_USER, then this argument must be an array of size (depth-1) providing the order (from 0 to (depth-2)) in wich levels are walked.
* when resolving indexes. Underneath, a product iterator of range iterator returns indexes on last levels upon iterator queries. This set of indexes is then
* computed to a single leaf index. For instance TLEAF_POLICY_ROUND_ROBIN is obtained from walking from leaves to root whereas TLEAF_POLICY_SCATTER is
* "user_policy": If policy is TLEAF_POLICY_USER, then this argument must be an array of size (depth-1) providing the
* order (from 0 to (depth-2)) in which levels are walked.
* when resolving indexes. Underneath, a product iterator of range iterator returns indexes on last
* levels upon iterator queries. This set of indexes is then
* computed to a single leaf index. For instance TLEAF_POLICY_ROUND_ROBIN is obtained from walking
* from leaves to root whereas TLEAF_POLICY_SCATTER is
* obtained from walking from root to leaves.
*/
int excit_tleaf_init(excit_t it,
const ssize_t depth,
const ssize_t *arities,
const excit_t *index,
const enum tleaf_it_policy_e policy,
const ssize_t *user_policy);
/*
* Split a tree at a given level. The behaviour is different from the generic function excit_split for the split might be sparse.
* Split a tree at a given level. The behaviour is different from the generic function excit_split for the
* split might be sparse, depending on the tree level where the split occures and the number of parts.
* "it": a tleaf iterator.
* "level": The level to split.
* "n": The number of slices. n must divide the target level arity.
* "n": The number of parts. n must divide the target level arity.
* "out": an array of n allocated tleaf iterators.
*/
int tleaf_it_split(const excit_t it, const ssize_t level, const ssize_t n, excit_t *out);
#endif
......@@ -3,6 +3,14 @@
#include "dev/excit.h"
#include "tleaf.h"
static int tleaf_init_with_it(excit_t it,
const ssize_t depth,
const ssize_t *arities,
const excit_t *indexes,
const enum tleaf_it_policy_e policy,
const ssize_t *user_policy,
excit_t levels, excit_t levels_inverse);
static int tleaf_it_alloc(excit_t it)
{
if (it == NULL || it->data == NULL)
......@@ -12,10 +20,11 @@ static int tleaf_it_alloc(excit_t it)
data_it->depth = 0;
data_it->arities = NULL;
data_it->order = NULL;
data_it->order_inverse = NULL;
data_it->buf = NULL;
data_it->order = NULL;
data_it->levels = NULL;
data_it->order_inverse = NULL;
data_it->levels_inverse = NULL;
return EXCIT_SUCCESS;
}
......@@ -24,140 +33,21 @@ static void tleaf_it_free(excit_t it)
struct tleaf_it_s *data_it = it->data;
free(data_it->arities);
free(data_it->order);
free(data_it->order_inverse);
free(data_it->buf);
free(data_it->order);
excit_free(data_it->levels);
}
static int excit_tleaf_init_with_it(excit_t it,
const ssize_t depth,
const ssize_t *arities,
const enum tleaf_it_policy_e policy,
const ssize_t *user_policy, excit_t levels)
{
if (it == NULL || it->data == NULL)
return -EXCIT_EINVAL;
int err = EXCIT_SUCCESS;
struct tleaf_it_s *data_it = it->data;
ssize_t i;
data_it->depth = depth - 1;
/* Set order according to policy */
data_it->order = malloc(sizeof(*data_it->order) * data_it->depth);
if (data_it->order == NULL) {
err = -EXCIT_ENOMEM;
goto error;
}
switch (policy) {
case TLEAF_POLICY_ROUND_ROBIN:
for (i = 0; i < data_it->depth; i++)
data_it->order[i] = data_it->depth - i - 1;
break;
case TLEAF_POLICY_SCATTER:
for (i = 0; i < data_it->depth; i++)
data_it->order[i] = i;
break;
case TLEAF_POLICY_USER:
for (i = 0; i < data_it->depth; i++)
data_it->order[i] = user_policy[i];
break;
default:
err = -EXCIT_EINVAL;
goto error_with_levels;
}
/* Set order inverse */
data_it->order_inverse =
malloc(sizeof(*data_it->order_inverse) * data_it->depth);
if (data_it->order_inverse == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_order;
}
for (i = 0; i < data_it->depth; i++)
data_it->order_inverse[data_it->order[i]] = i;
/* Set levels arity */
data_it->arities = malloc(sizeof(*data_it->arities) * data_it->depth);
if (data_it->arities == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_order_inverse;
}
for (i = 0; i < data_it->depth; i++)
data_it->arities[i] = arities[i];
/* Set storage buffer for output of product iterator */
data_it->buf = malloc(sizeof(*data_it->buf) * data_it->depth);
if (data_it->buf == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_arity;
}
/* Set product iterator if not provided */
if (levels == NULL) {
data_it->levels = excit_alloc(EXCIT_PRODUCT);
if (data_it->levels == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_buf;
}
for (i = 0; i < data_it->depth; i++) {
excit_t level = excit_alloc(EXCIT_RANGE);
if (level == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_levels;
}
err = excit_range_init(level, 0, arities[i] - 1, 1);
if (err != EXCIT_SUCCESS)
goto error_with_levels;
err = excit_product_add(data_it->levels, level);
if (err != EXCIT_SUCCESS)
goto error_with_levels;
}
} else {
data_it->levels = levels;
}
return EXCIT_SUCCESS;
error_with_levels:
excit_free(data_it->levels);
data_it->levels = NULL;
error_with_buf:
free(data_it->buf);
data_it->buf = NULL;
error_with_arity:
free(data_it->arities);
data_it->arities = NULL;
error_with_order_inverse:
free(data_it->order_inverse);
data_it->order_inverse = NULL;
error_with_order:
free(data_it->order);
data_it->order = NULL;
error:
return err;
}
int excit_tleaf_init(excit_t it,
const ssize_t depth,
const ssize_t *arities,
const enum tleaf_it_policy_e policy,
const ssize_t *user_policy)
{
return excit_tleaf_init_with_it(it, depth, arities, policy, user_policy,
NULL);
excit_free(data_it->levels_inverse);
}
static int tleaf_it_size(const excit_t it, ssize_t *size)
{
struct tleaf_it_s *data_it = it->data;
int err = excit_size(data_it->levels, size);
return excit_size(data_it->levels, size);
if (err != EXCIT_SUCCESS)
return err;
return EXCIT_SUCCESS;
}
static int tleaf_it_rewind(excit_t it)
......@@ -180,6 +70,7 @@ static int tleaf_it_copy(excit_t dst_it, const excit_t src_it)
free(dst->order);
free(dst->order_inverse);
excit_free(dst->levels);
excit_free(dst->levels_inverse);
}
/* dst is not initialized (anymore) */
......@@ -190,13 +81,23 @@ static int tleaf_it_copy(excit_t dst_it, const excit_t src_it)
goto error;
}
err = excit_tleaf_init_with_it(dst_it, src->depth + 1, src->arities,
TLEAF_POLICY_USER, src->order, levels);
if (err != EXCIT_SUCCESS)
excit_t levels_inverse = excit_dup(src->levels_inverse);
if (levels_inverse == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_levels;
}
err = tleaf_init_with_it(dst_it, src->depth + 1, src->arities, NULL,
TLEAF_POLICY_USER, src->order, levels,
levels_inverse);
if (err != EXCIT_SUCCESS)
goto error_with_levels_inverse;
return EXCIT_SUCCESS;
error_with_levels_inverse:
excit_free(levels_inverse);
error_with_levels:
excit_free(levels);
error:
......@@ -210,14 +111,14 @@ static int tleaf_it_pos(const excit_t it, ssize_t *value)
return excit_pos(data_it->levels, value);
}
static ssize_t tleaf_it_value(struct tleaf_it_s *it, const int inverse)
static ssize_t tleaf_it_value(struct tleaf_it_s *it)
{
ssize_t i, acc = 1, val = 0;
ssize_t *order = inverse ? it->order_inverse : it->order;
for (i = 0; i < it->depth; i++) {
val += acc * it->buf[order[i]];
acc *= it->arities[order[i]];
/* levels are stacked following order, then decode result backward order_inverse */
val += acc * it->buf[it->order_inverse[it->depth - i - 1]];
acc *= it->arities[it->depth - i - 1];
}
return val;
}
......@@ -229,7 +130,8 @@ int tleaf_it_nth(const excit_t it, ssize_t n, ssize_t *indexes)
if (err != EXCIT_SUCCESS)
return err;
*indexes = tleaf_it_value(data_it, 0);
if (indexes != NULL)
*indexes = tleaf_it_value(data_it);
return EXCIT_SUCCESS;
}
......@@ -240,7 +142,8 @@ int tleaf_it_peek(const excit_t it, ssize_t *value)
if (err != EXCIT_SUCCESS)
return err;
*value = tleaf_it_value(data_it, 0);
if (value != NULL)
*value = tleaf_it_value(data_it);
return EXCIT_SUCCESS;
}
......@@ -251,81 +154,301 @@ int tleaf_it_next(excit_t it, ssize_t *indexes)
if (err != EXCIT_SUCCESS)
return err;
*indexes = tleaf_it_value(data_it, 0);
if (indexes != NULL)
*indexes = tleaf_it_value(data_it);
return EXCIT_SUCCESS;
}
int tleaf_it_rank(const excit_t it, const ssize_t *indexes, ssize_t *n)
{
ssize_t size;
int err;
err = tleaf_it_size(it, &size);
if (err != EXCIT_SUCCESS)
return err;
if (indexes == NULL || *indexes < 0 || *indexes >= size)
return -EXCIT_EINVAL;
struct tleaf_it_s *data_it = it->data;
int err = excit_nth(data_it->levels, *indexes, data_it->buf);
err = excit_nth(data_it->levels_inverse, *indexes, data_it->buf);
if (err != EXCIT_SUCCESS)
return err;
*n = tleaf_it_value(data_it, 1);
ssize_t i, acc = 1, val = 0;
for (i = data_it->depth - 1; i >= 0; i--) {
val += acc * data_it->buf[data_it->order[i]];
acc *= data_it->arities[i];
}
if (n != NULL)
*n = val;
return EXCIT_SUCCESS;
}
int tleaf_it_split(const excit_t it, const ssize_t level,
const ssize_t n, excit_t *out)
int tleaf_it_make_levels(struct tleaf_it_s *tleaf, const excit_t *indexes,
ssize_t *order, excit_t *levels)
{
ssize_t i;
int err;
excit_t index, range, comp;
if (out == NULL)
return EXCIT_SUCCESS;
if (it == NULL || it->data == NULL)
return -EXCIT_EINVAL;
*levels = excit_alloc(EXCIT_PRODUCT);
if (*levels == NULL)
return -EXCIT_ENOMEM;
struct tleaf_it_s *data_it = it->data;
for (i = 0; i < tleaf->depth; i++) {
ssize_t l = order[i];
if (data_it->arities[level] % n != 0)
return -EXCIT_EINVAL;
index = indexes == NULL ? NULL : indexes[l];
range = excit_alloc(EXCIT_RANGE);
if (range == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_levels;
}
err = excit_range_init(range, 0, tleaf->arities[l] - 1, 1);
if (err != EXCIT_SUCCESS)
goto error_with_range;
if (index != NULL) {
comp = excit_alloc(EXCIT_COMPOSITION);
if (comp == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_range;
}
index = excit_dup(index);
if (index == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_comp;
}
err = excit_composition_init(comp, range, index);
if (err != EXCIT_SUCCESS)
goto error_with_index;
err = excit_product_add(*levels, comp);
if (err != EXCIT_SUCCESS)
goto error_with_index;
} else {
err = excit_product_add(*levels, range);
if (err != EXCIT_SUCCESS)
goto error_with_range;
}
}
return EXCIT_SUCCESS;
error_with_index:
excit_free(index);
error_with_comp:
excit_free(comp);
error_with_range:
excit_free(range);
error_with_levels:
excit_free(*levels);
*levels = NULL;
return err;
}
static int tleaf_init_with_it(excit_t it,
const ssize_t depth,
const ssize_t *arities,
const excit_t *indexes,
const enum tleaf_it_policy_e policy,
const ssize_t *user_policy,
excit_t levels, excit_t levels_inverse)
{
if (it == NULL || it->data == NULL)
return -EXCIT_EINVAL;
int err = EXCIT_SUCCESS;
excit_t *levels = malloc(sizeof(*levels) * n);
struct tleaf_it_s *data_it = it->data;
ssize_t i;
if (levels == NULL) {
data_it->depth = depth - 1;
/* Set order according to policy */
data_it->order = malloc(sizeof(*data_it->order) * data_it->depth);
if (data_it->order == NULL) {
err = -EXCIT_ENOMEM;
goto error;
}
switch (policy) {
case TLEAF_POLICY_ROUND_ROBIN:
for (i = 0; i < data_it->depth; i++)
data_it->order[i] = i;
break;
case TLEAF_POLICY_SCATTER:
for (i = 0; i < data_it->depth; i++)
data_it->order[i] = data_it->depth - i - 1;
break;
case TLEAF_POLICY_USER:
for (i = 0; i < data_it->depth; i++)
data_it->order[i] = user_policy[i];
break;
default:
err = -EXCIT_EINVAL;
goto error_with_order;
}
/* Set order inverse */
data_it->order_inverse =
malloc(sizeof(*data_it->order_inverse) * data_it->depth);
if (data_it->order_inverse == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_order;
}
for (i = 0; i < data_it->depth; i++)
data_it->order_inverse[data_it->order[i]] = i;
/* Set levels arity. */
data_it->arities = malloc(sizeof(*data_it->arities) * data_it->depth);
if (data_it->arities == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_order_inverse;
}
for (i = 0; i < data_it->depth; i++)
data_it->arities[i] = arities[i];
/* Set storage buffer for output of product iterator */
data_it->buf = malloc(sizeof(*data_it->buf) * data_it->depth);
if (data_it->buf == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_arity;
}
/* Set product iterator if not provided */
data_it->levels = levels;
data_it->levels_inverse = levels_inverse;
if (levels == NULL)
err =
tleaf_it_make_levels(data_it, indexes, data_it->order,
&(data_it->levels));
if (err != EXCIT_SUCCESS)
goto error_with_buf;
err = excit_product_split_dim(data_it->levels, level, n, levels);
if (levels_inverse == NULL)
err =
tleaf_it_make_levels(data_it, indexes,
data_it->order_inverse,
&(data_it->levels_inverse));
if (err != EXCIT_SUCCESS)
goto error_with_levels;
ssize_t *arities = malloc(sizeof(*arities) * data_it->depth);
return EXCIT_SUCCESS;
if (arities == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_levels_initialized;
error_with_levels:
excit_free(data_it->levels);
data_it->levels = NULL;
error_with_buf:
free(data_it->buf);
data_it->buf = NULL;
error_with_arity:
free(data_it->arities);
data_it->arities = NULL;
error_with_order_inverse:
free(data_it->order_inverse);
data_it->order_inverse = NULL;
error_with_order:
free(data_it->order);
data_it->order = NULL;
error:
return err;
}
int excit_tleaf_init(excit_t it,
const ssize_t depth,
const ssize_t *arities,
const excit_t *indexes,
const enum tleaf_it_policy_e policy,
const ssize_t *user_policy)
{
return tleaf_init_with_it(it, depth, arities, indexes, policy,
user_policy, NULL, NULL);
}
int tleaf_split_levels(excit_t levels, const ssize_t depth, const ssize_t n,
excit_t **out)
{
*out = malloc(sizeof(**out) * n);
if (*out == NULL)
return -EXCIT_ENOMEM;
int err = excit_product_split_dim(levels, depth, n, *out);
if (err != EXCIT_SUCCESS) {
free(*out);
*out = NULL;
return err;
}
return EXCIT_SUCCESS;
}
for (i = 0; i < data_it->depth; i++)
arities[i] = data_it->arities[i];
/* arities[level] /= n; */
int tleaf_it_split(const excit_t it, const ssize_t depth,
const ssize_t n, excit_t *out)
{
ssize_t i;
if (out == NULL)
return EXCIT_SUCCESS;
if (it == NULL || it->data == NULL)
return -EXCIT_EINVAL;
struct tleaf_it_s *data_it = it->data;
if (data_it->arities[depth] % n != 0)
return -EXCIT_EINVAL;
if (out == NULL)
return EXCIT_SUCCESS;
int err;
excit_t *levels, *levels_inverse;
err =
tleaf_split_levels(data_it->levels, data_it->order[depth], n,
&levels);
if (err != EXCIT_SUCCESS)
return err;
err =
tleaf_split_levels(data_it->levels_inverse,
data_it->order_inverse[depth], n,
&levels_inverse);
if (err != EXCIT_SUCCESS)
goto error_with_levels;
for (i = 0; i < n; i++) {
err = excit_tleaf_init_with_it(out[i],
data_it->depth + 1,
arities,
TLEAF_POLICY_USER,
data_it->order, levels[i]);
out[i] = excit_alloc(EXCIT_TLEAF);
if (out == NULL) {
err = -EXCIT_ENOMEM;
goto error_with_levels_inverse;
}
err = tleaf_init_with_it(out[i],
data_it->depth + 1,
data_it->arities,
NULL,
TLEAF_POLICY_USER,
data_it->order, levels[i],
levels_inverse[i]);
if (err != EXCIT_SUCCESS)
goto error_with_arity;
goto error_with_levels_inverse;
}
free(levels);
free(arities);
free(levels_inverse);
return EXCIT_SUCCESS;
error_with_arity:
free(arities);
error_with_levels_initialized:
error_with_levels_inverse:
for (i = 0; i < n; i++)
excit_free(levels[i]);
excit_free(levels_inverse[i]);
free(levels_inverse);
error_with_levels:
for (i = 0; i < n; i++)
excit_free(levels[i]);
free(levels);
error:
return err;
}
......
......@@ -6,10 +6,11 @@
struct tleaf_it_s {
ssize_t depth;
ssize_t *arities;
ssize_t *order;
ssize_t *order_inverse;
ssize_t *buf;
ssize_t *order;
excit_t levels;
ssize_t *order_inverse;
excit_t levels_inverse;
};
extern struct excit_func_table_s excit_tleaf_func_table;
......
......@@ -10,10 +10,11 @@ excit_range_SOURCES = $(LIBHSOURCES) $(LIBCSOURCES) excit_range.c
excit_product_SOURCES = $(LIBHSOURCES) $(LIBCSOURCES) excit_product.c
excit_repeat_SOURCES = $(LIBHSOURCES) $(LIBCSOURCES) excit_repeat.c
excit_cons_SOURCES = $(LIBHSOURCES) $(LIBCSOURCES) excit_cons.c
excit_tleaf_SOURCES = $(LIBHSOURCES) $(LIBCSOURCES) excit_tleaf.c
excit_hilbert2d_SOURCES = $(LIBHSOURCES) $(LIBCSOURCES) excit_hilbert2d.c
excit_slice_SOURCES = $(LIBHSOURCES) $(LIBCSOURCES) excit_slice.c
excit_composition_SOURCES = $(LIBHSOURCES) $(LIBCSOURCES) excit_composition.c
UNIT_TESTS = excit_range excit_product excit_repeat excit_cons excit_hilbert2d excit_slice
UNIT_TESTS = excit_range excit_product excit_repeat excit_cons excit_hilbert2d excit_composition excit_tleaf
# all tests
check_PROGRAMS = $(UNIT_TESTS)
......
......@@ -15,16 +15,16 @@ excit_t create_test_range(ssize_t start, ssize_t stop, ssize_t step)
return it;
}
void test_alloc_init_slice(excit_t source, excit_t indexer)
void test_alloc_init_composition(excit_t source, excit_t indexer)
{
excit_t it;
ssize_t dim, expected_dim, size, expected_size;
it = excit_alloc_test(EXCIT_SLICE);
it = excit_alloc_test(EXCIT_COMPOSITION);
assert(excit_dimension(it, &dim) == ES);
assert(dim == 0);
assert(excit_slice_init(it, excit_dup(source), excit_dup(indexer)) ==
assert(excit_composition_init(it, excit_dup(source), excit_dup(indexer)) ==
ES);
assert(excit_dimension(it, &dim) == ES);
assert(excit_dimension(source, &expected_dim) == ES);
......@@ -36,19 +36,19 @@ void test_alloc_init_slice(excit_t source, excit_t indexer)
excit_free(it);
}
excit_t create_test_slice(excit_t source, excit_t indexer)
excit_t create_test_composition(excit_t source, excit_t indexer)
{
excit_t it;
it = excit_alloc_test(EXCIT_SLICE);
assert(excit_slice_init(it, excit_dup(source), excit_dup(indexer)) ==
it = excit_alloc_test(EXCIT_COMPOSITION);
assert(excit_composition_init(it, excit_dup(source), excit_dup(indexer)) ==
ES);
return it;
}
void test_next_slice(excit_t source, excit_t indexer)
void test_next_composition(excit_t source, excit_t indexer)
{
excit_t it = create_test_slice(source, indexer);
excit_t it = create_test_composition(source, indexer);
excit_t iit = excit_dup(indexer);
......@@ -73,16 +73,16 @@ void test_next_slice(excit_t source, excit_t indexer)
excit_free(iit);
}
void test_slice_iterator(excit_t source, excit_t indexer)
void test_composition_iterator(excit_t source, excit_t indexer)
{
test_alloc_init_slice(source, indexer);
test_alloc_init_composition(source, indexer);
test_next_slice(source, indexer);
test_next_composition(source, indexer);
int i = 0;
while (synthetic_tests[i]) {
excit_t it = create_test_slice(source, indexer);
excit_t it = create_test_composition(source, indexer);
synthetic_tests[i] (it);
excit_free(it);
......@@ -96,13 +96,13 @@ int main(int argc, char *argv[])
source = create_test_range(-15, 14, 2);
indexer = create_test_range(4, 12, 3);
test_slice_iterator(source, indexer);
test_composition_iterator(source, indexer);
source2 = excit_alloc_test(EXCIT_PRODUCT);
assert(excit_product_add(source2, create_test_range(-15, 14, 2)) == ES);
assert(excit_product_add(source2, create_test_range(4, 12, 3)) == ES);
indexer2 = create_test_range(4, 35, 2);
test_slice_iterator(source2, indexer2);
test_composition_iterator(source2, indexer2);
excit_free(source);
excit_free(source2);
......
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "excit.h"
#include "excit_test.h"
static excit_t create_test_tleaf(const ssize_t depth,
const ssize_t *arities,
excit_t *indexes,
const enum tleaf_it_policy_e policy,
const ssize_t *user_policy)
{
int err = EXCIT_SUCCESS;
excit_t it;
it = excit_alloc_test(EXCIT_TLEAF);
assert(it != NULL);
err =
excit_tleaf_init(it, depth + 1, arities, indexes, policy,
user_policy);
assert(err == EXCIT_SUCCESS);
ssize_t i, size = 1, it_size, arity;
for (i = 0; i < depth; i++) {
if (indexes && indexes[i])
assert(excit_size(indexes[i], &arity) == EXCIT_SUCCESS);
else
arity = arities[i];
size *= arity;
}
assert(excit_size(it, &it_size) == EXCIT_SUCCESS);
assert(it_size == size);
return it;
}
static void tleaf_test_round_robin_policy(excit_t tleaf)
{
ssize_t i, value, size;
assert(excit_size(tleaf, &size) == EXCIT_SUCCESS);
assert(excit_rewind(tleaf) == EXCIT_SUCCESS);
for (i = 0; i < size; i++) {
assert(excit_next(tleaf, &value) == EXCIT_SUCCESS);
assert(value == i);
}
assert(excit_next(tleaf, &value) == EXCIT_STOPIT);
}
static void tleaf_test_indexed_round_robin_policy(excit_t tleaf,
const ssize_t depth,
const ssize_t *arities,
excit_t *_indexes)
{
ssize_t i, j, value, indexed_value, indexed_mul, size, arity;
ssize_t *values = malloc(depth * sizeof(*values));
excit_t check = excit_alloc(EXCIT_PRODUCT);
assert(values != NULL);
assert(check != NULL);
for (i = 0; i < depth; i++) {
excit_t range = excit_alloc(EXCIT_RANGE);
assert(range != NULL);
assert(excit_range_init(range, 0, arities[i] - 1, 1) ==
EXCIT_SUCCESS);
if (_indexes[i] != NULL) {
excit_t comp = excit_alloc(EXCIT_COMPOSITION);
assert(comp != NULL);
excit_t index = excit_dup(_indexes[i]);
assert(index != NULL);
assert(excit_rewind(index) == EXCIT_SUCCESS);
assert(excit_composition_init(comp, range, index) ==
EXCIT_SUCCESS);
assert(excit_product_add(check, comp) == EXCIT_SUCCESS);
} else {
assert(excit_product_add(check, range) ==
EXCIT_SUCCESS);
}
}
assert(excit_size(tleaf, &size) == EXCIT_SUCCESS);
assert(excit_rewind(tleaf) == EXCIT_SUCCESS);
assert(excit_rewind(check) == EXCIT_SUCCESS);
for (i = 0; i < size; i++) {
assert(excit_next(tleaf, &value) == EXCIT_SUCCESS);
assert(excit_next(check, values) == EXCIT_SUCCESS);
indexed_value = 0;
indexed_mul = 1;
for (j = 0; j < depth; j++) {
arity = arities[depth - j - 1];
indexed_value += indexed_mul * values[depth - j - 1];
indexed_mul *= arity;
}
assert(value == indexed_value);
}
excit_free(check);
free(values);
}
static void tleaf_test_scatter_policy_no_split(excit_t tleaf,
const ssize_t depth,
const ssize_t *arities)
{
ssize_t i, j, r, n, c, value, val, size;
assert(excit_size(tleaf, &size) == EXCIT_SUCCESS);
assert(excit_rewind(tleaf) == EXCIT_SUCCESS);
for (i = 0; i < size; i++) {
c = i;
n = size;
val = 0;
assert(excit_next(tleaf, &value) == EXCIT_SUCCESS);
for (j = 0; j < depth; j++) {
r = c % arities[j];
n = n / arities[j];
c = c / arities[j];
val += n * r;
}
assert(value == val);
}
assert(excit_next(tleaf, &value) == EXCIT_STOPIT);
}
static void tleaf_test_round_robin_split(excit_t tleaf,
const ssize_t depth,
const ssize_t *arities)
{
ssize_t i, value, size, cut_size;
ssize_t ncut = arities[0];
assert(excit_size(tleaf, &size) == EXCIT_SUCCESS);
cut_size = size / ncut;
excit_t *split = malloc(sizeof(*split) * ncut);
assert(split != NULL);
int err = tleaf_it_split(tleaf, 0, ncut, split);
assert(err == EXCIT_SUCCESS);
ssize_t *cut_sizes = malloc(sizeof(*cut_sizes) * ncut);
assert(cut_sizes != NULL);
for (i = 0; i < ncut; i++) {
assert(excit_size(split[i], cut_sizes + i) == EXCIT_SUCCESS);
assert(cut_sizes[i] == cut_size);
}
for (i = 0; i < size; i++) {
excit_t it = split[i * ncut / size];
assert(excit_next(it, &value) == EXCIT_SUCCESS);
assert(value == i);
}
for (i = 0; i < ncut; i++)
excit_free(split[i]);
free(split);
free(cut_sizes);
}
void run_tests(const ssize_t depth, const ssize_t *arities)
{
/* Test of round robin policy */
excit_t rrobin =
create_test_tleaf(depth, arities, NULL, TLEAF_POLICY_ROUND_ROBIN,
NULL);
assert(rrobin != NULL);
tleaf_test_round_robin_policy(rrobin);
assert(excit_rewind(rrobin) == EXCIT_SUCCESS);
/* Test of split operation on round robin policy */
tleaf_test_round_robin_split(rrobin, depth, arities);
excit_free(rrobin);
/* Test of indexing on a round robin policy */
ssize_t i;
excit_t *indexes = malloc(depth * sizeof(*indexes));
assert(indexes != NULL);
for (i = 0; i < depth; i++) {
if (arities[i] > 2) {
indexes[i] = excit_alloc(EXCIT_RANGE);
assert(indexes[i] != NULL);
assert(excit_range_init
(indexes[i], 0, arities[i] / 2 - 1,
1) == EXCIT_SUCCESS);
} else {
indexes[i] = NULL;
}
}
excit_t indexed_rrobin =
create_test_tleaf(depth, arities, indexes, TLEAF_POLICY_ROUND_ROBIN,
NULL);
assert(indexed_rrobin != NULL);
tleaf_test_indexed_round_robin_policy(indexed_rrobin, depth, arities,
indexes);
excit_free(indexed_rrobin);
for (i = 0; i < depth; i++)
excit_free(indexes[i]);
free(indexes);
/* Test of scatter policy */
excit_t scatter =
create_test_tleaf(depth, arities, NULL, TLEAF_POLICY_SCATTER, NULL);
assert(scatter != NULL);
tleaf_test_scatter_policy_no_split(scatter, depth, arities);
excit_free(scatter);
/* Generic iterator tests */
i = 0;
while (synthetic_tests[i]) {
excit_t it =
create_test_tleaf(depth, arities, NULL,
TLEAF_POLICY_ROUND_ROBIN,
NULL);
synthetic_tests[i] (it);
excit_free(it);
i++;
}
}
int main(int argc, char *argv[])
{
ssize_t depth = 4;
const ssize_t arities_0[4] = { 4, 8, 2, 4 };
run_tests(depth, arities_0);
depth = 8;
const ssize_t arities_1[8] = { 4, 6, 2, 4, 3, 6, 2, 9 };
run_tests(depth, arities_1);
return 0;
}