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