Commit | Line | Data |
---|---|---|
448d3cc7 | 1 | /* |
ccd7e1c8 | 2 | * enum.c |
448d3cc7 | 3 | * |
ccd7e1c8 | 4 | * BabelTrace - Enumeration Type |
448d3cc7 | 5 | * |
c054553d | 6 | * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
448d3cc7 | 7 | * |
ccd7e1c8 MD |
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | * of this software and associated documentation files (the "Software"), to deal | |
10 | * in the Software without restriction, including without limitation the rights | |
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
12 | * copies of the Software, and to permit persons to whom the Software is | |
13 | * furnished to do so, subject to the following conditions: | |
448d3cc7 | 14 | * |
ccd7e1c8 MD |
15 | * The above copyright notice and this permission notice shall be included in |
16 | * all copies or substantial portions of the Software. | |
448d3cc7 MD |
17 | */ |
18 | ||
19 | #include <babeltrace/compiler.h> | |
4c8bfb7e | 20 | #include <babeltrace/format.h> |
448d3cc7 MD |
21 | #include <stdint.h> |
22 | #include <glib.h> | |
23 | ||
c054553d | 24 | static |
f6625916 | 25 | struct definition *_enum_definition_new(struct declaration *declaration, |
05c749e5 MD |
26 | struct definition_scope *parent_scope, |
27 | GQuark field_name, int index); | |
c054553d | 28 | static |
e1151715 | 29 | void _enum_definition_free(struct definition *definition); |
c054553d | 30 | |
d65d8abb MD |
31 | static |
32 | void enum_range_set_free(void *ptr) | |
448d3cc7 | 33 | { |
d65d8abb | 34 | g_array_unref(ptr); |
448d3cc7 MD |
35 | } |
36 | ||
d65d8abb MD |
37 | /* |
38 | * Returns a GArray or NULL. | |
39 | * Caller must release the GArray with g_array_unref(). | |
40 | */ | |
f6625916 | 41 | GArray *enum_uint_to_quark_set(const struct declaration_enum *enum_declaration, |
d65d8abb | 42 | uint64_t v) |
448d3cc7 | 43 | { |
d65d8abb MD |
44 | struct enum_range_to_quark *iter; |
45 | GArray *qs, *ranges = NULL; | |
448d3cc7 | 46 | |
d65d8abb | 47 | /* Single values lookup */ |
f6625916 | 48 | qs = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, &v); |
d65d8abb MD |
49 | |
50 | /* Range lookup */ | |
f6625916 | 51 | cds_list_for_each_entry(iter, &enum_declaration->table.range_to_quark, node) { |
d65d8abb MD |
52 | if (iter->range.start._unsigned > v || iter->range.end._unsigned < v) |
53 | continue; | |
54 | if (!ranges) { | |
55 | size_t qs_len = 0; | |
56 | ||
57 | if (qs) | |
58 | qs_len = qs->len; | |
59 | ranges = g_array_sized_new(FALSE, TRUE, | |
60 | sizeof(struct enum_range), | |
61 | qs_len + 1); | |
62 | g_array_set_size(ranges, qs_len + 1); | |
63 | if (qs) | |
64 | memcpy(ranges->data, qs->data, | |
65 | sizeof(struct enum_range) * qs_len); | |
66 | g_array_index(ranges, struct enum_range, qs_len) = iter->range; | |
67 | } else { | |
68 | g_array_set_size(ranges, ranges->len + 1); | |
69 | g_array_index(ranges, struct enum_range, ranges->len) = iter->range; | |
70 | } | |
71 | } | |
fdacfb73 | 72 | if (!ranges) { |
d65d8abb | 73 | ranges = qs; |
fdacfb73 MD |
74 | g_array_ref(ranges); |
75 | } | |
d65d8abb | 76 | return ranges; |
448d3cc7 MD |
77 | } |
78 | ||
d65d8abb MD |
79 | /* |
80 | * Returns a GArray or NULL. | |
81 | * Caller must release the GArray with g_array_unref(). | |
82 | */ | |
f6625916 MD |
83 | GArray *enum_int_to_quark_set(const struct declaration_enum *enum_declaration, |
84 | uint64_t v) | |
448d3cc7 | 85 | { |
d65d8abb MD |
86 | struct enum_range_to_quark *iter; |
87 | GArray *qs, *ranges = NULL; | |
88 | ||
89 | /* Single values lookup */ | |
f6625916 | 90 | qs = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, &v); |
d65d8abb MD |
91 | |
92 | /* Range lookup */ | |
f6625916 | 93 | cds_list_for_each_entry(iter, &enum_declaration->table.range_to_quark, node) { |
d65d8abb MD |
94 | if (iter->range.start._signed > v || iter->range.end._signed < v) |
95 | continue; | |
96 | if (!ranges) { | |
97 | size_t qs_len = 0; | |
98 | ||
99 | if (qs) | |
100 | qs_len = qs->len; | |
101 | ranges = g_array_sized_new(FALSE, TRUE, | |
102 | sizeof(struct enum_range), | |
103 | qs_len + 1); | |
104 | g_array_set_size(ranges, qs_len + 1); | |
105 | if (qs) | |
106 | memcpy(ranges->data, qs->data, | |
107 | sizeof(struct enum_range) * qs_len); | |
108 | g_array_index(ranges, struct enum_range, qs_len) = iter->range; | |
109 | } else { | |
110 | g_array_set_size(ranges, ranges->len + 1); | |
111 | g_array_index(ranges, struct enum_range, ranges->len) = iter->range; | |
112 | } | |
113 | } | |
fdacfb73 | 114 | if (!ranges) { |
d65d8abb | 115 | ranges = qs; |
fdacfb73 MD |
116 | g_array_ref(ranges); |
117 | } | |
d65d8abb | 118 | return ranges; |
448d3cc7 MD |
119 | } |
120 | ||
d65d8abb MD |
121 | #if (__WORDSIZE == 32) |
122 | static | |
448d3cc7 MD |
123 | guint enum_val_hash(gconstpointer key) |
124 | { | |
125 | int64_t ukey = *(const int64_t *)key; | |
126 | ||
127 | return (guint)ukey ^ (guint)(ukey >> 32); | |
128 | } | |
129 | ||
d65d8abb | 130 | static |
448d3cc7 MD |
131 | gboolean enum_val_equal(gconstpointer a, gconstpointer b) |
132 | { | |
133 | int64_t ua = *(const int64_t *)a; | |
134 | int64_t ub = *(const int64_t *)b; | |
135 | ||
136 | return ua == ub; | |
137 | } | |
138 | ||
d65d8abb | 139 | static |
448d3cc7 MD |
140 | void enum_val_free(void *ptr) |
141 | { | |
142 | g_free(ptr); | |
143 | } | |
144 | ||
d65d8abb | 145 | static |
f6625916 | 146 | void enum_signed_insert_value_to_quark_set(struct declaration_enum *enum_declaration, |
d65d8abb | 147 | int64_t v, GQuark q) |
448d3cc7 | 148 | { |
d65d8abb MD |
149 | int64_t *valuep; |
150 | GArray *array; | |
448d3cc7 | 151 | |
f6625916 | 152 | array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, &v); |
d65d8abb MD |
153 | if (!array) { |
154 | array = g_array_sized_new(FALSE, TRUE, sizeof(GQuark), 1); | |
155 | g_array_set_size(array, 1); | |
156 | g_array_index(array, GQuark, array->len - 1) = q; | |
157 | valuep = g_new(int64_t, 1); | |
158 | *valuep = v; | |
f6625916 | 159 | g_hash_table_insert(enum_declaration->table.value_to_quark_set, valuep, array); |
d65d8abb MD |
160 | } else { |
161 | g_array_set_size(array, array->len + 1); | |
162 | g_array_index(array, GQuark, array->len - 1) = q; | |
163 | } | |
448d3cc7 MD |
164 | } |
165 | ||
d65d8abb | 166 | static |
f6625916 | 167 | void enum_unsigned_insert_value_to_quark_set(struct declaration_enum *enum_declaration, |
d65d8abb | 168 | uint64_t v, GQuark q) |
448d3cc7 | 169 | { |
d65d8abb MD |
170 | uint64_t *valuep; |
171 | GArray *array; | |
448d3cc7 | 172 | |
f6625916 | 173 | array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, &v); |
d65d8abb MD |
174 | if (!array) { |
175 | array = g_array_sized_new(FALSE, TRUE, sizeof(GQuark), 1); | |
176 | g_array_set_size(array, 1); | |
177 | g_array_index(array, GQuark, array->len - 1) = q; | |
178 | valuep = g_new(uint64_t, 1); | |
179 | *valuep = v; | |
f6625916 | 180 | g_hash_table_insert(enum_declaration->table.value_to_quark_set, valuep, array); |
d65d8abb MD |
181 | } else { |
182 | g_array_set_size(array, array->len + 1); | |
183 | g_array_index(array, GQuark, array->len - 1) = q; | |
184 | } | |
448d3cc7 | 185 | } |
d65d8abb MD |
186 | #else /* __WORDSIZE != 32 */ |
187 | static | |
188 | guint enum_val_hash(gconstpointer key) | |
448d3cc7 | 189 | { |
d65d8abb | 190 | return g_direct_hash(key); |
448d3cc7 MD |
191 | } |
192 | ||
d65d8abb MD |
193 | static |
194 | gboolean enum_val_equal(gconstpointer a, gconstpointer b) | |
448d3cc7 | 195 | { |
d65d8abb | 196 | return g_direct_equal(a, b); |
448d3cc7 MD |
197 | } |
198 | ||
d65d8abb MD |
199 | static |
200 | void enum_val_free(void *ptr) | |
448d3cc7 | 201 | { |
448d3cc7 MD |
202 | } |
203 | ||
d65d8abb | 204 | static |
f6625916 | 205 | void enum_signed_insert_value_to_quark_set(struct declaration_enum *enum_declaration, |
d65d8abb MD |
206 | int64_t v, GQuark q) |
207 | { | |
208 | GArray *array; | |
209 | ||
f6625916 | 210 | array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, |
d65d8abb MD |
211 | (gconstpointer) v); |
212 | if (!array) { | |
213 | array = g_array_sized_new(FALSE, TRUE, sizeof(GQuark), 1); | |
214 | g_array_set_size(array, 1); | |
215 | g_array_index(array, GQuark, array->len - 1) = q; | |
f6625916 | 216 | g_hash_table_insert(enum_declaration->table.value_to_quark_set, |
380d60b1 | 217 | (gpointer) v, array); |
d65d8abb MD |
218 | } else { |
219 | g_array_set_size(array, array->len + 1); | |
220 | g_array_index(array, GQuark, array->len - 1) = q; | |
221 | } | |
222 | } | |
223 | ||
224 | static | |
f6625916 | 225 | void enum_unsigned_insert_value_to_quark_set(struct declaration_enum *enum_declaration, |
d65d8abb | 226 | uint64_t v, GQuark q) |
448d3cc7 | 227 | { |
d65d8abb MD |
228 | GArray *array; |
229 | ||
f6625916 | 230 | array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, |
d65d8abb MD |
231 | (gconstpointer) v); |
232 | if (!array) { | |
233 | array = g_array_sized_new(FALSE, TRUE, sizeof(GQuark), 1); | |
234 | g_array_set_size(array, 1); | |
235 | g_array_index(array, GQuark, array->len - 1) = q; | |
f6625916 | 236 | g_hash_table_insert(enum_declaration->table.value_to_quark_set, |
380d60b1 | 237 | (gpointer) v, array); |
d65d8abb MD |
238 | } else { |
239 | g_array_set_size(array, array->len + 1); | |
240 | g_array_index(array, GQuark, array->len - 1) = q; | |
241 | } | |
448d3cc7 | 242 | } |
d65d8abb | 243 | #endif /* __WORDSIZE != 32 */ |
448d3cc7 | 244 | |
f6625916 | 245 | GArray *enum_quark_to_range_set(const struct declaration_enum *enum_declaration, |
d65d8abb | 246 | GQuark q) |
448d3cc7 | 247 | { |
f6625916 | 248 | return g_hash_table_lookup(enum_declaration->table.quark_to_range_set, |
47e0f2e2 | 249 | (gconstpointer) (unsigned long) q); |
448d3cc7 MD |
250 | } |
251 | ||
d65d8abb | 252 | static |
f6625916 | 253 | void enum_signed_insert_range_to_quark(struct declaration_enum *enum_declaration, |
d65d8abb | 254 | int64_t start, int64_t end, GQuark q) |
448d3cc7 | 255 | { |
d65d8abb MD |
256 | struct enum_range_to_quark *rtoq; |
257 | ||
258 | rtoq = g_new(struct enum_range_to_quark, 1); | |
f6625916 | 259 | cds_list_add(&rtoq->node, &enum_declaration->table.range_to_quark); |
d65d8abb MD |
260 | rtoq->range.start._signed = start; |
261 | rtoq->range.end._signed = end; | |
262 | rtoq->quark = q; | |
448d3cc7 MD |
263 | } |
264 | ||
d65d8abb | 265 | static |
f6625916 | 266 | void enum_unsigned_insert_range_to_quark(struct declaration_enum *enum_declaration, |
d65d8abb | 267 | uint64_t start, uint64_t end, GQuark q) |
448d3cc7 | 268 | { |
d65d8abb MD |
269 | struct enum_range_to_quark *rtoq; |
270 | ||
271 | rtoq = g_new(struct enum_range_to_quark, 1); | |
f6625916 | 272 | cds_list_add(&rtoq->node, &enum_declaration->table.range_to_quark); |
d65d8abb MD |
273 | rtoq->range.start._unsigned = start; |
274 | rtoq->range.end._unsigned = end; | |
275 | rtoq->quark = q; | |
448d3cc7 MD |
276 | } |
277 | ||
f6625916 | 278 | void enum_signed_insert(struct declaration_enum *enum_declaration, |
d65d8abb | 279 | int64_t start, int64_t end, GQuark q) |
448d3cc7 | 280 | { |
d65d8abb MD |
281 | GArray *array; |
282 | struct enum_range *range; | |
283 | ||
284 | if (start == end) { | |
f6625916 | 285 | enum_signed_insert_value_to_quark_set(enum_declaration, start, q); |
d65d8abb MD |
286 | } else { |
287 | if (start > end) { | |
288 | uint64_t tmp; | |
289 | ||
290 | tmp = start; | |
291 | start = end; | |
292 | end = tmp; | |
293 | } | |
f6625916 | 294 | enum_signed_insert_range_to_quark(enum_declaration, start, end, q); |
d65d8abb MD |
295 | } |
296 | ||
f6625916 | 297 | array = g_hash_table_lookup(enum_declaration->table.quark_to_range_set, |
d65d8abb MD |
298 | (gconstpointer) (unsigned long) q); |
299 | if (!array) { | |
300 | array = g_array_sized_new(FALSE, TRUE, | |
301 | sizeof(struct enum_range), 1); | |
f6625916 | 302 | g_hash_table_insert(enum_declaration->table.quark_to_range_set, |
d65d8abb MD |
303 | (gpointer) (unsigned long) q, |
304 | array); | |
305 | } | |
306 | g_array_set_size(array, array->len + 1); | |
307 | range = &g_array_index(array, struct enum_range, array->len - 1); | |
308 | range->start._signed = start; | |
309 | range->end._signed = end; | |
448d3cc7 MD |
310 | } |
311 | ||
f6625916 | 312 | void enum_unsigned_insert(struct declaration_enum *enum_declaration, |
d65d8abb | 313 | uint64_t start, uint64_t end, GQuark q) |
448d3cc7 | 314 | { |
d65d8abb MD |
315 | GArray *array; |
316 | struct enum_range *range; | |
317 | ||
318 | ||
319 | if (start == end) { | |
f6625916 | 320 | enum_unsigned_insert_value_to_quark_set(enum_declaration, start, q); |
d65d8abb MD |
321 | } else { |
322 | if (start > end) { | |
323 | uint64_t tmp; | |
324 | ||
325 | tmp = start; | |
326 | start = end; | |
327 | end = tmp; | |
328 | } | |
f6625916 | 329 | enum_unsigned_insert_range_to_quark(enum_declaration, start, end, q); |
d65d8abb MD |
330 | } |
331 | ||
f6625916 | 332 | array = g_hash_table_lookup(enum_declaration->table.quark_to_range_set, |
d65d8abb MD |
333 | (gconstpointer) (unsigned long) q); |
334 | if (!array) { | |
335 | array = g_array_sized_new(FALSE, TRUE, | |
336 | sizeof(struct enum_range), 1); | |
f6625916 | 337 | g_hash_table_insert(enum_declaration->table.quark_to_range_set, |
d65d8abb MD |
338 | (gpointer) (unsigned long) q, |
339 | array); | |
340 | } | |
341 | g_array_set_size(array, array->len + 1); | |
342 | range = &g_array_index(array, struct enum_range, array->len - 1); | |
343 | range->start._unsigned = start; | |
344 | range->end._unsigned = end; | |
448d3cc7 | 345 | } |
448d3cc7 | 346 | |
f6625916 | 347 | size_t enum_get_nr_enumerators(struct declaration_enum *enum_declaration) |
c054553d | 348 | { |
f6625916 | 349 | return g_hash_table_size(enum_declaration->table.quark_to_range_set); |
c054553d MD |
350 | } |
351 | ||
c054553d | 352 | static |
f6625916 | 353 | void _enum_declaration_free(struct declaration *declaration) |
90b676d7 | 354 | { |
f6625916 MD |
355 | struct declaration_enum *enum_declaration = |
356 | container_of(declaration, struct declaration_enum, p); | |
d65d8abb MD |
357 | struct enum_range_to_quark *iter, *tmp; |
358 | ||
f6625916 MD |
359 | g_hash_table_destroy(enum_declaration->table.value_to_quark_set); |
360 | cds_list_for_each_entry_safe(iter, tmp, &enum_declaration->table.range_to_quark, node) { | |
d65d8abb MD |
361 | cds_list_del(&iter->node); |
362 | g_free(iter); | |
363 | } | |
f6625916 MD |
364 | g_hash_table_destroy(enum_declaration->table.quark_to_range_set); |
365 | declaration_unref(&enum_declaration->integer_declaration->p); | |
366 | g_free(enum_declaration); | |
90b676d7 MD |
367 | } |
368 | ||
f6625916 | 369 | struct declaration_enum * |
78af2bcd | 370 | enum_declaration_new(struct declaration_integer *integer_declaration) |
448d3cc7 | 371 | { |
f6625916 | 372 | struct declaration_enum *enum_declaration; |
448d3cc7 | 373 | |
f6625916 | 374 | enum_declaration = g_new(struct declaration_enum, 1); |
e19c3d69 | 375 | |
f6625916 | 376 | enum_declaration->table.value_to_quark_set = g_hash_table_new_full(enum_val_hash, |
d65d8abb MD |
377 | enum_val_equal, |
378 | enum_val_free, | |
379 | enum_range_set_free); | |
f6625916 | 380 | CDS_INIT_LIST_HEAD(&enum_declaration->table.range_to_quark); |
068665f5 MD |
381 | enum_declaration->table.quark_to_range_set = g_hash_table_new_full(g_direct_hash, |
382 | g_direct_equal, | |
d65d8abb | 383 | NULL, enum_range_set_free); |
f6625916 MD |
384 | declaration_ref(&integer_declaration->p); |
385 | enum_declaration->integer_declaration = integer_declaration; | |
386 | enum_declaration->p.id = CTF_TYPE_ENUM; | |
f6625916 | 387 | enum_declaration->p.alignment = 1; |
f6625916 MD |
388 | enum_declaration->p.declaration_free = _enum_declaration_free; |
389 | enum_declaration->p.definition_new = _enum_definition_new; | |
390 | enum_declaration->p.definition_free = _enum_definition_free; | |
391 | enum_declaration->p.ref = 1; | |
392 | return enum_declaration; | |
c054553d MD |
393 | } |
394 | ||
395 | static | |
e1151715 | 396 | struct definition * |
f6625916 | 397 | _enum_definition_new(struct declaration *declaration, |
05c749e5 MD |
398 | struct definition_scope *parent_scope, |
399 | GQuark field_name, int index) | |
c054553d | 400 | { |
f6625916 MD |
401 | struct declaration_enum *enum_declaration = |
402 | container_of(declaration, struct declaration_enum, p); | |
e1151715 MD |
403 | struct definition_enum *_enum; |
404 | struct definition *definition_integer_parent; | |
e19c3d69 | 405 | |
e1151715 | 406 | _enum = g_new(struct definition_enum, 1); |
f6625916 MD |
407 | declaration_ref(&enum_declaration->p); |
408 | _enum->p.declaration = declaration; | |
409 | _enum->declaration = enum_declaration; | |
c054553d | 410 | _enum->p.ref = 1; |
05c749e5 | 411 | _enum->p.index = index; |
c054553d | 412 | _enum->value = NULL; |
e1151715 | 413 | definition_integer_parent = |
f6625916 | 414 | enum_declaration->integer_declaration->p.definition_new(&enum_declaration->integer_declaration->p, |
05c749e5 | 415 | parent_scope, field_name, 0); |
e1151715 MD |
416 | _enum->integer = container_of(definition_integer_parent, |
417 | struct definition_integer, p); | |
c054553d MD |
418 | return &_enum->p; |
419 | } | |
420 | ||
421 | static | |
e1151715 | 422 | void _enum_definition_free(struct definition *definition) |
c054553d | 423 | { |
e1151715 MD |
424 | struct definition_enum *_enum = |
425 | container_of(definition, struct definition_enum, p); | |
c054553d | 426 | |
e1151715 | 427 | definition_unref(&_enum->integer->p); |
f6625916 | 428 | declaration_unref(_enum->p.declaration); |
c054553d | 429 | if (_enum->value) |
6ee5115e | 430 | g_array_unref(_enum->value); |
c054553d | 431 | g_free(_enum); |
448d3cc7 | 432 | } |