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