1 /* EINA - EFL data type library
2 * Copyright (C) 2007-2008 Cedric BAIL, Carsten Haitzler
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/>.
30 #include "eina_config.h"
31 #include "eina_private.h"
32 #include "eina_magic.h"
33 #include "eina_inlist.h"
34 #include "eina_mempool.h"
35 #include "eina_list.h"
36 #include "eina_trash.h"
39 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
40 #include "eina_safety_checks.h"
41 #include "eina_rectangle.h"
43 /*============================================================================*
45 *============================================================================*/
51 #define EINA_RECTANGLE_POOL_MAGIC 0x1578FCB0
52 #define EINA_RECTANGLE_ALLOC_MAGIC 0x1578FCB1
54 #define BUCKET_THRESHOLD 110
56 typedef struct _Eina_Rectangle_Alloc Eina_Rectangle_Alloc;
58 struct _Eina_Rectangle_Pool
65 unsigned int bucket_count;
67 unsigned int references;
75 struct _Eina_Rectangle_Alloc
78 Eina_Rectangle_Pool *pool;
82 #define EINA_MAGIC_CHECK_RECTANGLE_POOL(d) \
84 if (!EINA_MAGIC_CHECK((d), EINA_RECTANGLE_POOL_MAGIC)) { \
85 EINA_MAGIC_FAIL((d), EINA_RECTANGLE_POOL_MAGIC); } \
88 #define EINA_MAGIC_CHECK_RECTANGLE_ALLOC(d) \
90 if (!EINA_MAGIC_CHECK((d), EINA_RECTANGLE_ALLOC_MAGIC)) { \
91 EINA_MAGIC_FAIL((d), EINA_RECTANGLE_ALLOC_MAGIC); } \
94 static Eina_Mempool *_eina_rectangle_alloc_mp = NULL;
95 static Eina_Mempool *_eina_rectangle_mp = NULL;
97 static Eina_Trash *_eina_rectangles = NULL;
98 static unsigned int _eina_rectangles_count = 0;
99 static int _eina_rectangle_log_dom = -1;
104 #define ERR(...) EINA_LOG_DOM_ERR(_eina_rectangle_log_dom, __VA_ARGS__)
109 #define DBG(...) EINA_LOG_DOM_DBG(_eina_rectangle_log_dom, __VA_ARGS__)
112 _eina_rectangle_cmp(const Eina_Rectangle *r1, const Eina_Rectangle *r2)
114 return (r2->w * r2->h) - (r1->w * r1->h);
118 _eina_rectangle_merge_list(Eina_List *empty, Eina_Rectangle *r)
120 Eina_Rectangle *match;
125 if (r->w == 0 || r->h == 0)
127 eina_rectangle_free(r);
135 EINA_LIST_FOREACH(empty, l, match)
137 if (match->x == r->x && match->w == r->w
138 && (match->y == yh || r->y == match->y + match->h))
145 eina_rectangle_free(r);
147 empty = eina_list_remove_list(empty, l);
153 else if (match->y == r->y && match->h == r->h
154 && (match->x == xw || r->x == match->x + match->w))
161 eina_rectangle_free(r);
163 empty = eina_list_remove_list(empty, l);
171 return eina_list_append(empty, r);
175 _eina_rectangle_empty_space_find(Eina_List *empty, int w, int h, int *x, int *y)
180 EINA_LIST_FOREACH(empty, l, r)
182 if (r->w >= w && r->h >= h)
184 /* Remove l from empty */
185 empty = eina_list_remove_list(empty, l);
186 /* Remember x and y */
189 /* Split r in 2 rectangle if needed (only the empty one) and insert them */
202 int rx1, ry1, rw1, rh1;
208 /* h1 could be h or r->h */
211 /* w2 could be w or r->w */
214 if (rw1 * r->h > h2 * r->w)
225 EINA_RECTANGLE_SET(r, rx1, ry1, rw1, rh1);
226 empty = _eina_rectangle_merge_list(empty, r);
228 r = eina_rectangle_new(x2, y2, w2, h2);
233 empty = _eina_rectangle_merge_list(empty, r); /* Return empty */
250 /*============================================================================*
252 *============================================================================*/
255 eina_rectangle_init(void)
257 const char *choice, *tmp;
259 _eina_rectangle_log_dom = eina_log_domain_register("eina_rectangle",
260 EINA_LOG_COLOR_DEFAULT);
261 if (_eina_rectangle_log_dom < 0)
263 EINA_LOG_ERR("Could not register log domain: eina_rectangle");
267 #ifdef EINA_DEFAULT_MEMPOOL
268 choice = "pass_through";
270 choice = "chained_mempool";
272 tmp = getenv("EINA_MEMPOOL");
276 _eina_rectangle_alloc_mp = eina_mempool_add
277 (choice, "rectangle-alloc", NULL,
278 sizeof(Eina_Rectangle_Alloc) + sizeof(Eina_Rectangle), 64);
279 if (!_eina_rectangle_alloc_mp)
281 ERR("Mempool for rectangle cannot be allocated in rectangle init.");
285 _eina_rectangle_mp = eina_mempool_add
286 (choice, "rectangle", NULL, sizeof(Eina_Rectangle), 32);
287 if (!_eina_rectangle_mp)
289 ERR("Mempool for rectangle cannot be allocated in rectangle init.");
296 eina_log_domain_unregister(_eina_rectangle_log_dom);
297 _eina_rectangle_log_dom = -1;
303 eina_rectangle_shutdown(void)
307 while ((del = eina_trash_pop(&_eina_rectangles)))
308 eina_mempool_free(_eina_rectangle_mp, del);
309 _eina_rectangles_count = 0;
311 eina_mempool_del(_eina_rectangle_alloc_mp);
312 eina_mempool_del(_eina_rectangle_mp);
314 eina_log_domain_unregister(_eina_rectangle_log_dom);
315 _eina_rectangle_log_dom = -1;
320 /*============================================================================*
322 *============================================================================*/
324 EAPI Eina_Rectangle *
325 eina_rectangle_new(int x, int y, int w, int h)
327 Eina_Rectangle *rect;
329 if (_eina_rectangles)
331 rect = eina_trash_pop(&_eina_rectangles);
332 _eina_rectangles_count--;
335 rect = eina_mempool_malloc(_eina_rectangle_mp, sizeof (Eina_Rectangle));
340 EINA_RECTANGLE_SET(rect, x, y, w, h);
346 eina_rectangle_free(Eina_Rectangle *rect)
348 EINA_SAFETY_ON_NULL_RETURN(rect);
350 if (_eina_rectangles_count > BUCKET_THRESHOLD)
351 eina_mempool_free(_eina_rectangle_mp, rect);
354 eina_trash_push(&_eina_rectangles, rect);
355 _eina_rectangles_count++;
359 EAPI Eina_Rectangle_Pool *
360 eina_rectangle_pool_new(int w, int h)
362 Eina_Rectangle_Pool *new;
364 new = malloc(sizeof (Eina_Rectangle_Pool));
369 new->empty = eina_list_append(NULL, eina_rectangle_new(0, 0, w, h));
371 new->sorted = EINA_FALSE;
375 new->bucket_count = 0;
377 EINA_MAGIC_SET(new, EINA_RECTANGLE_POOL_MAGIC);
378 DBG("pool=%p, size=(%d, %d)", new, w, h);
384 eina_rectangle_pool_free(Eina_Rectangle_Pool *pool)
386 Eina_Rectangle_Alloc *del;
388 EINA_SAFETY_ON_NULL_RETURN(pool);
389 DBG("pool=%p, size=(%d, %d), references=%u",
390 pool, pool->w, pool->h, pool->references);
393 del = (Eina_Rectangle_Alloc *)pool->head;
395 pool->head = (EINA_INLIST_GET(del))->next;
397 EINA_MAGIC_SET(del, EINA_MAGIC_NONE);
398 eina_mempool_free(_eina_rectangle_alloc_mp, del);
403 del = eina_trash_pop(&pool->bucket);
404 eina_mempool_free(_eina_rectangle_alloc_mp, del);
411 eina_rectangle_pool_count(Eina_Rectangle_Pool *pool)
413 EINA_SAFETY_ON_NULL_RETURN_VAL(pool, 0);
414 return pool->references;
417 EAPI Eina_Rectangle *
418 eina_rectangle_pool_request(Eina_Rectangle_Pool *pool, int w, int h)
420 Eina_Rectangle_Alloc *new;
421 Eina_Rectangle *rect;
425 EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
427 DBG("pool=%p, size=(%d, %d), references=%u",
428 pool, pool->w, pool->h, pool->references);
430 if (w <= 0 || h <= 0)
433 if (w > pool->w || h > pool->h)
436 /* Sort empty if dirty */
440 eina_list_sort(pool->empty, 0, EINA_COMPARE_CB(_eina_rectangle_cmp));
441 pool->sorted = EINA_TRUE;
444 pool->empty = _eina_rectangle_empty_space_find(pool->empty, w, h, &x, &y);
448 pool->sorted = EINA_FALSE;
450 if (pool->bucket_count > 0)
452 new = eina_trash_pop(&pool->bucket);
453 pool->bucket_count--;
456 new = eina_mempool_malloc(_eina_rectangle_alloc_mp,
457 sizeof (Eina_Rectangle_Alloc) +
458 sizeof (Eina_Rectangle));
463 rect = (Eina_Rectangle *)(new + 1);
464 eina_rectangle_coords_from(rect, x, y, w, h);
466 pool->head = eina_inlist_prepend(pool->head, EINA_INLIST_GET(new));
471 EINA_MAGIC_SET(new, EINA_RECTANGLE_ALLOC_MAGIC);
472 DBG("rect=%p pool=%p, size=(%d, %d), references=%u",
473 rect, pool, pool->w, pool->h, pool->references);
479 eina_rectangle_pool_release(Eina_Rectangle *rect)
481 Eina_Rectangle_Alloc *era = ((Eina_Rectangle_Alloc *)rect) - 1;
484 EINA_SAFETY_ON_NULL_RETURN(rect);
486 EINA_MAGIC_CHECK_RECTANGLE_ALLOC(era);
487 EINA_MAGIC_CHECK_RECTANGLE_POOL(era->pool);
489 DBG("rect=%p pool=%p, size=(%d, %d), references=%u",
490 rect, era->pool, era->pool->w, era->pool->h, era->pool->references);
492 era->pool->references--;
493 era->pool->head = eina_inlist_remove(era->pool->head, EINA_INLIST_GET(era));
495 r = eina_rectangle_new(rect->x, rect->y, rect->w, rect->h);
498 era->pool->empty = _eina_rectangle_merge_list(era->pool->empty, r);
499 era->pool->sorted = EINA_FALSE;
502 if (era->pool->bucket_count < BUCKET_THRESHOLD)
504 Eina_Rectangle_Pool *pool;
508 pool->bucket_count++;
509 eina_trash_push(&pool->bucket, era);
513 EINA_MAGIC_SET(era, EINA_MAGIC_NONE);
514 eina_mempool_free(_eina_rectangle_alloc_mp, era);
518 EAPI Eina_Rectangle_Pool *
519 eina_rectangle_pool_get(Eina_Rectangle *rect)
521 Eina_Rectangle_Alloc *era = ((Eina_Rectangle_Alloc *)rect) - 1;
523 EINA_SAFETY_ON_NULL_RETURN_VAL(rect, NULL);
525 EINA_MAGIC_CHECK_RECTANGLE_ALLOC(era);
526 EINA_MAGIC_CHECK_RECTANGLE_POOL(era->pool);
532 eina_rectangle_pool_data_set(Eina_Rectangle_Pool *pool, const void *data)
534 EINA_MAGIC_CHECK_RECTANGLE_POOL(pool);
535 EINA_SAFETY_ON_NULL_RETURN(pool);
537 DBG("data=%p pool=%p, size=(%d, %d), references=%u",
538 data, pool, pool->w, pool->h, pool->references);
540 pool->data = (void *)data;
544 eina_rectangle_pool_data_get(Eina_Rectangle_Pool *pool)
546 EINA_MAGIC_CHECK_RECTANGLE_POOL(pool);
547 EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
553 eina_rectangle_pool_geometry_get(Eina_Rectangle_Pool *pool, int *w, int *h)
558 EINA_MAGIC_CHECK_RECTANGLE_POOL(pool);
559 EINA_SAFETY_ON_NULL_RETURN_VAL(pool, EINA_FALSE);