forked from enlightenment/efl
271 lines
6.2 KiB
C
271 lines
6.2 KiB
C
/* EINA - EFL data type library
|
|
* Copyright (C) 2008 Cedric BAIL
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library;
|
|
* if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifndef _MSC_VER
|
|
# include <stdint.h>
|
|
#endif
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#ifdef HAVE_EVIL
|
|
# include <Evil.h>
|
|
#endif
|
|
|
|
#include "eina_inlist.h"
|
|
#include "eina_rbtree.h"
|
|
#include "eina_error.h"
|
|
|
|
#include "eina_mempool.h"
|
|
|
|
#include "eina_private.h"
|
|
|
|
typedef struct _Eina_Fixed_Bitmap Eina_Fixed_Bitmap;
|
|
typedef struct _Eina_Fixed_Bitmap_Pool Eina_Fixed_Bitmap_Pool;
|
|
|
|
struct _Eina_Fixed_Bitmap
|
|
{
|
|
Eina_Rbtree *lookup;
|
|
Eina_Inlist *head;
|
|
|
|
int item_size;
|
|
};
|
|
|
|
struct _Eina_Fixed_Bitmap_Pool
|
|
{
|
|
EINA_RBTREE;
|
|
EINA_INLIST;
|
|
|
|
uint32_t bitmask;
|
|
};
|
|
|
|
static inline size_t
|
|
_eina_rbtree_inlist_delta(void)
|
|
{
|
|
Eina_Fixed_Bitmap_Pool tmp;
|
|
void *a = &tmp.__rbtree;
|
|
void *b = &tmp.__in_list;
|
|
|
|
return (char *)a - (char *)b;
|
|
}
|
|
|
|
static Eina_Rbtree_Direction
|
|
_eina_fixed_cmp(const Eina_Rbtree *left,
|
|
const Eina_Rbtree *right,
|
|
EINA_UNUSED void *data)
|
|
{
|
|
if (left - right < 0)
|
|
return EINA_RBTREE_LEFT;
|
|
|
|
return EINA_RBTREE_RIGHT;
|
|
}
|
|
|
|
static int
|
|
_eina_fixed_cmp_key(const Eina_Rbtree *node,
|
|
const void *key,
|
|
EINA_UNUSED int length,
|
|
Eina_Fixed_Bitmap *mp)
|
|
{
|
|
const void *a = node;
|
|
const void *b = key;
|
|
ssize_t delta;
|
|
ssize_t limit;
|
|
|
|
limit = sizeof (Eina_Fixed_Bitmap_Pool) + mp->item_size * 32;
|
|
delta = (char *)a - (char *)b;
|
|
|
|
if (delta > 0)
|
|
return 1;
|
|
|
|
if (delta + limit < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
_eina_fixed_bitmap_pool_free(Eina_Fixed_Bitmap_Pool *pool,
|
|
EINA_UNUSED void *data)
|
|
{
|
|
free(pool);
|
|
}
|
|
|
|
static void *
|
|
eina_fixed_bitmap_malloc(void *data, EINA_UNUSED unsigned int size)
|
|
{
|
|
Eina_Fixed_Bitmap *mp = data;
|
|
Eina_Fixed_Bitmap_Pool *pool = NULL;
|
|
void *ptr;
|
|
int idx;
|
|
|
|
if (mp->head)
|
|
{
|
|
pool =
|
|
(Eina_Fixed_Bitmap_Pool *)((unsigned char *)mp->head +
|
|
_eina_rbtree_inlist_delta());
|
|
|
|
if (pool->bitmask == 0)
|
|
pool = NULL;
|
|
}
|
|
|
|
if (!pool)
|
|
{
|
|
eina_error_set(0);
|
|
pool = malloc(sizeof (Eina_Fixed_Bitmap_Pool) + mp->item_size * 32);
|
|
if (!pool)
|
|
{
|
|
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
pool->bitmask = 0xFFFFFFFF;
|
|
|
|
mp->head = eina_inlist_prepend(mp->head, EINA_INLIST_GET(pool));
|
|
mp->lookup = eina_rbtree_inline_insert(mp->lookup, EINA_RBTREE_GET(
|
|
pool),
|
|
EINA_RBTREE_CMP_NODE_CB(
|
|
_eina_fixed_cmp), NULL);
|
|
}
|
|
|
|
idx = ffs(pool->bitmask) - 1;
|
|
pool->bitmask &= ~(1 << idx);
|
|
ptr = (unsigned char *)(pool + 1) + idx * mp->item_size;
|
|
|
|
if (pool->bitmask == 0)
|
|
mp->head = eina_inlist_demote(mp->head, EINA_INLIST_GET(pool));
|
|
|
|
return ptr;
|
|
}
|
|
|
|
static void
|
|
eina_fixed_bitmap_free(void *data, void *ptr)
|
|
{
|
|
Eina_Fixed_Bitmap *mp = data;
|
|
Eina_Fixed_Bitmap_Pool *pool;
|
|
void *a;
|
|
Eina_Bool push_front = EINA_FALSE;
|
|
ssize_t delta;
|
|
|
|
pool = (Eina_Fixed_Bitmap_Pool *)eina_rbtree_inline_lookup(
|
|
mp->lookup,
|
|
ptr,
|
|
0,
|
|
EINA_RBTREE_CMP_KEY_CB(
|
|
_eina_fixed_cmp_key),
|
|
mp);
|
|
if (!pool)
|
|
return;
|
|
|
|
if (pool->bitmask != 0xFFFFFFFF)
|
|
push_front = EINA_TRUE;
|
|
|
|
a = pool;
|
|
delta =
|
|
((char *)ptr - (char *)a -
|
|
sizeof (Eina_Fixed_Bitmap_Pool)) / mp->item_size;
|
|
|
|
assert(delta >= 0 && delta < 32);
|
|
|
|
pool->bitmask |= (1 << (delta & 0x1F));
|
|
|
|
if (pool->bitmask == 0xFFFFFFFF)
|
|
{
|
|
mp->head = eina_inlist_remove(mp->head, EINA_INLIST_GET(pool));
|
|
mp->lookup = eina_rbtree_inline_remove(mp->lookup, EINA_RBTREE_GET(
|
|
pool),
|
|
EINA_RBTREE_CMP_NODE_CB(
|
|
_eina_fixed_cmp), NULL);
|
|
free(pool);
|
|
}
|
|
else if (push_front)
|
|
mp->head = eina_inlist_promote(mp->head, EINA_INLIST_GET(pool));
|
|
}
|
|
|
|
static void *
|
|
eina_fixed_bitmap_realloc(EINA_UNUSED void *data,
|
|
EINA_UNUSED void *element,
|
|
EINA_UNUSED unsigned int size)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void *
|
|
eina_fixed_bitmap_init(EINA_UNUSED const char *context,
|
|
EINA_UNUSED const char *option,
|
|
va_list args)
|
|
{
|
|
Eina_Fixed_Bitmap *mp;
|
|
int item_size;
|
|
|
|
mp = malloc(sizeof (Eina_Fixed_Bitmap));
|
|
if (!mp)
|
|
return NULL;
|
|
|
|
item_size = va_arg(args, int);
|
|
|
|
mp->item_size = eina_mempool_alignof(item_size);
|
|
|
|
mp->lookup = NULL;
|
|
mp->head = NULL;
|
|
|
|
return mp;
|
|
}
|
|
|
|
static void
|
|
eina_fixed_bitmap_shutdown(void *data)
|
|
{
|
|
Eina_Fixed_Bitmap *mp = data;
|
|
|
|
eina_rbtree_delete(mp->lookup,
|
|
EINA_RBTREE_FREE_CB(_eina_fixed_bitmap_pool_free), NULL);
|
|
free(mp);
|
|
}
|
|
|
|
static Eina_Mempool_Backend _eina_fixed_bitmap_mp_backend = {
|
|
"fixed_bitmap",
|
|
&eina_fixed_bitmap_init,
|
|
&eina_fixed_bitmap_free,
|
|
&eina_fixed_bitmap_malloc,
|
|
&eina_fixed_bitmap_realloc,
|
|
NULL,
|
|
NULL,
|
|
&eina_fixed_bitmap_shutdown,
|
|
NULL
|
|
};
|
|
|
|
Eina_Bool fixed_bitmap_init(void)
|
|
{
|
|
return eina_mempool_register(&_eina_fixed_bitmap_mp_backend);
|
|
}
|
|
|
|
void fixed_bitmap_shutdown(void)
|
|
{
|
|
eina_mempool_unregister(&_eina_fixed_bitmap_mp_backend);
|
|
}
|
|
|
|
#ifndef EINA_STATIC_BUILD_FIXED_BITMAP
|
|
|
|
EINA_MODULE_INIT(fixed_bitmap_init);
|
|
EINA_MODULE_SHUTDOWN(fixed_bitmap_shutdown);
|
|
|
|
#endif /* ! EINA_STATIC_BUILD_FIXED_BITMAP */
|
|
|