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