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