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