Rename "type" to "declaration"
[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 definition *_enum_definition_new(struct declaration *declaration,
26 struct definition_scope *parent_scope);
27 static
28 void _enum_definition_free(struct definition *definition);
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 declaration_enum *enum_declaration,
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_declaration->table.value_to_quark_set, &v);
48
49 /* Range lookup */
50 cds_list_for_each_entry(iter, &enum_declaration->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 declaration_enum *enum_declaration,
83 uint64_t v)
84 {
85 struct enum_range_to_quark *iter;
86 GArray *qs, *ranges = NULL;
87
88 /* Single values lookup */
89 qs = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, &v);
90
91 /* Range lookup */
92 cds_list_for_each_entry(iter, &enum_declaration->table.range_to_quark, node) {
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 }
113 if (!ranges) {
114 ranges = qs;
115 g_array_ref(ranges);
116 }
117 return ranges;
118 }
119
120 #if (__WORDSIZE == 32)
121 static
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
129 static
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
138 static
139 void enum_val_free(void *ptr)
140 {
141 g_free(ptr);
142 }
143
144 static
145 void enum_signed_insert_value_to_quark_set(struct declaration_enum *enum_declaration,
146 int64_t v, GQuark q)
147 {
148 int64_t *valuep;
149 GArray *array;
150
151 array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, &v);
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;
158 g_hash_table_insert(enum_declaration->table.value_to_quark_set, valuep, array);
159 } else {
160 g_array_set_size(array, array->len + 1);
161 g_array_index(array, GQuark, array->len - 1) = q;
162 }
163 }
164
165 static
166 void enum_unsigned_insert_value_to_quark_set(struct declaration_enum *enum_declaration,
167 uint64_t v, GQuark q)
168 {
169 uint64_t *valuep;
170 GArray *array;
171
172 array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set, &v);
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;
179 g_hash_table_insert(enum_declaration->table.value_to_quark_set, valuep, array);
180 } else {
181 g_array_set_size(array, array->len + 1);
182 g_array_index(array, GQuark, array->len - 1) = q;
183 }
184 }
185 #else /* __WORDSIZE != 32 */
186 static
187 guint enum_val_hash(gconstpointer key)
188 {
189 return g_direct_hash(key);
190 }
191
192 static
193 gboolean enum_val_equal(gconstpointer a, gconstpointer b)
194 {
195 return g_direct_equal(a, b);
196 }
197
198 static
199 void enum_val_free(void *ptr)
200 {
201 }
202
203 static
204 void enum_signed_insert_value_to_quark_set(struct declaration_enum *enum_declaration,
205 int64_t v, GQuark q)
206 {
207 GArray *array;
208
209 array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set,
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;
215 g_hash_table_insert(enum_declaration->table.value_to_quark_set,
216 (gpointer) v, array);
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
224 void enum_unsigned_insert_value_to_quark_set(struct declaration_enum *enum_declaration,
225 uint64_t v, GQuark q)
226 {
227 GArray *array;
228
229 array = g_hash_table_lookup(enum_declaration->table.value_to_quark_set,
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;
235 g_hash_table_insert(enum_declaration->table.value_to_quark_set,
236 (gpointer) v, array);
237 } else {
238 g_array_set_size(array, array->len + 1);
239 g_array_index(array, GQuark, array->len - 1) = q;
240 }
241 }
242 #endif /* __WORDSIZE != 32 */
243
244 GArray *enum_quark_to_range_set(const struct declaration_enum *enum_declaration,
245 GQuark q)
246 {
247 return g_hash_table_lookup(enum_declaration->table.quark_to_range_set,
248 (gconstpointer) (unsigned long) q);
249 }
250
251 static
252 void enum_signed_insert_range_to_quark(struct declaration_enum *enum_declaration,
253 int64_t start, int64_t end, GQuark q)
254 {
255 struct enum_range_to_quark *rtoq;
256
257 rtoq = g_new(struct enum_range_to_quark, 1);
258 cds_list_add(&rtoq->node, &enum_declaration->table.range_to_quark);
259 rtoq->range.start._signed = start;
260 rtoq->range.end._signed = end;
261 rtoq->quark = q;
262 }
263
264 static
265 void enum_unsigned_insert_range_to_quark(struct declaration_enum *enum_declaration,
266 uint64_t start, uint64_t end, GQuark q)
267 {
268 struct enum_range_to_quark *rtoq;
269
270 rtoq = g_new(struct enum_range_to_quark, 1);
271 cds_list_add(&rtoq->node, &enum_declaration->table.range_to_quark);
272 rtoq->range.start._unsigned = start;
273 rtoq->range.end._unsigned = end;
274 rtoq->quark = q;
275 }
276
277 void enum_signed_insert(struct declaration_enum *enum_declaration,
278 int64_t start, int64_t end, GQuark q)
279 {
280 GArray *array;
281 struct enum_range *range;
282
283 if (start == end) {
284 enum_signed_insert_value_to_quark_set(enum_declaration, start, q);
285 } else {
286 if (start > end) {
287 uint64_t tmp;
288
289 tmp = start;
290 start = end;
291 end = tmp;
292 }
293 enum_signed_insert_range_to_quark(enum_declaration, start, end, q);
294 }
295
296 array = g_hash_table_lookup(enum_declaration->table.quark_to_range_set,
297 (gconstpointer) (unsigned long) q);
298 if (!array) {
299 array = g_array_sized_new(FALSE, TRUE,
300 sizeof(struct enum_range), 1);
301 g_hash_table_insert(enum_declaration->table.quark_to_range_set,
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;
309 }
310
311 void enum_unsigned_insert(struct declaration_enum *enum_declaration,
312 uint64_t start, uint64_t end, GQuark q)
313 {
314 GArray *array;
315 struct enum_range *range;
316
317
318 if (start == end) {
319 enum_unsigned_insert_value_to_quark_set(enum_declaration, start, q);
320 } else {
321 if (start > end) {
322 uint64_t tmp;
323
324 tmp = start;
325 start = end;
326 end = tmp;
327 }
328 enum_unsigned_insert_range_to_quark(enum_declaration, start, end, q);
329 }
330
331 array = g_hash_table_lookup(enum_declaration->table.quark_to_range_set,
332 (gconstpointer) (unsigned long) q);
333 if (!array) {
334 array = g_array_sized_new(FALSE, TRUE,
335 sizeof(struct enum_range), 1);
336 g_hash_table_insert(enum_declaration->table.quark_to_range_set,
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;
344 }
345
346 size_t enum_get_nr_enumerators(struct declaration_enum *enum_declaration)
347 {
348 return g_hash_table_size(enum_declaration->table.quark_to_range_set);
349 }
350
351 void enum_copy(struct stream_pos *dest, const struct format *fdest,
352 struct stream_pos *src, const struct format *fsrc,
353 struct definition *definition)
354 {
355 struct definition_enum *_enum =
356 container_of(definition, struct definition_enum, p);
357 struct declaration_enum *enum_declaration= _enum->declaration;
358 GArray *array;
359 GQuark v;
360
361 array = fsrc->enum_read(src, enum_declaration);
362 assert(array);
363 /* unref previous array */
364 if (_enum->value)
365 g_array_unref(_enum->value);
366 _enum->value = array;
367 /*
368 * Arbitrarily choose the first one.
369 * TODO: use direct underlying declaration read/write intead. Not doing it for
370 * now to test enum read and write code.
371 */
372 v = g_array_index(array, GQuark, 0);
373 return fdest->enum_write(dest, enum_declaration, v);
374 }
375
376 static
377 void _enum_declaration_free(struct declaration *declaration)
378 {
379 struct declaration_enum *enum_declaration =
380 container_of(declaration, struct declaration_enum, p);
381 struct enum_range_to_quark *iter, *tmp;
382
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) {
385 cds_list_del(&iter->node);
386 g_free(iter);
387 }
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);
391 }
392
393 struct declaration_enum *
394 _enum_declaration_new(const char *name, struct declaration_integer *integer_declaration)
395 {
396 struct declaration_enum *enum_declaration;
397
398 enum_declaration = g_new(struct declaration_enum, 1);
399
400 enum_declaration->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_declaration->table.range_to_quark);
405 enum_declaration->table.quark_to_range_set = g_hash_table_new_full(g_int_hash,
406 g_int_equal,
407 NULL, enum_range_set_free);
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;
419 }
420
421 static
422 struct definition *
423 _enum_definition_new(struct declaration *declaration,
424 struct definition_scope *parent_scope)
425 {
426 struct declaration_enum *enum_declaration =
427 container_of(declaration, struct declaration_enum, p);
428 struct definition_enum *_enum;
429 struct definition *definition_integer_parent;
430
431 _enum = g_new(struct definition_enum, 1);
432 declaration_ref(&enum_declaration->p);
433 _enum->p.declaration = declaration;
434 _enum->declaration = enum_declaration;
435 _enum->p.ref = 1;
436 _enum->value = NULL;
437 definition_integer_parent =
438 enum_declaration->integer_declaration->p.definition_new(&enum_declaration->integer_declaration->p,
439 parent_scope);
440 _enum->integer = container_of(definition_integer_parent,
441 struct definition_integer, p);
442 return &_enum->p;
443 }
444
445 static
446 void _enum_definition_free(struct definition *definition)
447 {
448 struct definition_enum *_enum =
449 container_of(definition, struct definition_enum, p);
450
451 definition_unref(&_enum->integer->p);
452 declaration_unref(_enum->p.declaration);
453 if (_enum->value)
454 g_array_unref(_enum->value);
455 g_free(_enum);
456 }
This page took 0.037736 seconds and 4 git commands to generate.