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 <string.h> |
11 | #include <isl_ctx_private.h> |
12 | #include <isl_id_private.h> |
13 | |
14 | #undef EL_BASE |
15 | #define EL_BASE id |
16 | |
17 | #include <isl_list_templ.c> |
18 | #include <isl_list_read_templ.c> |
19 | |
20 | /* A special, static isl_id to use as domains (and ranges) |
21 | * of sets and parameters domains. |
22 | * The user should never get a hold on this isl_id. |
23 | */ |
24 | isl_id isl_id_none = { |
25 | .ref = -1, |
26 | .ctx = NULL, |
27 | .name = "#none" , |
28 | .user = NULL |
29 | }; |
30 | |
31 | isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id) |
32 | { |
33 | return id ? id->ctx : NULL; |
34 | } |
35 | |
36 | void *isl_id_get_user(__isl_keep isl_id *id) |
37 | { |
38 | return id ? id->user : NULL; |
39 | } |
40 | |
41 | const char *isl_id_get_name(__isl_keep isl_id *id) |
42 | { |
43 | return id ? id->name : NULL; |
44 | } |
45 | |
46 | static __isl_give isl_id *id_alloc(isl_ctx *ctx, const char *name, void *user) |
47 | { |
48 | const char *copy = name ? strdup(s: name) : NULL; |
49 | isl_id *id; |
50 | |
51 | if (name && !copy) |
52 | return NULL; |
53 | id = isl_calloc_type(ctx, struct isl_id); |
54 | if (!id) |
55 | goto error; |
56 | |
57 | id->ctx = ctx; |
58 | isl_ctx_ref(ctx: id->ctx); |
59 | id->ref = 1; |
60 | id->name = copy; |
61 | id->user = user; |
62 | |
63 | id->hash = isl_hash_init(); |
64 | if (name) |
65 | id->hash = isl_hash_string(hash: id->hash, s: name); |
66 | else |
67 | id->hash = isl_hash_builtin(id->hash, user); |
68 | |
69 | return id; |
70 | error: |
71 | free(ptr: (char *)copy); |
72 | return NULL; |
73 | } |
74 | |
75 | uint32_t isl_id_get_hash(__isl_keep isl_id *id) |
76 | { |
77 | return id ? id->hash : 0; |
78 | } |
79 | |
80 | struct isl_name_and_user { |
81 | const char *name; |
82 | void *user; |
83 | }; |
84 | |
85 | static isl_bool isl_id_has_name_and_user(const void *entry, const void *val) |
86 | { |
87 | isl_id *id = (isl_id *)entry; |
88 | struct isl_name_and_user *nu = (struct isl_name_and_user *) val; |
89 | |
90 | if (id->user != nu->user) |
91 | return isl_bool_false; |
92 | if (id->name == nu->name) |
93 | return isl_bool_true; |
94 | if (!id->name || !nu->name) |
95 | return isl_bool_false; |
96 | |
97 | return isl_bool_ok(b: !strcmp(s1: id->name, s2: nu->name)); |
98 | } |
99 | |
100 | __isl_give isl_id *isl_id_alloc(isl_ctx *ctx, const char *name, void *user) |
101 | { |
102 | struct isl_hash_table_entry *entry; |
103 | uint32_t id_hash; |
104 | struct isl_name_and_user nu = { name, user }; |
105 | |
106 | if (!ctx) |
107 | return NULL; |
108 | |
109 | id_hash = isl_hash_init(); |
110 | if (name) |
111 | id_hash = isl_hash_string(hash: id_hash, s: name); |
112 | else |
113 | id_hash = isl_hash_builtin(id_hash, user); |
114 | entry = isl_hash_table_find(ctx, table: &ctx->id_table, key_hash: id_hash, |
115 | eq: isl_id_has_name_and_user, val: &nu, reserve: 1); |
116 | if (!entry) |
117 | return NULL; |
118 | if (entry->data) |
119 | return isl_id_copy(id: entry->data); |
120 | entry->data = id_alloc(ctx, name, user); |
121 | if (!entry->data) |
122 | ctx->id_table.n--; |
123 | return entry->data; |
124 | } |
125 | |
126 | /* If the id has a negative refcount, then it is a static isl_id |
127 | * which should not be changed. |
128 | */ |
129 | __isl_give isl_id *isl_id_copy(isl_id *id) |
130 | { |
131 | if (!id) |
132 | return NULL; |
133 | |
134 | if (id->ref < 0) |
135 | return id; |
136 | |
137 | id->ref++; |
138 | return id; |
139 | } |
140 | |
141 | /* Compare two isl_ids. |
142 | * |
143 | * The order is fairly arbitrary. We do keep the comparison of |
144 | * the user pointers as a last resort since these pointer values |
145 | * may not be stable across different systems or even different runs. |
146 | */ |
147 | int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2) |
148 | { |
149 | if (id1 == id2) |
150 | return 0; |
151 | if (!id1) |
152 | return -1; |
153 | if (!id2) |
154 | return 1; |
155 | if (!id1->name != !id2->name) |
156 | return !id1->name - !id2->name; |
157 | if (id1->name) { |
158 | int cmp = strcmp(s1: id1->name, s2: id2->name); |
159 | if (cmp != 0) |
160 | return cmp; |
161 | } |
162 | if (id1->user < id2->user) |
163 | return -1; |
164 | else |
165 | return 1; |
166 | } |
167 | |
168 | static isl_bool isl_id_eq(const void *entry, const void *name) |
169 | { |
170 | return isl_bool_ok(b: entry == name); |
171 | } |
172 | |
173 | uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id) |
174 | { |
175 | if (id) |
176 | isl_hash_hash(hash, id->hash); |
177 | |
178 | return hash; |
179 | } |
180 | |
181 | /* Replace the free_user callback by "free_user". |
182 | */ |
183 | __isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, |
184 | void (*free_user)(void *user)) |
185 | { |
186 | if (!id) |
187 | return NULL; |
188 | |
189 | id->free_user = free_user; |
190 | |
191 | return id; |
192 | } |
193 | |
194 | /* Retrieve the callback set by isl_id_set_free_user, |
195 | * or NULL if no such callback was set. |
196 | */ |
197 | void (*isl_id_get_free_user(__isl_keep isl_id *id))(void *user) |
198 | { |
199 | if (!id) |
200 | return NULL; |
201 | return id->free_user; |
202 | } |
203 | |
204 | /* If the id has a negative refcount, then it is a static isl_id |
205 | * and should not be freed. |
206 | */ |
207 | __isl_null isl_id *isl_id_free(__isl_take isl_id *id) |
208 | { |
209 | struct isl_hash_table_entry *entry; |
210 | |
211 | if (!id) |
212 | return NULL; |
213 | |
214 | if (id->ref < 0) |
215 | return NULL; |
216 | |
217 | if (--id->ref > 0) |
218 | return NULL; |
219 | |
220 | entry = isl_hash_table_find(ctx: id->ctx, table: &id->ctx->id_table, key_hash: id->hash, |
221 | eq: isl_id_eq, val: id, reserve: 0); |
222 | if (!entry) |
223 | return NULL; |
224 | if (entry == isl_hash_table_entry_none) |
225 | isl_die(id->ctx, isl_error_unknown, |
226 | "unable to find id" , (void)0); |
227 | else |
228 | isl_hash_table_remove(ctx: id->ctx, table: &id->ctx->id_table, entry); |
229 | |
230 | if (id->free_user) |
231 | id->free_user(id->user); |
232 | |
233 | free(ptr: (char *)id->name); |
234 | isl_ctx_deref(ctx: id->ctx); |
235 | free(ptr: id); |
236 | |
237 | return NULL; |
238 | } |
239 | |
240 | __isl_give isl_printer *isl_printer_print_id(__isl_take isl_printer *p, |
241 | __isl_keep isl_id *id) |
242 | { |
243 | if (!id) |
244 | goto error; |
245 | |
246 | if (id->name) |
247 | p = isl_printer_print_str(p, s: id->name); |
248 | if (id->user) { |
249 | char buffer[50]; |
250 | snprintf(s: buffer, maxlen: sizeof(buffer), format: "@%p" , id->user); |
251 | p = isl_printer_print_str(p, s: buffer); |
252 | } |
253 | return p; |
254 | error: |
255 | isl_printer_free(printer: p); |
256 | return NULL; |
257 | } |
258 | |
259 | /* Read an isl_id from "s" based on its name. |
260 | */ |
261 | __isl_give isl_id *isl_stream_read_id(__isl_keep isl_stream *s) |
262 | { |
263 | struct isl_token *tok; |
264 | char *str; |
265 | isl_ctx *ctx; |
266 | isl_id *id; |
267 | |
268 | if (!s) |
269 | return NULL; |
270 | tok = isl_stream_next_token(s); |
271 | if (!tok) { |
272 | isl_stream_error(s, NULL, msg: "unexpected EOF" ); |
273 | return NULL; |
274 | } |
275 | ctx = isl_stream_get_ctx(s); |
276 | str = isl_token_get_str(ctx, tok); |
277 | isl_token_free(tok); |
278 | if (!str) |
279 | return NULL; |
280 | id = isl_id_alloc(ctx, name: str, NULL); |
281 | free(ptr: str); |
282 | |
283 | return id; |
284 | } |
285 | |
286 | #undef TYPE_BASE |
287 | #define TYPE_BASE id |
288 | #include "isl_read_from_str_templ.c" |
289 | |
290 | /* Is "id1" (obviously) equal to "id2"? |
291 | * |
292 | * isl_id objects can be compared by pointer value, but |
293 | * isl_multi_*_plain_is_equal needs an isl_*_plain_is_equal. |
294 | */ |
295 | static isl_bool isl_id_plain_is_equal(__isl_keep isl_id *id1, |
296 | __isl_keep isl_id *id2) |
297 | { |
298 | if (!id1 || !id2) |
299 | return isl_bool_error; |
300 | return id1 == id2; |
301 | } |
302 | |
303 | #undef BASE |
304 | #define BASE id |
305 | |
306 | #include <isl_multi_no_domain_templ.c> |
307 | #include <isl_multi_no_explicit_domain.c> |
308 | #include <isl_multi_templ.c> |
309 | |