likely/unlikely branch prediction
[lttv.git] / ltt / branches / poly / lttv / lttv / attribute.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #include <string.h>
20 #include <lttv/attribute.h>
21 #include <ltt/ltt.h>
22 #include <ltt/compiler.h>
23
24 typedef union _AttributeValue {
25 int dv_int;
26 unsigned dv_uint;
27 long dv_long;
28 unsigned long dv_ulong;
29 float dv_float;
30 double dv_double;
31 LttTime dv_time;
32 gpointer dv_pointer;
33 char *dv_string;
34 GObject *dv_gobject;
35 } AttributeValue;
36
37
38 typedef struct _Attribute {
39 LttvAttributeName name;
40 LttvAttributeType type;
41 AttributeValue value;
42 } Attribute;
43
44
45 static __inline__ LttvAttributeValue address_of_value(LttvAttributeType t,
46 AttributeValue *v)
47 {
48 LttvAttributeValue va;
49
50 switch(t) {
51 case LTTV_INT: va.v_int = &v->dv_int; break;
52 case LTTV_UINT: va.v_uint = &v->dv_uint; break;
53 case LTTV_LONG: va.v_long = &v->dv_long; break;
54 case LTTV_ULONG: va.v_ulong = &v->dv_ulong; break;
55 case LTTV_FLOAT: va.v_float = &v->dv_float; break;
56 case LTTV_DOUBLE: va.v_double = &v->dv_double; break;
57 case LTTV_TIME: va.v_time = &v->dv_time; break;
58 case LTTV_POINTER: va.v_pointer = &v->dv_pointer; break;
59 case LTTV_STRING: va.v_string = &v->dv_string; break;
60 case LTTV_GOBJECT: va.v_gobject = &v->dv_gobject; break;
61 case LTTV_NONE: break;
62 }
63 return va;
64 }
65
66
67 AttributeValue init_value(LttvAttributeType t)
68 {
69 AttributeValue v;
70
71 switch(t) {
72 case LTTV_INT: v.dv_int = 0; break;
73 case LTTV_UINT: v.dv_uint = 0; break;
74 case LTTV_LONG: v.dv_long = 0; break;
75 case LTTV_ULONG: v.dv_ulong = 0; break;
76 case LTTV_FLOAT: v.dv_float = 0; break;
77 case LTTV_DOUBLE: v.dv_double = 0; break;
78 case LTTV_TIME: v.dv_time.tv_sec = 0; v.dv_time.tv_nsec = 0; break;
79 case LTTV_POINTER: v.dv_pointer = NULL; break;
80 case LTTV_STRING: v.dv_string = NULL; break;
81 case LTTV_GOBJECT: v.dv_gobject = NULL; break;
82 case LTTV_NONE: break;
83 }
84 return v;
85 }
86
87
88 unsigned int
89 lttv_attribute_get_number(LttvAttribute *self)
90 {
91 return self->attributes->len;
92 }
93
94
95 gboolean
96 lttv_attribute_named(LttvAttribute *self, gboolean *homogeneous)
97 {
98 *homogeneous = FALSE;
99 return TRUE;
100 }
101
102
103 LttvAttributeType
104 lttv_attribute_get(LttvAttribute *self, unsigned i, LttvAttributeName *name,
105 LttvAttributeValue *v)
106 {
107 Attribute *a;
108
109 a = &g_array_index(self->attributes, Attribute, i);
110 *name = a->name;
111 *v = address_of_value(a->type, &(a->value));
112 return a->type;
113 }
114
115
116 LttvAttributeType
117 lttv_attribute_get_by_name(LttvAttribute *self, LttvAttributeName name,
118 LttvAttributeValue *v)
119 {
120 Attribute *a;
121
122 unsigned i;
123
124 gpointer p;
125
126 p = g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
127 if(p == NULL) return LTTV_NONE;
128
129 i = GPOINTER_TO_UINT(p);
130 i--;
131 a = &g_array_index(self->attributes, Attribute, i);
132 *v = address_of_value(a->type, &(a->value));
133 return a->type;
134 }
135
136
137 LttvAttributeValue
138 lttv_attribute_add(LttvAttribute *self, LttvAttributeName name,
139 LttvAttributeType t)
140 {
141 unsigned i;
142
143 Attribute a, *pa;
144
145 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
146 if(i != 0) g_error("duplicate entry in attribute table");
147
148 a.name = name;
149 a.type = t;
150 a.value = init_value(t);
151 g_array_append_val(self->attributes, a);
152 i = self->attributes->len - 1;
153 pa = &g_array_index(self->attributes, Attribute, i);
154 g_hash_table_insert(self->names, GUINT_TO_POINTER(name),
155 GUINT_TO_POINTER(i + 1));
156 return address_of_value(t, &(pa->value));
157 }
158
159
160 /* Remove an attribute */
161
162 void
163 lttv_attribute_remove(LttvAttribute *self, unsigned i)
164 {
165 Attribute *a;
166
167 a = &g_array_index(self->attributes, Attribute, i);
168
169 /* If the element is a gobject, unreference it. */
170 if(a->type == LTTV_GOBJECT && a->value.dv_gobject != NULL)
171 g_object_unref(a->value.dv_gobject);
172
173 /* Remove the array element and its entry in the name index */
174
175 g_hash_table_remove(self->names, GUINT_TO_POINTER(a->name));
176 g_array_remove_index_fast(self->attributes, i);
177
178 /* The element used to replace the removed element has its index entry
179 all wrong now. Reinsert it with its new position. */
180
181 if(likely(self->attributes->len != i)){
182 g_hash_table_remove(self->names, GUINT_TO_POINTER(a->name));
183 g_hash_table_insert(self->names, GUINT_TO_POINTER(a->name), GUINT_TO_POINTER(i + 1));
184 }
185 }
186
187 void
188 lttv_attribute_remove_by_name(LttvAttribute *self, LttvAttributeName name)
189 {
190 unsigned i;
191
192 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
193 if(unlikely(i == 0)) g_error("remove by name non existent attribute");
194
195 lttv_attribute_remove(self, i - 1);
196 }
197
198 /* Create an empty iattribute object and add it as an attribute under the
199 specified name, or return an existing iattribute attribute. If an
200 attribute of that name already exists but is not a GObject supporting the
201 iattribute interface, return NULL. */
202
203 /*CHECK*/LttvAttribute*
204 lttv_attribute_find_subdir(LttvAttribute *self, LttvAttributeName name)
205 {
206 unsigned i;
207
208 Attribute a;
209
210 LttvAttribute *new;
211
212 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
213 if(likely(i != 0)) {
214 a = g_array_index(self->attributes, Attribute, i - 1);
215 if(likely(a.type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(a.value.dv_gobject))) {
216 return LTTV_ATTRIBUTE(a.value.dv_gobject);
217 }
218 else return NULL;
219 }
220 new = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
221 *(lttv_attribute_add(self, name, LTTV_GOBJECT).v_gobject) = G_OBJECT(new);
222 return (LttvAttribute *)new;
223 }
224
225 gboolean
226 lttv_attribute_find(LttvAttribute *self, LttvAttributeName name,
227 LttvAttributeType t, LttvAttributeValue *v)
228 {
229 unsigned i;
230
231 Attribute *a;
232
233 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
234 if(likely(i != 0)) {
235 a = &g_array_index(self->attributes, Attribute, i - 1);
236 if(unlikely(a->type != t)) return FALSE;
237 *v = address_of_value(t, &(a->value));
238 return TRUE;
239 }
240
241 *v = lttv_attribute_add(self, name, t);
242 return TRUE;
243 }
244
245
246 /*void lttv_attribute_recursive_free(LttvAttribute *self)
247 {
248 int i, nb;
249
250 Attribute *a;
251
252 nb = self->attributes->len;
253
254 for(i = 0 ; i < nb ; i++) {
255 a = &g_array_index(self->attributes, Attribute, i);
256 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
257 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
258 }
259 }
260 g_object_unref(self);
261 }*/
262
263
264 void lttv_attribute_recursive_add(LttvAttribute *dest, LttvAttribute *src)
265 {
266 int i, nb;
267
268 Attribute *a;
269
270 LttvAttributeValue value;
271
272 nb = src->attributes->len;
273
274 for(i = 0 ; i < nb ; i++) {
275 a = &g_array_index(src->attributes, Attribute, i);
276 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
277 lttv_attribute_recursive_add(
278 /*CHECK*/(LttvAttribute *)lttv_attribute_find_subdir(dest, a->name),
279 (LttvAttribute *)(a->value.dv_gobject));
280 }
281 else {
282 g_assert(lttv_attribute_find(dest, a->name, a->type, &value));
283 switch(a->type) {
284 case LTTV_INT:
285 *value.v_int += a->value.dv_int;
286 break;
287 case LTTV_UINT:
288 *value.v_uint += a->value.dv_uint;
289 break;
290 case LTTV_LONG:
291 *value.v_long += a->value.dv_long;
292 break;
293 case LTTV_ULONG:
294 *value.v_ulong += a->value.dv_ulong;
295 break;
296 case LTTV_FLOAT:
297 *value.v_float += a->value.dv_float;
298 break;
299 case LTTV_DOUBLE:
300 *value.v_double += a->value.dv_double;
301 break;
302 case LTTV_TIME:
303 *value.v_time = ltt_time_add(*value.v_time, a->value.dv_time);
304 break;
305 case LTTV_POINTER:
306 break;
307 case LTTV_STRING:
308 break;
309 case LTTV_GOBJECT:
310 break;
311 case LTTV_NONE:
312 break;
313 }
314 }
315 }
316 }
317
318
319 static void
320 print_indent(FILE *fp, int pos)
321 {
322 int i;
323
324 for(i = 0 ; i < pos ; i++) putc(' ', fp);
325 }
326
327
328 void
329 lttv_attribute_write_xml(LttvAttribute *self, FILE *fp, int pos, int indent)
330 {
331 int i, nb;
332
333 Attribute *a;
334
335 nb = self->attributes->len;
336
337 fprintf(fp,"<ATTRS>\n");
338 for(i = 0 ; i < nb ; i++) {
339 a = &g_array_index(self->attributes, Attribute, i);
340 print_indent(fp, pos);
341 fprintf(fp, "<ATTR NAME=\"%s\" ", g_quark_to_string(a->name));
342 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
343 fprintf(fp, "TYPE=ATTRS>");
344 lttv_attribute_write_xml((LttvAttribute *)(a->value.dv_gobject), fp,
345 pos + indent, indent);
346 }
347 else {
348 switch(a->type) {
349 case LTTV_INT:
350 fprintf(fp, "TYPE=INT VALUE=%d/>\n", a->value.dv_int);
351 break;
352 case LTTV_UINT:
353 fprintf(fp, "TYPE=UINT VALUE=%u/>\n", a->value.dv_uint);
354 break;
355 case LTTV_LONG:
356 fprintf(fp, "TYPE=LONG VALUE=%ld/>\n", a->value.dv_long);
357 break;
358 case LTTV_ULONG:
359 fprintf(fp, "TYPE=ULONG VALUE=%lu/>\n", a->value.dv_ulong);
360 break;
361 case LTTV_FLOAT:
362 fprintf(fp, "TYPE=FLOAT VALUE=%f/>\n", a->value.dv_float);
363 break;
364 case LTTV_DOUBLE:
365 fprintf(fp, "TYPE=DOUBLE VALUE=%f/>\n", a->value.dv_double);
366 break;
367 case LTTV_TIME:
368 fprintf(fp, "TYPE=TIME SEC=%lu NSEC=%lu/>\n", a->value.dv_time.tv_sec,
369 a->value.dv_time.tv_nsec);
370 break;
371 case LTTV_POINTER:
372 fprintf(fp, "TYPE=POINTER VALUE=%p/>\n", a->value.dv_pointer);
373 break;
374 case LTTV_STRING:
375 fprintf(fp, "TYPE=STRING VALUE=\"%s\"/>\n", a->value.dv_string);
376 break;
377 case LTTV_GOBJECT:
378 fprintf(fp, "TYPE=GOBJECT VALUE=%p/>\n", a->value.dv_gobject);
379 break;
380 case LTTV_NONE:
381 fprintf(fp, "TYPE=NONE/>\n");
382 break;
383 }
384 }
385 }
386 print_indent(fp, pos);
387 fprintf(fp,"</ATTRS>\n");
388 }
389
390
391 void
392 lttv_attribute_read_xml(LttvAttribute *self, FILE *fp)
393 {
394 int res;
395
396 char buffer[256], type[10];
397
398 LttvAttributeName name;
399
400 LttvAttributeValue value;
401
402 LttvAttribute *subtree;
403
404 fscanf(fp,"<ATTRS>");
405 while(1) {
406 res = fscanf(fp, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer, type);
407 g_assert(res == 2);
408 name = g_quark_from_string(buffer);
409 if(strcmp(type, "ATTRS") == 0) {
410 fscanf(fp, ">");
411 subtree = lttv_attribute_find_subdir(self, name);
412 lttv_attribute_read_xml(subtree, fp);
413 }
414 else if(strcmp(type, "INT") == 0) {
415 value = lttv_attribute_add(self, name, LTTV_INT);
416 res = fscanf(fp, " VALUE=%d/>", value.v_int);
417 g_assert(res == 1);
418 }
419 else if(strcmp(type, "UINT") == 0) {
420 value = lttv_attribute_add(self, name, LTTV_UINT);
421 res = fscanf(fp, " VALUE=%u/>", value.v_uint);
422 g_assert(res == 1);
423 }
424 else if(strcmp(type, "LONG") == 0) {
425 value = lttv_attribute_add(self, name, LTTV_LONG);
426 res = fscanf(fp, " VALUE=%ld/>", value.v_long);
427 g_assert(res == 1);
428 }
429 else if(strcmp(type, "ULONG") == 0) {
430 value = lttv_attribute_add(self, name, LTTV_ULONG);
431 res = fscanf(fp, " VALUE=%lu/>", value.v_ulong);
432 g_assert(res == 1);
433 }
434 else if(strcmp(type, "FLOAT") == 0) {
435 float d;
436 value = lttv_attribute_add(self, name, LTTV_FLOAT);
437 res = fscanf(fp, " VALUE=%f/>", &d);
438 *(value.v_float) = d;
439 g_assert(res == 1);
440 }
441 else if(strcmp(type, "DOUBLE") == 0) {
442 value = lttv_attribute_add(self, name, LTTV_DOUBLE);
443 res = fscanf(fp, " VALUE=%lf/>", value.v_double);
444 g_assert(res == 1);
445 }
446 else if(strcmp(type, "TIME") == 0) {
447 value = lttv_attribute_add(self, name, LTTV_TIME);
448 res = fscanf(fp, " SEC=%lu NSEC=%lu/>", &(value.v_time->tv_sec),
449 &(value.v_time->tv_nsec));
450 g_assert(res == 2);
451 }
452 else if(strcmp(type, "POINTER") == 0) {
453 value = lttv_attribute_add(self, name, LTTV_POINTER);
454 res = fscanf(fp, " VALUE=%p/>", value.v_pointer);
455 g_error("Cannot read a pointer");
456 }
457 else if(strcmp(type, "STRING") == 0) {
458 value = lttv_attribute_add(self, name, LTTV_STRING);
459 res = fscanf(fp, " VALUE=\"%256[^\"]\"/>", buffer);
460 *(value.v_string) = g_strdup(buffer);
461 g_assert(res == 1);
462 }
463 else if(strcmp(type, "GOBJECT") == 0) {
464 value = lttv_attribute_add(self, name, LTTV_GOBJECT);
465 res = fscanf(fp, " VALUE=%p/>", value.v_gobject);
466 g_error("Cannot read a pointer");
467 }
468 else if(strcmp(type, "NONE") == 0) {
469 value = lttv_attribute_add(self, name, LTTV_NONE);
470 fscanf(fp, "/>");
471 }
472 else g_error("Unknown type to read");
473 }
474 fscanf(fp,"</ATTRS>");
475 }
476
477 static LttvAttribute *
478 new_attribute (LttvAttribute *self)
479 {
480 return g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
481 }
482
483
484 static void
485 attribute_interface_init (gpointer g_iface, gpointer iface_data)
486 {
487 LttvIAttributeClass *klass = (LttvIAttributeClass *)g_iface;
488
489 klass->new_attribute = (LttvIAttribute* (*) (LttvIAttribute *self))
490 new_attribute;
491
492 klass->get_number = (unsigned int (*) (LttvIAttribute *self))
493 lttv_attribute_get_number;
494
495 klass->named = (gboolean (*) (LttvIAttribute *self, gboolean *homogeneous))
496 lttv_attribute_named;
497
498 klass->get = (LttvAttributeType (*) (LttvIAttribute *self, unsigned i,
499 LttvAttributeName *name, LttvAttributeValue *v)) lttv_attribute_get;
500
501 klass->get_by_name = (LttvAttributeType (*) (LttvIAttribute *self,
502 LttvAttributeName name, LttvAttributeValue *v))
503 lttv_attribute_get_by_name;
504
505 klass->add = (LttvAttributeValue (*) (LttvIAttribute *self,
506 LttvAttributeName name, LttvAttributeType t)) lttv_attribute_add;
507
508 klass->remove = (void (*) (LttvIAttribute *self, unsigned i))
509 lttv_attribute_remove;
510
511 klass->remove_by_name = (void (*) (LttvIAttribute *self,
512 LttvAttributeName name)) lttv_attribute_remove_by_name;
513
514 klass->find_subdir = (LttvIAttribute* (*) (LttvIAttribute *self,
515 LttvAttributeName name)) lttv_attribute_find_subdir;
516
517 }
518
519 static void
520 attribute_instance_init (GTypeInstance *instance, gpointer g_class)
521 {
522 LttvAttribute *self = (LttvAttribute *)instance;
523 self->names = g_hash_table_new(g_direct_hash,
524 g_direct_equal);
525 self->attributes = g_array_new(FALSE, FALSE, sizeof(Attribute));
526 }
527
528
529 static void
530 attribute_finalize (LttvAttribute *self)
531 {
532 guint i;
533 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "attribute_finalize()");
534
535 for(i=0;i<self->attributes->len;i++) {
536 lttv_attribute_remove(self, i);
537 }
538
539 g_hash_table_destroy(self->names);
540 g_array_free(self->attributes, TRUE);
541 }
542
543
544 static void
545 attribute_class_init (LttvAttributeClass *klass)
546 {
547 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
548
549 gobject_class->finalize = (void (*)(GObject *self))attribute_finalize;
550 }
551
552 GType
553 lttv_attribute_get_type (void)
554 {
555 static GType type = 0;
556 if (type == 0) {
557 static const GTypeInfo info = {
558 sizeof (LttvAttributeClass),
559 NULL, /* base_init */
560 NULL, /* base_finalize */
561 (GClassInitFunc) attribute_class_init, /* class_init */
562 NULL, /* class_finalize */
563 NULL, /* class_data */
564 sizeof (LttvAttribute),
565 0, /* n_preallocs */
566 (GInstanceInitFunc) attribute_instance_init, /* instance_init */
567 NULL /* value handling */
568 };
569
570 static const GInterfaceInfo iattribute_info = {
571 (GInterfaceInitFunc) attribute_interface_init, /* interface_init */
572 NULL, /* interface_finalize */
573 NULL /* interface_data */
574 };
575
576 type = g_type_register_static (G_TYPE_OBJECT, "LttvAttributeType", &info,
577 0);
578 g_type_add_interface_static (type, LTTV_IATTRIBUTE_TYPE, &iattribute_info);
579 }
580 return type;
581 }
582
583
This page took 0.043142 seconds and 4 git commands to generate.