-#include <lttv/attribute.h>
-
-inline lttv_string_id lttv_string_id_from_string(const char *s) {
- return g_quark_from_string(s);
-}
-
-
-inline void lttv_string_id_release(lttv_string_id i) {}
-
-
-inline const char *lttv_string_id_to_string(lttv_string_id i) {
- return g_quark_to_string(i);
-}
-
-
-inline lttv_key *lttv_key_new() {
- return g_array_new(FALSE, FALSE, sizeof(lttv_string_id));
-}
-
-/* Changed this function to destroy the element also, caused memory leak? */
-/* Mathieu Desnoyers */
-inline void lttv_key_destroy(lttv_key *k) {
- g_array_free(k, TRUE);
-}
-
-
-#define _lttv_key_index(k,i) g_array_index(k, lttv_string_id, i)
-
-
-inline void lttv_key_append(lttv_key *k, lttv_string_id i) {
- g_array_append_val(k,i);
-}
-
-
-inline unsigned int lttv_key_component_number(lttv_key *k) {
- return k->len;
-}
-
-
-lttv_key *lttv_key_copy(lttv_key *k) {
- lttv_key *nk;
- int i;
- nk = lttv_key_new();
- for(i = 0 ; i < k->len ; i++) lttv_key_append(nk,lttv_key_index(k,i));
- return nk;
+#include <lttv/attribute.h>
+#include <ltt/ltt.h>
+
+typedef union _AttributeValue {
+ int dv_int;
+ unsigned dv_uint;
+ long dv_long;
+ unsigned long dv_ulong;
+ float dv_float;
+ double dv_double;
+ LttTime dv_time;
+ gpointer dv_pointer;
+ char *dv_string;
+ GObject *dv_gobject;
+} AttributeValue;
+
+
+typedef struct _Attribute {
+ LttvAttributeName name;
+ LttvAttributeType type;
+ AttributeValue value;
+} Attribute;
+
+
+LttvAttributeValue address_of_value(LttvAttributeType t, AttributeValue *v)
+{
+ LttvAttributeValue va;
+
+ switch(t) {
+ case LTTV_INT: va.v_int = &v->dv_int; break;
+ case LTTV_UINT: va.v_uint = &v->dv_uint; break;
+ case LTTV_LONG: va.v_long = &v->dv_long; break;
+ case LTTV_ULONG: va.v_ulong = &v->dv_ulong; break;
+ case LTTV_FLOAT: va.v_float = &v->dv_float; break;
+ case LTTV_DOUBLE: va.v_double = &v->dv_double; break;
+ case LTTV_TIME: va.v_time = &v->dv_time; break;
+ case LTTV_POINTER: va.v_pointer = &v->dv_pointer; break;
+ case LTTV_STRING: va.v_string = &v->dv_string; break;
+ case LTTV_GOBJECT: va.v_gobject = &v->dv_gobject; break;
+ }
+ return va;
}
-/* It is also possible to create a key directly from a pathname,
- key components separated by /, (e.g., "/hooks/options/before"). */
-lttv_key *lttv_key_new_pathname(const char *p) {
- char **v, **cursor;
- lttv_key *k;
-
- v = cursor = g_strsplit(p, "/", -1);
- k = lttv_key_new();
-
- while(*cursor != NULL) {
- lttv_key_append(k, lttv_string_id_from_string(*cursor));
- cursor++;
+AttributeValue init_value(LttvAttributeType t)
+{
+ AttributeValue v;
+
+ switch(t) {
+ case LTTV_INT: v.dv_int = 0; break;
+ case LTTV_UINT: v.dv_uint = 0; break;
+ case LTTV_LONG: v.dv_long = 0; break;
+ case LTTV_ULONG: v.dv_ulong = 0; break;
+ case LTTV_FLOAT: v.dv_float = 0; break;
+ case LTTV_DOUBLE: v.dv_double = 0; break;
+ case LTTV_TIME: v.dv_time.tv_sec = 0; v.dv_time.tv_nsec = 0; break;
+ case LTTV_POINTER: v.dv_pointer = NULL; break;
+ case LTTV_STRING: v.dv_string = NULL; break;
+ case LTTV_GOBJECT: v.dv_gobject = NULL; break;
}
- g_strfreev(v);
- return k;
+ return v;
}
-static guint lttv_key_hash(gconstpointer key) {
- lttv_key * k = (lttv_key *)key;
- guint h = 0;
- int i;
- for(i = 0 ; i < k->len ; i++) h = h ^ lttv_key_index(k,i);
- return h;
+
+unsigned int
+lttv_attribute_get_number(LttvAttribute *self)
+{
+ return self->attributes->len;
}
-static gboolean lttv_key_equal(gconstpointer key1,gconstpointer key2) {
- lttv_key * k1 = (lttv_key *)key1;
- lttv_key * k2 = (lttv_key *)key2;
- int i;
- if(k1->len != k2->len) return FALSE;
- for(i = 0 ; i < k1->len ; i++)
- if(lttv_key_index(k1,i) != lttv_key_index(k2,i)) return FALSE;
+gboolean
+lttv_attribute_named(LttvAttribute *self, gboolean *homogeneous)
+{
+ *homogeneous = FALSE;
return TRUE;
}
-static void lttv_key_free(gpointer data)
+LttvAttributeType
+lttv_attribute_get(LttvAttribute *self, unsigned i, LttvAttributeName *name,
+ LttvAttributeValue *v)
{
- lttv_key_destroy((lttv_key *)data);
+ Attribute *a;
+
+ a = &g_array_index(self->attributes, Attribute, i);
+ *name = a->name;
+ *v = address_of_value(a->type, &(a->value));
+ return a->type;
}
-static void lttv_attribute_value_free(gpointer data)
+LttvAttributeType
+lttv_attribute_get_by_name(LttvAttribute *self, LttvAttributeName name,
+ LttvAttributeValue *v)
{
- g_free(data);
-}
+ Attribute *a;
+ unsigned i;
-lttv_attributes *lttv_attributes_new() {
- lttv_attributes *a;
+ gpointer p;
- a = g_new(lttv_attributes, 1);
- a->ints = g_hash_table_new_full(lttv_key_hash, lttv_key_equal,
- lttv_key_free, lttv_attribute_value_free);
- a->times = g_hash_table_new_full(lttv_key_hash, lttv_key_equal,
- lttv_key_free, lttv_attribute_value_free);
- a->doubles = g_hash_table_new_full(lttv_key_hash, lttv_key_equal,
- lttv_key_free, lttv_attribute_value_free);
- a->pointers = g_hash_table_new(lttv_key_hash, lttv_key_equal);
+ p = g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
+ if(p == NULL) return LTTV_NONE;
- return a;
+ i = GPOINTER_TO_UINT(p);
+ i--;
+ a = &g_array_index(self->attributes, Attribute, i);
+ *v = address_of_value(a->type, &(a->value));
+ return a->type;
}
-/* Free the hash table containing the stats and all the contained keys/vals */
-
-static void lttv_attribute_key_free(gpointer k, gpointer v, gpointer data) {
- lttv_key_free(k);
-}
+LttvAttributeValue
+lttv_attribute_add(LttvAttribute *self, LttvAttributeName name,
+ LttvAttributeType t)
+{
+ unsigned i;
+ Attribute a, *pa;
-void lttv_attributes_destroy(lttv_attributes *a) {
- g_hash_table_destroy(a->ints);
- g_hash_table_destroy(a->times);
- g_hash_table_destroy(a->doubles);
+ i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
+ if(i != 0) g_error("duplicate entry in attribute table");
- g_hash_table_foreach(a->pointers, lttv_attribute_key_free, NULL);
- g_hash_table_destroy(a->pointers);
- g_free(a);
+ a.name = name;
+ a.type = t;
+ a.value = init_value(t);
+ g_array_append_val(self->attributes, a);
+ i = self->attributes->len - 1;
+ pa = &g_array_index(self->attributes, Attribute, i);
+ g_hash_table_insert(self->names, GUINT_TO_POINTER(name),
+ GUINT_TO_POINTER(i + 1));
+ return address_of_value(t, &(pa->value));
}
-unsigned int lttv_attributes_number(lttv_attributes *a) {
- return g_hash_table_size(a->ints) + g_hash_table_size(a->times) +
- g_hash_table_size(a->doubles) + g_hash_table_size(a->pointers);
-}
+/* Remove an attribute */
-/* If it is a new entry, insert it in the hash table, and set it to 0 */
-
-int *lttv_attributes_get_integer(lttv_attributes *a, lttv_key *k)
+void
+lttv_attribute_remove(LttvAttribute *self, unsigned i)
{
- gpointer found;
+ Attribute *a;
- found = g_hash_table_lookup(a->ints, k);
- if(found == NULL) {
- found = g_new(gint, 1);
- *(gint *)found = 0;
- g_hash_table_insert(a->ints, lttv_key_copy(k), found);
- }
- return found;
-}
+ a = &g_array_index(self->attributes, Attribute, i);
+ /* Remove the array element and its entry in the name index */
-lttv_time *lttv_attributes_get_time(lttv_attributes *a, lttv_key *k)
-{
- gpointer found;
-
- found = g_hash_table_lookup(a->times, k);
- if(found == NULL) {
- found = g_new0(lttv_time, 1);
- /* *(lttv_time *)found = ZeroTime; */
- g_hash_table_insert(a->times, lttv_key_copy(k), found);
- }
- return found;
-}
+ g_hash_table_remove(self->names, GUINT_TO_POINTER(a->name));
+ g_array_remove_index_fast(self->attributes, i);
-double *lttv_attributes_get_double(lttv_attributes *a, lttv_key *k)
-{
- gpointer found;
+ /* The element used to replace the removed element has its index entry
+ all wrong now. Reinsert it with its new position. */
- found = g_hash_table_lookup(a->doubles,k);
- if(found == NULL) {
- found = g_new(double,1);
- *(double *)found = 0;
- g_hash_table_insert(a->doubles, lttv_key_copy(k),found);
+ if(self->attributes->len != i){
+ g_hash_table_remove(self->names, GUINT_TO_POINTER(a->name));
+ g_hash_table_insert(self->names, GUINT_TO_POINTER(a->name), GUINT_TO_POINTER(i + 1));
}
- return found;
}
-void *lttv_attributes_get_pointer_pathname(lttv_attributes *a, char *pn)
+void
+lttv_attribute_remove_by_name(LttvAttribute *self, LttvAttributeName name)
{
- lttv_key *key;
- void *p;
+ unsigned i;
- key = lttv_key_new_pathname(pn);
- p = lttv_attributes_get_pointer(a, key);
- lttv_key_destroy(key);
+ i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
+ if(i == 0) g_error("remove by name non existent attribute");
- return p;
+ lttv_attribute_remove(self, i - 1);
}
-void *lttv_attributes_get_pointer(lttv_attributes *a, lttv_key *k)
-{
- return g_hash_table_lookup(a->pointers,k);
-}
+/* Create an empty iattribute object and add it as an attribute under the
+ specified name, or return an existing iattribute attribute. If an
+ attribute of that name already exists but is not a GObject supporting the
+ iattribute interface, return NULL. */
-void lttv_attributes_set_pointer_pathname(lttv_attributes *a,char *pn,void *p)
+/*CHECK*/LttvAttribute*
+lttv_attribute_find_subdir(LttvAttribute *self, LttvAttributeName name)
{
- lttv_key *key = lttv_key_new_pathname(pn);
-
- lttv_attributes_set_pointer(a, key, p);
- lttv_key_destroy(key);
-}
+ unsigned i;
-void lttv_attributes_set_pointer(lttv_attributes *a, lttv_key *k, void *p) {
- lttv_key * oldk;
- void *oldv;
+ Attribute a;
- if(g_hash_table_lookup_extended(a->pointers, k, (gpointer)oldk, &oldv)) {
- if(p == NULL) {
- g_hash_table_remove(a->pointers,k);
- }
- else {
- g_hash_table_insert(a->pointers,oldk,p);
+ LttvAttribute *new;
+
+ i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
+ if(i != 0) {
+ a = g_array_index(self->attributes, Attribute, i - 1);
+ if(a.type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(a.value.dv_gobject)) {
+ return LTTV_ATTRIBUTE(a.value.dv_gobject);
}
- }
- else {
- if(p == NULL) return;
- g_hash_table_insert(a->pointers,lttv_key_copy(k),p);
+ else return NULL;
}
+ new = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
+ *(lttv_attribute_add(self, name, LTTV_GOBJECT).v_gobject) = G_OBJECT(new);
+ return (LttvAttribute *)new;
}
+gboolean
+lttv_attribute_find(LttvAttribute *self, LttvAttributeName name,
+ LttvAttributeType t, LttvAttributeValue *v)
+{
+ unsigned i;
-/* Sometimes the attributes must be accessed in bulk, sorted in different
- ways. For this purpose they may be converted to arrays and sorted
- multiple times. The keys used in the array belong to the lttv_attributes
- object from which the array was obtained and are freed when it is
- destroyed. Each element in the array is an lttv_attribute, a structure
- containing the key, the value type, and a union containing a value of
- that type. Multiple attributes with equal keys may be possible in some
- implementations if their type differs. */
-
+ Attribute *a;
-typedef struct _lttv_attribute_fill_position {
- unsigned i;
- lttv_attribute_type t;
- lttv_attribute *a;
-} lttv_attribute_fill_position;
-
-
-static void lttv_attribute_fill(void *key, void *value, void *user_data) {
- lttv_attribute_fill_position * p = (lttv_attribute_fill_position *)user_data;
- lttv_attribute *a = p->a + p->i;
-
- a->key = (lttv_key *)key;
- a->t = p->t;
- switch(p->t) {
- case LTTV_INTEGER:
- a->v.i = *((int *)value);
- case LTTV_TIME:
- a->v.t = *((lttv_time *)value);
- case LTTV_DOUBLE:
- a->v.d = *((double *)value);
- case LTTV_POINTER:
- a->v.p = value;
+ i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
+ if(i != 0) {
+ a = &g_array_index(self->attributes, Attribute, i - 1);
+ if(a->type != t) return FALSE;
+ *v = address_of_value(t, &(a->value));
+ return TRUE;
}
- p->i++;
+
+ *v = lttv_attribute_add(self, name, t);
+ return TRUE;
}
-lttv_attribute *lttv_attributes_array_get(lttv_attributes *a) {
- unsigned size;
- lttv_attribute *v;
- lttv_attribute_fill_position p;
-
- size = lttv_attributes_number(a);
- v = g_new(lttv_attribute,size);
-
- p.a = v;
- p.i = 0;
- p.t = LTTV_INTEGER;
- g_hash_table_foreach(a->ints, lttv_attribute_fill, &p);
- p.t = LTTV_TIME;
- g_hash_table_foreach(a->times, lttv_attribute_fill, &p);
- p.t = LTTV_DOUBLE;
- g_hash_table_foreach(a->doubles, lttv_attribute_fill, &p);
- p.t = LTTV_POINTER;
- g_hash_table_foreach(a->pointers, lttv_attribute_fill, &p);
- return v;
-}
+void lttv_attribute_recursive_free(LttvAttribute *self)
+{
+ int i, nb;
+ Attribute *a;
-lttv_attribute *lttv_attribute_array_destroy(lttv_attribute *a) {
- g_free(a);
+ nb = self->attributes->len;
+
+ for(i = 0 ; i < nb ; i++) {
+ a = &g_array_index(self->attributes, Attribute, i);
+ if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
+ lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
+ }
+ }
+ g_object_unref(self);
}
-void lttv_attribute_array_sort(lttv_attribute *a,
- unsigned size, lttv_key_compare f,
- void *compare_data)
+void lttv_attribute_recursive_add(LttvAttribute *dest, LttvAttribute *src)
{
-
- g_qsort_with_data(a, size, sizeof(lttv_attribute), f,
- compare_data);
-}
+ int i, nb;
+ Attribute *a;
-int lttv_key_compare_priority(lttv_key *a, lttv_key *b, void *compare_data)
-{
- int i, res;
- int *priority = (int *)compare_data;
+ LttvAttributeValue value;
- g_assert(a->len == b->len);
+ nb = src->attributes->len;
- for(i = 0 ; i < a->len ; i++)
- {
- res = strcmp(lttv_string_id_to_string(lttv_key_index(a,priority[i])),
- lttv_string_id_to_string(lttv_key_index(a,priority[i])));
- if(res != 0) return res;
+ for(i = 0 ; i < nb ; i++) {
+ a = &g_array_index(src->attributes, Attribute, i);
+ if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
+ lttv_attribute_recursive_add(
+ /*CHECK*/(LttvAttribute *)lttv_attribute_find_subdir(dest, a->name),
+ (LttvAttribute *)(a->value.dv_gobject));
+ }
+ else {
+ g_assert(lttv_attribute_find(dest, a->name, a->type, &value));
+ switch(a->type) {
+ case LTTV_INT:
+ *value.v_int += a->value.dv_int;
+ break;
+ case LTTV_UINT:
+ *value.v_uint += a->value.dv_uint;
+ break;
+ case LTTV_LONG:
+ *value.v_long += a->value.dv_long;
+ break;
+ case LTTV_ULONG:
+ *value.v_ulong += a->value.dv_ulong;
+ break;
+ case LTTV_FLOAT:
+ *value.v_float += a->value.dv_float;
+ break;
+ case LTTV_DOUBLE:
+ *value.v_double += a->value.dv_double;
+ break;
+ case LTTV_TIME:
+ *value.v_time = ltt_time_add(*value.v_time, a->value.dv_time);
+ break;
+ case LTTV_POINTER:
+ break;
+ case LTTV_STRING:
+ break;
+ case LTTV_GOBJECT:
+ break;
+ case LTTV_NONE:
+ break;
+ }
+ }
}
- return 0;
}
-typedef struct _select_data {
- lttv_attributes *a;
- lttv_key *k;
- void *user_data;
- lttv_key_select select;
-} select_data;
-
-static void select_integer(void *key, void *value, void *user_data);
-static void select_double(void *key, void *value, void *user_data);
-static void select_time(void *key, void *value, void *user_data);
-static void select_pointer(void *key, void *value, void *user_data);
-
-lttv_attributes *lttv_attributes_select(lttv_attributes *a, lttv_key_select f,
- void *user_data)
-{
- select_data *d;
-
- d = g_new(select_data, 1);
- d->a = lttv_attributes_new();
- d->k = lttv_key_new();
- d->user_data = user_data;
- d->select = f;
-
- g_hash_table_foreach(a->ints,select_integer, d);
- g_hash_table_foreach(a->doubles,select_double, d);
- g_hash_table_foreach(a->times,select_time, d);
- g_hash_table_foreach(a->pointers,select_pointer, d);
-}
-
-int lttv_key_select_spec(lttv_key *in, lttv_key *out, void *user_data)
+static void
+attribute_interface_init (gpointer g_iface, gpointer iface_data)
{
- lttv_key_select_spec_data *d = (lttv_key_select_spec_data *)user_data;
- int i;
+ LttvIAttributeClass *klass = (LttvIAttributeClass *)g_iface;
- /* not defined yet */
- /* lttv_key_set_size(out, 0); */
+ klass->get_number = (unsigned int (*) (LttvIAttribute *self))
+ lttv_attribute_get_number;
- for(i = 0 ; i < d->length ; i++) {
- switch(d->spec[i]) {
- case LTTV_KEEP:
- break;
+ klass->named = (gboolean (*) (LttvIAttribute *self, gboolean *homogeneous))
+ lttv_attribute_named;
- case LTTV_KEEP_EQUAL:
- break;
+ klass->get = (LttvAttributeType (*) (LttvIAttribute *self, unsigned i,
+ LttvAttributeName *name, LttvAttributeValue *v)) lttv_attribute_get;
- case LTTV_KEEP_SMALLER:
- break;
+ klass->get_by_name = (LttvAttributeType (*) (LttvIAttribute *self,
+ LttvAttributeName name, LttvAttributeValue *v))
+ lttv_attribute_get_by_name;
- case LTTV_KEEP_GREATER:
- break;
+ klass->add = (LttvAttributeValue (*) (LttvIAttribute *self,
+ LttvAttributeName name, LttvAttributeType t)) lttv_attribute_add;
- case LTTV_IGNORE:
- break;
+ klass->remove = (void (*) (LttvIAttribute *self, unsigned i))
+ lttv_attribute_remove;
- }
- }
+ klass->remove_by_name = (void (*) (LttvIAttribute *self,
+ LttvAttributeName name)) lttv_attribute_remove_by_name;
- return 1;
+ klass->find_subdir = (LttvIAttribute* (*) (LttvIAttribute *self,
+ LttvAttributeName name)) lttv_attribute_find_subdir;
}
-static void select_integer(void *key, void *value, void *user_data)
-{
- lttv_key *k = (lttv_key *)key;
- int *pi = (int *)value;
- select_data *d = (select_data *)user_data;
- if(d->select(k,d->k,d->user_data)) {
- *(lttv_attributes_get_integer(d->a,d->k)) += *pi;
- }
+static void
+attribute_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+ LttvAttribute *self = (LttvAttribute *)instance;
+ self->names = g_hash_table_new(g_direct_hash, g_direct_equal);
+ self->attributes = g_array_new(FALSE, FALSE, sizeof(Attribute));
}
-static void select_double(void *key, void *value, void *user_data)
-{
- lttv_key *k = (lttv_key *)key;
- double *pf = (double *)value;
- select_data *d = (select_data *)user_data;
- if(d->select(k,d->k,d->user_data)) {
- *(lttv_attributes_get_double(d->a,d->k)) += *pf;
- }
+static void
+attribute_finalize (LttvAttribute *self)
+{
+ g_hash_table_destroy(self->names);
+ g_critical("attribute_finalize()");
+ g_array_free(self->attributes, TRUE);
+ G_OBJECT_CLASS(g_type_class_peek_parent(
+ g_type_class_peek(LTTV_ATTRIBUTE_TYPE)))->finalize(G_OBJECT(self));
}
-static void select_time(void *key, void *value, void *user_data)
+
+static void
+attribute_class_init (LttvAttributeClass *klass)
{
- lttv_key *k = (lttv_key *)key;
- lttv_time *ptSum, *pt = (lttv_time *)value;
- select_data *d = (select_data *)user_data;
-
- if(d->select(k,d->k,d->user_data)) {
- ptSum = lttv_attributes_get_time(d->a,d->k);
- ptSum->tv_sec += pt->tv_sec;
- ptSum->tv_nsec += pt->tv_nsec;
- }
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->finalize = (void (*)(GObject *self))attribute_finalize;
}
-static void select_pointer(void *key, void *value, void *user_data)
+GType
+lttv_attribute_get_type (void)
{
- lttv_key *k = (lttv_key *)key;
- select_data *d = (select_data *)user_data;
-
- if(d->select(k,d->k,d->user_data)) {
- lttv_attributes_set_pointer(d->a,d->k,value);
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof (LttvAttributeClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) attribute_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (LttvAttribute),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attribute_instance_init /* instance_init */
+ };
+
+ static const GInterfaceInfo iattribute_info = {
+ (GInterfaceInitFunc) attribute_interface_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "LttvAttributeType", &info,
+ 0);
+ g_type_add_interface_static (type, LTTV_IATTRIBUTE_TYPE, &iattribute_info);
}
+ return type;
}
-
-
-