1 /* EINA - EFL data type library
2 * Copyright (C) 2002-2008 Cedric Bail
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <stdlib.h>
24
25 #include "eina_config.h"
26 #include "eina_private.h"
27
28 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
29 #include "eina_safety_checks.h"
30 #include "eina_iterator.h"
31
32 #include "eina_list.h"
33
34 /*============================================================================*
35 * Local *
36 *============================================================================*/
37
38 /**
39 * @cond LOCAL
40 */
41
42 static const char EINA_MAGIC_ITERATOR_STR[] = "Eina Iterator";
43
44 #define EINA_MAGIC_CHECK_ITERATOR(d) \
45 do { \
46 if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_ITERATOR)) { \
47 EINA_MAGIC_FAIL(d, EINA_MAGIC_ITERATOR); } \
48 } while(0)
49
50 /**
51 * @endcond
52 */
53
54
55 /*============================================================================*
56 * Global *
57 *============================================================================*/
58
59 /**
60 * @internal
61 * @brief Initialize the iterator module.
62 *
63 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
64 *
65 * This function sets up the iterator module of Eina. It is called by
66 * eina_init().
67 *
68 * @see eina_init()
69 */
70 Eina_Bool
eina_iterator_init(void)71 eina_iterator_init(void)
72 {
73 return eina_magic_string_set(EINA_MAGIC_ITERATOR, EINA_MAGIC_ITERATOR_STR);
74 }
75
76 /**
77 * @internal
78 * @brief Shut down the iterator module.
79 *
80 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
81 *
82 * This function shuts down the iterator module set up by
83 * eina_iterator_init(). It is called by eina_shutdown().
84 *
85 * @see eina_shutdown()
86 */
87 Eina_Bool
eina_iterator_shutdown(void)88 eina_iterator_shutdown(void)
89 {
90 return EINA_TRUE;
91 }
92
93 /*============================================================================*
94 * API *
95 *============================================================================*/
96
97 EAPI void
eina_iterator_free(Eina_Iterator * iterator)98 eina_iterator_free(Eina_Iterator *iterator)
99 {
100 if (!iterator)
101 return;
102
103 EINA_MAGIC_CHECK_ITERATOR(iterator);
104 EINA_SAFETY_ON_NULL_RETURN(iterator->free);
105 iterator->free(iterator);
106 }
107
108 EAPI void *
eina_iterator_container_get(Eina_Iterator * iterator)109 eina_iterator_container_get(Eina_Iterator *iterator)
110 {
111 EINA_MAGIC_CHECK_ITERATOR(iterator);
112 EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, NULL);
113 EINA_SAFETY_ON_NULL_RETURN_VAL(iterator->get_container, NULL);
114 return iterator->get_container(iterator);
115 }
116
117 EAPI Eina_Bool
eina_iterator_next(Eina_Iterator * iterator,void ** data)118 eina_iterator_next(Eina_Iterator *iterator, void **data)
119 {
120 if (!iterator)
121 return EINA_FALSE;
122
123 EINA_MAGIC_CHECK_ITERATOR(iterator);
124 EINA_SAFETY_ON_NULL_RETURN_VAL(iterator->next, EINA_FALSE);
125 EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
126 return iterator->next(iterator, data);
127 }
128
129 EAPI void
eina_iterator_foreach(Eina_Iterator * iterator,Eina_Each_Cb cb,const void * fdata)130 eina_iterator_foreach(Eina_Iterator *iterator,
131 Eina_Each_Cb cb,
132 const void *fdata)
133 {
134 const void *container;
135 void *data;
136
137 if (!iterator)
138 return;
139
140 EINA_MAGIC_CHECK_ITERATOR(iterator);
141 EINA_SAFETY_ON_NULL_RETURN(iterator->get_container);
142 EINA_SAFETY_ON_NULL_RETURN(iterator->next);
143 EINA_SAFETY_ON_NULL_RETURN(cb);
144
145 if (!eina_iterator_lock(iterator)) return;
146
147 container = iterator->get_container(iterator);
148 while (iterator->next(iterator, &data) == EINA_TRUE)
149 {
150 if (cb(container, data, (void *)fdata) != EINA_TRUE)
151 goto on_exit;
152 }
153
154 on_exit:
155 (void) eina_iterator_unlock(iterator);
156 }
157
158 EAPI Eina_Bool
eina_iterator_lock(Eina_Iterator * iterator)159 eina_iterator_lock(Eina_Iterator *iterator)
160 {
161 EINA_MAGIC_CHECK_ITERATOR(iterator);
162 EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, EINA_FALSE);
163
164 if (iterator->lock)
165 return iterator->lock(iterator);
166 return EINA_TRUE;
167 }
168
169 EAPI Eina_Bool
eina_iterator_unlock(Eina_Iterator * iterator)170 eina_iterator_unlock(Eina_Iterator *iterator)
171 {
172 EINA_MAGIC_CHECK_ITERATOR(iterator);
173 EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, EINA_FALSE);
174
175 if (iterator->unlock)
176 return iterator->unlock(iterator);
177 return EINA_TRUE;
178 }
179
180 typedef struct _Eina_Iterator_CArray Eina_Iterator_CArray;
181
182 struct _Eina_Iterator_CArray
183 {
184 Eina_Iterator iterator;
185
186 void** array;
187 void** current;
188 };
189
190 static Eina_Bool
eina_carray_iterator_next(Eina_Iterator_CArray * it,void ** data)191 eina_carray_iterator_next(Eina_Iterator_CArray *it, void **data)
192 {
193 if (!it->current || !*it->current)
194 return EINA_FALSE;
195
196 *data = *it->current++;
197
198 return EINA_TRUE;
199 }
200
201 static void**
eina_carray_iterator_get_container(Eina_Iterator_CArray * it)202 eina_carray_iterator_get_container(Eina_Iterator_CArray *it)
203 {
204 return it->array;
205 }
206
207 static void
eina_carray_iterator_free(Eina_Iterator_CArray * it)208 eina_carray_iterator_free(Eina_Iterator_CArray *it)
209 {
210 free(it);
211 }
212
213 EAPI Eina_Iterator*
eina_carray_iterator_new(void ** array)214 eina_carray_iterator_new(void** array)
215 {
216 Eina_Iterator_CArray *it;
217
218 it = calloc(1, sizeof (Eina_Iterator_CArray));
219 if (!it) return NULL;
220
221 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
222
223 it->array = it->current = array;
224
225 it->iterator.version = EINA_ITERATOR_VERSION;
226 it->iterator.next = FUNC_ITERATOR_NEXT(eina_carray_iterator_next);
227 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
228 eina_carray_iterator_get_container);
229 it->iterator.free = FUNC_ITERATOR_FREE(eina_carray_iterator_free);
230
231 return &it->iterator;
232 }
233
234 typedef struct _Eina_Iterator_CArray_Length Eina_Iterator_CArray_Length;
235
236 struct _Eina_Iterator_CArray_Length
237 {
238 Eina_Iterator iterator;
239
240 void** array;
241 uintptr_t current;
242
243 uintptr_t end;
244 unsigned int step;
245 };
246
247 static Eina_Bool
eina_carray_length_iterator_next(Eina_Iterator_CArray_Length * it,void ** data)248 eina_carray_length_iterator_next(Eina_Iterator_CArray_Length *it, void **data)
249 {
250 if (it->current >= it->end)
251 return EINA_FALSE;
252
253 memcpy(data, (void*) it->current, it->step);
254 it->current += it->step;
255
256 return EINA_TRUE;
257 }
258
259 static void**
eina_carray_length_iterator_get_container(Eina_Iterator_CArray_Length * it)260 eina_carray_length_iterator_get_container(Eina_Iterator_CArray_Length *it)
261 {
262 return it->array;
263 }
264
265 static void
eina_carray_length_iterator_free(Eina_Iterator_CArray_Length * it)266 eina_carray_length_iterator_free(Eina_Iterator_CArray_Length *it)
267 {
268 free(it);
269 }
270
271 EAPI Eina_Iterator *
eina_carray_length_iterator_new(void ** array,unsigned int step,unsigned int length)272 eina_carray_length_iterator_new(void** array, unsigned int step, unsigned int length)
273 {
274 Eina_Iterator_CArray_Length *it;
275
276 it = calloc(1, sizeof (Eina_Iterator_CArray_Length));
277 if (!it) return NULL;
278
279 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
280
281 it->array = array;
282 it->current = (uintptr_t) it->array;
283 it->end = it->current + length * step;
284 it->step = step;
285
286 it->iterator.version = EINA_ITERATOR_VERSION;
287 it->iterator.next = FUNC_ITERATOR_NEXT(eina_carray_length_iterator_next);
288 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
289 eina_carray_length_iterator_get_container);
290 it->iterator.free = FUNC_ITERATOR_FREE(eina_carray_length_iterator_free);
291
292 return &it->iterator;
293 }
294
295 typedef struct _Eina_Iterator_Multi Eina_Multi_Iterator;
296
297 struct _Eina_Iterator_Multi
298 {
299 Eina_Iterator iterator;
300
301 Eina_List *iterators;
302 };
303
304 static Eina_Bool
eina_multi_iterator_next(Eina_Multi_Iterator * it,void ** data)305 eina_multi_iterator_next(Eina_Multi_Iterator *it, void **data)
306 {
307 if (!it->iterators)
308 return EINA_FALSE;
309
310 // Search for an iterator that do have some data
311 while (!eina_iterator_next(eina_list_data_get(it->iterators), data))
312 {
313 eina_iterator_free(eina_list_data_get(it->iterators));
314 it->iterators = eina_list_remove_list(it->iterators, it->iterators);
315
316 if (!it->iterators) return EINA_FALSE;
317 }
318
319 return EINA_TRUE;
320 }
321
322 static void**
eina_multi_iterator_get_container(Eina_Multi_Iterator * it)323 eina_multi_iterator_get_container(Eina_Multi_Iterator *it)
324 {
325 if (!it->iterators) return NULL;
326 return eina_iterator_container_get(eina_list_data_get(it->iterators));
327 }
328
329 static void
eina_multi_iterator_free(Eina_Multi_Iterator * it)330 eina_multi_iterator_free(Eina_Multi_Iterator *it)
331 {
332 Eina_Iterator *itc;
333
334 EINA_LIST_FREE(it->iterators, itc)
335 eina_iterator_free(itc);
336 free(it);
337 }
338
339 EAPI Eina_Iterator *
eina_multi_iterator_internal_new(Eina_Iterator * itc,...)340 eina_multi_iterator_internal_new(Eina_Iterator *itc, ...)
341 {
342 Eina_Multi_Iterator *it;
343 va_list args;
344
345 it = calloc(1, sizeof (Eina_Multi_Iterator));
346 if (!it) return NULL;
347
348 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
349
350 it->iterators = eina_list_append(it->iterators, itc);
351
352 va_start(args, itc);
353
354 while ((itc = (Eina_Iterator *) va_arg(args, Eina_Iterator *)))
355 {
356 it->iterators = eina_list_append(it->iterators, itc);
357 }
358
359 va_end(args);
360
361 it->iterator.version = EINA_ITERATOR_VERSION;
362 it->iterator.next = FUNC_ITERATOR_NEXT(eina_multi_iterator_next);
363 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
364 eina_multi_iterator_get_container);
365 it->iterator.free = FUNC_ITERATOR_FREE(eina_multi_iterator_free);
366
367 return &it->iterator;
368 }
369
370 typedef struct {
371 Eina_Iterator iterator;
372
373 void *data;
374 Eina_Iterator *original;
375 Eina_Each_Cb cb;
376 Eina_Free_Cb free;
377 } Eina_Iterator_Filter;
378
379 static Eina_Bool
eina_iterator_filter_next(Eina_Iterator_Filter * it,void ** data)380 eina_iterator_filter_next(Eina_Iterator_Filter *it, void **data)
381 {
382 do
383 {
384 if (!eina_iterator_next(it->original , data))
385 return EINA_FALSE;
386 }
387 while (!it->cb(it->original, *data, it->data));
388
389 return EINA_TRUE;
390 }
391
392 static void*
eina_iterator_filter_get_container(Eina_Iterator_Filter * it)393 eina_iterator_filter_get_container(Eina_Iterator_Filter *it)
394 {
395 return it->original;
396 }
397
398 static void
eina_iterator_filter_free(Eina_Iterator_Filter * it)399 eina_iterator_filter_free(Eina_Iterator_Filter *it)
400 {
401 if (it->free)
402 it->free(it->data);
403 eina_iterator_free(it->original);
404 free(it);
405 }
406
407 EAPI Eina_Iterator*
eina_iterator_filter_new(Eina_Iterator * iterator,Eina_Each_Cb filter,Eina_Free_Cb free_cb,void * data)408 eina_iterator_filter_new(Eina_Iterator *iterator, Eina_Each_Cb filter, Eina_Free_Cb free_cb, void *data)
409 {
410 Eina_Iterator_Filter *it;
411
412 EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, NULL);
413 EINA_SAFETY_ON_NULL_RETURN_VAL(filter, NULL);
414
415 it = calloc(1, sizeof(Eina_Iterator_Filter));
416
417 it->original = iterator;
418 it->data = data;
419 it->cb = filter;
420 it->free = free_cb;
421
422 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
423
424 it->iterator.version = EINA_ITERATOR_VERSION;
425 it->iterator.next = FUNC_ITERATOR_NEXT(eina_iterator_filter_next);
426 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
427 eina_iterator_filter_get_container);
428 it->iterator.free = FUNC_ITERATOR_FREE(eina_iterator_filter_free);
429
430 return &it->iterator;
431 }
432
433 typedef struct {
434 Eina_Iterator iterator;
435
436 void *data;
437 Eina_Iterator *original;
438 Eina_Process_Cb cb;
439 Eina_Free_Cb free;
440 } Eina_Iterator_Processor;
441
442 static Eina_Bool
eina_iterator_process_next(Eina_Iterator_Processor * it,void ** data)443 eina_iterator_process_next(Eina_Iterator_Processor *it, void **data)
444 {
445 if (!eina_iterator_next(it->original, data))
446 return EINA_FALSE;
447
448 *data = it->cb(it->original, *data, it->data);
449
450 return EINA_TRUE;
451 }
452
453 static void*
eina_iterator_process_get_container(Eina_Iterator_Processor * it)454 eina_iterator_process_get_container(Eina_Iterator_Processor *it)
455 {
456 return it->original;
457 }
458
459 static void
eina_iterator_process_free(Eina_Iterator_Processor * it)460 eina_iterator_process_free(Eina_Iterator_Processor *it)
461 {
462 if (it->free)
463 it->free(it->data);
464 eina_iterator_free(it->original);
465 free(it);
466 }
467
468 EAPI Eina_Iterator*
eina_iterator_processed_new(Eina_Iterator * iterator,Eina_Process_Cb process,Eina_Free_Cb free_cb,void * data)469 eina_iterator_processed_new(Eina_Iterator *iterator, Eina_Process_Cb process, Eina_Free_Cb free_cb, void *data)
470 {
471 Eina_Iterator_Processor *it;
472
473 EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, NULL);
474 EINA_SAFETY_ON_NULL_RETURN_VAL(process, NULL);
475
476 it = calloc(1, sizeof(Eina_Iterator_Processor));
477 it->data = data;
478 it->cb = process;
479 it->free = free_cb;
480 it->original = iterator;
481
482 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
483
484 it->iterator.version = EINA_ITERATOR_VERSION;
485 it->iterator.next = FUNC_ITERATOR_NEXT(eina_iterator_process_next);
486 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(eina_iterator_process_get_container);
487 it->iterator.free = FUNC_ITERATOR_FREE(eina_iterator_process_free);
488
489 return &it->iterator;
490 }
491