1 /* EINA - EFL data type library
2 * Copyright (C) 2012 - ProFUSION embedded systems
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.
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.
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/>.
26 #include "eina_config.h"
27 #include "eina_private.h"
28 #include "eina_error.h"
31 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
32 #include "eina_safety_checks.h"
33 #include "eina_inarray.h"
35 /*============================================================================*
37 *============================================================================*/
43 static const char EINA_MAGIC_INARRAY_STR[] = "Eina Inline Array";
44 static const char EINA_MAGIC_INARRAY_ITERATOR_STR[] = "Eina Inline Array Iterator";
45 static const char EINA_MAGIC_INARRAY_ACCESSOR_STR[] = "Eina Inline Array Accessor";
47 typedef struct _Eina_Iterator_Inarray Eina_Iterator_Inarray;
48 typedef struct _Eina_Accessor_Inarray Eina_Accessor_Inarray;
50 struct _Eina_Iterator_Inarray
52 Eina_Iterator iterator;
53 const Eina_Inarray *array;
58 struct _Eina_Accessor_Inarray
60 Eina_Accessor accessor;
61 const Eina_Inarray *array;
65 static int _eina_inarray_log_dom = -1;
70 #define ERR(...) EINA_LOG_DOM_ERR(_eina_inarray_log_dom, __VA_ARGS__)
75 #define DBG(...) EINA_LOG_DOM_DBG(_eina_inarray_log_dom, __VA_ARGS__)
77 #define EINA_MAGIC_CHECK_INARRAY(d, ...) \
80 if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_INARRAY)) \
82 EINA_MAGIC_FAIL(d, EINA_MAGIC_INARRAY); \
89 #define EINA_MAGIC_CHECK_INARRAY_ITERATOR(d, ...) \
92 if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_INARRAY_ITERATOR)) \
94 EINA_MAGIC_FAIL(d, EINA_MAGIC_INARRAY_ITERATOR); \
101 #define EINA_MAGIC_CHECK_INARRAY_ACCESSOR(d, ...) \
104 if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_INARRAY_ACCESSOR)) \
106 EINA_MAGIC_FAIL(d, EINA_MAGIC_INARRAY_ACCESSOR); \
107 return __VA_ARGS__; \
114 _eina_inarray_setup(Eina_Inarray *array, unsigned int member_size, unsigned int step)
116 EINA_MAGIC_SET(array, EINA_MAGIC_INARRAY);
117 array->version = EINA_ARRAY_VERSION;
118 array->member_size = member_size;
121 array->step = (step > 0) ? step : 32;
122 array->members = NULL;
126 _eina_inarray_resize(Eina_Inarray *array, unsigned int new_size)
128 unsigned int new_max;
131 if (new_size < array->max) /* don't change this behaviour as eina_inarray_pop rely on it */
134 if (new_size % array->step == 0)
137 new_max = ((new_size / array->step) + 1) * array->step;
139 tmp = realloc(array->members, new_max * array->member_size);
140 if ((!tmp) && (new_max > 0))
142 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
146 array->members = tmp;
147 array->max = new_max;
152 _eina_inarray_get(const Eina_Inarray *array, unsigned int position)
154 unsigned int offset = position * array->member_size;
155 return (unsigned char *)array->members + offset;
159 _eina_inarray_search(const Eina_Inarray *array, const void *data, Eina_Compare_Cb compare)
161 const unsigned char *start, *found;
162 start = array->members;
163 found = bsearch(data, start, array->len, array->member_size, compare);
166 return (found - start) / array->member_size;
170 _eina_inarray_search_sorted_near(const Eina_Inarray *array, const void *data, Eina_Compare_Cb compare, int *cmp)
172 unsigned int start, last, middle;
179 else if (array->len == 1)
181 *cmp = compare(data, array->members);
186 last = array->len - 1; /* inclusive */
190 middle = start + (last - start) / 2; /* avoid overflow */
191 p = _eina_inarray_get(array, middle);
192 *cmp = compare(data, p);
202 while (start <= last);
208 _eina_inarray_iterator_next(Eina_Iterator_Inarray *it, void **data)
210 EINA_MAGIC_CHECK_INARRAY_ITERATOR(it, EINA_FALSE);
212 if (it->pos >= it->array->len)
215 *data = _eina_inarray_get(it->array, it->pos);
222 _eina_inarray_iterator_prev(Eina_Iterator_Inarray *it, void **data)
224 EINA_MAGIC_CHECK_INARRAY_ITERATOR(it, EINA_FALSE);
230 *data = _eina_inarray_get(it->array, it->pos);
235 static Eina_Inarray *
236 _eina_inarray_iterator_get_container(Eina_Iterator_Inarray *it)
238 EINA_MAGIC_CHECK_INARRAY_ITERATOR(it, NULL);
239 return (Eina_Inarray *)it->array;
243 _eina_inarray_iterator_free(Eina_Iterator_Inarray *it)
245 EINA_MAGIC_CHECK_INARRAY_ITERATOR(it);
250 _eina_inarray_accessor_get_at(Eina_Accessor_Inarray *it, unsigned int pos, void **data)
252 EINA_MAGIC_CHECK_INARRAY_ACCESSOR(it, EINA_FALSE);
254 if (pos >= it->array->len)
257 *data = _eina_inarray_get(it->array, pos);
261 static Eina_Inarray *
262 _eina_inarray_accessor_get_container(Eina_Accessor_Inarray *it)
264 EINA_MAGIC_CHECK_INARRAY_ACCESSOR(it, NULL);
265 return (Eina_Inarray *)it->array;
269 _eina_inarray_accessor_free(Eina_Accessor_Inarray *it)
271 EINA_MAGIC_CHECK_INARRAY_ACCESSOR(it);
280 /*============================================================================*
282 *============================================================================*/
286 * @brief Initialize the inline array module.
288 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
290 * This function sets up the inline array module of Eina. It is called
296 eina_inarray_init(void)
298 _eina_inarray_log_dom = eina_log_domain_register("eina_inarray",
299 EINA_LOG_COLOR_DEFAULT);
300 if (_eina_inarray_log_dom < 0)
302 EINA_LOG_ERR("Could not register log domain: eina_inarray");
306 #define EMS(n) eina_magic_string_static_set(n, n ## _STR)
307 EMS(EINA_MAGIC_INARRAY);
308 EMS(EINA_MAGIC_INARRAY_ITERATOR);
309 EMS(EINA_MAGIC_INARRAY_ACCESSOR);
317 * @brief Shut down the inline array module.
319 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
321 * This function shuts down the inline array module set up by
322 * eina_inarray_init(). It is called by eina_shutdown().
324 * @see eina_shutdown()
327 eina_inarray_shutdown(void)
329 eina_log_domain_unregister(_eina_inarray_log_dom);
330 _eina_inarray_log_dom = -1;
334 /*============================================================================*
336 *============================================================================*/
338 eina_inarray_new(unsigned int member_size, unsigned int step)
342 EINA_SAFETY_ON_TRUE_RETURN_VAL(member_size == 0, NULL);
344 ret = malloc(sizeof(*ret));
347 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
351 _eina_inarray_setup(ret, member_size, step);
356 eina_inarray_free(Eina_Inarray *array)
361 EINA_MAGIC_CHECK_INARRAY(array);
362 free(array->members);
367 eina_inarray_step_set(Eina_Inarray *array,
368 unsigned int sizeof_eina_inarray,
369 unsigned int member_size,
372 EINA_SAFETY_ON_NULL_RETURN(array);
373 EINA_SAFETY_ON_TRUE_RETURN(member_size == 0);
375 if (sizeof (Eina_Inarray) != sizeof_eina_inarray)
377 ERR("Unknow Eina_Inarray size ! Got %i, expected %i\n",
379 (int) sizeof (Eina_Inarray));
380 /* Force memory to zero to provide a small layer of security */
381 memset(array, 0, sizeof_eina_inarray);
385 _eina_inarray_setup(array, member_size, step);
389 eina_inarray_flush(Eina_Inarray *array)
391 EINA_MAGIC_CHECK_INARRAY(array);
392 free(array->members);
395 array->members = NULL;
399 eina_inarray_push(Eina_Inarray *array, const void *data)
403 EINA_MAGIC_CHECK_INARRAY(array, -1);
404 EINA_SAFETY_ON_NULL_RETURN_VAL(data, -1);
406 if (!_eina_inarray_resize(array, array->len + 1))
409 p = _eina_inarray_get(array, array->len);
410 memcpy(p, data, array->member_size);
413 return array->len - 1;
417 eina_inarray_insert(Eina_Inarray *array, const void *data, Eina_Compare_Cb compare)
419 const unsigned char *itr, *itr_end;
422 EINA_MAGIC_CHECK_INARRAY(array, -1);
423 EINA_SAFETY_ON_NULL_RETURN_VAL(data, -1);
424 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, -1);
426 sz = array->member_size;
427 itr = array->members;
428 itr_end = itr + array->len * sz;
429 for (; itr < itr_end; itr += sz)
431 unsigned int offset, position;
432 int cmp = compare(itr, data);
436 offset = itr - (unsigned char *)array->members;
437 position = offset / sz;
438 if (!eina_inarray_insert_at(array, position, data))
442 return eina_inarray_push(array, data);
446 eina_inarray_insert_sorted(Eina_Inarray *array, const void *data, Eina_Compare_Cb compare)
451 EINA_MAGIC_CHECK_INARRAY(array, -1);
452 EINA_SAFETY_ON_NULL_RETURN_VAL(data, -1);
453 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, -1);
455 pos = _eina_inarray_search_sorted_near(array, data, compare, &cmp);
459 if (!eina_inarray_insert_at(array, pos, data))
465 eina_inarray_remove(Eina_Inarray *array, const void *data)
467 const unsigned char *itr, *itr_end;
468 unsigned int position, sz;
470 EINA_MAGIC_CHECK_INARRAY(array, -1);
471 EINA_SAFETY_ON_NULL_RETURN_VAL(data, -1);
473 sz = array->member_size;
474 if ((data >= array->members) &&
475 (data < _eina_inarray_get(array, array->len)))
477 unsigned int offset = ((unsigned char *)data -
478 (unsigned char *)array->members);
479 position = offset / sz;
483 itr = array->members;
484 itr_end = itr + array->len * sz;
485 for (; itr < itr_end; itr += sz)
487 if (memcmp(data, itr, sz) == 0)
489 unsigned int offset = itr - (unsigned char *)array->members;
490 position = offset / sz;
497 if (!eina_inarray_remove_at(array, position))
503 eina_inarray_pop(Eina_Inarray *array)
505 EINA_MAGIC_CHECK_INARRAY(array, NULL);
506 EINA_SAFETY_ON_TRUE_RETURN_VAL(array->len == 0, NULL);
507 if (!_eina_inarray_resize(array, array->len - 1))
510 return _eina_inarray_get(array, array->len + 1);
514 eina_inarray_nth(const Eina_Inarray *array, unsigned int position)
516 EINA_MAGIC_CHECK_INARRAY(array, NULL);
517 EINA_SAFETY_ON_TRUE_RETURN_VAL(position >= array->len, NULL);
518 return _eina_inarray_get(array, position);
522 eina_inarray_insert_at(Eina_Inarray *array, unsigned int position, const void *data)
527 EINA_MAGIC_CHECK_INARRAY(array, EINA_FALSE);
528 EINA_SAFETY_ON_TRUE_RETURN_VAL(position > array->len, EINA_FALSE);
530 if (!_eina_inarray_resize(array, array->len + 1))
533 p = _eina_inarray_get(array, position);
534 sz = array->member_size;
535 if (array->len > position)
536 memmove(p + sz, p, (array->len - position) * sz);
544 eina_inarray_alloc_at(Eina_Inarray *array, unsigned int position, unsigned int member_count)
549 EINA_MAGIC_CHECK_INARRAY(array, NULL);
550 EINA_SAFETY_ON_TRUE_RETURN_VAL(position > array->len, NULL);
551 EINA_SAFETY_ON_TRUE_RETURN_VAL(member_count == 0, NULL);
553 if (!_eina_inarray_resize(array, array->len + member_count))
556 p = _eina_inarray_get(array, position);
557 sz = array->member_size;
558 if (array->len > position)
559 memmove(p + member_count * sz, p, (array->len - position) * sz);
561 array->len += member_count;
566 eina_inarray_replace_at(Eina_Inarray *array, unsigned int position, const void *data)
570 EINA_MAGIC_CHECK_INARRAY(array, EINA_FALSE);
571 EINA_SAFETY_ON_TRUE_RETURN_VAL(position >= array->len, EINA_FALSE);
573 p = _eina_inarray_get(array, position);
574 memcpy(p, data, array->member_size);
580 eina_inarray_remove_at(Eina_Inarray *array, unsigned int position)
582 EINA_MAGIC_CHECK_INARRAY(array, EINA_FALSE);
583 EINA_SAFETY_ON_TRUE_RETURN_VAL(position >= array->len, EINA_FALSE);
585 if (position + 1 < array->len)
587 unsigned int sz = array->member_size;
588 unsigned char *p = _eina_inarray_get(array, position);
589 memmove(p, p + sz, (array->len - position - 1) * sz);
592 _eina_inarray_resize(array, array->len - 1);
598 eina_inarray_reverse(Eina_Inarray *array)
601 unsigned char *fwd, *rev, *fwd_end;
604 EINA_MAGIC_CHECK_INARRAY(array);
609 sz = array->member_size;
612 EINA_SAFETY_ON_NULL_RETURN(tmp);
614 fwd = array->members;
615 fwd_end = fwd + (array->len / 2) * sz;
617 rev = fwd + (array->len - 1) * sz;
619 for (; fwd < fwd_end; fwd += sz, rev -= sz)
621 memcpy(tmp, fwd, sz);
622 memcpy(fwd, rev, sz);
623 memcpy(rev, tmp, sz);
628 eina_inarray_sort(Eina_Inarray *array, Eina_Compare_Cb compare)
630 EINA_MAGIC_CHECK_INARRAY(array);
631 EINA_SAFETY_ON_NULL_RETURN(compare);
632 qsort(array->members, array->len, array->member_size, compare);
636 eina_inarray_search(const Eina_Inarray *array, const void *data, Eina_Compare_Cb compare)
638 EINA_MAGIC_CHECK_INARRAY(array, -1);
639 EINA_SAFETY_ON_NULL_RETURN_VAL(data, -1);
640 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, -1);
641 return _eina_inarray_search(array, data, compare);
645 eina_inarray_search_sorted(const Eina_Inarray *array, const void *data, Eina_Compare_Cb compare)
650 EINA_MAGIC_CHECK_INARRAY(array, -1);
651 EINA_SAFETY_ON_NULL_RETURN_VAL(data, -1);
652 EINA_SAFETY_ON_NULL_RETURN_VAL(compare, -1);
654 pos = _eina_inarray_search_sorted_near(array, data, compare, &cmp);
661 eina_inarray_foreach(const Eina_Inarray *array, Eina_Each_Cb function, const void *user_data)
663 unsigned char *itr, *itr_end;
665 Eina_Bool ret = EINA_TRUE;
667 EINA_MAGIC_CHECK_INARRAY(array, EINA_FALSE);
668 EINA_SAFETY_ON_NULL_RETURN_VAL(function, EINA_FALSE);
670 sz = array->member_size;
671 itr = array->members;
672 itr_end = itr + array->len * sz;
673 for (; (itr < itr_end) && (ret); itr += sz)
674 ret = function(array, itr, (void *)user_data);
679 eina_inarray_foreach_remove(Eina_Inarray *array, Eina_Each_Cb match, const void *user_data)
681 unsigned int i = 0, count = 0;
683 EINA_MAGIC_CHECK_INARRAY(array, -1);
684 EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1);
686 while (i < array->len)
688 void *p = _eina_inarray_get(array, i);
689 if (match(array, p, (void *)user_data) == EINA_FALSE)
695 eina_inarray_remove_at(array, i);
703 eina_inarray_count(const Eina_Inarray *array)
705 EINA_MAGIC_CHECK_INARRAY(array, 0);
710 eina_inarray_iterator_new(const Eina_Inarray *array)
712 Eina_Iterator_Inarray *it;
714 EINA_MAGIC_CHECK_INARRAY(array, NULL);
717 it = calloc(1, sizeof(Eina_Iterator_Inarray));
720 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
724 EINA_MAGIC_SET(it, EINA_MAGIC_INARRAY_ITERATOR);
725 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
729 it->iterator.version = EINA_ITERATOR_VERSION;
730 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_inarray_iterator_next);
731 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER
732 (_eina_inarray_iterator_get_container);
733 it->iterator.free = FUNC_ITERATOR_FREE(_eina_inarray_iterator_free);
735 return &it->iterator;
739 eina_inarray_iterator_reversed_new(const Eina_Inarray *array)
741 Eina_Iterator_Inarray *it;
743 EINA_MAGIC_CHECK_INARRAY(array, NULL);
746 it = calloc(1, sizeof(Eina_Iterator_Inarray));
749 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
753 EINA_MAGIC_SET(it, EINA_MAGIC_INARRAY_ITERATOR);
754 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
757 it->pos = array->len;
759 it->iterator.version = EINA_ITERATOR_VERSION;
760 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_inarray_iterator_prev);
761 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER
762 (_eina_inarray_iterator_get_container);
763 it->iterator.free = FUNC_ITERATOR_FREE(_eina_inarray_iterator_free);
765 return &it->iterator;
769 eina_inarray_accessor_new(const Eina_Inarray *array)
771 Eina_Accessor_Inarray *ac;
773 EINA_MAGIC_CHECK_INARRAY(array, NULL);
776 ac = calloc(1, sizeof(Eina_Accessor_Inarray));
779 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
783 EINA_MAGIC_SET(ac, EINA_MAGIC_INARRAY_ACCESSOR);
784 EINA_MAGIC_SET(&ac->accessor, EINA_MAGIC_ACCESSOR);
788 ac->accessor.version = EINA_ACCESSOR_VERSION;
789 ac->accessor.get_at = FUNC_ACCESSOR_GET_AT(_eina_inarray_accessor_get_at);
790 ac->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER
791 (_eina_inarray_accessor_get_container);
792 ac->accessor.free = FUNC_ACCESSOR_FREE(_eina_inarray_accessor_free);
794 return &ac->accessor;