fcdf0ec2 |
1 | #include <lttv/attribute.h> |
f32847a1 |
2 | |
3 | inline lttv_string_id lttv_string_id_from_string(const char *s) { |
4 | return g_quark_from_string(s); |
5 | } |
6 | |
7 | |
8 | inline void lttv_string_id_release(lttv_string_id i) {} |
9 | |
10 | |
11 | inline const char *lttv_string_id_to_string(lttv_string_id i) { |
12 | return g_quark_to_string(i); |
13 | } |
14 | |
15 | |
16 | inline lttv_key *lttv_key_new() { |
17 | return g_array_new(FALSE, FALSE, sizeof(lttv_string_id)); |
18 | } |
19 | |
20 | /* Changed this function to destroy the element also, caused memory leak? */ |
21 | /* Mathieu Desnoyers */ |
22 | inline void lttv_key_destroy(lttv_key *k) { |
23 | g_array_free(k, TRUE); |
24 | } |
25 | |
26 | |
27 | #define _lttv_key_index(k,i) g_array_index(k, lttv_string_id, i) |
28 | |
29 | |
30 | inline void lttv_key_append(lttv_key *k, lttv_string_id i) { |
31 | g_array_append_val(k,i); |
32 | } |
33 | |
34 | |
35 | inline unsigned int lttv_key_component_number(lttv_key *k) { |
36 | return k->len; |
37 | } |
38 | |
39 | |
40 | lttv_key *lttv_key_copy(lttv_key *k) { |
41 | lttv_key *nk; |
42 | int i; |
43 | |
44 | nk = lttv_key_new(); |
45 | for(i = 0 ; i < k->len ; i++) lttv_key_append(nk,lttv_key_index(k,i)); |
46 | return nk; |
47 | } |
48 | |
49 | /* It is also possible to create a key directly from a pathname, |
50 | key components separated by /, (e.g., "/hooks/options/before"). */ |
51 | |
52 | lttv_key *lttv_key_new_pathname(const char *p) { |
53 | char **v, **cursor; |
54 | lttv_key *k; |
55 | |
56 | v = cursor = g_strsplit(p, "/", -1); |
57 | k = lttv_key_new(); |
58 | |
59 | while(*cursor != NULL) { |
60 | lttv_key_append(k, lttv_string_id_from_string(*cursor)); |
61 | cursor++; |
62 | } |
63 | g_strfreev(v); |
64 | return k; |
65 | } |
66 | |
67 | static guint lttv_key_hash(gconstpointer key) { |
68 | lttv_key * k = (lttv_key *)key; |
69 | guint h = 0; |
70 | int i; |
71 | for(i = 0 ; i < k->len ; i++) h = h ^ lttv_key_index(k,i); |
72 | return h; |
73 | } |
74 | |
75 | static gboolean lttv_key_equal(gconstpointer key1,gconstpointer key2) { |
76 | lttv_key * k1 = (lttv_key *)key1; |
77 | lttv_key * k2 = (lttv_key *)key2; |
78 | int i; |
79 | |
80 | if(k1->len != k2->len) return FALSE; |
81 | for(i = 0 ; i < k1->len ; i++) |
82 | if(lttv_key_index(k1,i) != lttv_key_index(k2,i)) return FALSE; |
83 | return TRUE; |
84 | } |
85 | |
86 | |
87 | static void lttv_key_free(gpointer data) |
88 | { |
89 | lttv_key_destroy((lttv_key *)data); |
90 | } |
91 | |
92 | |
93 | static void lttv_attribute_value_free(gpointer data) |
94 | { |
95 | g_free(data); |
96 | } |
97 | |
98 | |
99 | lttv_attributes *lttv_attributes_new() { |
100 | lttv_attributes *a; |
101 | |
102 | a = g_new(lttv_attributes, 1); |
103 | a->ints = g_hash_table_new_full(lttv_key_hash, lttv_key_equal, |
104 | lttv_key_free, lttv_attribute_value_free); |
105 | a->times = g_hash_table_new_full(lttv_key_hash, lttv_key_equal, |
106 | lttv_key_free, lttv_attribute_value_free); |
107 | a->doubles = g_hash_table_new_full(lttv_key_hash, lttv_key_equal, |
108 | lttv_key_free, lttv_attribute_value_free); |
109 | a->pointers = g_hash_table_new(lttv_key_hash, lttv_key_equal); |
110 | |
111 | return a; |
112 | } |
113 | |
114 | |
115 | /* Free the hash table containing the stats and all the contained keys/vals */ |
116 | |
117 | static void lttv_attribute_key_free(gpointer k, gpointer v, gpointer data) { |
118 | lttv_key_free(k); |
119 | } |
120 | |
121 | |
122 | void lttv_attributes_destroy(lttv_attributes *a) { |
123 | g_hash_table_destroy(a->ints); |
124 | g_hash_table_destroy(a->times); |
125 | g_hash_table_destroy(a->doubles); |
126 | |
127 | g_hash_table_foreach(a->pointers, lttv_attribute_key_free, NULL); |
128 | g_hash_table_destroy(a->pointers); |
129 | g_free(a); |
130 | } |
131 | |
132 | unsigned int lttv_attributes_number(lttv_attributes *a) { |
133 | return g_hash_table_size(a->ints) + g_hash_table_size(a->times) + |
134 | g_hash_table_size(a->doubles) + g_hash_table_size(a->pointers); |
135 | } |
136 | |
137 | |
138 | /* If it is a new entry, insert it in the hash table, and set it to 0 */ |
139 | |
140 | int *lttv_attributes_get_integer(lttv_attributes *a, lttv_key *k) |
141 | { |
142 | gpointer found; |
143 | |
144 | found = g_hash_table_lookup(a->ints, k); |
145 | if(found == NULL) { |
146 | found = g_new(gint, 1); |
147 | *(gint *)found = 0; |
148 | g_hash_table_insert(a->ints, lttv_key_copy(k), found); |
149 | } |
150 | return found; |
151 | } |
152 | |
153 | |
154 | lttv_time *lttv_attributes_get_time(lttv_attributes *a, lttv_key *k) |
155 | { |
156 | gpointer found; |
157 | |
158 | found = g_hash_table_lookup(a->times, k); |
159 | if(found == NULL) { |
160 | found = g_new0(lttv_time, 1); |
161 | /* *(lttv_time *)found = ZeroTime; */ |
162 | g_hash_table_insert(a->times, lttv_key_copy(k), found); |
163 | } |
164 | return found; |
165 | } |
166 | |
167 | double *lttv_attributes_get_double(lttv_attributes *a, lttv_key *k) |
168 | { |
169 | gpointer found; |
170 | |
171 | found = g_hash_table_lookup(a->doubles,k); |
172 | if(found == NULL) { |
173 | found = g_new(double,1); |
174 | *(double *)found = 0; |
175 | g_hash_table_insert(a->doubles, lttv_key_copy(k),found); |
176 | } |
177 | return found; |
178 | } |
179 | |
180 | void *lttv_attributes_get_pointer_pathname(lttv_attributes *a, char *pn) |
181 | { |
182 | lttv_key *key; |
183 | void *p; |
184 | |
185 | key = lttv_key_new_pathname(pn); |
186 | p = lttv_attributes_get_pointer(a, key); |
187 | lttv_key_destroy(key); |
188 | |
189 | return p; |
190 | } |
191 | |
192 | void *lttv_attributes_get_pointer(lttv_attributes *a, lttv_key *k) |
193 | { |
194 | return g_hash_table_lookup(a->pointers,k); |
195 | } |
196 | |
197 | void lttv_attributes_set_pointer_pathname(lttv_attributes *a,char *pn,void *p) |
198 | { |
199 | lttv_key *key = lttv_key_new_pathname(pn); |
200 | |
201 | lttv_attributes_set_pointer(a, key, p); |
202 | lttv_key_destroy(key); |
203 | } |
204 | |
205 | void lttv_attributes_set_pointer(lttv_attributes *a, lttv_key *k, void *p) { |
206 | lttv_key * oldk; |
207 | void *oldv; |
208 | |
209 | if(g_hash_table_lookup_extended(a->pointers, k, (gpointer)oldk, &oldv)) { |
210 | if(p == NULL) { |
211 | g_hash_table_remove(a->pointers,k); |
212 | } |
213 | else { |
214 | g_hash_table_insert(a->pointers,oldk,p); |
215 | } |
216 | } |
217 | else { |
218 | if(p == NULL) return; |
219 | g_hash_table_insert(a->pointers,lttv_key_copy(k),p); |
220 | } |
221 | } |
222 | |
223 | |
c27d48bb |
224 | #ifdef EXT_ATTRIBS |
f32847a1 |
225 | /* Sometimes the attributes must be accessed in bulk, sorted in different |
226 | ways. For this purpose they may be converted to arrays and sorted |
227 | multiple times. The keys used in the array belong to the lttv_attributes |
228 | object from which the array was obtained and are freed when it is |
229 | destroyed. Each element in the array is an lttv_attribute, a structure |
230 | containing the key, the value type, and a union containing a value of |
231 | that type. Multiple attributes with equal keys may be possible in some |
232 | implementations if their type differs. */ |
233 | |
234 | |
235 | typedef struct _lttv_attribute_fill_position { |
236 | unsigned i; |
237 | lttv_attribute_type t; |
238 | lttv_attribute *a; |
239 | } lttv_attribute_fill_position; |
240 | |
241 | |
242 | static void lttv_attribute_fill(void *key, void *value, void *user_data) { |
243 | lttv_attribute_fill_position * p = (lttv_attribute_fill_position *)user_data; |
244 | lttv_attribute *a = p->a + p->i; |
245 | |
246 | a->key = (lttv_key *)key; |
247 | a->t = p->t; |
248 | switch(p->t) { |
249 | case LTTV_INTEGER: |
250 | a->v.i = *((int *)value); |
251 | case LTTV_TIME: |
252 | a->v.t = *((lttv_time *)value); |
253 | case LTTV_DOUBLE: |
254 | a->v.d = *((double *)value); |
255 | case LTTV_POINTER: |
256 | a->v.p = value; |
257 | } |
258 | p->i++; |
259 | } |
260 | |
261 | |
262 | lttv_attribute *lttv_attributes_array_get(lttv_attributes *a) { |
263 | unsigned size; |
264 | lttv_attribute *v; |
265 | lttv_attribute_fill_position p; |
266 | |
267 | size = lttv_attributes_number(a); |
268 | v = g_new(lttv_attribute,size); |
269 | |
270 | p.a = v; |
271 | p.i = 0; |
272 | p.t = LTTV_INTEGER; |
273 | g_hash_table_foreach(a->ints, lttv_attribute_fill, &p); |
274 | p.t = LTTV_TIME; |
275 | g_hash_table_foreach(a->times, lttv_attribute_fill, &p); |
276 | p.t = LTTV_DOUBLE; |
277 | g_hash_table_foreach(a->doubles, lttv_attribute_fill, &p); |
278 | p.t = LTTV_POINTER; |
279 | g_hash_table_foreach(a->pointers, lttv_attribute_fill, &p); |
280 | return v; |
281 | } |
282 | |
283 | |
284 | lttv_attribute *lttv_attribute_array_destroy(lttv_attribute *a) { |
285 | g_free(a); |
286 | } |
287 | |
288 | |
289 | void lttv_attribute_array_sort(lttv_attribute *a, |
290 | unsigned size, lttv_key_compare f, |
291 | void *compare_data) |
292 | { |
293 | |
294 | g_qsort_with_data(a, size, sizeof(lttv_attribute), f, |
295 | compare_data); |
296 | } |
297 | |
298 | |
299 | int lttv_key_compare_priority(lttv_key *a, lttv_key *b, void *compare_data) |
300 | { |
301 | int i, res; |
302 | int *priority = (int *)compare_data; |
303 | |
304 | g_assert(a->len == b->len); |
305 | |
306 | for(i = 0 ; i < a->len ; i++) |
307 | { |
308 | res = strcmp(lttv_string_id_to_string(lttv_key_index(a,priority[i])), |
309 | lttv_string_id_to_string(lttv_key_index(a,priority[i]))); |
310 | if(res != 0) return res; |
311 | } |
312 | return 0; |
313 | } |
314 | |
f32847a1 |
315 | typedef struct _select_data { |
316 | lttv_attributes *a; |
317 | lttv_key *k; |
318 | void *user_data; |
319 | lttv_key_select select; |
320 | } select_data; |
321 | |
322 | static void select_integer(void *key, void *value, void *user_data); |
323 | static void select_double(void *key, void *value, void *user_data); |
324 | static void select_time(void *key, void *value, void *user_data); |
325 | static void select_pointer(void *key, void *value, void *user_data); |
326 | |
327 | lttv_attributes *lttv_attributes_select(lttv_attributes *a, lttv_key_select f, |
328 | void *user_data) |
329 | { |
330 | select_data *d; |
331 | |
332 | d = g_new(select_data, 1); |
333 | d->a = lttv_attributes_new(); |
334 | d->k = lttv_key_new(); |
335 | d->user_data = user_data; |
336 | d->select = f; |
337 | |
338 | g_hash_table_foreach(a->ints,select_integer, d); |
339 | g_hash_table_foreach(a->doubles,select_double, d); |
340 | g_hash_table_foreach(a->times,select_time, d); |
341 | g_hash_table_foreach(a->pointers,select_pointer, d); |
342 | } |
343 | |
344 | int lttv_key_select_spec(lttv_key *in, lttv_key *out, void *user_data) |
345 | { |
346 | lttv_key_select_spec_data *d = (lttv_key_select_spec_data *)user_data; |
347 | int i; |
348 | |
349 | /* not defined yet */ |
350 | /* lttv_key_set_size(out, 0); */ |
351 | |
352 | for(i = 0 ; i < d->length ; i++) { |
353 | switch(d->spec[i]) { |
354 | case LTTV_KEEP: |
355 | break; |
356 | |
357 | case LTTV_KEEP_EQUAL: |
358 | break; |
359 | |
360 | case LTTV_KEEP_SMALLER: |
361 | break; |
362 | |
363 | case LTTV_KEEP_GREATER: |
364 | break; |
365 | |
366 | case LTTV_IGNORE: |
367 | break; |
368 | |
369 | } |
370 | } |
371 | |
372 | return 1; |
373 | } |
374 | |
375 | static void select_integer(void *key, void *value, void *user_data) |
376 | { |
377 | lttv_key *k = (lttv_key *)key; |
378 | int *pi = (int *)value; |
379 | select_data *d = (select_data *)user_data; |
380 | |
381 | if(d->select(k,d->k,d->user_data)) { |
382 | *(lttv_attributes_get_integer(d->a,d->k)) += *pi; |
383 | } |
384 | } |
385 | |
386 | static void select_double(void *key, void *value, void *user_data) |
387 | { |
388 | lttv_key *k = (lttv_key *)key; |
389 | double *pf = (double *)value; |
390 | select_data *d = (select_data *)user_data; |
391 | |
392 | if(d->select(k,d->k,d->user_data)) { |
393 | *(lttv_attributes_get_double(d->a,d->k)) += *pf; |
394 | } |
395 | } |
396 | |
397 | static void select_time(void *key, void *value, void *user_data) |
398 | { |
399 | lttv_key *k = (lttv_key *)key; |
400 | lttv_time *ptSum, *pt = (lttv_time *)value; |
401 | select_data *d = (select_data *)user_data; |
402 | |
403 | if(d->select(k,d->k,d->user_data)) { |
404 | ptSum = lttv_attributes_get_time(d->a,d->k); |
405 | ptSum->tv_sec += pt->tv_sec; |
406 | ptSum->tv_nsec += pt->tv_nsec; |
407 | } |
408 | } |
409 | |
410 | static void select_pointer(void *key, void *value, void *user_data) |
411 | { |
412 | lttv_key *k = (lttv_key *)key; |
413 | select_data *d = (select_data *)user_data; |
414 | |
415 | if(d->select(k,d->k,d->user_data)) { |
416 | lttv_attributes_set_pointer(d->a,d->k,value); |
417 | } |
418 | } |
419 | |
420 | |
421 | |
422 | |
423 | |
c27d48bb |
424 | #endif // EXT_ATTRIBS |