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