dc877563 |
1 | |
fcdf0ec2 |
2 | #include <lttv/attribute.h> |
f32847a1 |
3 | |
dc877563 |
4 | typedef union _AttributeValue { |
5 | int dv_int; |
6 | unsigned dv_uint; |
7 | long dv_long; |
8 | unsigned long dv_ulong; |
9 | float dv_float; |
10 | double dv_double; |
11 | timespec dv_timespec; |
12 | gpointer dv_pointer; |
13 | char *dv_string; |
14 | gobject *dv_gobject; |
15 | } AttributeValue; |
16 | |
17 | |
18 | typedef struct _Attribute { |
19 | LttvAttributeName name; |
20 | LttvAttributeType type; |
21 | AttributeValue value; |
22 | } Attribute; |
23 | |
24 | |
25 | GType |
26 | lttv_attribute_get_type (void) |
27 | { |
28 | static GType type = 0; |
29 | if (type == 0) { |
30 | static const GTypeInfo info = { |
31 | sizeof (LttvAttributeClass), |
32 | NULL, /* base_init */ |
33 | NULL, /* base_finalize */ |
34 | attribute_class_init, /* class_init */ |
35 | NULL, /* class_finalize */ |
36 | NULL, /* class_data */ |
37 | sizeof (LttvAttribute), |
38 | 0, /* n_preallocs */ |
39 | attribute_instance_init /* instance_init */ |
40 | }; |
41 | |
42 | static const GInterfaceInfo iattribute_info = { |
43 | (GInterfaceInitFunc) attribute_interface_init, /* interface_init */ |
44 | NULL, /* interface_finalize */ |
45 | NULL /* interface_data */ |
46 | }; |
47 | |
48 | type = g_type_register_static (G_TYPE_OBJECT, "LttvAttributeType", &info, |
49 | 0); |
50 | g_type_add_interface_static (type, LTTV_IATTRIBUTE_TYPE, &iattribute_info); |
51 | } |
52 | return type; |
f32847a1 |
53 | } |
54 | |
55 | |
dc877563 |
56 | unsigned int |
57 | lttv_attribute_get_number(LttvAttribute *self) |
58 | { |
59 | return self->attributes->len; |
f32847a1 |
60 | } |
61 | |
62 | |
dc877563 |
63 | gboolean |
64 | lttv_attribute_named(LttvAttribute *self, gboolean *homogeneous) |
65 | { |
66 | *homogeneous = FALSE; |
67 | return TRUE; |
f32847a1 |
68 | } |
69 | |
70 | |
dc877563 |
71 | LttvAttributeType |
72 | lttv_attribute_get(LttvAttribute *self, unsigned i, LttvAttributeName *name, |
73 | LttvAttributeValue *v) |
74 | { |
75 | Attribute *a; |
f32847a1 |
76 | |
dc877563 |
77 | a = &g_array_index(self->attributes, Attribute, i); |
78 | *name = a->name; |
79 | *v = address_of_value(a->type, a->value); |
80 | return a->type; |
f32847a1 |
81 | } |
82 | |
83 | |
dc877563 |
84 | LttvAttributeType |
85 | lttv_attribute_get_by_name(LttvAttribute *self, LttvAttributeName name, |
86 | LttvAttributeValue *v) |
87 | { |
88 | Attribute *a; |
f32847a1 |
89 | |
dc877563 |
90 | unsigned i; |
f32847a1 |
91 | |
dc877563 |
92 | i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); |
93 | if(i == 0) return LTTV_NONE; |
f32847a1 |
94 | |
dc877563 |
95 | i--; |
96 | a = &g_array_index(self->attributes, Attribute, i); |
97 | *v = address_of_value(a->type, a->value); |
98 | return a->type; |
f32847a1 |
99 | } |
100 | |
f32847a1 |
101 | |
dc877563 |
102 | LttvAttributeValue |
103 | lttv_attribute_add(LttvAttribute *self, LttvAttributeName name, |
104 | LttvAttributeType t) |
105 | { |
106 | unsigned i; |
f32847a1 |
107 | |
dc877563 |
108 | Attribute a, *pa; |
f32847a1 |
109 | |
dc877563 |
110 | i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); |
111 | if(i != 0) g_error("duplicate entry in attribute table"); |
f32847a1 |
112 | |
dc877563 |
113 | a->name = name; |
114 | a->type = t; |
115 | a->value = init_value(t); |
116 | g_array_append_val(self->attributes, a); |
117 | i = self->attributes->len - 1; |
118 | pa = &g_array_index(self->attributes, Attribute, i) |
119 | g_hash_table_insert(self->names, (gconstpointer)name, (gconstpointer)i + 1); |
120 | return address_of_value(pa->value, t); |
f32847a1 |
121 | } |
122 | |
123 | |
dc877563 |
124 | /* Remove an attribute */ |
f32847a1 |
125 | |
dc877563 |
126 | void |
127 | lttv_attribute_remove(LttvAttribute *self, unsigned i) |
f32847a1 |
128 | { |
dc877563 |
129 | Attribute *a; |
f32847a1 |
130 | |
dc877563 |
131 | a = &g_array_index(self->attributes, Attribute, i); |
f32847a1 |
132 | |
dc877563 |
133 | /* Remove the array element and its entry in the name index */ |
f32847a1 |
134 | |
dc877563 |
135 | g_hash_table_remove(self->names, (gconspointer)a->name); |
136 | g_array_remove_index_fast(self->attributes, i); |
f32847a1 |
137 | |
dc877563 |
138 | /* The element used to replace the removed element has its index entry |
139 | all wrong now. Reinsert it with its new position. */ |
f32847a1 |
140 | |
dc877563 |
141 | g_hash_table_remove(self->names, (gconstpointer)a->name); |
142 | g_hash_table_insert(self->names, (gconstpointer)a->name, i + 1); |
f32847a1 |
143 | } |
144 | |
dc877563 |
145 | void |
146 | lttv_attribute_remove_by_name(LttvAttribute *self, LttvAttributeName name) |
147 | { |
148 | unsigned i; |
f32847a1 |
149 | |
dc877563 |
150 | i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); |
151 | if(i == 0) g_error("remove by name non existent attribute"); |
f32847a1 |
152 | |
dc877563 |
153 | lttv_attribute_remove(self, i - 1); |
f32847a1 |
154 | } |
155 | |
dc877563 |
156 | /* Create an empty iattribute object and add it as an attribute under the |
157 | specified name, or return an existing iattribute attribute. If an |
158 | attribute of that name already exists but is not a GObject supporting the |
159 | iattribute interface, return NULL. */ |
f32847a1 |
160 | |
dc877563 |
161 | LttvIAttribute* |
162 | lttv_attribute_create_subdir(LttvAttribute *self, LttvAttributeName name) |
f32847a1 |
163 | { |
dc877563 |
164 | unsigned i; |
f32847a1 |
165 | |
dc877563 |
166 | Attribute a; |
f32847a1 |
167 | |
dc877563 |
168 | LttvAttribute *new; |
f32847a1 |
169 | |
dc877563 |
170 | i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); |
171 | if(i != 0) { |
172 | a = g_array_index(self->attributes, Attribute, i - 1); |
173 | if(a->type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(a->value->dv_gobject)) { |
174 | return LTTV_IATTRIBUTE(a->value->dv_gobject); |
175 | } |
176 | else return NULL; |
f32847a1 |
177 | } |
dc877563 |
178 | new = g_object_new(LTTV_ATTRIBUTE_TYPE); |
179 | *(lttv_attribute_add(self, name, LTTV_GOBJECT)->v_gobject) = new; |
180 | return new; |
f32847a1 |
181 | } |
182 | |
dc877563 |
183 | gboolean |
184 | lttv_attribute_find(LttvAttribute *self, LttvAttributeName name, |
185 | LttvAttributeType t, LttvAttributeValue *v) |
f32847a1 |
186 | { |
dc877563 |
187 | unsigned i; |
f32847a1 |
188 | |
dc877563 |
189 | Attribute *a; |
f32847a1 |
190 | |
dc877563 |
191 | i = (unsigned)g_hash_table_lookup(self->names, (gconstpointer)name); |
192 | if(i != 0) { |
193 | a = &g_array_index(self->attributes, Attribute, i - 1); |
194 | if(a->type != t) return FALSE; |
195 | *v = address_of_value(a->value, t); |
196 | return TRUE; |
197 | } |
f32847a1 |
198 | |
dc877563 |
199 | *v = lttv_attribute_add(self, name, t); |
200 | return TRUE; |
f32847a1 |
201 | } |
202 | |
f32847a1 |
203 | |
dc877563 |
204 | static void |
205 | attribute_interface_init (gpointer g_iface, gpointer iface_data) |
f32847a1 |
206 | { |
dc877563 |
207 | LttvIAttributeClass *klass = (LttvIAttributeClass *)g_iface; |
f32847a1 |
208 | |
dc877563 |
209 | klass->get_number = (unsigned int (*) (LttvIAttribute *self)) |
210 | lttv_attribute_get_number; |
f32847a1 |
211 | |
dc877563 |
212 | klass->named = (gboolean (*) (LttvIAttribute *self, gboolean *homogeneous)) |
213 | lttv_attribute_named; |
f32847a1 |
214 | |
dc877563 |
215 | klass->get = (LttvAttributeType (*) (LttvIAttribute *self, unsigned i, |
216 | LttvAttributeName *name, LttvAttributeValue *v)) lttv_attribute_get; |
f32847a1 |
217 | |
dc877563 |
218 | klass->get_by_name = (LttvAttributeType (*) (LttvIAttribute *self, |
219 | LttvAttributeName name, LttvAttributeValue *v)) |
220 | lttv_attribute_get_by_name; |
f32847a1 |
221 | |
dc877563 |
222 | klass->add = (LttvAttributeValue (*) (LttvIAttribute *self, |
223 | LttvAttributeName name, LttvAttributeType t)) lttv_attribute_add; |
f32847a1 |
224 | |
dc877563 |
225 | klass->remove = (void (*) (LttvIAttribute *self, unsigned i)) |
226 | lttv_attribute_remove; |
f32847a1 |
227 | |
dc877563 |
228 | klass->remove_by_name = (void (*) (LttvIAttribute *self, |
229 | LttvAttributeName name)) lttv_attribute_remove_by_name; |
f32847a1 |
230 | |
dc877563 |
231 | klass->create_subdir = (LttvIAttribute* (*) (LttvIAttribute *self, |
232 | LttvAttributeName name)) lttv_attribute_create_subdir; |
f32847a1 |
233 | } |
234 | |
235 | |
dc877563 |
236 | static guint |
237 | quark_hash(gconstpointer key) |
f32847a1 |
238 | { |
dc877563 |
239 | return (guint)key; |
f32847a1 |
240 | } |
241 | |
242 | |
dc877563 |
243 | static gboolean |
244 | quark_equal(gconstpointer a, gconstpointer b) |
f32847a1 |
245 | { |
dc877563 |
246 | return (a == b) |
f32847a1 |
247 | } |
248 | |
dc877563 |
249 | static void |
250 | attribute_instance_init (GTypeInstance *instance, gpointer g_class) |
f32847a1 |
251 | { |
dc877563 |
252 | LttvAttribute *self = (LttvAttribute *)instance; |
253 | self->names = g_hash_table_new(quark_hash, quark_equal); |
254 | self->attributes = g_array_new(FALSE, FALSE, |
255 | sizeof(Attribute)); |
f32847a1 |
256 | } |
257 | |
f32847a1 |
258 | |
dc877563 |
259 | static void |
260 | attribute_finalize (LttvAttribute *self) |
f32847a1 |
261 | { |
dc877563 |
262 | g_hash_table_free(self->names); |
263 | g_array_free(self->attributes, TRUE); |
264 | G_OBJECT_CLASS(g_type_class_peek_parent(LTTV_ATTRIBUTE_TYPE))->finalize(self); |
f32847a1 |
265 | } |
266 | |
f32847a1 |
267 | |
dc877563 |
268 | static void |
269 | attribute_class_init (LttvAttributeClass *klass) |
f32847a1 |
270 | { |
dc877563 |
271 | GObjectClass *gobject_class = G_OBJECT_CLASS(klass); |
f32847a1 |
272 | |
dc877563 |
273 | gobject_class->finalize = attribute_finalize; |
f32847a1 |
274 | } |
275 | |