208b303f1e00c270694572ee48a1667db0a01001
[babeltrace.git] / types / types.c
1 /*
2 * declarations.c
3 *
4 * BabelTrace - Converter
5 *
6 * Types registry.
7 *
8 * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 */
20
21 #include <babeltrace/format.h>
22 #include <glib.h>
23 #include <errno.h>
24
25 static
26 struct definition *
27 lookup_typedef_declaration_scope(GQuark declaration_name,
28 struct declaration_scope *scope)
29 {
30 return g_hash_table_lookup(scope->typedef_declarations,
31 (gconstpointer) (unsigned long) declaration_name);
32 }
33
34 struct definition *lookup_typedef_declaration(GQuark declaration_name,
35 struct declaration_scope *scope)
36 {
37 struct definition *definition;
38
39 while (scope) {
40 definition = lookup_typedef_declaration_scope(declaration_name,
41 scope);
42 if (definition)
43 return definition;
44 scope = scope->parent_scope;
45 }
46 return NULL;
47 }
48
49 int register_typedef_declaration(GQuark name, struct declaration *declaration,
50 struct declaration_scope *scope)
51 {
52 if (!name)
53 return -EPERM;
54
55 /* Only lookup in local scope */
56 if (lookup_typedef_declaration_scope(name, scope))
57 return -EEXIST;
58
59 g_hash_table_insert(scope->typedef_declarations,
60 (gpointer) (unsigned long) name,
61 declaration);
62 declaration_ref(declaration);
63 return 0;
64 }
65
66 static
67 struct definition *
68 lookup_field_definition_scope(GQuark field_name,
69 struct definition_scope *scope)
70 {
71 return g_hash_table_lookup(scope->definitions,
72 (gconstpointer) (unsigned long) field_name);
73 }
74
75 /*
76 * Returns the index at which the paths differ.
77 * If the value returned equals len, it means the paths are identical
78 * from index 0 to len-1.
79 */
80 static int compare_paths(GArray *a, GArray *b, int len)
81 {
82 int i;
83
84 assert(len <= a->len);
85 assert(len <= b->len);
86
87 for (i = 0; i < len; i++) {
88 GQuark qa, qb;
89
90 qa = g_array_index(a, GQuark, i);
91 qb = g_array_index(b, GQuark, i);
92 if (qa != qb)
93 return i;
94 }
95 return i;
96 }
97
98 static int is_path_child_of(GArray *path, GArray *maybe_parent)
99 {
100 if (path->len <= maybe_parent->len)
101 return 0;
102 if (compare_paths(path, maybe_parent, maybe_parent->len)
103 == maybe_parent->len)
104 return 1;
105 else
106 return 0;
107 }
108
109 static struct definition_scope *
110 get_definition_scope(struct definition *definition)
111 {
112 switch (definition->declaration->id) {
113 case CTF_TYPE_STRUCT:
114 {
115 struct definition_struct *def =
116 container_of(definition, struct definition_struct, p);
117 return def->scope;
118 }
119 case CTF_TYPE_VARIANT:
120 {
121 struct definition_variant *def =
122 container_of(definition, struct definition_variant, p);
123 return def->scope;
124 }
125 case CTF_TYPE_ARRAY:
126 {
127 struct definition_array *def =
128 container_of(definition, struct definition_array, p);
129 return def->scope;
130 }
131 case CTF_TYPE_SEQUENCE:
132 {
133 struct definition_sequence *def =
134 container_of(definition, struct definition_sequence, p);
135 return def->scope;
136 }
137
138 case CTF_TYPE_INTEGER:
139 case CTF_TYPE_FLOAT:
140 case CTF_TYPE_ENUM:
141 case CTF_TYPE_STRING:
142 case CTF_TYPE_UNKNOWN:
143 default:
144 return NULL;
145 }
146 }
147
148 /*
149 * OK, here is the fun. We want to lookup a field that is:
150 * - either in the current scope, but prior to the current field.
151 * - or in a parent scope (or parent of parent ...) still in a field
152 * prior to the current field position within the parents.
153 * A reaching through a dynamic scoping (e.g. from payload structure to
154 * event header structure), the parent fields are always entirely prior
155 * to the child.
156 * If we cannot find such a field that is prior to our current path, we
157 * return NULL.
158 *
159 * cur_path: the path leading to the variant definition.
160 * lookup_path: the path leading to the enum we want to look for.
161 * scope: the definition scope containing the variant definition.
162 */
163 struct definition *
164 lookup_definition(GArray *cur_path,
165 GArray *lookup_path,
166 struct definition_scope *scope)
167 {
168 struct definition *definition, *lookup_definition;
169 GQuark last;
170 int index;
171
172 while (scope) {
173 /* going up in the hierarchy. Check where we come from. */
174 assert(is_path_child_of(cur_path, scope->scope_path));
175 assert(cur_path->len - scope->scope_path->len == 1);
176 last = g_array_index(cur_path, GQuark, cur_path->len - 1);
177 definition = lookup_field_definition_scope(last, scope);
178 assert(definition);
179 index = definition->index;
180 lookup:
181 if (is_path_child_of(lookup_path, scope->scope_path)) {
182 /* Means we can lookup the field in this scope */
183 last = g_array_index(lookup_path, GQuark,
184 scope->scope_path->len);
185 lookup_definition = lookup_field_definition_scope(last, scope);
186 if (!lookup_definition || ((index != -1) && lookup_definition->index >= index))
187 return NULL;
188 /* Found it! And it is prior to the current field. */
189 if (lookup_path->len - scope->scope_path->len == 1) {
190 /* Direct child */
191 return lookup_definition;
192 } else {
193 scope = get_definition_scope(lookup_definition);
194 /* Check if the definition has a sub-scope */
195 if (!scope)
196 return NULL;
197 /*
198 * Don't compare index anymore, because we are
199 * going within a scope that has been validated
200 * to be entirely prior to the current scope.
201 */
202 cur_path = NULL;
203 index = -1;
204 goto lookup;
205 }
206 } else {
207 assert(index != -1);
208 /* lookup_path is within an upper scope */
209 cur_path = scope->scope_path;
210 scope = scope->parent_scope;
211 }
212 }
213 return NULL;
214 }
215
216 int register_field_definition(GQuark field_name, struct definition *definition,
217 struct definition_scope *scope)
218 {
219 if (!field_name)
220 return -EPERM;
221
222 /* Only lookup in local scope */
223 if (lookup_field_definition_scope(field_name, scope))
224 return -EEXIST;
225
226 g_hash_table_insert(scope->definitions,
227 (gpointer) (unsigned long) field_name,
228 definition);
229 definition_ref(definition);
230 return 0;
231 }
232
233 void declaration_ref(struct declaration *declaration)
234 {
235 declaration->ref++;
236 }
237
238 void declaration_unref(struct declaration *declaration)
239 {
240 if (!--declaration->ref)
241 declaration->declaration_free(declaration);
242 }
243
244 void definition_ref(struct definition *definition)
245 {
246 definition->ref++;
247 }
248
249 void definition_unref(struct definition *definition)
250 {
251 if (!--definition->ref)
252 definition->declaration->definition_free(definition);
253 }
254
255 struct declaration_scope *
256 new_declaration_scope(struct declaration_scope *parent_scope)
257 {
258 struct declaration_scope *scope = g_new(struct declaration_scope, 1);
259
260 scope->typedef_declarations = g_hash_table_new_full(g_direct_hash,
261 g_direct_equal, NULL,
262 (GDestroyNotify) definition_unref);
263 scope->struct_declarations = g_hash_table_new_full(g_direct_hash,
264 g_direct_equal, NULL,
265 (GDestroyNotify) declaration_unref);
266 scope->variant_declarations = g_hash_table_new_full(g_direct_hash,
267 g_direct_equal, NULL,
268 (GDestroyNotify) declaration_unref);
269 scope->enum_declarations = g_hash_table_new_full(g_direct_hash,
270 g_direct_equal, NULL,
271 (GDestroyNotify) declaration_unref);
272 scope->parent_scope = parent_scope;
273 return scope;
274 }
275
276 void free_declaration_scope(struct declaration_scope *scope)
277 {
278 g_hash_table_destroy(scope->enum_declarations);
279 g_hash_table_destroy(scope->variant_declarations);
280 g_hash_table_destroy(scope->struct_declarations);
281 g_hash_table_destroy(scope->typedef_declarations);
282 g_free(scope);
283 }
284
285 static
286 struct declaration_struct *lookup_struct_declaration_scope(GQuark struct_name,
287 struct declaration_scope *scope)
288 {
289 return g_hash_table_lookup(scope->struct_declarations,
290 (gconstpointer) (unsigned long) struct_name);
291 }
292
293 struct declaration_struct *lookup_struct_declaration(GQuark struct_name,
294 struct declaration_scope *scope)
295 {
296 struct declaration_struct *declaration;
297
298 while (scope) {
299 declaration = lookup_struct_declaration_scope(struct_name, scope);
300 if (declaration)
301 return declaration;
302 scope = scope->parent_scope;
303 }
304 return NULL;
305 }
306
307 int register_struct_declaration(GQuark struct_name,
308 struct declaration_struct *struct_declaration,
309 struct declaration_scope *scope)
310 {
311 if (!struct_name)
312 return -EPERM;
313
314 /* Only lookup in local scope */
315 if (lookup_struct_declaration_scope(struct_name, scope))
316 return -EEXIST;
317
318 g_hash_table_insert(scope->struct_declarations,
319 (gpointer) (unsigned long) struct_name,
320 struct_declaration);
321 declaration_ref(&struct_declaration->p);
322 return 0;
323 }
324
325 static
326 struct declaration_variant *
327 lookup_variant_declaration_scope(GQuark variant_name,
328 struct declaration_scope *scope)
329 {
330 return g_hash_table_lookup(scope->variant_declarations,
331 (gconstpointer) (unsigned long) variant_name);
332 }
333
334 struct declaration_variant *
335 lookup_variant_declaration(GQuark variant_name,
336 struct declaration_scope *scope)
337 {
338 struct declaration_variant *declaration;
339
340 while (scope) {
341 declaration = lookup_variant_declaration_scope(variant_name, scope);
342 if (declaration)
343 return declaration;
344 scope = scope->parent_scope;
345 }
346 return NULL;
347 }
348
349 int register_variant_declaration(GQuark variant_name,
350 struct declaration_variant *variant_declaration,
351 struct declaration_scope *scope)
352 {
353 if (!variant_name)
354 return -EPERM;
355
356 /* Only lookup in local scope */
357 if (lookup_variant_declaration_scope(variant_name, scope))
358 return -EEXIST;
359
360 g_hash_table_insert(scope->variant_declarations,
361 (gpointer) (unsigned long) variant_name,
362 variant_declaration);
363 declaration_ref(&variant_declaration->p);
364 return 0;
365 }
366
367 static
368 struct declaration_enum *
369 lookup_enum_declaration_scope(GQuark enum_name,
370 struct declaration_scope *scope)
371 {
372 return g_hash_table_lookup(scope->enum_declarations,
373 (gconstpointer) (unsigned long) enum_name);
374 }
375
376 struct declaration_enum *
377 lookup_enum_declaration(GQuark enum_name,
378 struct declaration_scope *scope)
379 {
380 struct declaration_enum *declaration;
381
382 while (scope) {
383 declaration = lookup_enum_declaration_scope(enum_name, scope);
384 if (declaration)
385 return declaration;
386 scope = scope->parent_scope;
387 }
388 return NULL;
389 }
390
391 int register_enum_declaration(GQuark enum_name,
392 struct declaration_enum *enum_declaration,
393 struct declaration_scope *scope)
394 {
395 if (!enum_name)
396 return -EPERM;
397
398 /* Only lookup in local scope */
399 if (lookup_enum_declaration_scope(enum_name, scope))
400 return -EEXIST;
401
402 g_hash_table_insert(scope->enum_declarations,
403 (gpointer) (unsigned long) enum_name,
404 enum_declaration);
405 declaration_ref(&enum_declaration->p);
406 return 0;
407 }
408
409 struct definition_scope *
410 new_definition_scope(struct definition_scope *parent_scope,
411 GQuark field_name)
412 {
413 struct definition_scope *scope = g_new(struct definition_scope, 1);
414 int scope_path_len = 1;
415
416 scope->definitions = g_hash_table_new_full(g_direct_hash,
417 g_direct_equal, NULL,
418 (GDestroyNotify) definition_unref);
419 scope->parent_scope = parent_scope;
420 if (scope->parent_scope)
421 scope_path_len += scope->parent_scope->scope_path->len;
422 scope->scope_path = g_array_sized_new(FALSE, TRUE, sizeof(GQuark),
423 scope_path_len);
424 g_array_set_size(scope->scope_path, scope_path_len);
425 if (scope->parent_scope)
426 memcpy(scope->scope_path, scope->parent_scope->scope_path,
427 sizeof(GQuark) * (scope_path_len - 1));
428 g_array_index(scope->scope_path, GQuark, scope_path_len - 1) =
429 field_name;
430 return scope;
431 }
432
433 void free_definition_scope(struct definition_scope *scope)
434 {
435 g_array_free(scope->scope_path, TRUE);
436 g_hash_table_destroy(scope->definitions);
437 g_free(scope);
438 }
This page took 0.042508 seconds and 4 git commands to generate.