| 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 | |