isl_multi_*_get_at: extract out isl_multi_*_peek_at
[isl.git] / isl_multi_templ.c
blobe06898912c158c6dd651f135b65a1525efafcc0b
1 /*
2 * Copyright 2011 Sven Verdoolaege
3 * Copyright 2012-2014 Ecole Normale Superieure
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege,
8 * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
9 */
11 #include <isl/id.h>
12 #include <isl_space_private.h>
13 #include <isl/set.h>
14 #include <isl_reordering.h>
16 #include <isl_multi_macro.h>
18 #define MULTI_NAME(BASE) "isl_multi_" #BASE
20 isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi)
22 return multi ? isl_space_get_ctx(multi->space) : NULL;
25 /* Return the space of "multi".
27 __isl_keep isl_space *FN(MULTI(BASE),peek_space)(__isl_keep MULTI(BASE) *multi)
29 return multi ? multi->space : NULL;
32 __isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi)
34 return isl_space_copy(FN(MULTI(BASE),peek_space)(multi));
37 __isl_give isl_space *FN(MULTI(BASE),get_domain_space)(
38 __isl_keep MULTI(BASE) *multi)
40 return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL;
43 /* Allocate a multi expression living in "space".
45 * If the number of base expressions is zero, then make sure
46 * there is enough room in the structure for the explicit domain,
47 * in case the type supports such an explicit domain.
49 __isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space)
51 isl_ctx *ctx;
52 isl_size n;
53 MULTI(BASE) *multi;
55 n = isl_space_dim(space, isl_dim_out);
56 if (n < 0)
57 goto error;
59 ctx = isl_space_get_ctx(space);
60 if (n > 0)
61 multi = isl_calloc(ctx, MULTI(BASE),
62 sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *));
63 else
64 multi = isl_calloc(ctx, MULTI(BASE), sizeof(MULTI(BASE)));
65 if (!multi)
66 goto error;
68 multi->space = space;
69 multi->n = n;
70 multi->ref = 1;
71 if (FN(MULTI(BASE),has_explicit_domain)(multi))
72 multi = FN(MULTI(BASE),init_explicit_domain)(multi);
73 return multi;
74 error:
75 isl_space_free(space);
76 return NULL;
79 __isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
81 int i;
82 MULTI(BASE) *dup;
84 if (!multi)
85 return NULL;
87 dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
88 if (!dup)
89 return NULL;
91 for (i = 0; i < multi->n; ++i)
92 dup = FN(FN(MULTI(BASE),set),BASE)(dup, i,
93 FN(EL,copy)(multi->u.p[i]));
94 if (FN(MULTI(BASE),has_explicit_domain)(multi))
95 dup = FN(MULTI(BASE),copy_explicit_domain)(dup, multi);
97 return dup;
100 __isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
102 if (!multi)
103 return NULL;
105 if (multi->ref == 1)
106 return multi;
108 multi->ref--;
109 return FN(MULTI(BASE),dup)(multi);
112 __isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
114 if (!multi)
115 return NULL;
117 multi->ref++;
118 return multi;
121 __isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
123 int i;
125 if (!multi)
126 return NULL;
128 if (--multi->ref > 0)
129 return NULL;
131 isl_space_free(multi->space);
132 for (i = 0; i < multi->n; ++i)
133 FN(EL,free)(multi->u.p[i]);
134 if (FN(MULTI(BASE),has_explicit_domain)(multi))
135 FN(MULTI(BASE),free_explicit_domain)(multi);
136 free(multi);
138 return NULL;
141 isl_size FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
142 enum isl_dim_type type)
144 return isl_space_dim(FN(MULTI(BASE),peek_space)(multi), type);
147 /* Return the number of base expressions in "multi".
149 isl_size FN(MULTI(BASE),size)(__isl_keep MULTI(BASE) *multi)
151 return multi ? multi->n : isl_size_error;
154 #undef TYPE
155 #define TYPE MULTI(BASE)
156 static
157 #include "check_type_range_templ.c"
159 /* Return the base expression at position "pos" in "multi".
161 static __isl_give EL *FN(MULTI(BASE),peek_at)(__isl_keep MULTI(BASE) *multi,
162 int pos)
164 if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0)
165 return NULL;
166 return multi->u.p[pos];
169 /* Return a copy of the base expression at position "pos" in "multi".
171 __isl_give EL *FN(MULTI(BASE),get_at)(__isl_keep MULTI(BASE) *multi, int pos)
173 return FN(EL,copy)(FN(MULTI(BASE),peek_at)(multi, pos));
176 /* This is an alternative name for the function above.
178 __isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
179 int pos)
181 return FN(MULTI(BASE),get_at)(multi, pos);
184 /* Set the element at position "pos" of "multi" to "el",
185 * where the position may be empty if "multi" has only a single reference.
187 static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore)(
188 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
190 multi = FN(MULTI(BASE),cow)(multi);
191 if (!multi || !el)
192 goto error;
194 if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0)
195 goto error;
197 FN(EL,free)(multi->u.p[pos]);
198 multi->u.p[pos] = el;
200 return multi;
201 error:
202 FN(MULTI(BASE),free)(multi);
203 FN(EL,free)(el);
204 return NULL;
207 /* Set the element at position "pos" of "multi" to "el",
208 * where the position may be empty if "multi" has only a single reference.
209 * However, the space of "multi" is available and is checked
210 * for compatibility with "el".
212 static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore_check_space)(
213 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
215 isl_space *space;
217 space = FN(MULTI(BASE),peek_space)(multi);
218 if (FN(EL,check_match_domain_space)(el, space) < 0)
219 multi = FN(MULTI(BASE),free)(multi);
220 return FN(MULTI(BASE),restore)(multi, pos, el);
223 /* Replace the base expression at position "pos" in "multi" with "el".
225 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_at)(
226 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
228 isl_space *multi_space = NULL;
229 isl_space *el_space = NULL;
230 isl_bool match;
232 multi_space = FN(MULTI(BASE),get_space)(multi);
233 match = FN(EL,matching_params)(el, multi_space);
234 if (match < 0)
235 goto error;
236 if (!match) {
237 multi = FN(MULTI(BASE),align_params)(multi,
238 FN(EL,get_space)(el));
239 isl_space_free(multi_space);
240 multi_space = FN(MULTI(BASE),get_space)(multi);
241 el = FN(EL,align_params)(el, isl_space_copy(multi_space));
244 multi = FN(MULTI(BASE),restore_check_space)(multi, pos, el);
246 isl_space_free(multi_space);
247 isl_space_free(el_space);
249 return multi;
250 error:
251 FN(MULTI(BASE),free)(multi);
252 FN(EL,free)(el);
253 isl_space_free(multi_space);
254 isl_space_free(el_space);
255 return NULL;
258 /* This is an alternative name for the function above.
260 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
261 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
263 return FN(MULTI(BASE),set_at)(multi, pos, el);
266 /* Return the base expressions of "multi" as a list.
268 __isl_give LIST(EL) *FN(MULTI(BASE),get_list)(
269 __isl_keep MULTI(BASE) *multi)
271 isl_size n;
272 int i;
273 LIST(EL) *list;
275 n = FN(MULTI(BASE),size)(multi);
276 if (n < 0)
277 return NULL;
278 list = FN(LIST(EL),alloc)(FN(MULTI(BASE),get_ctx(multi)), n);
279 for (i = 0; i < n; ++i) {
280 EL *el = FN(MULTI(BASE),get_at)(multi, i);
281 list = FN(LIST(EL),add)(list, el);
284 return list;
287 /* Reset the space of "multi". This function is called from isl_pw_templ.c
288 * and doesn't know if the space of an element object is represented
289 * directly or through its domain. It therefore passes along both,
290 * which we pass along to the element function since we don't know how
291 * that is represented either.
293 * If "multi" has an explicit domain, then the caller is expected
294 * to make sure that any modification that would change the dimensions
295 * of the explicit domain has bee applied before this function is called.
297 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
298 __isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
299 __isl_take isl_space *domain)
301 isl_size n;
302 int i;
304 multi = FN(MULTI(BASE),cow)(multi);
305 n = FN(MULTI(BASE),size)(multi);
306 if (n < 0 || !space || !domain)
307 goto error;
309 for (i = 0; i < n; ++i) {
310 multi->u.p[i] = FN(EL,reset_domain_space)(multi->u.p[i],
311 isl_space_copy(domain));
312 if (!multi->u.p[i])
313 goto error;
315 if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
316 multi = FN(MULTI(BASE),reset_explicit_domain_space)(multi,
317 isl_space_copy(domain));
318 if (!multi)
319 goto error;
321 isl_space_free(domain);
322 isl_space_free(multi->space);
323 multi->space = space;
325 return multi;
326 error:
327 isl_space_free(domain);
328 isl_space_free(space);
329 FN(MULTI(BASE),free)(multi);
330 return NULL;
333 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
334 __isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
336 isl_space *space;
338 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
339 isl_space_copy(multi->space));
340 return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
343 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
344 __isl_take MULTI(BASE) *multi, __isl_take isl_space *space)
346 isl_space *domain;
348 domain = isl_space_domain(isl_space_copy(space));
349 return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
352 /* Reset the user pointer on all identifiers of parameters and tuples
353 * of the space of "multi".
355 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_user)(
356 __isl_take MULTI(BASE) *multi)
358 isl_space *space;
360 space = FN(MULTI(BASE),get_space)(multi);
361 space = isl_space_reset_user(space);
363 return FN(MULTI(BASE),reset_space)(multi, space);
366 __isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
367 __isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp)
369 int i;
370 isl_size n;
371 isl_space *space;
373 multi = FN(MULTI(BASE),cow)(multi);
374 n = FN(MULTI(BASE),size)(multi);
375 if (n < 0 || !exp)
376 goto error;
378 for (i = 0; i < n; ++i) {
379 multi->u.p[i] = FN(EL,realign_domain)(multi->u.p[i],
380 isl_reordering_copy(exp));
381 if (!multi->u.p[i])
382 goto error;
385 space = isl_reordering_get_space(exp);
386 multi = FN(MULTI(BASE),reset_domain_space)(multi, space);
388 isl_reordering_free(exp);
389 return multi;
390 error:
391 isl_reordering_free(exp);
392 FN(MULTI(BASE),free)(multi);
393 return NULL;
396 /* Align the parameters of "multi" to those of "model".
398 * If "multi" has an explicit domain, then align the parameters
399 * of the domain first.
401 __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
402 __isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
404 isl_ctx *ctx;
405 isl_bool equal_params;
406 isl_reordering *exp;
408 if (!multi || !model)
409 goto error;
411 equal_params = isl_space_has_equal_params(multi->space, model);
412 if (equal_params < 0)
413 goto error;
414 if (equal_params) {
415 isl_space_free(model);
416 return multi;
419 ctx = isl_space_get_ctx(model);
420 if (!isl_space_has_named_params(model))
421 isl_die(ctx, isl_error_invalid,
422 "model has unnamed parameters", goto error);
423 if (!isl_space_has_named_params(multi->space))
424 isl_die(ctx, isl_error_invalid,
425 "input has unnamed parameters", goto error);
427 if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
428 multi = FN(MULTI(BASE),align_explicit_domain_params)(multi,
429 isl_space_copy(model));
430 if (!multi)
431 goto error;
433 exp = isl_parameter_alignment_reordering(multi->space, model);
434 exp = isl_reordering_extend_space(exp,
435 FN(MULTI(BASE),get_domain_space)(multi));
436 multi = FN(MULTI(BASE),realign_domain)(multi, exp);
438 isl_space_free(model);
439 return multi;
440 error:
441 isl_space_free(model);
442 FN(MULTI(BASE),free)(multi);
443 return NULL;
446 /* Create a multi expression in the given space with the elements of "list"
447 * as base expressions.
449 * Since isl_multi_*_restore_* assumes that the element and
450 * the multi expression have matching spaces, the alignment
451 * (if any) needs to be performed beforehand.
453 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
454 __isl_take isl_space *space, __isl_take LIST(EL) *list)
456 int i;
457 isl_size n, dim;
458 isl_ctx *ctx;
459 MULTI(BASE) *multi;
461 dim = isl_space_dim(space, isl_dim_out);
462 n = FN(FN(LIST(EL),n),BASE)(list);
463 if (dim < 0 || n < 0)
464 goto error;
466 ctx = isl_space_get_ctx(space);
467 if (n != dim)
468 isl_die(ctx, isl_error_invalid,
469 "invalid number of elements in list", goto error);
471 for (i = 0; i < n; ++i) {
472 EL *el = FN(LIST(EL),peek)(list, i);
473 space = isl_space_align_params(space, FN(EL,get_space)(el));
475 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
476 for (i = 0; i < n; ++i) {
477 EL *el = FN(FN(LIST(EL),get),BASE)(list, i);
478 el = FN(EL,align_params)(el, isl_space_copy(space));
479 multi = FN(MULTI(BASE),restore_check_space)(multi, i, el);
482 isl_space_free(space);
483 FN(LIST(EL),free)(list);
484 return multi;
485 error:
486 isl_space_free(space);
487 FN(LIST(EL),free)(list);
488 return NULL;
491 /* This function performs the same operation as isl_multi_*_from_*_list,
492 * but is considered as a function on an isl_space when exported.
494 __isl_give MULTI(BASE) *FN(isl_space_multi,BASE)(__isl_take isl_space *space,
495 __isl_take LIST(EL) *list)
497 return FN(FN(MULTI(BASE),from),LIST(BASE))(space, list);
500 /* Drop the "n" output dimensions of "multi" starting at "first",
501 * where the space is assumed to have been adjusted already.
503 static __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_output_dims)(
504 __isl_take MULTI(BASE) *multi, unsigned first, unsigned n)
506 int i;
508 multi = FN(MULTI(BASE),cow)(multi);
509 if (!multi)
510 return NULL;
512 for (i = 0; i < n; ++i)
513 FN(EL,free)(multi->u.p[first + i]);
514 for (i = first; i + n < multi->n; ++i)
515 multi->u.p[i] = multi->u.p[i + n];
516 multi->n -= n;
517 if (n > 0 && FN(MULTI(BASE),has_explicit_domain)(multi))
518 multi = FN(MULTI(BASE),init_explicit_domain)(multi);
520 return multi;
523 __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
524 __isl_take MULTI(BASE) *multi,
525 enum isl_dim_type type, unsigned first, unsigned n)
527 isl_size size;
528 int i;
530 multi = FN(MULTI(BASE),cow)(multi);
531 if (FN(MULTI(BASE),check_range)(multi, type, first, n) < 0)
532 return FN(MULTI(BASE),free)(multi);
534 multi->space = isl_space_drop_dims(multi->space, type, first, n);
535 if (!multi->space)
536 return FN(MULTI(BASE),free)(multi);
538 if (type == isl_dim_out)
539 return FN(MULTI(BASE),drop_output_dims)(multi, first, n);
541 if (FN(MULTI(BASE),has_explicit_domain)(multi))
542 multi = FN(MULTI(BASE),drop_explicit_domain_dims)(multi,
543 type, first, n);
545 size = FN(MULTI(BASE),size)(multi);
546 if (size < 0)
547 return FN(MULTI(BASE),free)(multi);
548 for (i = 0; i < size; ++i) {
549 multi->u.p[i] = FN(EL,drop_dims)(multi->u.p[i], type, first, n);
550 if (!multi->u.p[i])
551 return FN(MULTI(BASE),free)(multi);
554 return multi;
557 #undef TYPE
558 #define TYPE MULTI(BASE)
560 #include "isl_check_named_params_templ.c"
561 static
562 #include "isl_align_params_bin_templ.c"
564 /* Given two MULTI(BASE)s A -> B and C -> D,
565 * construct a MULTI(BASE) (A * C) -> [B -> D].
567 * If "multi1" and/or "multi2" has an explicit domain, then
568 * intersect the domain of the result with these explicit domains.
570 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
571 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
573 int i;
574 isl_size n1, n2;
575 EL *el;
576 isl_space *space;
577 MULTI(BASE) *res;
579 FN(MULTI(BASE),align_params_bin)(&multi1, &multi2);
580 n1 = FN(MULTI(BASE),size)(multi1);
581 n2 = FN(MULTI(BASE),size)(multi2);
582 if (n1 < 0 || n2 < 0)
583 goto error;
585 space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
586 FN(MULTI(BASE),get_space)(multi2));
587 res = FN(MULTI(BASE),alloc)(space);
589 for (i = 0; i < n1; ++i) {
590 el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
591 res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
594 for (i = 0; i < n2; ++i) {
595 el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
596 res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
599 if (FN(MULTI(BASE),has_explicit_domain)(multi1))
600 res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi1);
601 if (FN(MULTI(BASE),has_explicit_domain)(multi2))
602 res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi2);
604 FN(MULTI(BASE),free)(multi1);
605 FN(MULTI(BASE),free)(multi2);
606 return res;
607 error:
608 FN(MULTI(BASE),free)(multi1);
609 FN(MULTI(BASE),free)(multi2);
610 return NULL;
613 /* Is the range of "multi" a wrapped relation?
615 isl_bool FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
617 if (!multi)
618 return isl_bool_error;
619 return isl_space_range_is_wrapping(multi->space);
622 /* Given a function A -> [B -> C], extract the function A -> B.
624 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
625 __isl_take MULTI(BASE) *multi)
627 isl_space *space;
628 isl_size total, keep;
630 total = FN(MULTI(BASE),dim)(multi, isl_dim_out);
631 if (total < 0)
632 return FN(MULTI(BASE),free)(multi);
633 if (!isl_space_range_is_wrapping(multi->space))
634 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
635 "range is not a product",
636 return FN(MULTI(BASE),free)(multi));
638 space = FN(MULTI(BASE),get_space)(multi);
639 space = isl_space_range_factor_domain(space);
640 keep = isl_space_dim(space, isl_dim_out);
641 if (keep < 0)
642 multi = FN(MULTI(BASE),free)(multi);
643 multi = FN(MULTI(BASE),drop_dims)(multi,
644 isl_dim_out, keep, total - keep);
645 multi = FN(MULTI(BASE),reset_space)(multi, space);
647 return multi;
650 /* Given a function A -> [B -> C], extract the function A -> C.
652 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
653 __isl_take MULTI(BASE) *multi)
655 isl_space *space;
656 isl_size total, keep;
658 total = FN(MULTI(BASE),dim)(multi, isl_dim_out);
659 if (total < 0)
660 return FN(MULTI(BASE),free)(multi);
661 if (!isl_space_range_is_wrapping(multi->space))
662 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
663 "range is not a product",
664 return FN(MULTI(BASE),free)(multi));
666 space = FN(MULTI(BASE),get_space)(multi);
667 space = isl_space_range_factor_range(space);
668 keep = isl_space_dim(space, isl_dim_out);
669 if (keep < 0)
670 multi = FN(MULTI(BASE),free)(multi);
671 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
672 multi = FN(MULTI(BASE),reset_space)(multi, space);
674 return multi;
677 /* Given a function [B -> C], extract the function C.
679 __isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)(
680 __isl_take MULTI(BASE) *multi)
682 isl_space *space;
683 isl_size total, keep;
685 total = FN(MULTI(BASE),dim)(multi, isl_dim_set);
686 if (total < 0)
687 return FN(MULTI(BASE),free)(multi);
688 if (!isl_space_is_wrapping(multi->space))
689 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
690 "not a product", return FN(MULTI(BASE),free)(multi));
692 space = FN(MULTI(BASE),get_space)(multi);
693 space = isl_space_factor_range(space);
694 keep = isl_space_dim(space, isl_dim_set);
695 if (keep < 0)
696 multi = FN(MULTI(BASE),free)(multi);
697 multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_set, 0, total - keep);
698 multi = FN(MULTI(BASE),reset_space)(multi, space);
700 return multi;
703 __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
704 __isl_take MULTI(BASE) *multi)
706 if (!multi)
707 return NULL;
709 if (!multi->space->nested[1])
710 return multi;
712 multi = FN(MULTI(BASE),cow)(multi);
713 if (!multi)
714 return NULL;
716 multi->space = isl_space_flatten_range(multi->space);
717 if (!multi->space)
718 return FN(MULTI(BASE),free)(multi);
720 return multi;
723 /* Given two MULTI(BASE)s A -> B and C -> D,
724 * construct a MULTI(BASE) (A * C) -> (B, D).
726 __isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
727 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
729 MULTI(BASE) *multi;
731 multi = FN(MULTI(BASE),range_product)(multi1, multi2);
732 multi = FN(MULTI(BASE),flatten_range)(multi);
733 return multi;
736 /* Given two multi expressions, "multi1"
738 * [A] -> [B1 B2]
740 * where B2 starts at position "pos", and "multi2"
742 * [A] -> [D]
744 * return the multi expression
746 * [A] -> [B1 D B2]
748 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
749 __isl_take MULTI(BASE) *multi1, unsigned pos,
750 __isl_take MULTI(BASE) *multi2)
752 MULTI(BASE) *res;
753 isl_size dim;
755 dim = FN(MULTI(BASE),size)(multi1);
756 if (dim < 0 || !multi2)
757 goto error;
759 if (FN(MULTI(BASE),check_range)(multi1, isl_dim_out, pos, 0) < 0)
760 goto error;
762 res = FN(MULTI(BASE),copy)(multi1);
763 res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
764 multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
766 res = FN(MULTI(BASE),flat_range_product)(res, multi2);
767 res = FN(MULTI(BASE),flat_range_product)(res, multi1);
769 return res;
770 error:
771 FN(MULTI(BASE),free)(multi1);
772 FN(MULTI(BASE),free)(multi2);
773 return NULL;
776 #undef TYPE
777 #define TYPE MULTI(BASE)
779 static
780 #include "isl_type_has_equal_space_bin_templ.c"
781 static
782 #include "isl_type_check_equal_space_templ.c"
784 /* This function is currently only used from isl_aff.c
786 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
787 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
788 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
789 __attribute__ ((unused));
791 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
792 * return the result.
794 * If "multi2" has an explicit domain, then
795 * intersect the domain of the result with this explicit domain.
797 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
798 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
799 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
801 isl_size n;
802 int i;
804 FN(MULTI(BASE),align_params_bin)(&multi1, &multi2);
805 multi1 = FN(MULTI(BASE),cow)(multi1);
806 n = FN(MULTI(BASE),size)(multi1);
807 if (n < 0 || FN(MULTI(BASE),check_equal_space)(multi1, multi2) < 0)
808 goto error;
810 for (i = 0; i < n; ++i) {
811 multi1->u.p[i] = fn(multi1->u.p[i],
812 FN(EL,copy)(multi2->u.p[i]));
813 if (!multi1->u.p[i])
814 goto error;
817 if (FN(MULTI(BASE),has_explicit_domain)(multi2))
818 multi1 = FN(MULTI(BASE),intersect_explicit_domain)(multi1,
819 multi2);
821 FN(MULTI(BASE),free)(multi2);
822 return multi1;
823 error:
824 FN(MULTI(BASE),free)(multi1);
825 FN(MULTI(BASE),free)(multi2);
826 return NULL;
829 /* Only used on some multi-expressions.
831 static isl_bool FN(MULTI(BASE),any)(__isl_keep MULTI(BASE) *multi,
832 isl_bool (*test)(__isl_keep EL *)) __attribute__ ((unused));
834 /* Does "test" succeed on any base expression of "multi"?
836 static isl_bool FN(MULTI(BASE),any)(__isl_keep MULTI(BASE) *multi,
837 isl_bool (*test)(__isl_keep EL *))
839 isl_size n;
840 int i;
842 n = FN(MULTI(BASE),size)(multi);
843 if (n < 0)
844 return isl_bool_error;
846 for (i = 0; i < n; ++i) {
847 isl_bool any = test(multi->u.p[i]);
848 if (any < 0 || any)
849 return any;
852 return isl_bool_false;
855 /* Only used on some multi-expressions.
857 static isl_bool FN(MULTI(BASE),every)(__isl_keep MULTI(BASE) *multi,
858 isl_bool (*test)(__isl_keep EL *)) __attribute__ ((unused));
860 /* Does "test" succeed on every base expression of "multi"?
862 static isl_bool FN(MULTI(BASE),every)(__isl_keep MULTI(BASE) *multi,
863 isl_bool (*test)(__isl_keep EL *))
865 isl_size n;
866 int i;
868 n = FN(MULTI(BASE),size)(multi);
869 if (n < 0)
870 return isl_bool_error;
872 for (i = 0; i < n; ++i) {
873 isl_bool every = test(multi->u.p[i]);
874 if (every < 0 || !every)
875 return every;
878 return isl_bool_true;
881 /* Convert a multiple expression defined over a parameter domain
882 * into one that is defined over a zero-dimensional set.
884 __isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
885 __isl_take MULTI(BASE) *multi)
887 isl_space *space;
889 if (!multi)
890 return NULL;
891 if (!isl_space_is_set(multi->space))
892 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
893 "not living in a set space",
894 return FN(MULTI(BASE),free)(multi));
896 space = FN(MULTI(BASE),get_space)(multi);
897 space = isl_space_from_range(space);
898 multi = FN(MULTI(BASE),reset_space)(multi, space);
900 return multi;
903 /* Are "multi1" and "multi2" obviously equal?
905 isl_bool FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
906 __isl_keep MULTI(BASE) *multi2)
908 int i;
909 isl_bool equal;
911 if (!multi1 || !multi2)
912 return isl_bool_error;
913 if (multi1->n != multi2->n)
914 return isl_bool_false;
915 equal = isl_space_is_equal(multi1->space, multi2->space);
916 if (equal < 0 || !equal)
917 return equal;
919 for (i = 0; i < multi1->n; ++i) {
920 equal = FN(EL,plain_is_equal)(multi1->u.p[i], multi2->u.p[i]);
921 if (equal < 0 || !equal)
922 return equal;
925 if (FN(MULTI(BASE),has_explicit_domain)(multi1) ||
926 FN(MULTI(BASE),has_explicit_domain)(multi2)) {
927 equal = FN(MULTI(BASE),equal_explicit_domain)(multi1, multi2);
928 if (equal < 0 || !equal)
929 return equal;
932 return isl_bool_true;