isl_qpolynomial_fold: use isl_qpolynomial_list to represent list of polynomials
authorSven Verdoolaege <sven.verdoolaege@gmail.com>
Fri, 4 Sep 2020 10:14:25 +0000 (4 12:14 +0200)
committerSven Verdoolaege <sven.verdoolaege@gmail.com>
Thu, 31 Dec 2020 13:56:38 +0000 (31 14:56 +0100)
When isl_qpolynomial_fold was introduced in isl-0.01-303-g92cc4b47ef
(add isl_pw_qpolynomial_fold, Mon Mar 8 15:04:57 2010 +0100),
the generic list infrastructure of isl-0.06-145-g93bcc60cff
(generalize isl_basic_set_list to generic lists,
Sat Apr 16 14:40:23 2011 +0200) was not yet available.
In fact the isl_fold_list enum value suggests that
isl_qpolynomial_fold was also intended to be used to represent
a list of polynomials.
In any case, using isl_qpolynomial_list reuses
the generic infrastructure, avoiding some code duplication.

Signed-off-by: Sven Verdoolaege <sven.verdoolaege@gmail.com>
isl_fold.c
isl_output.c
isl_polynomial_private.h

index f1387dd..5bf36d6 100644 (file)
@@ -41,32 +41,33 @@ enum isl_fold isl_fold_type_negate(enum isl_fold type)
        isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort());
 }
 
+/* Construct a new reduction with the given type, domain space and
+ * list of polynomials.
+ */
 static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc(
-       enum isl_fold type, __isl_take isl_space *space, int n)
+       enum isl_fold type, __isl_take isl_space *space,
+       __isl_take isl_qpolynomial_list *list)
 {
        isl_ctx *ctx;
        isl_qpolynomial_fold *fold;
 
-       if (!space)
+       if (type < 0 || !space || !list)
                goto error;
 
        ctx = isl_space_get_ctx(space);
-       isl_assert(ctx, n >= 0, goto error);
-       fold = isl_calloc(ctx, struct isl_qpolynomial_fold,
-                       sizeof(struct isl_qpolynomial_fold) +
-                       (n - 1) * sizeof(struct isl_qpolynomial *));
+       fold = isl_calloc_type(ctx, struct isl_qpolynomial_fold);
        if (!fold)
                goto error;
 
        fold->ref = 1;
-       fold->size = n;
-       fold->n = 0;
        fold->type = type;
        fold->dim = space;
+       fold->list = list;
 
        return fold;
 error:
        isl_space_free(space);
+       isl_qpolynomial_list_free(list);
        return NULL;
 }
 
@@ -155,32 +156,107 @@ __isl_give isl_space *isl_qpolynomial_fold_get_space(
        return space;
 }
 
-__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
-       __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space)
+/* Return the list of polynomials in the reduction "fold".
+ */
+__isl_keep isl_qpolynomial_list *isl_qpolynomial_fold_peek_list(
+       __isl_keep isl_qpolynomial_fold *fold)
 {
-       int i;
+       return fold ? fold->list : NULL;
+}
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold || !space)
+/* Return a copy of the list of polynomials in the reduction "fold".
+ */
+static __isl_give isl_qpolynomial_list *isl_qpolynomial_fold_get_list(
+       __isl_keep isl_qpolynomial_fold *fold)
+{
+       return isl_qpolynomial_list_copy(isl_qpolynomial_fold_peek_list(fold));
+}
+
+/* Return the list of polynomials of "fold".
+ * This may be either a copy or the list itself
+ * if there is only one reference to "fold".
+ * This allows the list to be modified inplace
+ * if both the expression and its list have only a single reference.
+ * The caller is not allowed to modify "fold" between this call and
+ * a subsequent call to isl_qpolynomial_fold_restore_list.
+ * The only exception is that isl_qpolynomial_fold_free can be called instead.
+ */
+static __isl_give isl_qpolynomial_list *isl_qpolynomial_fold_take_list(
+       __isl_keep isl_qpolynomial_fold *fold)
+{
+       isl_qpolynomial_list *list;
+
+       if (!fold)
+               return NULL;
+       if (fold->ref != 1)
+               return isl_qpolynomial_fold_get_list(fold);
+       list = fold->list;
+       fold->list = NULL;
+       return list;
+}
+
+/* Set the space of the list of polynomials of "fold" to "space",
+ * where the list of polynomials of "fold" may be missing
+ * due to a preceding call to isl_qpolynomial_fold_take_list.
+ * However, in this case, "fold" only has a single reference and
+ * then the call to isl_qpolynomial_fold_cow has no effect.
+ */
+static __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_restore_list(
+       __isl_keep isl_qpolynomial_fold *fold,
+       __isl_take isl_qpolynomial_list *list)
+{
+       if (!fold || !list)
                goto error;
 
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_reset_domain_space(fold->qp[i],
-                                                       isl_space_copy(space));
-               if (!fold->qp[i])
-                       goto error;
+       if (fold->list == list) {
+               isl_qpolynomial_list_free(list);
+               return fold;
        }
 
-       isl_space_free(isl_qpolynomial_fold_take_domain_space(fold));
-       fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
+       fold = isl_qpolynomial_fold_cow(fold);
+       if (!fold)
+               goto error;
+       isl_qpolynomial_list_free(fold->list);
+       fold->list = list;
 
        return fold;
 error:
        isl_qpolynomial_fold_free(fold);
-       isl_space_free(space);
+       isl_qpolynomial_list_free(list);
        return NULL;
 }
 
+/* isl_qpolynomial_list_map callback that calls
+ * isl_qpolynomial_reset_domain_space on "qp".
+ */
+static __isl_give isl_qpolynomial *reset_domain_space(
+       __isl_take isl_qpolynomial *qp, void *user)
+{
+       isl_space *space = user;
+
+       return isl_qpolynomial_reset_domain_space(qp, isl_space_copy(space));
+}
+
+/* Replace the domain space of "fold" by "space".
+ *
+ * Replace the domain space itself and that of all polynomials
+ * in the list.
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
+       __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space)
+{
+       isl_qpolynomial_list *list;
+
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &reset_domain_space, space);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
+
+       isl_space_free(isl_qpolynomial_fold_take_domain_space(fold));
+       fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
+
+       return fold;
+}
+
 /* Reset the space of "fold".  This function is called from isl_pw_templ.c
  * and doesn't know if the space of an element object is represented
  * directly or through its domain.  It therefore passes along both.
@@ -193,24 +269,71 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain(
        return isl_qpolynomial_fold_reset_domain_space(fold, domain);
 }
 
+/* Internal data structure for isl_qpolynomial_fold_*_dims
+ * representing their arguments.
+ */
+struct isl_fold_dims_data {
+       enum isl_dim_type type;
+       unsigned first;
+       unsigned n;
+};
+
+/* isl_qpolynomial_list_every callback that checks whether "qp"
+ * does not involve any dimensions in the given range.
+ */
+static isl_bool not_involved(__isl_keep isl_qpolynomial *qp, void *user)
+{
+       struct isl_fold_dims_data *data = user;
+       isl_bool involves;
+
+       involves = isl_qpolynomial_involves_dims(qp, data->type,
+                                                       data->first, data->n);
+       return isl_bool_not(involves);
+}
+
+/* Does "fold" involve any dimensions in the given range.
+ *
+ * It involves any of those dimensions if it is not the case
+ * that every polynomial in the reduction does not involve
+ * any of the dimensions.
+ */
 static isl_bool isl_qpolynomial_fold_involves_dims(
        __isl_keep isl_qpolynomial_fold *fold,
        enum isl_dim_type type, unsigned first, unsigned n)
 {
-       int i;
+       struct isl_fold_dims_data data = { type, first, n };
+       isl_qpolynomial_list *list;
+       isl_bool not;
 
        if (!fold)
                return isl_bool_error;
-       if (fold->n == 0 || n == 0)
+       if (n == 0)
                return isl_bool_false;
 
-       for (i = 0; i < fold->n; ++i) {
-               isl_bool involves = isl_qpolynomial_involves_dims(fold->qp[i],
-                                                           type, first, n);
-               if (involves < 0 || involves)
-                       return involves;
-       }
-       return isl_bool_false;
+       list = isl_qpolynomial_fold_peek_list(fold);
+       not = isl_qpolynomial_list_every(list, &not_involved, &data);
+       return isl_bool_not(not);
+}
+
+/* Internal data structure for isl_qpolynomial_fold_set_dim_name
+ * representing its arguments.
+ */
+struct isl_fold_set_dim_name_data {
+       enum isl_dim_type type;
+       unsigned pos;
+       const char *s;
+};
+
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_set_dim_name on "qp".
+ */
+static __isl_give isl_qpolynomial *set_dim_name(__isl_take isl_qpolynomial *qp,
+       void *user)
+{
+       struct isl_fold_set_dim_name_data *data = user;
+
+       qp = isl_qpolynomial_set_dim_name(qp, data->type, data->pos, data->s);
+       return qp;
 }
 
 /* Given a dimension type for an isl_qpolynomial_fold,
@@ -227,20 +350,14 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name(
        __isl_take isl_qpolynomial_fold *fold,
        enum isl_dim_type type, unsigned pos, const char *s)
 {
-       int i;
+       struct isl_fold_set_dim_name_data data = { type, pos, s };
        enum isl_dim_type set_type;
        isl_space *space;
+       isl_qpolynomial_list *list;
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               return NULL;
-
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_set_dim_name(fold->qp[i],
-                                                           type, pos, s);
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &set_dim_name, &data);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        set_type = domain_type(type);
        space = isl_qpolynomial_fold_take_domain_space(fold);
@@ -248,18 +365,28 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name(
        fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
 
        return fold;
-error:
-       isl_qpolynomial_fold_free(fold);
-       return NULL;
+}
+
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_drop_dims on "qp".
+ */
+static __isl_give isl_qpolynomial *drop_dims(__isl_take isl_qpolynomial *qp,
+       void *user)
+{
+       struct isl_fold_dims_data *data = user;
+
+       qp = isl_qpolynomial_drop_dims(qp, data->type, data->first, data->n);
+       return qp;
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims(
        __isl_take isl_qpolynomial_fold *fold,
        enum isl_dim_type type, unsigned first, unsigned n)
 {
-       int i;
+       struct isl_fold_dims_data data = { type, first, n };
        enum isl_dim_type set_type;
        isl_space *space;
+       isl_qpolynomial_list *list;
 
        if (!fold)
                return NULL;
@@ -268,50 +395,46 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims(
 
        set_type = domain_type(type);
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               return NULL;
-
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_drop_dims(fold->qp[i],
-                                                           type, first, n);
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &drop_dims, &data);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        space = isl_qpolynomial_fold_take_domain_space(fold);
        space = isl_space_drop_dims(space, set_type, first, n);
        fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
 
        return fold;
-error:
-       isl_qpolynomial_fold_free(fold);
-       return NULL;
+}
+
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_insert_dims on "qp".
+ */
+static __isl_give isl_qpolynomial *insert_dims(__isl_take isl_qpolynomial *qp,
+       void *user)
+{
+       struct isl_fold_dims_data *data = user;
+
+       qp = isl_qpolynomial_insert_dims(qp, data->type, data->first, data->n);
+       return qp;
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims(
        __isl_take isl_qpolynomial_fold *fold,
        enum isl_dim_type type, unsigned first, unsigned n)
 {
-       int i;
+       struct isl_fold_dims_data data = { type, first, n };
        enum isl_dim_type set_type;
        isl_space *space;
+       isl_qpolynomial_list *list;
 
        if (!fold)
                return NULL;
        if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type))
                return fold;
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               return NULL;
-
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_insert_dims(fold->qp[i],
-                                                           type, first, n);
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &insert_dims, &data);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        set_type = domain_type(type);
        space = isl_qpolynomial_fold_take_domain_space(fold);
@@ -319,9 +442,6 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims(
        fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
 
        return fold;
-error:
-       isl_qpolynomial_fold_free(fold);
-       return NULL;
 }
 
 /* Determine the sign of the constant quasipolynomial "qp".
@@ -536,72 +656,61 @@ static isl_stat isl_qpolynomial_fold_check_equal_space(
        return isl_stat_ok;
 }
 
-/* Combine "fold1" and "fold2" into a single reduction, eliminating
- * those elements of one reduction that are already covered by the other
- * reduction on "set".
+/* Combine "list1" and "list2" into a single list, eliminating
+ * those elements of one list that are already covered by the other
+ * list on "set".
  *
  * "better" is the sign that the difference qp1 - qp2 needs to have for qp1
  * to be covered by qp2.
  */
-static __isl_give isl_qpolynomial_fold *merge_folds(__isl_keep isl_set *set,
-       __isl_keep isl_qpolynomial_fold *fold1,
-       __isl_keep isl_qpolynomial_fold *fold2, int better)
+static __isl_give isl_qpolynomial_list *merge_lists(__isl_keep isl_set *set,
+       __isl_take isl_qpolynomial_list *list1,
+       __isl_take isl_qpolynomial_list *list2, int better)
 {
        int i, j;
-       int n1;
-       isl_qpolynomial_fold *res;
+       isl_size n1, n2;
 
-       res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
-                                       fold1->n + fold2->n);
-       if (!res)
-               return NULL;
-
-       for (i = 0; i < fold1->n; ++i) {
-               res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
-               if (!res->qp[res->n])
-                       return isl_qpolynomial_fold_free(res);
-               res->n++;
-       }
-       n1 = res->n;
+       n1 = isl_qpolynomial_list_size(list1);
+       n2 = isl_qpolynomial_list_size(list2);
+       if (n1 < 0 || n2 < 0)
+               goto error;
 
-       for (i = 0; i < fold2->n; ++i) {
+       for (i = n2 - 1; i >= 0; --i) {
                for (j = n1 - 1; j >= 0; --j) {
-                       isl_qpolynomial *d;
+                       isl_qpolynomial *qp1, *qp2, *d;
                        int sgn;
                        isl_bool equal;
 
-                       equal = isl_qpolynomial_plain_is_equal(res->qp[j],
-                                                               fold2->qp[i]);
+                       qp1 = isl_qpolynomial_list_peek(list1, j);
+                       qp2 = isl_qpolynomial_list_peek(list2, i);
+                       equal = isl_qpolynomial_plain_is_equal(qp1, qp2);
                        if (equal < 0)
-                               return isl_qpolynomial_fold_free(res);
+                               goto error;
                        if (equal)
                                break;
                        d = isl_qpolynomial_sub(
-                               isl_qpolynomial_copy(res->qp[j]),
-                               isl_qpolynomial_copy(fold2->qp[i]));
+                               isl_qpolynomial_copy(qp1),
+                               isl_qpolynomial_copy(qp2));
                        sgn = isl_qpolynomial_sign(set, d);
                        isl_qpolynomial_free(d);
                        if (sgn == 0)
                                continue;
                        if (sgn != better)
                                break;
-                       isl_qpolynomial_free(res->qp[j]);
-                       if (j != n1 - 1)
-                               res->qp[j] = res->qp[n1 - 1];
+                       list1 = isl_qpolynomial_list_drop(list1, j, 1);
                        n1--;
-                       if (n1 != res->n - 1)
-                               res->qp[n1] = res->qp[res->n - 1];
-                       res->n--;
                }
-               if (j >= 0)
+               if (j < 0)
                        continue;
-               res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
-               if (!res->qp[res->n])
-                       return isl_qpolynomial_fold_free(res);
-               res->n++;
+               list2 = isl_qpolynomial_list_drop(list2, i, 1);
+               n2--;
        }
 
-       return res;
+       return isl_qpolynomial_list_concat(list1, list2);
+error:
+       isl_qpolynomial_list_free(list1);
+       isl_qpolynomial_list_free(list2);
+       return NULL;
 }
 
 /* Combine "fold1" and "fold2" into a single reduction, eliminating
@@ -617,7 +726,8 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
        __isl_take isl_qpolynomial_fold *fold1,
        __isl_take isl_qpolynomial_fold *fold2)
 {
-       isl_qpolynomial_fold *res;
+       isl_qpolynomial_list *list1;
+       isl_qpolynomial_list *list2;
        int better;
 
        if (isl_qpolynomial_fold_check_equal_type(fold1, fold2) < 0)
@@ -639,22 +749,35 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
                return fold1;
        }
 
-       res = merge_folds(set, fold1, fold2, better);
+       list1 = isl_qpolynomial_fold_take_list(fold1);
+       list2 = isl_qpolynomial_fold_take_list(fold2);
 
-       isl_qpolynomial_fold_free(fold1);
+       list1 = merge_lists(set, list1, list2, better);
+
+       fold1 = isl_qpolynomial_fold_restore_list(fold1, list1);
        isl_qpolynomial_fold_free(fold2);
 
-       return res;
+       return fold1;
 error:
        isl_qpolynomial_fold_free(fold1);
        isl_qpolynomial_fold_free(fold2);
        return NULL;
 }
 
+/* isl_qpolynomial_list_map callback for adding "qp2" to "qp".
+ */
+static __isl_give isl_qpolynomial *add_qpolynomial(
+       __isl_take isl_qpolynomial *qp, void *user)
+{
+       isl_qpolynomial *qp2 = user;
+
+       return isl_qpolynomial_add(qp, isl_qpolynomial_copy(qp2));
+}
+
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp)
 {
-       int i;
+       isl_qpolynomial_list *list;
 
        if (!fold || !qp)
                goto error;
@@ -664,16 +787,9 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial(
                return fold;
        }
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               goto error;
-
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_add(fold->qp[i],
-                                               isl_qpolynomial_copy(qp));
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &add_qpolynomial, qp);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        isl_qpolynomial_free(qp);
        return fold;
@@ -689,7 +805,10 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
        __isl_take isl_qpolynomial_fold *fold2)
 {
        int i;
+       isl_size n1, n2;
        isl_qpolynomial_fold *res = NULL;
+       isl_qpolynomial *qp;
+       isl_qpolynomial_list *list1, *list2;
 
        if (!fold1 || !fold2)
                goto error;
@@ -704,25 +823,32 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
                return fold1;
        }
 
-       if (fold1->n == 1 && fold2->n != 1)
+       list1 = isl_qpolynomial_fold_peek_list(fold1);
+       list2 = isl_qpolynomial_fold_peek_list(fold2);
+       n1 = isl_qpolynomial_list_size(list1);
+       n2 = isl_qpolynomial_list_size(list2);
+       if (n1 < 0 || n2 < 0)
+               goto error;
+
+       if (n1 == 1 && n2 != 1)
                return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1);
 
-       if (fold2->n == 1) {
-               res = isl_qpolynomial_fold_add_qpolynomial(fold1,
-                                       isl_qpolynomial_copy(fold2->qp[0]));
+       qp = isl_qpolynomial_list_get_at(list2, 0);
+       if (n2 == 1) {
+               res = isl_qpolynomial_fold_add_qpolynomial(fold1, qp);
                isl_qpolynomial_fold_free(fold2);
                return res;
        }
 
        res = isl_qpolynomial_fold_add_qpolynomial(
-                               isl_qpolynomial_fold_copy(fold1),
-                               isl_qpolynomial_copy(fold2->qp[0]));
+                               isl_qpolynomial_fold_copy(fold1), qp);
 
-       for (i = 1; i < fold2->n; ++i) {
+       for (i = 1; i < n2; ++i) {
                isl_qpolynomial_fold *res_i;
+
+               qp = isl_qpolynomial_list_get_at(list2, i);
                res_i = isl_qpolynomial_fold_add_qpolynomial(
-                                       isl_qpolynomial_fold_copy(fold1),
-                                       isl_qpolynomial_copy(fold2->qp[i]));
+                                       isl_qpolynomial_fold_copy(fold1), qp);
                res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i);
        }
 
@@ -736,58 +862,53 @@ error:
        return NULL;
 }
 
-__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
-       __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq)
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_substitute_equalities on "qp" and "eq".
+ */
+static __isl_give isl_qpolynomial *substitute_equalities(
+       __isl_take isl_qpolynomial *qp, void *user)
 {
-       int i;
+       isl_basic_set *eq = user;
 
-       if (!fold || !eq)
-               goto error;
+       eq = isl_basic_set_copy(eq);
+       return isl_qpolynomial_substitute_equalities(qp, eq);
+}
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               return NULL;
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
+       __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq)
+{
+       isl_qpolynomial_list *list;
 
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_substitute_equalities(fold->qp[i],
-                                                       isl_basic_set_copy(eq));
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &substitute_equalities, eq);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        isl_basic_set_free(eq);
        return fold;
-error:
-       isl_basic_set_free(eq);
-       isl_qpolynomial_fold_free(fold);
-       return NULL;
 }
 
-__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
-       __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_substitute_equalities on "qp" and "context".
+ */
+static __isl_give isl_qpolynomial *gist(__isl_take isl_qpolynomial *qp,
+       void *user)
 {
-       int i;
+       isl_set *context = user;
 
-       if (!fold || !context)
-               goto error;
+       return isl_qpolynomial_gist(qp, isl_set_copy(context));
+}
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               return NULL;
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
+       __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
+{
+       isl_qpolynomial_list *list;
 
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_gist(fold->qp[i],
-                                                       isl_set_copy(context));
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &gist, context);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        isl_set_free(context);
        return fold;
-error:
-       isl_set_free(context);
-       isl_qpolynomial_fold_free(fold);
-       return NULL;
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
@@ -845,31 +966,34 @@ static __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_zero_in_space(
 #include <isl_union_single.c>
 #include <isl_union_eval.c>
 
+/* Construct a new reduction of the given type and space
+ * with an empty list of polynomials.
+ */
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
        __isl_take isl_space *space)
 {
-       return qpolynomial_fold_alloc(type, space, 0);
+       isl_ctx *ctx;
+       isl_qpolynomial_list *list;
+
+       if (!space)
+               return NULL;
+       ctx = isl_space_get_ctx(space);
+       list = isl_qpolynomial_list_alloc(ctx, 0);
+       return qpolynomial_fold_alloc(type, space, list);
 }
 
+/* Construct a new reduction of the given type and
+ * a single given polynomial.
+ */
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc(
        enum isl_fold type, __isl_take isl_qpolynomial *qp)
 {
        isl_space *space;
-       isl_qpolynomial_fold *fold;
+       isl_qpolynomial_list *list;
 
        space = isl_qpolynomial_get_domain_space(qp);
-       fold = qpolynomial_fold_alloc(type, space, 1);
-       if (!fold)
-               goto error;
-
-       fold->qp[0] = qp;
-       fold->n++;
-
-       return fold;
-error:
-       isl_qpolynomial_fold_free(fold);
-       isl_qpolynomial_free(qp);
-       return NULL;
+       list = isl_qpolynomial_list_from_qpolynomial(qp);
+       return qpolynomial_fold_alloc(type, space, list);
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
@@ -885,27 +1009,14 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
        __isl_keep isl_qpolynomial_fold *fold)
 {
-       int i;
-       isl_qpolynomial_fold *dup;
-
-       if (!fold)
-               return NULL;
-       dup = qpolynomial_fold_alloc(fold->type,
-                                       isl_space_copy(fold->dim), fold->n);
-       if (!dup)
-               return NULL;
-       
-       dup->n = fold->n;
-       for (i = 0; i < fold->n; ++i) {
-               dup->qp[i] = isl_qpolynomial_copy(fold->qp[i]);
-               if (!dup->qp[i])
-                       goto error;
-       }
+       enum isl_fold type;
+       isl_space *space;
+       isl_qpolynomial_list *list;
 
-       return dup;
-error:
-       isl_qpolynomial_fold_free(dup);
-       return NULL;
+       type = isl_qpolynomial_fold_get_type(fold);
+       space = isl_qpolynomial_fold_get_domain_space(fold);
+       list = isl_qpolynomial_fold_get_list(fold);
+       return qpolynomial_fold_alloc(type, space, list);
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
@@ -923,15 +1034,12 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
 __isl_null isl_qpolynomial_fold *isl_qpolynomial_fold_free(
        __isl_take isl_qpolynomial_fold *fold)
 {
-       int i;
-
        if (!fold)
                return NULL;
        if (--fold->ref > 0)
                return NULL;
 
-       for (i = 0; i < fold->n; ++i)
-               isl_qpolynomial_free(fold->qp[i]);
+       isl_qpolynomial_list_free(fold->list);
        isl_space_free(fold->dim);
        free(fold);
 
@@ -940,29 +1048,40 @@ __isl_null isl_qpolynomial_fold *isl_qpolynomial_fold_free(
 
 isl_bool isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold)
 {
-       if (!fold)
+       isl_size n;
+       isl_qpolynomial_list *list;
+
+       list = isl_qpolynomial_fold_peek_list(fold);
+       n = isl_qpolynomial_list_size(list);
+       if (n < 0)
                return isl_bool_error;
 
-       return isl_bool_ok(fold->n == 0);
+       return isl_bool_ok(n == 0);
 }
 
 /* Does "fold" represent max(NaN) or min(NaN)?
  */
 isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold)
 {
-       if (!fold)
+       isl_size n;
+       isl_qpolynomial *qp;
+       isl_qpolynomial_list *list;
+
+       list = isl_qpolynomial_fold_peek_list(fold);
+       n = isl_qpolynomial_list_size(list);
+       if (n < 0)
                return isl_bool_error;
-       if (fold->n != 1)
+       if (n != 1)
                return isl_bool_false;
-       return isl_qpolynomial_is_nan(fold->qp[0]);
+       qp = isl_qpolynomial_list_peek(list, 0);
+       return isl_qpolynomial_is_nan(qp);
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
        __isl_take isl_qpolynomial_fold *fold1,
        __isl_take isl_qpolynomial_fold *fold2)
 {
-       int i;
-       struct isl_qpolynomial_fold *res = NULL;
+       isl_qpolynomial_list *list1, *list2;
 
        if (isl_qpolynomial_fold_check_equal_type(fold1, fold2) < 0)
                goto error;
@@ -979,31 +1098,14 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
                return fold1;
        }
 
-       res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
-                                       fold1->n + fold2->n);
-       if (!res)
-               goto error;
-
-       for (i = 0; i < fold1->n; ++i) {
-               res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
-               if (!res->qp[res->n])
-                       goto error;
-               res->n++;
-       }
-
-       for (i = 0; i < fold2->n; ++i) {
-               res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
-               if (!res->qp[res->n])
-                       goto error;
-               res->n++;
-       }
-
-       isl_qpolynomial_fold_free(fold1);
+       list1 = isl_qpolynomial_fold_take_list(fold1);
+       list2 = isl_qpolynomial_fold_take_list(fold2);
+       list1 = isl_qpolynomial_list_concat(list1, list2);
+       fold1 = isl_qpolynomial_fold_restore_list(fold1, list1);
        isl_qpolynomial_fold_free(fold2);
 
-       return res;
+       return fold1;
 error:
-       isl_qpolynomial_fold_free(res);
        isl_qpolynomial_fold_free(fold1);
        isl_qpolynomial_fold_free(fold2);
        return NULL;
@@ -1187,21 +1289,30 @@ int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1,
        __isl_keep isl_qpolynomial_fold *fold2)
 {
        int i;
+       isl_size n1, n2;
+       isl_qpolynomial_list *list1, *list2;
 
        if (fold1 == fold2)
                return 0;
-       if (!fold1)
+       list1 = isl_qpolynomial_fold_peek_list(fold1);
+       list2 = isl_qpolynomial_fold_peek_list(fold2);
+       n1 = isl_qpolynomial_list_size(list1);
+       n2 = isl_qpolynomial_list_size(list2);
+       if (n1 < 0)
                return -1;
-       if (!fold2)
+       if (n2 < 0)
                return 1;
 
-       if (fold1->n != fold2->n)
-               return fold1->n - fold2->n;
+       if (n1 != n2)
+               return n1 - n2;
 
-       for (i = 0; i < fold1->n; ++i) {
+       for (i = 0; i < n1; ++i) {
                int cmp;
+               isl_qpolynomial *qp1, *qp2;
 
-               cmp = isl_qpolynomial_plain_cmp(fold1->qp[i], fold2->qp[i]);
+               qp1 = isl_qpolynomial_list_peek(list1, i);
+               qp2 = isl_qpolynomial_list_peek(list2, i);
+               cmp = isl_qpolynomial_plain_cmp(qp1, qp2);
                if (cmp != 0)
                        return cmp;
        }
@@ -1214,18 +1325,27 @@ isl_bool isl_qpolynomial_fold_plain_is_equal(
        __isl_keep isl_qpolynomial_fold *fold2)
 {
        int i;
-
-       if (!fold1 || !fold2)
+       isl_size n1, n2;
+       isl_qpolynomial_list *list1, *list2;
+
+       list1 = isl_qpolynomial_fold_peek_list(fold1);
+       list2 = isl_qpolynomial_fold_peek_list(fold2);
+       n1 = isl_qpolynomial_list_size(list1);
+       n2 = isl_qpolynomial_list_size(list2);
+       if (n1 < 0 || n2 < 0)
                return isl_bool_error;
 
-       if (fold1->n != fold2->n)
+       if (n1 != n2)
                return isl_bool_false;
 
        /* We probably want to sort the qps first... */
-       for (i = 0; i < fold1->n; ++i) {
+       for (i = 0; i < n1; ++i) {
                isl_bool eq;
+               isl_qpolynomial *qp1, *qp2;
 
-               eq = isl_qpolynomial_plain_is_equal(fold1->qp[i], fold2->qp[i]);
+               qp1 = isl_qpolynomial_list_peek(list1, i);
+               qp2 = isl_qpolynomial_list_peek(list2, i);
+               eq = isl_qpolynomial_plain_is_equal(qp1, qp2);
                if (eq < 0 || !eq)
                        return eq;
        }
@@ -1236,8 +1356,11 @@ isl_bool isl_qpolynomial_fold_plain_is_equal(
 __isl_give isl_val *isl_qpolynomial_fold_eval(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt)
 {
+       isl_size n;
        isl_ctx *ctx;
        isl_val *v;
+       isl_qpolynomial *qp;
+       isl_qpolynomial_list *list;
 
        if (!fold || !pnt)
                goto error;
@@ -1247,17 +1370,23 @@ __isl_give isl_val *isl_qpolynomial_fold_eval(
                fold->type == isl_fold_max || fold->type == isl_fold_min,
                goto error);
 
-       if (fold->n == 0)
+       list = isl_qpolynomial_fold_peek_list(fold);
+       n = isl_qpolynomial_list_size(list);
+       if (n < 0)
+               goto error;
+
+       if (n == 0)
                v = isl_val_zero(ctx);
        else {
                int i;
-               v = isl_qpolynomial_eval(isl_qpolynomial_copy(fold->qp[0]),
-                                               isl_point_copy(pnt));
-               for (i = 1; i < fold->n; ++i) {
+
+               qp = isl_qpolynomial_list_get_at(list, 0);
+               v = isl_qpolynomial_eval(qp, isl_point_copy(pnt));
+               for (i = 1; i < n; ++i) {
                        isl_val *v_i;
-                       v_i = isl_qpolynomial_eval(
-                                           isl_qpolynomial_copy(fold->qp[i]),
-                                           isl_point_copy(pnt));
+
+                       qp = isl_qpolynomial_list_get_at(list, i);
+                       v_i = isl_qpolynomial_eval(qp, isl_point_copy(pnt));
                        if (fold->type == isl_fold_max)
                                v = isl_val_max(v, v_i);
                        else
@@ -1279,8 +1408,17 @@ size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf)
        int i;
        size_t n = 0;
 
-       for (i = 0; i < pwf->n; ++i)
-               n += pwf->p[i].fold->n;
+       for (i = 0; i < pwf->n; ++i) {
+               isl_size n_i;
+               isl_qpolynomial_list *list;
+
+               list = isl_qpolynomial_fold_peek_list(pwf->p[i].fold);
+               n_i = isl_qpolynomial_list_size(list);
+               if (n_i < 0)
+                       return isl_size_error;
+
+               n += n_i;
+       }
 
        return n;
 }
@@ -1289,24 +1427,30 @@ __isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max)
 {
        int i;
+       isl_size n;
        isl_val *opt;
+       isl_qpolynomial *qp;
+       isl_qpolynomial_list *list;
 
-       if (!set || !fold)
+       list = isl_qpolynomial_fold_peek_list(fold);
+       n = isl_qpolynomial_list_size(list);
+       if (!set || n < 0)
                goto error;
 
-       if (fold->n == 0) {
+       if (n == 0) {
                opt = isl_val_zero(isl_set_get_ctx(set));
                isl_set_free(set);
                isl_qpolynomial_fold_free(fold);
                return opt;
        }
 
-       opt = isl_qpolynomial_opt_on_domain(isl_qpolynomial_copy(fold->qp[0]),
-                                               isl_set_copy(set), max);
-       for (i = 1; i < fold->n; ++i) {
+       qp = isl_qpolynomial_list_get_at(list, 0);
+       opt = isl_qpolynomial_opt_on_domain(qp, isl_set_copy(set), max);
+       for (i = 1; i < n; ++i) {
                isl_val *opt_i;
-               opt_i = isl_qpolynomial_opt_on_domain(
-                               isl_qpolynomial_copy(fold->qp[i]),
+
+               qp = isl_qpolynomial_list_get_at(list, i);
+               opt_i = isl_qpolynomial_opt_on_domain(qp,
                                isl_set_copy(set), max);
                if (max)
                        opt = isl_val_max(opt, opt_i);
@@ -1333,26 +1477,32 @@ static isl_bool qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set,
 {
        int i, j;
        int covers;
-
-       if (!set || !fold1 || !fold2)
+       isl_size n1, n2;
+       isl_qpolynomial_list *list1, *list2;
+
+       list1 = isl_qpolynomial_fold_peek_list(fold1);
+       list2 = isl_qpolynomial_fold_peek_list(fold2);
+       n1 = isl_qpolynomial_list_size(list1);
+       n2 = isl_qpolynomial_list_size(list2);
+       if (!set || n1 < 0 || n2 < 0)
                return isl_bool_error;
 
        covers = fold1->type == isl_fold_max ? 1 : -1;
 
-       for (i = 0; i < fold2->n; ++i) {
-               for (j = 0; j < fold1->n; ++j) {
-                       isl_qpolynomial *d;
+       for (i = 0; i < n2; ++i) {
+               for (j = 0; j < n1; ++j) {
+                       isl_qpolynomial *qp1, *qp2, *d;
                        int sgn;
 
-                       d = isl_qpolynomial_sub(
-                               isl_qpolynomial_copy(fold1->qp[j]),
-                               isl_qpolynomial_copy(fold2->qp[i]));
+                       qp1 = isl_qpolynomial_list_get_at(list1, j);
+                       qp2 = isl_qpolynomial_list_get_at(list2, i);
+                       d = isl_qpolynomial_sub(qp1, qp2);
                        sgn = isl_qpolynomial_sign(set, d);
                        isl_qpolynomial_free(d);
                        if (sgn == covers)
                                break;
                }
-               if (j >= fold1->n)
+               if (j >= n1)
                        return isl_bool_false;
        }
 
@@ -1414,26 +1564,30 @@ isl_bool isl_pw_qpolynomial_fold_covers(
        return isl_bool_true;
 }
 
+/* isl_qpolynomial_list_map callback that calls
+ * isl_qpolynomial_morph_domain on "qp".
+ */
+static __isl_give isl_qpolynomial *morph_domain(
+       __isl_take isl_qpolynomial *qp, void *user)
+{
+       isl_morph *morph = user;
+
+       return isl_qpolynomial_morph_domain(qp, isl_morph_copy(morph));
+}
+
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph)
 {
-       int i;
        isl_space *space;
+       isl_qpolynomial_list *list;
 
        space = isl_qpolynomial_fold_peek_domain_space(fold);
        if (isl_morph_check_applies(morph, space) < 0)
                goto error;
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               goto error;
-
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_morph_domain(fold->qp[i],
-                                               isl_morph_copy(morph));
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &morph_domain, morph);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        space = isl_morph_get_ran_space(morph);
        isl_space_free(isl_qpolynomial_fold_take_domain_space(fold));
@@ -1473,10 +1627,21 @@ enum isl_fold isl_union_pw_qpolynomial_fold_get_type(
        return upwf->type;
 }
 
+/* isl_qpolynomial_list_map callback that calls
+ * isl_qpolynomial_lift on "qp".
+ */
+static __isl_give isl_qpolynomial *lift(__isl_take isl_qpolynomial *qp,
+       void *user)
+{
+       isl_space *space = user;
+
+       return isl_qpolynomial_lift(qp, isl_space_copy(space));
+}
+
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space)
 {
-       int i;
+       isl_qpolynomial_list *list;
 
        if (!fold || !space)
                goto error;
@@ -1486,16 +1651,9 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
                return fold;
        }
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               goto error;
-
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_lift(fold->qp[i],
-                                               isl_space_copy(space));
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &lift, space);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        isl_space_free(isl_qpolynomial_fold_take_domain_space(fold));
        fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
@@ -1511,16 +1669,34 @@ isl_stat isl_qpolynomial_fold_foreach_qpolynomial(
        __isl_keep isl_qpolynomial_fold *fold,
        isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user)
 {
-       int i;
+       isl_qpolynomial_list *list;
 
-       if (!fold)
-               return isl_stat_error;
+       list = isl_qpolynomial_fold_peek_list(fold);
+       return isl_qpolynomial_list_foreach(list, fn, user);
+}
 
-       for (i = 0; i < fold->n; ++i)
-               if (fn(isl_qpolynomial_copy(fold->qp[i]), user) < 0)
-                       return isl_stat_error;
+/* Internal data structure for isl_qpolynomial_fold_move_dims
+ * representing its arguments.
+ */
+struct isl_fold_move_dims_data {
+       enum isl_dim_type dst_type;
+       unsigned dst_pos;
+       enum isl_dim_type src_type;
+       unsigned src_pos;
+       unsigned n;
+};
 
-       return isl_stat_ok;
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_move_dims on "qp".
+ */
+static __isl_give isl_qpolynomial *move_dims(__isl_take isl_qpolynomial *qp,
+       void *user)
+{
+       struct isl_fold_move_dims_data *data = user;
+
+       qp = isl_qpolynomial_move_dims(qp, data->dst_type, data->dst_pos,
+                                       data->src_type, data->src_pos, data->n);
+       return qp;
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
@@ -1528,9 +1704,11 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
        enum isl_dim_type dst_type, unsigned dst_pos,
        enum isl_dim_type src_type, unsigned src_pos, unsigned n)
 {
-       int i;
+       struct isl_fold_move_dims_data data =
+               { dst_type, dst_pos, src_type, src_pos, n };
        enum isl_dim_type set_src_type, set_dst_type;
        isl_space *space;
+       isl_qpolynomial_list *list;
 
        if (n == 0)
                return fold;
@@ -1542,12 +1720,9 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
        set_src_type = domain_type(src_type);
        set_dst_type = domain_type(dst_type);
 
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_move_dims(fold->qp[i],
-                               dst_type, dst_pos, src_type, src_pos, n);
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &move_dims, &data);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        space = isl_qpolynomial_fold_take_domain_space(fold);
        space = isl_space_move_dims(space, set_dst_type, dst_pos,
@@ -1555,9 +1730,29 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
        fold = isl_qpolynomial_fold_restore_domain_space(fold, space);
 
        return fold;
-error:
-       isl_qpolynomial_fold_free(fold);
-       return NULL;
+}
+
+/* Internal data structure for isl_qpolynomial_fold_substitute
+ * representing its arguments.
+ */
+struct isl_fold_substitute {
+       enum isl_dim_type type;
+       unsigned first;
+       unsigned n;
+       isl_qpolynomial **subs;
+};
+
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_substitute on "qp".
+ */
+static __isl_give isl_qpolynomial *substitute(__isl_take isl_qpolynomial *qp,
+       void *user)
+{
+       struct isl_fold_substitute *data = user;
+
+       qp = isl_qpolynomial_substitute(qp,
+                               data->type, data->first, data->n, data->subs);
+       return qp;
 }
 
 /* For each 0 <= i < "n", replace variable "first" + i of type "type"
@@ -1568,26 +1763,17 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute(
        enum isl_dim_type type, unsigned first, unsigned n,
        __isl_keep isl_qpolynomial **subs)
 {
-       int i;
+       struct isl_fold_substitute data = { type, first, n, subs };
+       isl_qpolynomial_list *list;
 
        if (n == 0)
                return fold;
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold)
-               return NULL;
-
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_substitute(fold->qp[i],
-                               type, first, n, subs);
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &substitute, &data);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        return fold;
-error:
-       isl_qpolynomial_fold_free(fold);
-       return NULL;
 }
 
 static isl_stat add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user)
@@ -1808,24 +1994,29 @@ __isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomi
        return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight);
 }
 
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_realign_domain on "qp".
+ */
+static __isl_give isl_qpolynomial *realign_domain(
+       __isl_take isl_qpolynomial *qp, void *user)
+{
+       isl_reordering *r = user;
+
+       qp = isl_qpolynomial_realign_domain(qp, isl_reordering_copy(r));
+       return qp;
+}
+
 /* Reorder the dimension of "fold" according to the given reordering.
  */
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r)
 {
-       int i;
        isl_space *space;
+       isl_qpolynomial_list *list;
 
-       fold = isl_qpolynomial_fold_cow(fold);
-       if (!fold || !r)
-               goto error;
-
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_realign_domain(fold->qp[i],
-                                                   isl_reordering_copy(r));
-               if (!fold->qp[i])
-                       goto error;
-       }
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &realign_domain, r);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        space = isl_reordering_get_space(r);
        fold = isl_qpolynomial_fold_reset_domain_space(fold, space);
@@ -1833,16 +2024,24 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
        isl_reordering_free(r);
 
        return fold;
-error:
-       isl_qpolynomial_fold_free(fold);
-       isl_reordering_free(r);
-       return NULL;
+}
+
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_mul_isl_int on "qp".
+ */
+static __isl_give isl_qpolynomial *mul_int(__isl_take isl_qpolynomial *qp,
+       void *user)
+{
+       isl_int *v = user;
+
+       qp = isl_qpolynomial_mul_isl_int(qp, *v);
+       return qp;
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
        __isl_take isl_qpolynomial_fold *fold, isl_int v)
 {
-       int i;
+       isl_qpolynomial_list *list;
 
        if (isl_int_is_one(v))
                return fold;
@@ -1860,16 +2059,12 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
 
        if (isl_int_is_neg(v))
                fold->type = isl_fold_type_negate(fold->type);
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_mul_isl_int(fold->qp[i], v);
-               if (!fold->qp[i])
-                       goto error;
-       }
+
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &mul_int, &v);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        return fold;
-error:
-       isl_qpolynomial_fold_free(fold);
-       return NULL;
 }
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
@@ -1878,12 +2073,24 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
        return isl_qpolynomial_fold_mul_isl_int(fold, v);
 }
 
+/* isl_qpolynomial_list_map callback for calling
+ * isl_qpolynomial_scale_val on "qp".
+ */
+static __isl_give isl_qpolynomial *scale_val(__isl_take isl_qpolynomial *qp,
+       void *user)
+{
+       isl_val *v = user;
+
+       qp = isl_qpolynomial_scale_val(qp, isl_val_copy(v));
+       return qp;
+}
+
 /* Multiply "fold" by "v".
  */
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
        __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
 {
-       int i;
+       isl_qpolynomial_list *list;
 
        if (!fold || !v)
                goto error;
@@ -1910,12 +2117,10 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
 
        if (isl_val_is_neg(v))
                fold->type = isl_fold_type_negate(fold->type);
-       for (i = 0; i < fold->n; ++i) {
-               fold->qp[i] = isl_qpolynomial_scale_val(fold->qp[i],
-                                                       isl_val_copy(v));
-               if (!fold->qp[i])
-                       goto error;
-       }
+
+       list = isl_qpolynomial_fold_take_list(fold);
+       list = isl_qpolynomial_list_map(list, &scale_val, v);
+       fold = isl_qpolynomial_fold_restore_list(fold, list);
 
        isl_val_free(v);
        return fold;
index ace3665..9839a52 100644 (file)
@@ -1988,16 +1988,25 @@ static __isl_give isl_printer *qpolynomial_fold_print(
        __isl_keep isl_qpolynomial_fold *fold, __isl_take isl_printer *p)
 {
        int i;
+       isl_qpolynomial_list *list;
+       isl_size n;
 
+       list = isl_qpolynomial_fold_peek_list(fold);
+       n = isl_qpolynomial_list_size(list);
+       if (n < 0)
+               return isl_printer_free(p);
        if (fold->type == isl_fold_min)
                p = isl_printer_print_str(p, "min");
        else if (fold->type == isl_fold_max)
                p = isl_printer_print_str(p, "max");
        p = isl_printer_print_str(p, "(");
-       for (i = 0; i < fold->n; ++i) {
+       for (i = 0; i < n; ++i) {
+               isl_qpolynomial *qp;
+
                if (i)
                        p = isl_printer_print_str(p, ", ");
-               p = print_qpolynomial(p, fold->qp[i]);
+               qp = isl_qpolynomial_list_peek(list, i);
+               p = print_qpolynomial(p, qp);
        }
        p = isl_printer_print_str(p, ")");
        return p;
@@ -2337,17 +2346,26 @@ static __isl_give isl_printer *print_qpolynomial_fold_c(
        __isl_keep isl_qpolynomial_fold *fold)
 {
        int i;
+       isl_qpolynomial_list *list;
+       isl_size n;
 
-       for (i = 0; i < fold->n - 1; ++i)
+       list = isl_qpolynomial_fold_peek_list(fold);
+       n = isl_qpolynomial_list_size(list);
+       if (n < 0)
+               return isl_printer_free(p);
+       for (i = 0; i < n - 1; ++i)
                if (fold->type == isl_fold_min)
                        p = isl_printer_print_str(p, "min(");
                else if (fold->type == isl_fold_max)
                        p = isl_printer_print_str(p, "max(");
 
-       for (i = 0; i < fold->n; ++i) {
+       for (i = 0; i < n; ++i) {
+               isl_qpolynomial *qp;
+
                if (i)
                        p = isl_printer_print_str(p, ", ");
-               p = print_qpolynomial_c(p, space, fold->qp[i]);
+               qp = isl_qpolynomial_list_peek(list, i);
+               p = print_qpolynomial_c(p, space, qp);
                if (i)
                        p = isl_printer_print_str(p, ")");
        }
index e4918da..acab078 100644 (file)
@@ -92,10 +92,7 @@ struct isl_qpolynomial_fold {
        enum isl_fold type;
        isl_space *dim;
 
-       int n;
-
-       size_t size;
-       struct isl_qpolynomial *qp[1];
+       isl_qpolynomial_list *list;
 };
 
 struct isl_pw_qpolynomial_fold_piece {
@@ -208,6 +205,9 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
        __isl_keep isl_qpolynomial_fold *fold);
 
+__isl_keep isl_qpolynomial_list *isl_qpolynomial_fold_peek_list(
+       __isl_keep isl_qpolynomial_fold *fold);
+
 __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_cow(
        __isl_take isl_pw_qpolynomial_fold *pwf);