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(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(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(id->hash, name); 66 else 67 id->hash = isl_hash_builtin(id->hash, user); 68 69 return id; 70 error: 71 free((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(!strcmp(id->name, 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(id_hash, name); 112 else 113 id_hash = isl_hash_builtin(id_hash, user); 114 entry = isl_hash_table_find(ctx, &ctx->id_table, id_hash, 115 isl_id_has_name_and_user, &nu, 1); 116 if (!entry) 117 return NULL; 118 if (entry->data) 119 return isl_id_copy(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(id1->name, 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(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(id->ctx, &id->ctx->id_table, id->hash, 221 isl_id_eq, id, 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(id->ctx, &id->ctx->id_table, entry); 229 230 if (id->free_user) 231 id->free_user(id->user); 232 233 free((char *)id->name); 234 isl_ctx_deref(id->ctx); 235 free(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, id->name); 248 if (id->user) { 249 char buffer[50]; 250 snprintf(buffer, sizeof(buffer), "@%p", id->user); 251 p = isl_printer_print_str(p, buffer); 252 } 253 return p; 254 error: 255 isl_printer_free(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, "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, str, NULL); 281 free(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