2 * Copyright 2008-2009 Katholieke Universiteit Leuven
3 * Copyright 2011 INRIA Saclay
4 * Copyright 2012-2013 Ecole Normale Superieure
6 * Use of this software is governed by the MIT license
8 * Written by Sven Verdoolaege, K.U.Leuven, Departement
9 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
10 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
11 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
12 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
16 #include <isl_tarjan.h>
18 #define xCAT(A,B) A ## B
19 #define CAT(A,B) xCAT(A,B)
21 #define EL CAT(isl_,BASE)
22 #define xFN(TYPE,NAME) TYPE ## _ ## NAME
23 #define FN(TYPE,NAME) xFN(TYPE,NAME)
24 #define xLIST(EL) EL ## _list
25 #define LIST(EL) xLIST(EL)
26 #define xS(TYPE,NAME) struct TYPE ## _ ## NAME
27 #define S(TYPE,NAME) xS(TYPE,NAME)
29 isl_ctx
*FN(LIST(EL
),get_ctx
)(__isl_keep
LIST(EL
) *list
)
31 return list
? list
->ctx
: NULL
;
34 __isl_give
LIST(EL
) *FN(LIST(EL
),alloc
)(isl_ctx
*ctx
, int n
)
39 isl_die(ctx
, isl_error_invalid
,
40 "cannot create list of negative length",
42 list
= isl_alloc(ctx
, LIST(EL
),
43 sizeof(LIST(EL
)) + (n
- 1) * sizeof(struct EL
*));
55 __isl_give
LIST(EL
) *FN(LIST(EL
),copy
)(__isl_keep
LIST(EL
) *list
)
64 __isl_give
LIST(EL
) *FN(LIST(EL
),dup
)(__isl_keep
LIST(EL
) *list
)
72 dup
= FN(LIST(EL
),alloc
)(FN(LIST(EL
),get_ctx
)(list
), list
->n
);
75 for (i
= 0; i
< list
->n
; ++i
)
76 dup
= FN(LIST(EL
),add
)(dup
, FN(EL
,copy
)(list
->p
[i
]));
80 __isl_give
LIST(EL
) *FN(LIST(EL
),cow
)(__isl_take
LIST(EL
) *list
)
88 return FN(LIST(EL
),dup
)(list
);
91 /* Make sure "list" has room for at least "n" more pieces.
92 * Always return a list with a single reference.
94 * If there is only one reference to list, we extend it in place.
95 * Otherwise, we create a new LIST(EL) and copy the elements.
97 static __isl_give
LIST(EL
) *FN(LIST(EL
),grow
)(__isl_take
LIST(EL
) *list
, int n
)
105 if (list
->ref
== 1 && list
->n
+ n
<= list
->size
)
108 ctx
= FN(LIST(EL
),get_ctx
)(list
);
109 new_size
= ((list
->n
+ n
+ 1) * 3) / 2;
110 if (list
->ref
== 1) {
111 res
= isl_realloc(ctx
, list
, LIST(EL
),
112 sizeof(LIST(EL
)) + (new_size
- 1) * sizeof(EL
*));
114 return FN(LIST(EL
),free
)(list
);
115 res
->size
= new_size
;
119 if (list
->n
+ n
<= list
->size
&& list
->size
< new_size
)
120 new_size
= list
->size
;
122 res
= FN(LIST(EL
),alloc
)(ctx
, new_size
);
124 return FN(LIST(EL
),free
)(list
);
126 for (i
= 0; i
< list
->n
; ++i
)
127 res
= FN(LIST(EL
),add
)(res
, FN(EL
,copy
)(list
->p
[i
]));
129 FN(LIST(EL
),free
)(list
);
133 __isl_give
LIST(EL
) *FN(LIST(EL
),add
)(__isl_take
LIST(EL
) *list
,
134 __isl_take
struct EL
*el
)
136 list
= FN(LIST(EL
),grow
)(list
, 1);
139 list
->p
[list
->n
] = el
;
144 FN(LIST(EL
),free
)(list
);
148 /* Remove the "n" elements starting at "first" from "list".
150 __isl_give
LIST(EL
) *FN(LIST(EL
),drop
)(__isl_take
LIST(EL
) *list
,
151 unsigned first
, unsigned n
)
157 if (first
+ n
> list
->n
|| first
+ n
< first
)
158 isl_die(list
->ctx
, isl_error_invalid
,
159 "index out of bounds", return FN(LIST(EL
),free
)(list
));
162 list
= FN(LIST(EL
),cow
)(list
);
165 for (i
= 0; i
< n
; ++i
)
166 FN(EL
,free
)(list
->p
[first
+ i
]);
167 for (i
= first
; i
+ n
< list
->n
; ++i
)
168 list
->p
[i
] = list
->p
[i
+ n
];
173 /* Insert "el" at position "pos" in "list".
175 * If there is only one reference to "list" and if it already has space
176 * for one extra element, we insert it directly into "list".
177 * Otherwise, we create a new list consisting of "el" and copied
178 * elements from "list".
180 __isl_give
LIST(EL
) *FN(LIST(EL
),insert
)(__isl_take
LIST(EL
) *list
,
181 unsigned pos
, __isl_take
struct EL
*el
)
189 ctx
= FN(LIST(EL
),get_ctx
)(list
);
191 isl_die(ctx
, isl_error_invalid
,
192 "index out of bounds", goto error
);
194 if (list
->ref
== 1 && list
->size
> list
->n
) {
195 for (i
= list
->n
; i
> pos
; --i
)
196 list
->p
[i
] = list
->p
[i
- 1];
202 res
= FN(LIST(EL
),alloc
)(ctx
, list
->n
+ 1);
203 for (i
= 0; i
< pos
; ++i
)
204 res
= FN(LIST(EL
),add
)(res
, FN(EL
,copy
)(list
->p
[i
]));
205 res
= FN(LIST(EL
),add
)(res
, el
);
206 for (i
= pos
; i
< list
->n
; ++i
)
207 res
= FN(LIST(EL
),add
)(res
, FN(EL
,copy
)(list
->p
[i
]));
208 FN(LIST(EL
),free
)(list
);
213 FN(LIST(EL
),free
)(list
);
217 __isl_null
LIST(EL
) *FN(LIST(EL
),free
)(__isl_take
LIST(EL
) *list
)
227 isl_ctx_deref(list
->ctx
);
228 for (i
= 0; i
< list
->n
; ++i
)
229 FN(EL
,free
)(list
->p
[i
]);
235 int FN(FN(LIST(EL
),n
),BASE
)(__isl_keep
LIST(EL
) *list
)
237 return list
? list
->n
: 0;
240 __isl_give EL
*FN(FN(LIST(EL
),get
),BASE
)(__isl_keep
LIST(EL
) *list
, int index
)
244 if (index
< 0 || index
>= list
->n
)
245 isl_die(list
->ctx
, isl_error_invalid
,
246 "index out of bounds", return NULL
);
247 return FN(EL
,copy
)(list
->p
[index
]);
250 /* Replace the element at position "index" in "list" by "el".
252 __isl_give
LIST(EL
) *FN(FN(LIST(EL
),set
),BASE
)(__isl_take
LIST(EL
) *list
,
253 int index
, __isl_take EL
*el
)
257 if (index
< 0 || index
>= list
->n
)
258 isl_die(list
->ctx
, isl_error_invalid
,
259 "index out of bounds", goto error
);
260 if (list
->p
[index
] == el
) {
264 list
= FN(LIST(EL
),cow
)(list
);
267 FN(EL
,free
)(list
->p
[index
]);
272 FN(LIST(EL
),free
)(list
);
276 isl_stat
FN(LIST(EL
),foreach
)(__isl_keep
LIST(EL
) *list
,
277 isl_stat (*fn
)(__isl_take EL
*el
, void *user
), void *user
)
282 return isl_stat_error
;
284 for (i
= 0; i
< list
->n
; ++i
) {
285 EL
*el
= FN(EL
,copy(list
->p
[i
]));
287 return isl_stat_error
;
288 if (fn(el
, user
) < 0)
289 return isl_stat_error
;
295 /* Internal data structure for isl_*_list_sort.
297 * "cmp" is the original comparison function.
298 * "user" is a user provided pointer that should be passed to "cmp".
300 S(LIST(EL
),sort_data
) {
301 int (*cmp
)(__isl_keep EL
*a
, __isl_keep EL
*b
, void *user
);
305 /* Compare two entries of an isl_*_list based on the user provided
306 * comparison function on pairs of isl_* objects.
308 static int FN(LIST(EL
),cmp
)(const void *a
, const void *b
, void *user
)
310 S(LIST(EL
),sort_data
) *data
= user
;
314 return data
->cmp(*el1
, *el2
, data
->user
);
317 /* Sort the elements of "list" in ascending order according to
318 * comparison function "cmp".
320 __isl_give
LIST(EL
) *FN(LIST(EL
),sort
)(__isl_take
LIST(EL
) *list
,
321 int (*cmp
)(__isl_keep EL
*a
, __isl_keep EL
*b
, void *user
), void *user
)
323 S(LIST(EL
),sort_data
) data
= { cmp
, user
};
329 list
= FN(LIST(EL
),cow
)(list
);
333 if (isl_sort(list
->p
, list
->n
, sizeof(list
->p
[0]),
334 &FN(LIST(EL
),cmp
), &data
) < 0)
335 return FN(LIST(EL
),free
)(list
);
340 /* Internal data structure for isl_*_list_foreach_scc.
342 * "list" is the original list.
343 * "follows" is the user provided callback that defines the edges of the graph.
345 S(LIST(EL
),foreach_scc_data
) {
347 isl_bool (*follows
)(__isl_keep EL
*a
, __isl_keep EL
*b
, void *user
);
351 /* Does element i of data->list follow element j?
353 * Use the user provided callback to find out.
355 static isl_bool
FN(LIST(EL
),follows
)(int i
, int j
, void *user
)
357 S(LIST(EL
),foreach_scc_data
) *data
= user
;
359 return data
->follows(data
->list
->p
[i
], data
->list
->p
[j
],
363 /* Call "fn" on the sublist of "list" that consists of the elements
364 * with indices specified by the "n" elements of "pos".
366 static isl_stat
FN(LIST(EL
),call_on_scc
)(__isl_keep
LIST(EL
) *list
, int *pos
,
367 int n
, isl_stat (*fn
)(__isl_take
LIST(EL
) *scc
, void *user
), void *user
)
373 ctx
= FN(LIST(EL
),get_ctx
)(list
);
374 slice
= FN(LIST(EL
),alloc
)(ctx
, n
);
375 for (i
= 0; i
< n
; ++i
) {
378 el
= FN(EL
,copy
)(list
->p
[pos
[i
]]);
379 slice
= FN(LIST(EL
),add
)(slice
, el
);
382 return fn(slice
, user
);
385 /* Call "fn" on each of the strongly connected components (SCCs) of
386 * the graph with as vertices the elements of "list" and
387 * a directed edge from node b to node a iff follows(a, b)
388 * returns 1. follows should return -1 on error.
390 * If SCC a contains a node i that follows a node j in another SCC b
391 * (i.e., follows(i, j, user) returns 1), then fn will be called on SCC a
392 * after being called on SCC b.
394 * We simply call isl_tarjan_graph_init, extract the SCCs from the result and
395 * call fn on each of them.
397 isl_stat
FN(LIST(EL
),foreach_scc
)(__isl_keep
LIST(EL
) *list
,
398 isl_bool (*follows
)(__isl_keep EL
*a
, __isl_keep EL
*b
, void *user
),
400 isl_stat (*fn
)(__isl_take
LIST(EL
) *scc
, void *user
), void *fn_user
)
402 S(LIST(EL
),foreach_scc_data
) data
= { list
, follows
, follows_user
};
405 struct isl_tarjan_graph
*g
;
408 return isl_stat_error
;
412 return fn(FN(LIST(EL
),copy
)(list
), fn_user
);
414 ctx
= FN(LIST(EL
),get_ctx
)(list
);
416 g
= isl_tarjan_graph_init(ctx
, n
, &FN(LIST(EL
),follows
), &data
);
418 return isl_stat_error
;
424 if (g
->order
[i
] == -1)
425 isl_die(ctx
, isl_error_internal
, "cannot happen",
428 while (g
->order
[i
] != -1) {
431 if (first
== 0 && n
== 0) {
432 isl_tarjan_graph_free(g
);
433 return fn(FN(LIST(EL
),copy
)(list
), fn_user
);
435 if (FN(LIST(EL
),call_on_scc
)(list
, g
->order
+ first
, i
- first
,
441 isl_tarjan_graph_free(g
);
443 return n
> 0 ? isl_stat_error
: isl_stat_ok
;
446 __isl_give
LIST(EL
) *FN(FN(LIST(EL
),from
),BASE
)(__isl_take EL
*el
)
453 ctx
= FN(EL
,get_ctx
)(el
);
454 list
= FN(LIST(EL
),alloc
)(ctx
, 1);
457 list
= FN(LIST(EL
),add
)(list
, el
);
464 __isl_give
LIST(EL
) *FN(LIST(EL
),concat
)(__isl_take
LIST(EL
) *list1
,
465 __isl_take
LIST(EL
) *list2
)
471 if (!list1
|| !list2
)
474 ctx
= FN(LIST(EL
),get_ctx
)(list1
);
475 res
= FN(LIST(EL
),alloc
)(ctx
, list1
->n
+ list2
->n
);
476 for (i
= 0; i
< list1
->n
; ++i
)
477 res
= FN(LIST(EL
),add
)(res
, FN(EL
,copy
)(list1
->p
[i
]));
478 for (i
= 0; i
< list2
->n
; ++i
)
479 res
= FN(LIST(EL
),add
)(res
, FN(EL
,copy
)(list2
->p
[i
]));
481 FN(LIST(EL
),free
)(list1
);
482 FN(LIST(EL
),free
)(list2
);
485 FN(LIST(EL
),free
)(list1
);
486 FN(LIST(EL
),free
)(list2
);
490 __isl_give isl_printer
*CAT(isl_printer_print_
,LIST(BASE
))(
491 __isl_take isl_printer
*p
, __isl_keep
LIST(EL
) *list
)
497 p
= isl_printer_print_str(p
, "(");
498 for (i
= 0; i
< list
->n
; ++i
) {
500 p
= isl_printer_print_str(p
, ",");
501 p
= CAT(isl_printer_print_
,BASE
)(p
, list
->p
[i
]);
503 p
= isl_printer_print_str(p
, ")");
510 void FN(LIST(EL
),dump
)(__isl_keep
LIST(EL
) *list
)
512 isl_printer
*printer
;
517 printer
= isl_printer_to_file(FN(LIST(EL
),get_ctx
)(list
), stderr
);
518 printer
= CAT(isl_printer_print_
,LIST(BASE
))(printer
, list
);
519 printer
= isl_printer_end_line(printer
);
521 isl_printer_free(printer
);