f425df02badb89afae51dc29be98823241518453
[babeltrace.git] / types / enum.c
1 /*
2 * enum.c
3 *
4 * BabelTrace - Enumeration Type
5 *
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
7 *
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
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:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 */
20
21 #include <babeltrace/compiler.h>
22 #include <babeltrace/format.h>
23 #include <babeltrace/types.h>
24 #include <stdint.h>
25 #include <glib.h>
26
27 static
28 struct definition *_enum_definition_new(struct declaration *declaration,
29 struct definition_scope *parent_scope,
30 GQuark field_name, int index,
31 const char *root_name);
32 static
33 void _enum_definition_free(struct definition *definition);
34
35 static
36 void enum_range_set_free(void *ptr)
37 {
38 g_array_unref(ptr);
39 }
40
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
107 /*
108 * Returns a GArray or NULL.
109 * Caller must release the GArray with g_array_unref().
110 */
111 GArray *enum_uint_to_quark_set(const struct declaration_enum *enum_declaration,
112 uint64_t v)
113 {
114 struct enum_range_to_quark *iter;
115 GArray *qs, *ranges = NULL;
116
117 /* Single values lookup */
118 qs = g_hash_table_lookup(enum_declaration->table.value_to_quark_set,
119 get_uint_v(&v));
120
121 /* Range lookup */
122 bt_list_for_each_entry(iter, &enum_declaration->table.range_to_quark, node) {
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,
131 sizeof(GQuark),
132 qs_len + 1);
133 g_array_set_size(ranges, qs_len + 1);
134 if (qs)
135 memcpy(ranges->data, qs->data,
136 sizeof(GQuark) * qs_len);
137 g_array_index(ranges, GQuark, qs_len) = iter->quark;
138 } else {
139 size_t qs_len = ranges->len;
140
141 g_array_set_size(ranges, qs_len + 1);
142 g_array_index(ranges, GQuark, qs_len) = iter->quark;
143 }
144 }
145 if (!ranges) {
146 if (!qs)
147 return NULL;
148 ranges = qs;
149 g_array_ref(ranges);
150 }
151 return ranges;
152 }
153
154 /*
155 * Returns a GArray or NULL.
156 * Caller must release the GArray with g_array_unref().
157 */
158 GArray *enum_int_to_quark_set(const struct declaration_enum *enum_declaration,
159 int64_t v)
160 {
161 struct enum_range_to_quark *iter;
162 GArray *qs, *ranges = NULL;
163
164 /* Single values lookup */
165 qs = g_hash_table_lookup(enum_declaration->table.value_to_quark_set,
166 get_int_v(&v));
167
168 /* Range lookup */
169 bt_list_for_each_entry(iter, &enum_declaration->table.range_to_quark, node) {
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,
178 sizeof(GQuark),
179 qs_len + 1);
180 g_array_set_size(ranges, qs_len + 1);
181 if (qs)
182 memcpy(ranges->data, qs->data,
183 sizeof(GQuark) * qs_len);
184 g_array_index(ranges, GQuark, qs_len) = iter->quark;
185 } else {
186 size_t qs_len = ranges->len;
187
188 g_array_set_size(ranges, qs_len + 1);
189 g_array_index(ranges, GQuark, qs_len) = iter->quark;
190 }
191 }
192 if (!ranges) {
193 if (!qs)
194 return NULL;
195 ranges = qs;
196 g_array_ref(ranges);
197 }
198 return ranges;
199 }
200
201 static
202 void enum_unsigned_insert_value_to_quark_set(struct declaration_enum *enum_declaration,
203 uint64_t v, GQuark q)
204 {
205 uint64_t *valuep;
206 GArray *array;
207
208 array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set,
209 get_uint_v(&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;
214 #if (__WORDSIZE == 32)
215 valuep = g_new(uint64_t, 1);
216 *valuep = v;
217 #else /* __WORDSIZE != 32 */
218 valuep = get_uint_v(&v);
219 #endif /* __WORDSIZE != 32 */
220 g_hash_table_insert(enum_declaration->table.value_to_quark_set, valuep, array);
221 } else {
222 g_array_set_size(array, array->len + 1);
223 g_array_index(array, GQuark, array->len - 1) = q;
224 }
225 }
226
227 static
228 void enum_signed_insert_value_to_quark_set(struct declaration_enum *enum_declaration,
229 int64_t v, GQuark q)
230 {
231 int64_t *valuep;
232 GArray *array;
233
234 array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set,
235 get_int_v(&v));
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;
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);
247 } else {
248 g_array_set_size(array, array->len + 1);
249 g_array_index(array, GQuark, array->len - 1) = q;
250 }
251 }
252
253 GArray *enum_quark_to_range_set(const struct declaration_enum *enum_declaration,
254 GQuark q)
255 {
256 return g_hash_table_lookup(enum_declaration->table.quark_to_range_set,
257 (gconstpointer) (unsigned long) q);
258 }
259
260 static
261 void enum_signed_insert_range_to_quark(struct declaration_enum *enum_declaration,
262 int64_t start, int64_t end, GQuark q)
263 {
264 struct enum_range_to_quark *rtoq;
265
266 rtoq = g_new(struct enum_range_to_quark, 1);
267 bt_list_add(&rtoq->node, &enum_declaration->table.range_to_quark);
268 rtoq->range.start._signed = start;
269 rtoq->range.end._signed = end;
270 rtoq->quark = q;
271 }
272
273 static
274 void enum_unsigned_insert_range_to_quark(struct declaration_enum *enum_declaration,
275 uint64_t start, uint64_t end, GQuark q)
276 {
277 struct enum_range_to_quark *rtoq;
278
279 rtoq = g_new(struct enum_range_to_quark, 1);
280 bt_list_add(&rtoq->node, &enum_declaration->table.range_to_quark);
281 rtoq->range.start._unsigned = start;
282 rtoq->range.end._unsigned = end;
283 rtoq->quark = q;
284 }
285
286 void enum_signed_insert(struct declaration_enum *enum_declaration,
287 int64_t start, int64_t end, GQuark q)
288 {
289 GArray *array;
290 struct enum_range *range;
291
292 if (start == end) {
293 enum_signed_insert_value_to_quark_set(enum_declaration, start, q);
294 } else {
295 if (start > end) {
296 uint64_t tmp;
297
298 tmp = start;
299 start = end;
300 end = tmp;
301 }
302 enum_signed_insert_range_to_quark(enum_declaration, start, end, q);
303 }
304
305 array = g_hash_table_lookup(enum_declaration->table.quark_to_range_set,
306 (gconstpointer) (unsigned long) q);
307 if (!array) {
308 array = g_array_sized_new(FALSE, TRUE,
309 sizeof(struct enum_range), 1);
310 g_hash_table_insert(enum_declaration->table.quark_to_range_set,
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;
318 }
319
320 void enum_unsigned_insert(struct declaration_enum *enum_declaration,
321 uint64_t start, uint64_t end, GQuark q)
322 {
323 GArray *array;
324 struct enum_range *range;
325
326
327 if (start == end) {
328 enum_unsigned_insert_value_to_quark_set(enum_declaration, start, q);
329 } else {
330 if (start > end) {
331 uint64_t tmp;
332
333 tmp = start;
334 start = end;
335 end = tmp;
336 }
337 enum_unsigned_insert_range_to_quark(enum_declaration, start, end, q);
338 }
339
340 array = g_hash_table_lookup(enum_declaration->table.quark_to_range_set,
341 (gconstpointer) (unsigned long) q);
342 if (!array) {
343 array = g_array_sized_new(FALSE, TRUE,
344 sizeof(struct enum_range), 1);
345 g_hash_table_insert(enum_declaration->table.quark_to_range_set,
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;
353 }
354
355 size_t enum_get_nr_enumerators(struct declaration_enum *enum_declaration)
356 {
357 return g_hash_table_size(enum_declaration->table.quark_to_range_set);
358 }
359
360 static
361 void _enum_declaration_free(struct declaration *declaration)
362 {
363 struct declaration_enum *enum_declaration =
364 container_of(declaration, struct declaration_enum, p);
365 struct enum_range_to_quark *iter, *tmp;
366
367 g_hash_table_destroy(enum_declaration->table.value_to_quark_set);
368 bt_list_for_each_entry_safe(iter, tmp, &enum_declaration->table.range_to_quark, node) {
369 bt_list_del(&iter->node);
370 g_free(iter);
371 }
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);
375 }
376
377 struct declaration_enum *
378 enum_declaration_new(struct declaration_integer *integer_declaration)
379 {
380 struct declaration_enum *enum_declaration;
381
382 enum_declaration = g_new(struct declaration_enum, 1);
383
384 enum_declaration->table.value_to_quark_set = g_hash_table_new_full(enum_val_hash,
385 enum_val_equal,
386 enum_val_free,
387 enum_range_set_free);
388 BT_INIT_LIST_HEAD(&enum_declaration->table.range_to_quark);
389 enum_declaration->table.quark_to_range_set = g_hash_table_new_full(g_direct_hash,
390 g_direct_equal,
391 NULL, enum_range_set_free);
392 declaration_ref(&integer_declaration->p);
393 enum_declaration->integer_declaration = integer_declaration;
394 enum_declaration->p.id = CTF_TYPE_ENUM;
395 enum_declaration->p.alignment = 1;
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;
401 }
402
403 static
404 struct definition *
405 _enum_definition_new(struct declaration *declaration,
406 struct definition_scope *parent_scope,
407 GQuark field_name, int index,
408 const char *root_name)
409 {
410 struct declaration_enum *enum_declaration =
411 container_of(declaration, struct declaration_enum, p);
412 struct definition_enum *_enum;
413 struct definition *definition_integer_parent;
414 int ret;
415
416 _enum = g_new(struct definition_enum, 1);
417 declaration_ref(&enum_declaration->p);
418 _enum->p.declaration = declaration;
419 _enum->declaration = enum_declaration;
420 _enum->p.ref = 1;
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;
426 _enum->p.name = field_name;
427 _enum->p.path = new_definition_path(parent_scope, field_name, root_name);
428 _enum->p.scope = new_definition_scope(parent_scope, field_name, root_name);
429 _enum->value = NULL;
430 ret = register_field_definition(field_name, &_enum->p,
431 parent_scope);
432 assert(!ret);
433 definition_integer_parent =
434 enum_declaration->integer_declaration->p.definition_new(&enum_declaration->integer_declaration->p,
435 _enum->p.scope,
436 g_quark_from_static_string("container"), 0, NULL);
437 _enum->integer = container_of(definition_integer_parent,
438 struct definition_integer, p);
439 return &_enum->p;
440 }
441
442 static
443 void _enum_definition_free(struct definition *definition)
444 {
445 struct definition_enum *_enum =
446 container_of(definition, struct definition_enum, p);
447
448 definition_unref(&_enum->integer->p);
449 free_definition_scope(_enum->p.scope);
450 declaration_unref(_enum->p.declaration);
451 if (_enum->value)
452 g_array_unref(_enum->value);
453 g_free(_enum);
454 }
This page took 0.057836 seconds and 3 git commands to generate.