isl_test_cpp17-generic.cc: work around std::optional::value issue in older macOS
[isl.git] / isl_union_multi.c
blobb630b18b89e05f9f324ea4c4ef7189d59bea1292
1 /*
2 * Copyright 2010 INRIA Saclay
3 * Copyright 2013 Ecole Normale Superieure
4 * Copyright 2015 INRIA Paris-Rocquencourt
6 * Use of this software is governed by the MIT license
8 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
9 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
10 * 91893 Orsay, France
11 * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
12 * and INRIA Paris-Rocquencourt, Domaine de Voluceau, Rocquenqourt, B.P. 105,
13 * 78153 Le Chesnay Cedex France
16 #include <isl/hash.h>
17 #include <isl_union_macro.h>
19 /* A group of expressions defined over the same domain space "domain_space".
20 * The entries of "part_table" are the individual expressions,
21 * keyed on the entire space of the expression (ignoring parameters).
23 * Each UNION has its own groups, so there can only ever be a single
24 * reference to each group.
26 S(UNION,group) {
27 isl_space *domain_space;
28 struct isl_hash_table part_table;
31 /* A union of expressions defined over different disjoint domains.
32 * "space" describes the parameters.
33 * The entries of "table" are keyed on the domain space of the entry
34 * (ignoring parameters) and
35 * contain groups of expressions that are defined over the same domain space.
37 struct UNION {
38 int ref;
39 isl_space *space;
41 struct isl_hash_table table;
44 /* Internal data structure for isl_union_*_foreach_group.
45 * "fn" is the function that needs to be called on each group.
47 S(UNION,foreach_group_data)
49 isl_stat (*fn)(__isl_keep S(UNION,group) *group, void *user);
50 void *user;
53 /* Call data->fn on the group stored at *entry.
55 static isl_stat FN(UNION,call_on_group)(void **entry, void *user)
57 S(UNION,group) *group = *entry;
58 S(UNION,foreach_group_data) *data;
60 data = (S(UNION,foreach_group_data) *) user;
61 return data->fn(group, data->user);
64 /* Call "fn" on each group of expressions in "u".
66 static isl_stat FN(UNION,foreach_group)(__isl_keep UNION *u,
67 isl_stat (*fn)(__isl_keep S(UNION,group) *group, void *user),
68 void *user)
70 S(UNION,foreach_group_data) data = { fn, user };
72 if (!u)
73 return isl_stat_error;
75 return isl_hash_table_foreach(u->space->ctx, &u->table,
76 &FN(UNION,call_on_group), &data);
79 /* A isl_union_*_foreach_group callback for counting the total number
80 * of expressions in a UNION. Add the number of expressions in "group"
81 * to *n.
83 static isl_stat FN(UNION,count_part)(__isl_keep S(UNION,group) *group,
84 void *user)
86 int *n = user;
88 if (!group)
89 return isl_stat_error;
91 *n += group->part_table.n;
92 return isl_stat_ok;
95 /* Return the number of base expressions in "u".
97 isl_size FN(FN(UNION,n),BASE)(__isl_keep UNION *u)
99 int n;
101 n = 0;
102 if (FN(UNION,foreach_group)(u, &FN(UNION,count_part), &n) < 0)
103 return isl_size_error;
104 return n;
107 /* Free an entry in a group of expressions.
108 * Each entry in such a group is a single expression.
110 static isl_stat FN(UNION,free_group_entry)(void **entry, void *user)
112 PART *part = *entry;
114 FN(PART,free)(part);
115 return isl_stat_ok;
118 /* Free all memory allocated for "group" and return NULL.
120 static __isl_null S(UNION,group) *FN(UNION,group_free)(
121 __isl_take S(UNION,group) *group)
123 isl_ctx *ctx;
125 if (!group)
126 return NULL;
128 ctx = isl_space_get_ctx(group->domain_space);
129 isl_hash_table_foreach(ctx, &group->part_table,
130 &FN(UNION,free_group_entry), NULL);
131 isl_hash_table_clear(&group->part_table);
132 isl_space_free(group->domain_space);
133 free(group);
134 return NULL;
137 /* Allocate a group of expressions defined over the same domain space
138 * with domain space "domain_space" and initial size "size".
140 static __isl_give S(UNION,group) *FN(UNION,group_alloc)(
141 __isl_take isl_space *domain_space, int size)
143 isl_ctx *ctx;
144 S(UNION,group) *group;
146 if (!domain_space)
147 return NULL;
148 ctx = isl_space_get_ctx(domain_space);
149 group = isl_calloc_type(ctx, S(UNION,group));
150 if (!group)
151 goto error;
152 group->domain_space = domain_space;
153 if (isl_hash_table_init(ctx, &group->part_table, size) < 0)
154 return FN(UNION,group_free)(group);
156 return group;
157 error:
158 isl_space_free(domain_space);
159 return NULL;
162 /* Is the space of "entry" equal to "space", ignoring parameters?
164 static isl_bool FN(UNION,has_space_tuples)(const void *entry, const void *val)
166 PART *part = (PART *) entry;
167 isl_space *space = (isl_space *) val;
168 isl_space *part_space;
170 part_space = FN(PART,peek_space)(part);
171 return isl_space_has_equal_tuples(part_space, space);
174 /* Return a group equal to "group", but with a single reference.
175 * Since all groups have only a single reference, simply return "group".
177 static __isl_give S(UNION,group) *FN(UNION,group_cow)(
178 __isl_take S(UNION,group) *group)
180 return group;
183 S(UNION,foreach_data)
185 isl_stat (*fn)(__isl_take PART *part, void *user);
186 void *user;
189 static isl_stat FN(UNION,call_on_copy)(void **entry, void *user)
191 PART *part = *entry;
192 S(UNION,foreach_data) *data = (S(UNION,foreach_data) *) user;
194 part = FN(PART,copy)(part);
195 if (!part)
196 return isl_stat_error;
197 return data->fn(part, data->user);
200 /* Call data->fn on a copy of each expression in "group".
202 static isl_stat FN(UNION,group_call_on_copy)(__isl_keep S(UNION,group) *group,
203 void *user)
205 isl_ctx *ctx;
207 if (!group)
208 return isl_stat_error;
210 ctx = isl_space_get_ctx(group->domain_space);
211 return isl_hash_table_foreach(ctx, &group->part_table,
212 &FN(UNION,call_on_copy), user);
215 isl_stat FN(FN(UNION,foreach),BASE)(__isl_keep UNION *u,
216 isl_stat (*fn)(__isl_take PART *part, void *user), void *user)
218 S(UNION,foreach_data) data = { fn, user };
220 if (!u)
221 return isl_stat_error;
223 return FN(UNION,foreach_group)(u, &FN(UNION,group_call_on_copy), &data);
226 /* Is the domain space of the group of expressions at "entry"
227 * equal to that of "space", ignoring parameters?
229 static isl_bool FN(UNION,group_has_same_domain_space_tuples)(const void *entry,
230 const void *val)
232 S(UNION,group) *group = (S(UNION,group) *) entry;
233 isl_space *space = (isl_space *) val;
235 return isl_space_has_domain_tuples(group->domain_space, space);
238 /* Return the entry, if any, in "u" that lives in "space".
239 * If "reserve" is set, then an entry is created if it does not exist yet.
240 * Return NULL on error and isl_hash_table_entry_none if no entry was found.
241 * Note that when "reserve" is set, the function will never return
242 * isl_hash_table_entry_none.
244 * First look for the group of expressions with the same domain space,
245 * creating one if needed.
246 * Then look for the expression living in the specified space in that group.
248 static struct isl_hash_table_entry *FN(UNION,find_part_entry)(
249 __isl_keep UNION *u, __isl_keep isl_space *space, int reserve)
251 isl_ctx *ctx;
252 uint32_t hash;
253 struct isl_hash_table_entry *group_entry;
254 S(UNION,group) *group;
256 if (!u || !space)
257 return NULL;
259 ctx = FN(UNION,get_ctx)(u);
260 hash = isl_space_get_tuple_domain_hash(space);
261 group_entry = isl_hash_table_find(ctx, &u->table, hash,
262 &FN(UNION,group_has_same_domain_space_tuples), space, reserve);
263 if (!group_entry || group_entry == isl_hash_table_entry_none)
264 return group_entry;
265 if (reserve && !group_entry->data) {
266 isl_space *domain = isl_space_domain(isl_space_copy(space));
267 group = FN(UNION,group_alloc)(domain, 1);
268 group_entry->data = group;
269 } else {
270 group = group_entry->data;
271 if (reserve)
272 group = FN(UNION,group_cow)(group);
274 if (!group)
275 return NULL;
276 hash = isl_space_get_tuple_hash(space);
277 return isl_hash_table_find(ctx, &group->part_table, hash,
278 &FN(UNION,has_space_tuples), space, reserve);
281 /* Remove "part_entry" from the hash table of "u".
283 * First look the group_entry in "u" holding the group that
284 * contains "part_entry". Remove "part_entry" from that group.
285 * If the group becomes empty, then also remove the group_entry from "u".
287 static __isl_give UNION *FN(UNION,remove_part_entry)(__isl_take UNION *u,
288 struct isl_hash_table_entry *part_entry)
290 isl_ctx *ctx;
291 uint32_t hash;
292 isl_space *space;
293 PART *part;
294 struct isl_hash_table_entry *group_entry;
295 S(UNION,group) *group;
297 if (!u || !part_entry)
298 return FN(UNION,free)(u);
300 part = part_entry->data;
301 ctx = FN(UNION,get_ctx)(u);
302 space = FN(PART,peek_space)(part);
303 hash = isl_space_get_tuple_domain_hash(space);
304 group_entry = isl_hash_table_find(ctx, &u->table, hash,
305 &FN(UNION,group_has_same_domain_space_tuples), space, 0);
306 if (!group_entry)
307 return FN(UNION,free)(u);
308 if (group_entry == isl_hash_table_entry_none)
309 isl_die(ctx, isl_error_internal, "missing group",
310 return FN(UNION,free)(u));
311 group = group_entry->data;
312 isl_hash_table_remove(ctx, &group->part_table, part_entry);
313 FN(PART,free)(part);
315 if (group->part_table.n != 0)
316 return u;
318 isl_hash_table_remove(ctx, &u->table, group_entry);
319 FN(UNION,group_free)(group);
321 return u;
324 /* Are the domains of "part1" and "part2" disjoint?
326 static isl_bool FN(UNION,disjoint_domain)(__isl_keep PART *part1,
327 __isl_keep PART *part2)
329 isl_set *dom1, *dom2;
330 isl_bool disjoint;
332 if (!part1 || !part2)
333 return isl_bool_error;
334 dom1 = FN(PART,domain)(FN(PART,copy)(part1));
335 dom2 = FN(PART,domain)(FN(PART,copy)(part2));
336 disjoint = isl_set_is_disjoint(dom1, dom2);
337 isl_set_free(dom1);
338 isl_set_free(dom2);
340 return disjoint;
343 /* Check that the expression at *entry has a domain that is disjoint
344 * from that of "part", unless they also have the same target space.
346 static isl_stat FN(UNION,check_disjoint_domain_entry)(void **entry, void *user)
348 PART *part = user;
349 PART *other = *entry;
350 isl_bool equal;
351 isl_bool disjoint;
353 equal = isl_space_is_equal(part->dim, other->dim);
354 if (equal < 0)
355 return isl_stat_error;
356 if (equal)
357 return isl_stat_ok;
359 disjoint = FN(UNION,disjoint_domain)(part, other);
360 if (disjoint < 0)
361 return isl_stat_error;
362 if (!disjoint)
363 isl_die(FN(PART,get_ctx)(part), isl_error_invalid,
364 "overlapping domain with other part",
365 return isl_stat_error);
366 return isl_stat_ok;
369 /* Check that the domain of "part" is disjoint from the domain of the entries
370 * in "u" that are defined on the same domain space, but have a different
371 * target space.
372 * If there is no group of expressions in "u" with the same domain space,
373 * then everything is fine. Otherwise, check the individual expressions
374 * in that group.
376 static isl_stat FN(UNION,check_disjoint_domain_other)(__isl_keep UNION *u,
377 __isl_keep PART *part)
379 isl_ctx *ctx;
380 uint32_t hash;
381 isl_space *space;
382 struct isl_hash_table_entry *group_entry;
383 S(UNION,group) *group;
385 if (!u || !part)
386 return isl_stat_error;
387 ctx = FN(UNION,get_ctx)(u);
388 space = FN(PART,peek_space)(part);
389 hash = isl_space_get_tuple_domain_hash(space);
390 group_entry = isl_hash_table_find(ctx, &u->table, hash,
391 &FN(UNION,group_has_same_domain_space_tuples), space, 0);
392 if (!group_entry)
393 return isl_stat_error;
394 if (group_entry == isl_hash_table_entry_none)
395 return isl_stat_ok;
396 group = group_entry->data;
397 return isl_hash_table_foreach(ctx, &group->part_table,
398 &FN(UNION,check_disjoint_domain_entry), part);
401 /* Check that the domain of "part1" is disjoint from the domain of "part2".
402 * This check is performed before "part2" is added to a UNION to ensure
403 * that the UNION expression remains a function.
405 static isl_stat FN(UNION,check_disjoint_domain)(__isl_keep PART *part1,
406 __isl_keep PART *part2)
408 isl_bool disjoint;
410 disjoint = FN(UNION,disjoint_domain)(part1, part2);
411 if (disjoint < 0)
412 return isl_stat_error;
413 if (!disjoint)
414 isl_die(FN(PART,get_ctx)(part1), isl_error_invalid,
415 "domain of additional part should be disjoint",
416 return isl_stat_error);
417 return isl_stat_ok;
420 /* Internal data structure for isl_union_*_foreach_inplace.
421 * "fn" is the function that needs to be called on each entry.
423 S(UNION,foreach_inplace_data)
425 isl_stat (*fn)(void **entry, void *user);
426 void *user;
429 /* isl_union_*_foreach_group callback for calling data->fn on
430 * each part entry in the group.
432 static isl_stat FN(UNION,group_call_inplace)(__isl_keep S(UNION,group) *group,
433 void *user)
435 isl_ctx *ctx;
436 S(UNION,foreach_inplace_data) *data;
438 if (!group)
439 return isl_stat_error;
441 data = (S(UNION,foreach_inplace_data) *) user;
442 ctx = isl_space_get_ctx(group->domain_space);
443 return isl_hash_table_foreach(ctx, &group->part_table,
444 data->fn, data->user);
447 /* Call "fn" on each part entry of "u".
449 static isl_stat FN(UNION,foreach_inplace)(__isl_keep UNION *u,
450 isl_stat (*fn)(void **part, void *user), void *user)
452 S(UNION,foreach_inplace_data) data = { fn, user };
454 return FN(UNION,foreach_group)(u, &FN(UNION,group_call_inplace), &data);
457 static isl_stat FN(UNION,free_u_entry)(void **entry, void *user)
459 S(UNION,group) *group = *entry;
460 FN(UNION,group_free)(group);
461 return isl_stat_ok;
464 /* Does "u" have an obviously empty definition domain?
466 isl_bool FN(UNION,plain_is_empty)(__isl_take UNION *u)
468 if (!u)
469 return isl_bool_error;
470 return isl_bool_ok(u->table.n == 0);
473 /* Set "single" to true if this group of expressions
474 * contains an expression living in exactly one space.
476 static isl_stat FN(UNION,group_single_space)(__isl_keep S(UNION,group) *group,
477 void *user)
479 isl_bool *single = user;
481 if (!group)
482 return isl_stat_error;
483 *single = isl_bool_ok(group->part_table.n == 1);
484 return isl_stat_ok;
487 /* Can this union expression be converted to a single base expression?
488 * That is, does it contain a base expression in exactly one space?
489 * In particular, is only one domain space involved and
490 * is only a single expression associated to that domain?
492 isl_bool FN(FN(UNION,isa),BASE)(__isl_take UNION *u)
494 isl_bool single;
496 if (!u)
497 return isl_bool_error;
498 if (u->table.n != 1)
499 return isl_bool_false;
500 if (FN(UNION,foreach_group)(u,
501 &FN(UNION,group_single_space), &single) < 0)
502 return isl_bool_error;
503 return single;
506 /* Callback for isl_union_*_foreach_inplace call
507 * on a union expression with a single base expression.
508 * Store that base expression in "user".
509 * This callback should only be called once
510 * for any given isl_union_*_foreach_inplace call.
512 static isl_stat FN(UNION,extract_part)(void **entry, void *user)
514 PART **part_p = user;
515 PART *part = *entry;
517 if (*part_p)
518 isl_die(FN(PART,get_ctx)(part), isl_error_internal,
519 "more than one part", return isl_stat_error);
520 *part_p = FN(PART,copy)(part);
521 if (!*part_p)
522 return isl_stat_error;
523 return isl_stat_ok;
526 /* Convert the union expression to its single base expression.
528 __isl_give PART *FN(FN(UNION,as),BASE)(__isl_take UNION *u)
530 isl_bool has_single_space;
531 PART *part = NULL;
533 has_single_space = FN(FN(UNION,isa),BASE)(u);
534 if (has_single_space < 0)
535 goto error;
536 if (!has_single_space)
537 isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
538 "expecting elements in exactly one space",
539 goto error);
540 if (FN(UNION,foreach_inplace)(u, &FN(UNION,extract_part), &part) < 0)
541 part = FN(PART,free)(part);
542 FN(UNION,free)(u);
543 return part;
544 error:
545 FN(UNION,free)(u);
546 return NULL;
549 #include <isl_union_templ.c>