Home | History | Annotate | Line # | Download | only in dist
      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