isl_basic_set_opt: avoid invalid access on error path
[platform/upstream/isl.git] / isl_vec.c
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the MIT license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9
10 #include <isl_ctx_private.h>
11 #include <isl/seq.h>
12 #include <isl/vec.h>
13
14 isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec)
15 {
16         return vec ? vec->ctx : NULL;
17 }
18
19 struct isl_vec *isl_vec_alloc(struct isl_ctx *ctx, unsigned size)
20 {
21         struct isl_vec *vec;
22
23         vec = isl_alloc_type(ctx, struct isl_vec);
24         if (!vec)
25                 return NULL;
26
27         vec->block = isl_blk_alloc(ctx, size);
28         if (isl_blk_is_error(vec->block))
29                 goto error;
30
31         vec->ctx = ctx;
32         isl_ctx_ref(ctx);
33         vec->ref = 1;
34         vec->size = size;
35         vec->el = vec->block.data;
36
37         return vec;
38 error:
39         isl_blk_free(ctx, vec->block);
40         return NULL;
41 }
42
43 __isl_give isl_vec *isl_vec_extend(__isl_take isl_vec *vec, unsigned size)
44 {
45         if (!vec)
46                 return NULL;
47         if (size <= vec->size)
48                 return vec;
49
50         vec = isl_vec_cow(vec);
51         if (!vec)
52                 return NULL;
53
54         vec->block = isl_blk_extend(vec->ctx, vec->block, size);
55         if (!vec->block.data)
56                 goto error;
57
58         vec->size = size;
59         vec->el = vec->block.data;
60
61         return vec;
62 error:
63         isl_vec_free(vec);
64         return NULL;
65 }
66
67 __isl_give isl_vec *isl_vec_zero_extend(__isl_take isl_vec *vec, unsigned size)
68 {
69         int extra;
70
71         if (!vec)
72                 return NULL;
73         if (size <= vec->size)
74                 return vec;
75
76         vec = isl_vec_cow(vec);
77         if (!vec)
78                 return NULL;
79
80         extra = size - vec->size;
81         vec = isl_vec_extend(vec, size);
82         if (!vec)
83                 return NULL;
84
85         isl_seq_clr(vec->el + size - extra, extra);
86
87         return vec;
88 }
89
90 /* Return a vector containing the elements of "vec1" followed by
91  * those of "vec2".
92  */
93 __isl_give isl_vec *isl_vec_concat(__isl_take isl_vec *vec1,
94         __isl_take isl_vec *vec2)
95 {
96         if (!vec1 || !vec2)
97                 goto error;
98
99         if (vec2->size == 0) {
100                 isl_vec_free(vec2);
101                 return vec1;
102         }
103
104         if (vec1->size == 0) {
105                 isl_vec_free(vec1);
106                 return vec2;
107         }
108
109         vec1 = isl_vec_extend(vec1, vec1->size + vec2->size);
110         if (!vec1)
111                 goto error;
112
113         isl_seq_cpy(vec1->el + vec1->size - vec2->size, vec2->el, vec2->size);
114
115         isl_vec_free(vec2);
116         return vec1;
117 error:
118         isl_vec_free(vec1);
119         isl_vec_free(vec2);
120         return NULL;
121 }
122
123 struct isl_vec *isl_vec_copy(struct isl_vec *vec)
124 {
125         if (!vec)
126                 return NULL;
127
128         vec->ref++;
129         return vec;
130 }
131
132 struct isl_vec *isl_vec_dup(struct isl_vec *vec)
133 {
134         struct isl_vec *vec2;
135
136         if (!vec)
137                 return NULL;
138         vec2 = isl_vec_alloc(vec->ctx, vec->size);
139         if (!vec2)
140                 return NULL;
141         isl_seq_cpy(vec2->el, vec->el, vec->size);
142         return vec2;
143 }
144
145 struct isl_vec *isl_vec_cow(struct isl_vec *vec)
146 {
147         struct isl_vec *vec2;
148         if (!vec)
149                 return NULL;
150
151         if (vec->ref == 1)
152                 return vec;
153
154         vec2 = isl_vec_dup(vec);
155         isl_vec_free(vec);
156         return vec2;
157 }
158
159 void *isl_vec_free(__isl_take isl_vec *vec)
160 {
161         if (!vec)
162                 return NULL;
163
164         if (--vec->ref > 0)
165                 return NULL;
166
167         isl_ctx_deref(vec->ctx);
168         isl_blk_free(vec->ctx, vec->block);
169         free(vec);
170
171         return NULL;
172 }
173
174 int isl_vec_size(__isl_keep isl_vec *vec)
175 {
176         return vec ? vec->size : -1;
177 }
178
179 int isl_vec_get_element(__isl_keep isl_vec *vec, int pos, isl_int *v)
180 {
181         if (!vec)
182                 return -1;
183
184         if (pos < 0 || pos >= vec->size)
185                 isl_die(vec->ctx, isl_error_invalid, "position out of range",
186                         return -1);
187         isl_int_set(*v, vec->el[pos]);
188         return 0;
189 }
190
191 __isl_give isl_vec *isl_vec_set_element(__isl_take isl_vec *vec,
192         int pos, isl_int v)
193 {
194         vec = isl_vec_cow(vec);
195         if (!vec)
196                 return NULL;
197         if (pos < 0 || pos >= vec->size)
198                 isl_die(vec->ctx, isl_error_invalid, "position out of range",
199                         goto error);
200         isl_int_set(vec->el[pos], v);
201         return vec;
202 error:
203         isl_vec_free(vec);
204         return NULL;
205 }
206
207 __isl_give isl_vec *isl_vec_set_element_si(__isl_take isl_vec *vec,
208         int pos, int v)
209 {
210         vec = isl_vec_cow(vec);
211         if (!vec)
212                 return NULL;
213         if (pos < 0 || pos >= vec->size)
214                 isl_die(vec->ctx, isl_error_invalid, "position out of range",
215                         goto error);
216         isl_int_set_si(vec->el[pos], v);
217         return vec;
218 error:
219         isl_vec_free(vec);
220         return NULL;
221 }
222
223 int isl_vec_is_equal(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2)
224 {
225         if (!vec1 || !vec2)
226                 return -1;
227
228         if (vec1->size != vec2->size)
229                 return 0;
230
231         return isl_seq_eq(vec1->el, vec2->el, vec1->size);
232 }
233
234 __isl_give isl_printer *isl_printer_print_vec(__isl_take isl_printer *printer,
235         __isl_keep isl_vec *vec)
236 {
237         int i;
238
239         if (!printer || !vec)
240                 goto error;
241
242         printer = isl_printer_print_str(printer, "[");
243         for (i = 0; i < vec->size; ++i) {
244                 if (i)
245                         printer = isl_printer_print_str(printer, ",");
246                 printer = isl_printer_print_isl_int(printer, vec->el[i]);
247         }
248         printer = isl_printer_print_str(printer, "]");
249
250         return printer;
251 error:
252         isl_printer_free(printer);
253         return NULL;
254 }
255
256 void isl_vec_dump(struct isl_vec *vec)
257 {
258         isl_printer *printer;
259
260         if (!vec)
261                 return;
262
263         printer = isl_printer_to_file(vec->ctx, stderr);
264         printer = isl_printer_print_vec(printer, vec);
265         printer = isl_printer_end_line(printer);
266
267         isl_printer_free(printer);
268 }
269
270 __isl_give isl_vec *isl_vec_set(__isl_take isl_vec *vec, isl_int v)
271 {
272         vec = isl_vec_cow(vec);
273         if (!vec)
274                 return NULL;
275         isl_seq_set(vec->el, v, vec->size);
276         return vec;
277 }
278
279 __isl_give isl_vec *isl_vec_set_si(__isl_take isl_vec *vec, int v)
280 {
281         vec = isl_vec_cow(vec);
282         if (!vec)
283                 return NULL;
284         isl_seq_set_si(vec->el, v, vec->size);
285         return vec;
286 }
287
288 __isl_give isl_vec *isl_vec_clr(__isl_take isl_vec *vec)
289 {
290         vec = isl_vec_cow(vec);
291         if (!vec)
292                 return NULL;
293         isl_seq_clr(vec->el, vec->size);
294         return vec;
295 }
296
297 void isl_vec_lcm(struct isl_vec *vec, isl_int *lcm)
298 {
299         isl_seq_lcm(vec->block.data, vec->size, lcm);
300 }
301
302 /* Given a rational vector, with the denominator in the first element
303  * of the vector, round up all coordinates.
304  */
305 struct isl_vec *isl_vec_ceil(struct isl_vec *vec)
306 {
307         vec = isl_vec_cow(vec);
308         if (!vec)
309                 return NULL;
310
311         isl_seq_cdiv_q(vec->el + 1, vec->el + 1, vec->el[0], vec->size - 1);
312
313         isl_int_set_si(vec->el[0], 1);
314
315         return vec;
316 }
317
318 struct isl_vec *isl_vec_normalize(struct isl_vec *vec)
319 {
320         if (!vec)
321                 return NULL;
322         isl_seq_normalize(vec->ctx, vec->el, vec->size);
323         return vec;
324 }
325
326 __isl_give isl_vec *isl_vec_neg(__isl_take isl_vec *vec)
327 {
328         vec = isl_vec_cow(vec);
329         if (!vec)
330                 return NULL;
331         isl_seq_neg(vec->el, vec->el, vec->size);
332         return vec;
333 }
334
335 __isl_give isl_vec *isl_vec_scale(__isl_take isl_vec *vec, isl_int m)
336 {
337         if (isl_int_is_one(m))
338                 return vec;
339         vec = isl_vec_cow(vec);
340         if (!vec)
341                 return NULL;
342         isl_seq_scale(vec->el, vec->el, m, vec->size);
343         return vec;
344 }
345
346 /* Reduce the elements of "vec" modulo "m".
347  */
348 __isl_give isl_vec *isl_vec_fdiv_r(__isl_take isl_vec *vec, isl_int m)
349 {
350         vec = isl_vec_cow(vec);
351         if (!vec)
352                 return NULL;
353
354         isl_seq_fdiv_r(vec->el, vec->el, m, vec->size);
355
356         return vec;
357 }
358
359 __isl_give isl_vec *isl_vec_add(__isl_take isl_vec *vec1,
360         __isl_take isl_vec *vec2)
361 {
362         vec1 = isl_vec_cow(vec1);
363         if (!vec1 || !vec2)
364                 goto error;
365
366         isl_assert(vec1->ctx, vec1->size == vec2->size, goto error);
367
368         isl_seq_combine(vec1->el, vec1->ctx->one, vec1->el,
369                         vec1->ctx->one, vec2->el, vec1->size);
370         
371         isl_vec_free(vec2);
372         return vec1;
373 error:
374         isl_vec_free(vec1);
375         isl_vec_free(vec2);
376         return NULL;
377 }
378
379 static int qsort_int_cmp(const void *p1, const void *p2)
380 {
381         const isl_int *i1 = (const isl_int *) p1;
382         const isl_int *i2 = (const isl_int *) p2;
383
384         return isl_int_cmp(*i1, *i2);
385 }
386
387 __isl_give isl_vec *isl_vec_sort(__isl_take isl_vec *vec)
388 {
389         if (!vec)
390                 return NULL;
391         
392         qsort(vec->el, vec->size, sizeof(*vec->el), &qsort_int_cmp);
393
394         return vec;
395 }
396
397 __isl_give isl_vec *isl_vec_drop_els(__isl_take isl_vec *vec,
398         unsigned pos, unsigned n)
399 {
400         if (n == 0)
401                 return vec;
402         vec = isl_vec_cow(vec);
403         if (!vec)
404                 return NULL;
405
406         if (pos + n > vec->size)
407                 isl_die(vec->ctx, isl_error_invalid,
408                         "range out of bounds", goto error);
409
410         if (pos + n != vec->size)
411                 isl_seq_cpy(vec->el + pos, vec->el + pos + n,
412                             vec->size - pos - n);
413
414         vec->size -= n;
415         
416         return vec;
417 error:
418         isl_vec_free(vec);
419         return NULL;
420 }
421
422 __isl_give isl_vec *isl_vec_insert_els(__isl_take isl_vec *vec,
423         unsigned pos, unsigned n)
424 {
425         isl_vec *ext = NULL;
426
427         if (n == 0)
428                 return vec;
429         if (!vec)
430                 return NULL;
431
432         if (pos > vec->size)
433                 isl_die(vec->ctx, isl_error_invalid,
434                         "position out of bounds", goto error);
435
436         ext =  isl_vec_alloc(vec->ctx, vec->size + n);
437         if (!ext)
438                 goto error;
439
440         isl_seq_cpy(ext->el, vec->el, pos);
441         isl_seq_cpy(ext->el + pos + n, vec->el + pos, vec->size - pos);
442
443         isl_vec_free(vec);
444         return ext;
445 error:
446         isl_vec_free(vec);
447         isl_vec_free(ext);
448         return NULL;
449 }
450
451 __isl_give isl_vec *isl_vec_insert_zero_els(__isl_take isl_vec *vec,
452         unsigned pos, unsigned n)
453 {
454         vec = isl_vec_insert_els(vec, pos, n);
455         if (!vec)
456                 return NULL;
457
458         isl_seq_clr(vec->el + pos, n);
459
460         return vec;
461 }