a6d56ac9dae131ef07be01b6fc185e0a643f19ef
[babeltrace.git] / types / enum.c
1 /*
2 * enum.c
3 *
4 * BabelTrace - Enumeration Type
5 *
6 * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 */
18
19 #include <babeltrace/compiler.h>
20 #include <babeltrace/format.h>
21 #include <stdint.h>
22 #include <glib.h>
23
24 static
25 struct declaration *_enum_declaration_new(struct type *type,
26 struct declaration_scope *parent_scope);
27 static
28 void _enum_declaration_free(struct declaration *declaration);
29
30 static
31 void enum_range_set_free(void *ptr)
32 {
33 g_array_unref(ptr);
34 }
35
36 /*
37 * Returns a GArray or NULL.
38 * Caller must release the GArray with g_array_unref().
39 */
40 GArray *enum_uint_to_quark_set(const struct type_enum *enum_type,
41 uint64_t v)
42 {
43 struct enum_range_to_quark *iter;
44 GArray *qs, *ranges = NULL;
45
46 /* Single values lookup */
47 qs = g_hash_table_lookup(enum_type->table.value_to_quark_set, &v);
48
49 /* Range lookup */
50 cds_list_for_each_entry(iter, &enum_type->table.range_to_quark, node) {
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 }
71 if (!ranges) {
72 ranges = qs;
73 g_array_ref(ranges);
74 }
75 return ranges;
76 }
77
78 /*
79 * Returns a GArray or NULL.
80 * Caller must release the GArray with g_array_unref().
81 */
82 GArray *enum_int_to_quark_set(const struct type_enum *enum_type, uint64_t v)
83 {
84 struct enum_range_to_quark *iter;
85 GArray *qs, *ranges = NULL;
86
87 /* Single values lookup */
88 qs = g_hash_table_lookup(enum_type->table.value_to_quark_set, &v);
89
90 /* Range lookup */
91 cds_list_for_each_entry(iter, &enum_type->table.range_to_quark, node) {
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 }
112 if (!ranges) {
113 ranges = qs;
114 g_array_ref(ranges);
115 }
116 return ranges;
117 }
118
119 #if (__WORDSIZE == 32)
120 static
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
128 static
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
137 static
138 void enum_val_free(void *ptr)
139 {
140 g_free(ptr);
141 }
142
143 static
144 void enum_signed_insert_value_to_quark_set(struct type_enum *enum_type,
145 int64_t v, GQuark q)
146 {
147 int64_t *valuep;
148 GArray *array;
149
150 array = g_hash_table_lookup(enum_type->table.value_to_quark_set, &v);
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;
157 g_hash_table_insert(enum_type->table.value_to_quark_set, valuep, array);
158 } else {
159 g_array_set_size(array, array->len + 1);
160 g_array_index(array, GQuark, array->len - 1) = q;
161 }
162 }
163
164 static
165 void enum_unsigned_insert_value_to_quark_set(struct type_enum *enum_type,
166 uint64_t v, GQuark q)
167 {
168 uint64_t *valuep;
169 GArray *array;
170
171 array = g_hash_table_lookup(enum_type->table.value_to_quark_set, &v);
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;
178 g_hash_table_insert(enum_type->table.value_to_quark_set, valuep, array);
179 } else {
180 g_array_set_size(array, array->len + 1);
181 g_array_index(array, GQuark, array->len - 1) = q;
182 }
183 }
184 #else /* __WORDSIZE != 32 */
185 static
186 guint enum_val_hash(gconstpointer key)
187 {
188 return g_direct_hash(key);
189 }
190
191 static
192 gboolean enum_val_equal(gconstpointer a, gconstpointer b)
193 {
194 return g_direct_equal(a, b);
195 }
196
197 static
198 void enum_val_free(void *ptr)
199 {
200 }
201
202 static
203 void enum_signed_insert_value_to_quark_set(struct type_enum *enum_type,
204 int64_t v, GQuark q)
205 {
206 GArray *array;
207
208 array = g_hash_table_lookup(enum_type->table.value_to_quark_set,
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;
214 g_hash_table_insert(enum_type->table.value_to_quark_set,
215 (gpointer) v, array);
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
223 void enum_unsigned_insert_value_to_quark_set(struct type_enum *enum_type,
224 uint64_t v, GQuark q)
225 {
226 GArray *array;
227
228 array = g_hash_table_lookup(enum_type->table.value_to_quark_set,
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;
234 g_hash_table_insert(enum_type->table.value_to_quark_set,
235 (gpointer) v, array);
236 } else {
237 g_array_set_size(array, array->len + 1);
238 g_array_index(array, GQuark, array->len - 1) = q;
239 }
240 }
241 #endif /* __WORDSIZE != 32 */
242
243 GArray *enum_quark_to_range_set(const struct type_enum *enum_type,
244 GQuark q)
245 {
246 return g_hash_table_lookup(enum_type->table.quark_to_range_set,
247 (gconstpointer) (unsigned long) q);
248 }
249
250 static
251 void enum_signed_insert_range_to_quark(struct type_enum *enum_type,
252 int64_t start, int64_t end, GQuark q)
253 {
254 struct enum_range_to_quark *rtoq;
255
256 rtoq = g_new(struct enum_range_to_quark, 1);
257 cds_list_add(&rtoq->node, &enum_type->table.range_to_quark);
258 rtoq->range.start._signed = start;
259 rtoq->range.end._signed = end;
260 rtoq->quark = q;
261 }
262
263 static
264 void enum_unsigned_insert_range_to_quark(struct type_enum *enum_type,
265 uint64_t start, uint64_t end, GQuark q)
266 {
267 struct enum_range_to_quark *rtoq;
268
269 rtoq = g_new(struct enum_range_to_quark, 1);
270 cds_list_add(&rtoq->node, &enum_type->table.range_to_quark);
271 rtoq->range.start._unsigned = start;
272 rtoq->range.end._unsigned = end;
273 rtoq->quark = q;
274 }
275
276 void enum_signed_insert(struct type_enum *enum_type,
277 int64_t start, int64_t end, GQuark q)
278 {
279 GArray *array;
280 struct enum_range *range;
281
282 if (start == end) {
283 enum_signed_insert_value_to_quark_set(enum_type, start, q);
284 } else {
285 if (start > end) {
286 uint64_t tmp;
287
288 tmp = start;
289 start = end;
290 end = tmp;
291 }
292 enum_signed_insert_range_to_quark(enum_type, start, end, q);
293 }
294
295 array = g_hash_table_lookup(enum_type->table.quark_to_range_set,
296 (gconstpointer) (unsigned long) q);
297 if (!array) {
298 array = g_array_sized_new(FALSE, TRUE,
299 sizeof(struct enum_range), 1);
300 g_hash_table_insert(enum_type->table.quark_to_range_set,
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;
308 }
309
310 void enum_unsigned_insert(struct type_enum *enum_type,
311 uint64_t start, uint64_t end, GQuark q)
312 {
313 GArray *array;
314 struct enum_range *range;
315
316
317 if (start == end) {
318 enum_unsigned_insert_value_to_quark_set(enum_type, start, q);
319 } else {
320 if (start > end) {
321 uint64_t tmp;
322
323 tmp = start;
324 start = end;
325 end = tmp;
326 }
327 enum_unsigned_insert_range_to_quark(enum_type, start, end, q);
328 }
329
330 array = g_hash_table_lookup(enum_type->table.quark_to_range_set,
331 (gconstpointer) (unsigned long) q);
332 if (!array) {
333 array = g_array_sized_new(FALSE, TRUE,
334 sizeof(struct enum_range), 1);
335 g_hash_table_insert(enum_type->table.quark_to_range_set,
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;
343 }
344
345 size_t enum_get_nr_enumerators(struct type_enum *enum_type)
346 {
347 return g_hash_table_size(enum_type->table.quark_to_range_set);
348 }
349
350 void enum_copy(struct stream_pos *dest, const struct format *fdest,
351 struct stream_pos *src, const struct format *fsrc,
352 struct declaration *declaration)
353 {
354 struct declaration_enum *_enum =
355 container_of(declaration, struct declaration_enum, p);
356 struct type_enum *enum_type= _enum->type;
357 GArray *array;
358 GQuark v;
359
360 array = fsrc->enum_read(src, enum_type);
361 assert(array);
362 /* unref previous array */
363 if (_enum->value)
364 g_array_unref(_enum->value, TRUE);
365 _enum->value = array;
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);
372 return fdest->enum_write(dest, enum_type, v);
373 }
374
375 static
376 void _enum_type_free(struct type *type)
377 {
378 struct type_enum *enum_type =
379 container_of(type, struct enum_type, p);
380 struct enum_range_to_quark *iter, *tmp;
381
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) {
384 cds_list_del(&iter->node);
385 g_free(iter);
386 }
387 g_hash_table_destroy(enum_type->table.quark_to_range_set);
388 type_unref(enum_type->integer_type);
389 g_free(enum_type);
390 }
391
392 struct type_enum *
393 _enum_type_new(const char *name, struct type_integer *integer_type)
394 {
395 struct type_enum *enum_type;
396 int ret;
397
398 enum_type = g_new(struct type_enum, 1);
399
400 enum_type->table.value_to_quark_set = g_hash_table_new_full(enum_val_hash,
401 enum_val_equal,
402 enum_val_free,
403 enum_range_set_free);
404 CDS_INIT_LIST_HEAD(&enum_type->table.range_to_quark);
405 enum_type->table.quark_to_range_set = g_hash_table_new_full(g_int_hash,
406 g_int_equal,
407 NULL, enum_range_set_free);
408 type_ref(integer_type);
409 enum_type->integer_type = integer_type;
410 enum_type->p.name = g_quark_from_string(name);
411 enum_type->p.alignment = 1;
412 enum_type->p.copy = enum_copy;
413 enum_type->p.type_free = _enum_type_free;
414 enum_type->p.declaration_new = _enum_declaration_new;
415 enum_type->p.declaration_free = _enum_declaration_free;
416 enum_type->p.ref = 1;
417 if (enum_type->p.name) {
418 ret = register_type(&enum_type->p);
419 if (ret)
420 goto register_error;
421 }
422 return enum_type;
423
424 register_error:
425 g_hash_table_destroy(enum_type->table.value_to_quark_set);
426 g_hash_table_destroy(enum_type->table.quark_to_range_set);
427 type_unref(enum_type->integer_type);
428 g_free(enum_type);
429 return NULL;
430 }
431
432 static
433 struct declaration *
434 _enum_declaration_new(struct type *type,
435 struct declaration_scope *parent_scope)
436 {
437 struct type_enum *enum_type =
438 container_of(type, struct type_enum, p);
439 struct declaration_enum *_enum;
440 struct declaration_integer_parent *declaration_integer_parent;
441
442 _enum = g_new(struct declaration_enum, 1);
443 type_ref(&enum_type->p);
444 _enum->p.type = enum_type;
445 _enum->p.ref = 1;
446 _enum->value = NULL;
447 declaration_integer_parent =
448 enum_type->integer_type->p.declaration_new(&enum_type->integer_type->p,
449 parent_scope);
450 _enum->integer = container_of(declaration_integer_parent,
451 struct declaration_integer, p);
452 return &_enum->p;
453 }
454
455 static
456 void _enum_declaration_free(struct declaration *declaration)
457 {
458 struct declaration_enum *_enum =
459 container_of(declaration, struct declaration_enum, p);
460
461 declaration_unref(_enum->integer);
462 type_unref(_enum->p.type);
463 if (_enum->value)
464 g_array_unref(_enum->value, TRUE);
465 g_free(_enum);
466 }
This page took 0.036395 seconds and 3 git commands to generate.