diff --git a/src/lib/eina/eina_inline_mempool.x b/src/lib/eina/eina_inline_mempool.x index d30364f097..0805c82f07 100644 --- a/src/lib/eina/eina_inline_mempool.x +++ b/src/lib/eina/eina_inline_mempool.x @@ -56,6 +56,11 @@ struct _Eina_Mempool_Backend * @see eina_mempool_from */ Eina_Bool (*from)(void *data, void *element); + /** Function to get an Eina_Iterator that will walk every allocated element + * in the pool. + * @use eina_mempool_iterator_new + */ + Eina_Iterator *(*iterator)(void *data); }; struct _Eina_Mempool_Backend_ABI1 @@ -74,6 +79,7 @@ struct _Eina_Mempool_Backend_ABI2 { void (*repack)(void *data, Eina_Mempool_Repack_Cb cb, void *cb_data); Eina_Bool (*from)(void *data, void *element); + Eina_Iterator *(*iterator)(void *data); }; struct _Eina_Mempool @@ -116,6 +122,13 @@ eina_mempool_from(Eina_Mempool *mp, void *element) return mp->backend2->from(mp->backend_data, element); } +static inline Eina_Iterator * +eina_mempool_iterator_new(Eina_Mempool *mp) +{ + if (!mp->backend2->iterator) return NULL; + return mp->backend2->iterator(mp->backend_data); +} + static inline unsigned int eina_mempool_alignof(unsigned int size) { diff --git a/src/lib/eina/eina_mempool.c b/src/lib/eina/eina_mempool.c index 56144a0f1c..51a29906f2 100644 --- a/src/lib/eina/eina_mempool.c +++ b/src/lib/eina/eina_mempool.c @@ -104,6 +104,7 @@ _new_va(const char *name, if (!mp->backend2) goto on_error; mp->backend2->repack = be->repack; mp->backend2->from = be->from; + mp->backend2->iterator = be->iterator; } mp->backend_data = mp->backend.init(context, options, args); diff --git a/src/lib/eina/eina_mempool.h b/src/lib/eina/eina_mempool.h index 606ecbaef9..d7759ce6c8 100644 --- a/src/lib/eina/eina_mempool.h +++ b/src/lib/eina/eina_mempool.h @@ -197,6 +197,17 @@ static inline Eina_Bool eina_mempool_from(Eina_Mempool *mp, void *element); */ EAPI void eina_mempool_statistics(Eina_Mempool *mp) EINA_ARG_NONNULL(1); +/** + * @brief Provide an iterator to walk all allocated elements from a specified mempool. + * + * @param[in] mp The mempool + * @return @c NULL if it is not possible to iterate over the mempool, a valid iterator otherwise. + * + * @note This call is expected to be slow and should not be used in any performance critical area. + * @since 1.23 + */ +static inline Eina_Iterator *eina_mempool_iterator_new(Eina_Mempool *mp); + /** * @brief Registers the given memory pool backend. * diff --git a/src/modules/eina/mp/chained_pool/eina_chained_mempool.c b/src/modules/eina/mp/chained_pool/eina_chained_mempool.c index d44f0bf6cb..6d4facf74d 100644 --- a/src/modules/eina/mp/chained_pool/eina_chained_mempool.c +++ b/src/modules/eina/mp/chained_pool/eina_chained_mempool.c @@ -79,7 +79,7 @@ struct _Chained_Pool EINA_INLIST; EINA_RBTREE; Eina_Trash *base; - int usage; + unsigned int usage; unsigned char *last; unsigned char *limit; @@ -91,11 +91,11 @@ struct _Chained_Mempool Eina_Inlist *first; Eina_Rbtree *root; const char *name; - int item_alloc; - int pool_size; - int alloc_size; - int group_size; - int usage; + unsigned int item_alloc; + unsigned int pool_size; + unsigned int alloc_size; + unsigned int group_size; + unsigned int usage; Chained_Pool* first_fill; //All allocation will happen in this chain,unless it is filled #ifdef EINA_DEBUG_MALLOC int minimal_size; @@ -453,6 +453,85 @@ eina_chained_mempool_from(void *data, void *ptr) return ret; } +typedef struct _Eina_Iterator_Chained_Mempool Eina_Iterator_Chained_Mempool; +struct _Eina_Iterator_Chained_Mempool +{ + Eina_Iterator iterator; + + Eina_Iterator *walker; + Chained_Pool *current; + Chained_Mempool *pool; + + unsigned int offset; +}; + +static Eina_Bool +eina_mempool_iterator_next(Eina_Iterator_Chained_Mempool *it, void **data) +{ + if (!it->current) + { + if (!eina_iterator_next(it->walker, (void**) &it->current)) + return EINA_FALSE; + if (!it->current) return EINA_FALSE; + } + + retry: + if (it->offset < it->pool->group_size) + { + unsigned char *ptr = (unsigned char *) (it->current + 1); + + ptr += it->offset; + it->offset += it->pool->item_alloc; + + if (!eina_chained_mempool_from(it->pool, ptr)) goto retry; + + if (data) *data = (void *) ptr; + return EINA_TRUE; + } + + if (!eina_iterator_next(it->walker, (void**) &it->current)) + return EINA_FALSE; + + it->offset = 0; + goto retry; +} + +static Chained_Mempool * +eina_mempool_iterator_get_container(Eina_Iterator_Chained_Mempool *it) +{ + return it->pool; +} + +static void +eina_mempool_iterator_free(Eina_Iterator_Chained_Mempool *it) +{ + eina_iterator_free(it->walker); + free(it); +} + +static Eina_Iterator * +eina_chained_mempool_iterator_new(void *data) +{ + Eina_Iterator_Chained_Mempool *it; + Chained_Mempool *pool = data; + + it = calloc(1, sizeof (Eina_Iterator_Chained_Mempool)); + if (!it) return NULL; + + it->walker = eina_inlist_iterator_new(pool->first); + it->pool = pool; + + it->iterator.version = EINA_ITERATOR_VERSION; + it->iterator.next = FUNC_ITERATOR_NEXT(eina_mempool_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER( + eina_mempool_iterator_get_container); + it->iterator.free = FUNC_ITERATOR_FREE(eina_mempool_iterator_free); + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + + return &it->iterator; +} + static void eina_chained_mempool_repack(void *data, Eina_Mempool_Repack_Cb cb, @@ -645,7 +724,8 @@ static Eina_Mempool_Backend _eina_chained_mp_backend = { NULL, &eina_chained_mempool_shutdown, &eina_chained_mempool_repack, - &eina_chained_mempool_from + &eina_chained_mempool_from, + &eina_chained_mempool_iterator_new }; Eina_Bool chained_init(void) diff --git a/src/modules/eina/mp/one_big/eina_one_big.c b/src/modules/eina/mp/one_big/eina_one_big.c index 39fd511cf1..b909dfbc51 100644 --- a/src/modules/eina/mp/one_big/eina_one_big.c +++ b/src/modules/eina/mp/one_big/eina_one_big.c @@ -63,14 +63,14 @@ struct _One_Big { const char *name; - int item_size; + unsigned int item_size; int offset_to_item_inlist; int usage; int over; - int served; - int max; + unsigned int served; + unsigned int max; unsigned char *base; Eina_Trash *empty; @@ -263,6 +263,79 @@ eina_one_big_from(void *data, void *ptr) return r; } +typedef struct _Eina_Iterator_One_Big_Mempool Eina_Iterator_One_Big_Mempool; +struct _Eina_Iterator_One_Big_Mempool +{ + Eina_Iterator iterator; + + Eina_Iterator *walker; + One_Big *pool; + + unsigned int offset; +}; + +static Eina_Bool +eina_mempool_iterator_next(Eina_Iterator_One_Big_Mempool *it, void **data) +{ + Eina_Inlist *il = NULL; + + retry: + if (it->offset < (it->pool->max * it->pool->item_size)) + { + unsigned char *ptr = (unsigned char *) (it->pool->base); + + ptr += it->offset; + it->offset += it->pool->item_size; + + if (!eina_one_big_from(it->pool, ptr)) goto retry; + + if (data) *data = (void *) ptr; + return EINA_TRUE; + } + + if (!eina_iterator_next(it->walker, (void **) &il)) + return EINA_FALSE; + + if (data) *data = OVER_MEM_FROM_LIST(it->pool, il); + return EINA_TRUE; +} + +static One_Big * +eina_mempool_iterator_get_container(Eina_Iterator_One_Big_Mempool *it) +{ + return it->pool; +} + +static void +eina_mempool_iterator_free(Eina_Iterator_One_Big_Mempool *it) +{ + eina_iterator_free(it->walker); + free(it); +} + +static Eina_Iterator * +eina_one_big_iterator_new(void *data) +{ + Eina_Iterator_One_Big_Mempool *it; + One_Big *pool = data; + + it = calloc(1, sizeof (Eina_Iterator_One_Big_Mempool)); + if (!it) return NULL; + + it->walker = eina_inlist_iterator_new(pool->over_list); + it->pool = pool; + + it->iterator.version = EINA_ITERATOR_VERSION; + it->iterator.next = FUNC_ITERATOR_NEXT(eina_mempool_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER( + eina_mempool_iterator_get_container); + it->iterator.free = FUNC_ITERATOR_FREE(eina_mempool_iterator_free); + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + + return &it->iterator; +} + static void * eina_one_big_realloc(EINA_UNUSED void *data, EINA_UNUSED void *element, @@ -378,7 +451,8 @@ static Eina_Mempool_Backend _eina_one_big_mp_backend = { NULL, &eina_one_big_shutdown, NULL, - &eina_one_big_from + &eina_one_big_from, + &eina_one_big_iterator_new }; Eina_Bool one_big_init(void) diff --git a/src/modules/eina/mp/pass_through/eina_pass_through.c b/src/modules/eina/mp/pass_through/eina_pass_through.c index 0e546f7987..2d2bc3834a 100644 --- a/src/modules/eina/mp/pass_through/eina_pass_through.c +++ b/src/modules/eina/mp/pass_through/eina_pass_through.c @@ -76,7 +76,8 @@ static Eina_Mempool_Backend _eina_pass_through_mp_backend = { NULL, &eina_pass_through_shutdown, NULL, - &eina_pass_through_from + &eina_pass_through_from, + NULL }; Eina_Bool pass_through_init(void) diff --git a/src/tests/eina/eina_test_mempool.c b/src/tests/eina/eina_test_mempool.c index 78656cea53..c36bab1717 100644 --- a/src/tests/eina/eina_test_mempool.c +++ b/src/tests/eina/eina_test_mempool.c @@ -28,10 +28,12 @@ static void _eina_mempool_test(Eina_Mempool *mp, Eina_Bool with_realloc, Eina_Bool with_gc, Eina_Bool accurate_from) { + Eina_Iterator *it; int *tbl[512]; + int *ptr; int i; - fail_if(!mp); + fail_if(!mp); for (i = 0; i < 512; ++i) { @@ -52,6 +54,20 @@ _eina_mempool_test(Eina_Mempool *mp, fail_if(eina_mempool_from(mp, tbl[i]) != EINA_FALSE); } + it = eina_mempool_iterator_new(mp); + EINA_ITERATOR_FOREACH(it, ptr) + { + ck_assert_int_gt(*ptr, 255); + *ptr = 0; + } + eina_iterator_free(it); + + if (it) // Only check if the mempool support iterator + { + for (; i < 512; ++i) + ck_assert_int_eq(*tbl[i], 0); + } + if (with_realloc) fail_if(eina_mempool_realloc(mp, tbl[500], 25) == NULL); else