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