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