cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=9382bfc0bc1c6a5fb3aafce18094016b110036c0

commit 9382bfc0bc1c6a5fb3aafce18094016b110036c0
Author: Cedric Bail <cedric.b...@free.fr>
Date:   Sat Sep 14 10:54:05 2019 -0700

    eina: add eina_mempool_iterator_new to slowly iterate every allocated 
pointer in a mempool.
    
    Reviewed-by: Mike Blumenkrantz <michael.blumenkra...@gmail.com>
    Differential Revision: https://phab.enlightenment.org/D9941
---
 src/lib/eina/eina_inline_mempool.x                 | 13 +++
 src/lib/eina/eina_mempool.c                        |  1 +
 src/lib/eina/eina_mempool.h                        | 11 +++
 .../eina/mp/chained_pool/eina_chained_mempool.c    | 94 ++++++++++++++++++++--
 src/modules/eina/mp/one_big/eina_one_big.c         | 82 ++++++++++++++++++-
 .../eina/mp/pass_through/eina_pass_through.c       |  3 +-
 src/tests/eina/eina_test_mempool.c                 | 18 ++++-
 7 files changed, 209 insertions(+), 13 deletions(-)

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

-- 


Reply via email to