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