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 | 26 | struct definition_scope *parent_scope, |
98df1c9f MD |
27 | GQuark field_name, int index, |
28 | const char *root_name); | |
c054553d | 29 | static |
e1151715 | 30 | void _enum_definition_free(struct definition *definition); |
c054553d | 31 | |
d65d8abb MD |
32 | static |
33 | void enum_range_set_free(void *ptr) | |
448d3cc7 | 34 | { |
d65d8abb | 35 | g_array_unref(ptr); |
448d3cc7 MD |
36 | } |
37 | ||
bcdf4cf2 MD |
38 | #if (__WORDSIZE == 32) |
39 | static inline | |
40 | gpointer get_uint_v(uint64_t *v) | |
41 | { | |
42 | return v; | |
43 | } | |
44 | ||
45 | static inline | |
46 | gpointer get_int_v(int64_t *v) | |
47 | { | |
48 | return v; | |
49 | } | |
50 | ||
51 | static | |
52 | guint enum_val_hash(gconstpointer key) | |
53 | { | |
54 | int64_t ukey = *(const int64_t *)key; | |
55 | ||
56 | return (guint)ukey ^ (guint)(ukey >> 32); | |
57 | } | |
58 | ||
59 | static | |
60 | gboolean enum_val_equal(gconstpointer a, gconstpointer b) | |
61 | { | |
62 | int64_t ua = *(const int64_t *)a; | |
63 | int64_t ub = *(const int64_t *)b; | |
64 | ||
65 | return ua == ub; | |
66 | } | |
67 | ||
68 | static | |
69 | void enum_val_free(void *ptr) | |
70 | { | |
71 | g_free(ptr); | |
72 | } | |
73 | #else /* __WORDSIZE != 32 */ | |
74 | static inline | |
75 | gpointer get_uint_v(uint64_t *v) | |
76 | { | |
77 | return (gpointer) *v; | |
78 | } | |
79 | ||
80 | static inline | |
81 | gpointer get_int_v(int64_t *v) | |
82 | { | |
83 | return (gpointer) *v; | |
84 | } | |
85 | ||
86 | static | |
87 | guint enum_val_hash(gconstpointer key) | |
88 | { | |
89 | return g_direct_hash(key); | |
90 | } | |
91 | ||
92 | static | |
93 | gboolean enum_val_equal(gconstpointer a, gconstpointer b) | |
94 | { | |
95 | return g_direct_equal(a, b); | |
96 | } | |
97 | ||
98 | static | |
99 | void enum_val_free(void *ptr) | |
100 | { | |
101 | } | |
102 | #endif /* __WORDSIZE != 32 */ | |
103 | ||
d65d8abb MD |
104 | /* |
105 | * Returns a GArray or NULL. | |
106 | * Caller must release the GArray with g_array_unref(). | |
107 | */ | |
f6625916 | 108 | GArray *enum_uint_to_quark_set(const struct declaration_enum *enum_declaration, |
d65d8abb | 109 | uint64_t v) |
448d3cc7 | 110 | { |
d65d8abb MD |
111 | struct enum_range_to_quark *iter; |
112 | GArray *qs, *ranges = NULL; | |
448d3cc7 | 113 | |
d65d8abb | 114 | /* Single values lookup */ |
bcdf4cf2 MD |
115 | qs = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, |
116 | get_uint_v(&v)); | |
d65d8abb MD |
117 | |
118 | /* Range lookup */ | |
f6625916 | 119 | cds_list_for_each_entry(iter, &enum_declaration->table.range_to_quark, node) { |
d65d8abb MD |
120 | if (iter->range.start._unsigned > v || iter->range.end._unsigned < v) |
121 | continue; | |
122 | if (!ranges) { | |
123 | size_t qs_len = 0; | |
124 | ||
125 | if (qs) | |
126 | qs_len = qs->len; | |
127 | ranges = g_array_sized_new(FALSE, TRUE, | |
ccdb988e | 128 | sizeof(GQuark), |
d65d8abb MD |
129 | qs_len + 1); |
130 | g_array_set_size(ranges, qs_len + 1); | |
131 | if (qs) | |
132 | memcpy(ranges->data, qs->data, | |
ccdb988e MD |
133 | sizeof(GQuark) * qs_len); |
134 | g_array_index(ranges, GQuark, qs_len) = iter->quark; | |
d65d8abb | 135 | } else { |
bcdf4cf2 MD |
136 | size_t qs_len = ranges->len; |
137 | ||
138 | g_array_set_size(ranges, qs_len + 1); | |
ccdb988e | 139 | g_array_index(ranges, GQuark, qs_len) = iter->quark; |
d65d8abb MD |
140 | } |
141 | } | |
fdacfb73 | 142 | if (!ranges) { |
bcdf4cf2 MD |
143 | if (!qs) |
144 | return NULL; | |
d65d8abb | 145 | ranges = qs; |
fdacfb73 MD |
146 | g_array_ref(ranges); |
147 | } | |
d65d8abb | 148 | return ranges; |
448d3cc7 MD |
149 | } |
150 | ||
d65d8abb MD |
151 | /* |
152 | * Returns a GArray or NULL. | |
153 | * Caller must release the GArray with g_array_unref(). | |
154 | */ | |
f6625916 | 155 | GArray *enum_int_to_quark_set(const struct declaration_enum *enum_declaration, |
bcdf4cf2 | 156 | int64_t v) |
448d3cc7 | 157 | { |
d65d8abb MD |
158 | struct enum_range_to_quark *iter; |
159 | GArray *qs, *ranges = NULL; | |
160 | ||
161 | /* Single values lookup */ | |
bcdf4cf2 MD |
162 | qs = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, |
163 | get_int_v(&v)); | |
d65d8abb MD |
164 | |
165 | /* Range lookup */ | |
f6625916 | 166 | cds_list_for_each_entry(iter, &enum_declaration->table.range_to_quark, node) { |
d65d8abb MD |
167 | if (iter->range.start._signed > v || iter->range.end._signed < v) |
168 | continue; | |
169 | if (!ranges) { | |
170 | size_t qs_len = 0; | |
171 | ||
172 | if (qs) | |
173 | qs_len = qs->len; | |
174 | ranges = g_array_sized_new(FALSE, TRUE, | |
ccdb988e | 175 | sizeof(GQuark), |
d65d8abb MD |
176 | qs_len + 1); |
177 | g_array_set_size(ranges, qs_len + 1); | |
178 | if (qs) | |
179 | memcpy(ranges->data, qs->data, | |
ccdb988e MD |
180 | sizeof(GQuark) * qs_len); |
181 | g_array_index(ranges, GQuark, qs_len) = iter->quark; | |
d65d8abb | 182 | } else { |
bcdf4cf2 MD |
183 | size_t qs_len = ranges->len; |
184 | ||
185 | g_array_set_size(ranges, qs_len + 1); | |
ccdb988e | 186 | g_array_index(ranges, GQuark, qs_len) = iter->quark; |
d65d8abb MD |
187 | } |
188 | } | |
fdacfb73 | 189 | if (!ranges) { |
bcdf4cf2 MD |
190 | if (!qs) |
191 | return NULL; | |
d65d8abb | 192 | ranges = qs; |
fdacfb73 MD |
193 | g_array_ref(ranges); |
194 | } | |
d65d8abb | 195 | return ranges; |
448d3cc7 MD |
196 | } |
197 | ||
d65d8abb | 198 | static |
f6625916 | 199 | void enum_unsigned_insert_value_to_quark_set(struct declaration_enum *enum_declaration, |
d65d8abb | 200 | uint64_t v, GQuark q) |
448d3cc7 | 201 | { |
d65d8abb MD |
202 | uint64_t *valuep; |
203 | GArray *array; | |
448d3cc7 | 204 | |
bcdf4cf2 MD |
205 | array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, |
206 | get_uint_v(&v)); | |
d65d8abb MD |
207 | if (!array) { |
208 | array = g_array_sized_new(FALSE, TRUE, sizeof(GQuark), 1); | |
209 | g_array_set_size(array, 1); | |
210 | g_array_index(array, GQuark, array->len - 1) = q; | |
bcdf4cf2 | 211 | #if (__WORDSIZE == 32) |
d65d8abb MD |
212 | valuep = g_new(uint64_t, 1); |
213 | *valuep = v; | |
bcdf4cf2 MD |
214 | #else /* __WORDSIZE != 32 */ |
215 | valuep = get_uint_v(&v); | |
216 | #endif /* __WORDSIZE != 32 */ | |
f6625916 | 217 | g_hash_table_insert(enum_declaration->table.value_to_quark_set, valuep, 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 | } | |
448d3cc7 | 222 | } |
448d3cc7 | 223 | |
d65d8abb | 224 | static |
f6625916 | 225 | void enum_signed_insert_value_to_quark_set(struct declaration_enum *enum_declaration, |
d65d8abb MD |
226 | int64_t v, GQuark q) |
227 | { | |
bcdf4cf2 | 228 | int64_t *valuep; |
d65d8abb MD |
229 | GArray *array; |
230 | ||
f6625916 | 231 | array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, |
bcdf4cf2 | 232 | get_int_v(&v)); |
d65d8abb MD |
233 | if (!array) { |
234 | array = g_array_sized_new(FALSE, TRUE, sizeof(GQuark), 1); | |
235 | g_array_set_size(array, 1); | |
236 | g_array_index(array, GQuark, array->len - 1) = q; | |
bcdf4cf2 MD |
237 | #if (__WORDSIZE == 32) |
238 | valuep = g_new(int64_t, 1); | |
239 | *valuep = v; | |
240 | #else /* __WORDSIZE != 32 */ | |
241 | valuep = get_int_v(&v); | |
242 | #endif /* __WORDSIZE != 32 */ | |
243 | g_hash_table_insert(enum_declaration->table.value_to_quark_set, valuep, array); | |
d65d8abb MD |
244 | } else { |
245 | g_array_set_size(array, array->len + 1); | |
246 | g_array_index(array, GQuark, array->len - 1) = q; | |
247 | } | |
448d3cc7 MD |
248 | } |
249 | ||
f6625916 | 250 | GArray *enum_quark_to_range_set(const struct declaration_enum *enum_declaration, |
d65d8abb | 251 | GQuark q) |
448d3cc7 | 252 | { |
f6625916 | 253 | return g_hash_table_lookup(enum_declaration->table.quark_to_range_set, |
47e0f2e2 | 254 | (gconstpointer) (unsigned long) q); |
448d3cc7 MD |
255 | } |
256 | ||
d65d8abb | 257 | static |
f6625916 | 258 | void enum_signed_insert_range_to_quark(struct declaration_enum *enum_declaration, |
d65d8abb | 259 | int64_t start, int64_t end, GQuark q) |
448d3cc7 | 260 | { |
d65d8abb MD |
261 | struct enum_range_to_quark *rtoq; |
262 | ||
263 | rtoq = g_new(struct enum_range_to_quark, 1); | |
f6625916 | 264 | cds_list_add(&rtoq->node, &enum_declaration->table.range_to_quark); |
d65d8abb MD |
265 | rtoq->range.start._signed = start; |
266 | rtoq->range.end._signed = end; | |
267 | rtoq->quark = q; | |
448d3cc7 MD |
268 | } |
269 | ||
d65d8abb | 270 | static |
f6625916 | 271 | void enum_unsigned_insert_range_to_quark(struct declaration_enum *enum_declaration, |
d65d8abb | 272 | uint64_t start, uint64_t end, GQuark q) |
448d3cc7 | 273 | { |
d65d8abb MD |
274 | struct enum_range_to_quark *rtoq; |
275 | ||
276 | rtoq = g_new(struct enum_range_to_quark, 1); | |
f6625916 | 277 | cds_list_add(&rtoq->node, &enum_declaration->table.range_to_quark); |
d65d8abb MD |
278 | rtoq->range.start._unsigned = start; |
279 | rtoq->range.end._unsigned = end; | |
280 | rtoq->quark = q; | |
448d3cc7 MD |
281 | } |
282 | ||
f6625916 | 283 | void enum_signed_insert(struct declaration_enum *enum_declaration, |
d65d8abb | 284 | int64_t start, int64_t end, GQuark q) |
448d3cc7 | 285 | { |
d65d8abb MD |
286 | GArray *array; |
287 | struct enum_range *range; | |
288 | ||
289 | if (start == end) { | |
f6625916 | 290 | enum_signed_insert_value_to_quark_set(enum_declaration, start, q); |
d65d8abb MD |
291 | } else { |
292 | if (start > end) { | |
293 | uint64_t tmp; | |
294 | ||
295 | tmp = start; | |
296 | start = end; | |
297 | end = tmp; | |
298 | } | |
f6625916 | 299 | enum_signed_insert_range_to_quark(enum_declaration, start, end, q); |
d65d8abb MD |
300 | } |
301 | ||
f6625916 | 302 | array = g_hash_table_lookup(enum_declaration->table.quark_to_range_set, |
d65d8abb MD |
303 | (gconstpointer) (unsigned long) q); |
304 | if (!array) { | |
305 | array = g_array_sized_new(FALSE, TRUE, | |
306 | sizeof(struct enum_range), 1); | |
f6625916 | 307 | g_hash_table_insert(enum_declaration->table.quark_to_range_set, |
d65d8abb MD |
308 | (gpointer) (unsigned long) q, |
309 | array); | |
310 | } | |
311 | g_array_set_size(array, array->len + 1); | |
312 | range = &g_array_index(array, struct enum_range, array->len - 1); | |
313 | range->start._signed = start; | |
314 | range->end._signed = end; | |
448d3cc7 MD |
315 | } |
316 | ||
f6625916 | 317 | void enum_unsigned_insert(struct declaration_enum *enum_declaration, |
d65d8abb | 318 | uint64_t start, uint64_t end, GQuark q) |
448d3cc7 | 319 | { |
d65d8abb MD |
320 | GArray *array; |
321 | struct enum_range *range; | |
322 | ||
323 | ||
324 | if (start == end) { | |
f6625916 | 325 | enum_unsigned_insert_value_to_quark_set(enum_declaration, start, q); |
d65d8abb MD |
326 | } else { |
327 | if (start > end) { | |
328 | uint64_t tmp; | |
329 | ||
330 | tmp = start; | |
331 | start = end; | |
332 | end = tmp; | |
333 | } | |
f6625916 | 334 | enum_unsigned_insert_range_to_quark(enum_declaration, start, end, q); |
d65d8abb MD |
335 | } |
336 | ||
f6625916 | 337 | array = g_hash_table_lookup(enum_declaration->table.quark_to_range_set, |
d65d8abb MD |
338 | (gconstpointer) (unsigned long) q); |
339 | if (!array) { | |
340 | array = g_array_sized_new(FALSE, TRUE, | |
341 | sizeof(struct enum_range), 1); | |
f6625916 | 342 | g_hash_table_insert(enum_declaration->table.quark_to_range_set, |
d65d8abb MD |
343 | (gpointer) (unsigned long) q, |
344 | array); | |
345 | } | |
346 | g_array_set_size(array, array->len + 1); | |
347 | range = &g_array_index(array, struct enum_range, array->len - 1); | |
348 | range->start._unsigned = start; | |
349 | range->end._unsigned = end; | |
448d3cc7 | 350 | } |
448d3cc7 | 351 | |
f6625916 | 352 | size_t enum_get_nr_enumerators(struct declaration_enum *enum_declaration) |
c054553d | 353 | { |
f6625916 | 354 | return g_hash_table_size(enum_declaration->table.quark_to_range_set); |
c054553d MD |
355 | } |
356 | ||
c054553d | 357 | static |
f6625916 | 358 | void _enum_declaration_free(struct declaration *declaration) |
90b676d7 | 359 | { |
f6625916 MD |
360 | struct declaration_enum *enum_declaration = |
361 | container_of(declaration, struct declaration_enum, p); | |
d65d8abb MD |
362 | struct enum_range_to_quark *iter, *tmp; |
363 | ||
f6625916 MD |
364 | g_hash_table_destroy(enum_declaration->table.value_to_quark_set); |
365 | cds_list_for_each_entry_safe(iter, tmp, &enum_declaration->table.range_to_quark, node) { | |
d65d8abb MD |
366 | cds_list_del(&iter->node); |
367 | g_free(iter); | |
368 | } | |
f6625916 MD |
369 | g_hash_table_destroy(enum_declaration->table.quark_to_range_set); |
370 | declaration_unref(&enum_declaration->integer_declaration->p); | |
371 | g_free(enum_declaration); | |
90b676d7 MD |
372 | } |
373 | ||
f6625916 | 374 | struct declaration_enum * |
78af2bcd | 375 | enum_declaration_new(struct declaration_integer *integer_declaration) |
448d3cc7 | 376 | { |
f6625916 | 377 | struct declaration_enum *enum_declaration; |
448d3cc7 | 378 | |
f6625916 | 379 | enum_declaration = g_new(struct declaration_enum, 1); |
e19c3d69 | 380 | |
f6625916 | 381 | enum_declaration->table.value_to_quark_set = g_hash_table_new_full(enum_val_hash, |
d65d8abb MD |
382 | enum_val_equal, |
383 | enum_val_free, | |
384 | enum_range_set_free); | |
f6625916 | 385 | CDS_INIT_LIST_HEAD(&enum_declaration->table.range_to_quark); |
068665f5 MD |
386 | enum_declaration->table.quark_to_range_set = g_hash_table_new_full(g_direct_hash, |
387 | g_direct_equal, | |
d65d8abb | 388 | NULL, enum_range_set_free); |
f6625916 MD |
389 | declaration_ref(&integer_declaration->p); |
390 | enum_declaration->integer_declaration = integer_declaration; | |
391 | enum_declaration->p.id = CTF_TYPE_ENUM; | |
f6625916 | 392 | enum_declaration->p.alignment = 1; |
f6625916 MD |
393 | enum_declaration->p.declaration_free = _enum_declaration_free; |
394 | enum_declaration->p.definition_new = _enum_definition_new; | |
395 | enum_declaration->p.definition_free = _enum_definition_free; | |
396 | enum_declaration->p.ref = 1; | |
397 | return enum_declaration; | |
c054553d MD |
398 | } |
399 | ||
400 | static | |
e1151715 | 401 | struct definition * |
f6625916 | 402 | _enum_definition_new(struct declaration *declaration, |
05c749e5 | 403 | struct definition_scope *parent_scope, |
98df1c9f MD |
404 | GQuark field_name, int index, |
405 | const char *root_name) | |
c054553d | 406 | { |
f6625916 MD |
407 | struct declaration_enum *enum_declaration = |
408 | container_of(declaration, struct declaration_enum, p); | |
e1151715 MD |
409 | struct definition_enum *_enum; |
410 | struct definition *definition_integer_parent; | |
98df1c9f | 411 | int ret; |
e19c3d69 | 412 | |
e1151715 | 413 | _enum = g_new(struct definition_enum, 1); |
f6625916 MD |
414 | declaration_ref(&enum_declaration->p); |
415 | _enum->p.declaration = declaration; | |
416 | _enum->declaration = enum_declaration; | |
c054553d | 417 | _enum->p.ref = 1; |
98df1c9f MD |
418 | /* |
419 | * Use INT_MAX order to ensure that all fields of the parent | |
420 | * scope are seen as being prior to this scope. | |
421 | */ | |
422 | _enum->p.index = root_name ? INT_MAX : index; | |
b1a2f580 | 423 | _enum->p.name = field_name; |
98df1c9f | 424 | _enum->p.path = new_definition_path(parent_scope, field_name, root_name); |
a35173fe | 425 | _enum->p.scope = new_definition_scope(parent_scope, field_name, root_name); |
c054553d | 426 | _enum->value = NULL; |
98df1c9f MD |
427 | ret = register_field_definition(field_name, &_enum->p, |
428 | parent_scope); | |
429 | assert(!ret); | |
e1151715 | 430 | definition_integer_parent = |
f6625916 | 431 | enum_declaration->integer_declaration->p.definition_new(&enum_declaration->integer_declaration->p, |
a35173fe | 432 | _enum->p.scope, |
98df1c9f | 433 | g_quark_from_static_string("container"), 0, NULL); |
e1151715 MD |
434 | _enum->integer = container_of(definition_integer_parent, |
435 | struct definition_integer, p); | |
c054553d MD |
436 | return &_enum->p; |
437 | } | |
438 | ||
439 | static | |
e1151715 | 440 | void _enum_definition_free(struct definition *definition) |
c054553d | 441 | { |
e1151715 MD |
442 | struct definition_enum *_enum = |
443 | container_of(definition, struct definition_enum, p); | |
c054553d | 444 | |
e1151715 | 445 | definition_unref(&_enum->integer->p); |
a35173fe | 446 | free_definition_scope(_enum->p.scope); |
f6625916 | 447 | declaration_unref(_enum->p.declaration); |
c054553d | 448 | if (_enum->value) |
6ee5115e | 449 | g_array_unref(_enum->value); |
c054553d | 450 | g_free(_enum); |
448d3cc7 | 451 | } |