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