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