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