1 /* EINA - EFL data type library
2 * Copyright (C) 2008 Cedric Bail
3 * Copyright (C) 2011 Alexandre Becoulet
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library;
17 * if not, see <http://www.gnu.org/licenses/>.
29 #include "eina_config.h"
30 #include "eina_private.h"
31 #include "eina_array.h"
33 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
34 #include "eina_safety_checks.h"
35 #include "eina_rbtree.h"
37 /*============================================================================*
39 *============================================================================*/
41 #define EINA_RBTREE_ITERATOR_PREFIX_MASK 0x1
42 #define EINA_RBTREE_ITERATOR_INFIX_MASK 0x2
43 #define EINA_RBTREE_ITERATOR_POSTFIX_MASK 0x4
45 typedef struct _Eina_Iterator_Rbtree Eina_Iterator_Rbtree;
46 typedef struct _Eina_Iterator_Rbtree_List Eina_Iterator_Rbtree_List;
48 struct _Eina_Iterator_Rbtree
50 Eina_Iterator iterator;
57 struct _Eina_Iterator_Rbtree_List
61 Eina_Rbtree_Direction dir : 1;
65 static Eina_Iterator_Rbtree_List *
66 _eina_rbtree_iterator_list_new(const Eina_Rbtree *tree)
68 Eina_Iterator_Rbtree_List *new;
71 new = malloc(sizeof (Eina_Iterator_Rbtree_List));
74 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
78 new->tree = (Eina_Rbtree *)tree;
79 new->dir = EINA_RBTREE_RIGHT;
86 _eina_rbtree_iterator_get_content(Eina_Iterator_Rbtree *it)
88 if (eina_array_count(it->stack) <= 0)
91 return eina_array_data_get(it->stack, 0);
95 _eina_rbtree_iterator_free(Eina_Iterator_Rbtree *it)
97 Eina_Iterator_Rbtree_List *item;
98 Eina_Array_Iterator et;
101 EINA_ARRAY_ITER_NEXT(it->stack, i, item, et)
104 eina_array_free(it->stack);
109 _eina_rbtree_iterator_next(Eina_Iterator_Rbtree *it, void **data)
111 Eina_Iterator_Rbtree_List *last;
112 Eina_Iterator_Rbtree_List *new;
115 if (eina_array_count(it->stack) <= 0)
118 last = eina_array_data_get(it->stack, eina_array_count(it->stack) - 1);
121 if (!last->tree || last->up == EINA_TRUE)
123 last = eina_array_pop(it->stack);
124 while (last->dir == EINA_RBTREE_LEFT
128 if ((it->mask & EINA_RBTREE_ITERATOR_POSTFIX_MASK) ==
129 EINA_RBTREE_ITERATOR_POSTFIX_MASK)
133 if (eina_array_count(it->stack) > 0)
135 last = eina_array_data_get(it->stack,
140 last->up = EINA_TRUE;
148 last = eina_array_pop(it->stack);
155 last->dir = EINA_RBTREE_LEFT;
156 last->up = EINA_FALSE;
158 eina_array_push(it->stack, last);
160 if ((it->mask & EINA_RBTREE_ITERATOR_INFIX_MASK) ==
161 EINA_RBTREE_ITERATOR_INFIX_MASK)
165 new = _eina_rbtree_iterator_list_new(last->tree->son[last->dir]);
169 eina_array_push(it->stack, new);
171 if (last->dir == EINA_RBTREE_RIGHT)
172 if ((it->mask & EINA_RBTREE_ITERATOR_PREFIX_MASK) ==
173 EINA_RBTREE_ITERATOR_PREFIX_MASK)
176 return _eina_rbtree_iterator_next(it, data);
183 static Eina_Iterator *
184 _eina_rbtree_iterator_build(const Eina_Rbtree *root, unsigned char mask)
186 Eina_Iterator_Rbtree_List *first;
187 Eina_Iterator_Rbtree *it;
190 it = calloc(1, sizeof (Eina_Iterator_Rbtree));
193 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
197 it->stack = eina_array_new(8);
201 first = _eina_rbtree_iterator_list_new(root);
205 eina_array_push(it->stack, first);
209 it->iterator.version = EINA_ITERATOR_VERSION;
210 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_rbtree_iterator_next);
211 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
212 _eina_rbtree_iterator_get_content);
213 it->iterator.free = FUNC_ITERATOR_FREE(_eina_rbtree_iterator_free);
215 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
217 return &it->iterator;
220 eina_array_free(it->stack);
228 _eina_rbtree_node_init(Eina_Rbtree *node)
236 node->color = EINA_RBTREE_RED;
239 static inline Eina_Bool
240 _eina_rbtree_is_red(Eina_Rbtree *node)
242 return !!node && node->color == EINA_RBTREE_RED;
245 static inline Eina_Rbtree *
246 _eina_rbtree_inline_single_rotation(Eina_Rbtree *node,
247 Eina_Rbtree_Direction dir)
249 Eina_Rbtree *save = node->son[dir ^ 1];
251 node->son[dir ^ 1] = save->son[dir];
252 save->son[dir] = node;
254 node->color = EINA_RBTREE_RED;
255 save->color = EINA_RBTREE_BLACK;
260 static inline Eina_Rbtree *
261 _eina_rbtree_inline_double_rotation(Eina_Rbtree *node,
262 Eina_Rbtree_Direction dir)
264 node->son[dir ^ 1] = _eina_rbtree_inline_single_rotation(node->son[dir ^ 1], dir ^ 1);
265 return _eina_rbtree_inline_single_rotation(node, dir);
268 /*============================================================================*
270 *============================================================================*/
272 /*============================================================================*
274 *============================================================================*/
277 eina_rbtree_inline_insert(Eina_Rbtree *root,
279 Eina_Rbtree_Cmp_Node_Cb cmp,
282 Eina_Rbtree **r = &root;
283 Eina_Rbtree *q = root;
287 EINA_SAFETY_ON_NULL_RETURN_VAL(node, root);
288 EINA_SAFETY_ON_NULL_RETURN_VAL( cmp, root);
290 /* Find insertion leaf */
293 Eina_Rbtree_Direction dir = cmp(q, node, (void *)data);
295 /* Keep path in stack */
296 stack[s++] = (uintptr_t)r | dir;
304 _eina_rbtree_node_init(node);
310 uintptr_t top = stack[--s]; /* Pop link pointer and direction */
311 Eina_Rbtree_Direction dir = top & 1;
313 r = (Eina_Rbtree **)(top & ~(uintptr_t)1);
317 /* Rebalance done ? */
318 if (a == NULL || a->color == EINA_RBTREE_BLACK)
322 if (b != NULL && b->color == EINA_RBTREE_RED)
324 q->color = EINA_RBTREE_RED;
325 b->color = a->color = EINA_RBTREE_BLACK;
329 Eina_Rbtree *c = a->son[dir];
330 Eina_Rbtree *d = a->son[dir ^ 1];
332 if (c != NULL && c->color == EINA_RBTREE_RED)
333 *r = _eina_rbtree_inline_single_rotation(*r, dir ^ 1);
334 else if (d != NULL && d->color == EINA_RBTREE_RED)
335 *r = _eina_rbtree_inline_double_rotation(*r, dir ^ 1);
339 root->color = EINA_RBTREE_BLACK;
344 eina_rbtree_inline_remove(Eina_Rbtree *root,
346 Eina_Rbtree_Cmp_Node_Cb cmp,
349 Eina_Rbtree *l0, *l1, *r, **rt = &root;
350 Eina_Rbtree_Direction dir;
354 EINA_SAFETY_ON_NULL_RETURN_VAL(node, root);
355 EINA_SAFETY_ON_NULL_RETURN_VAL( cmp, root);
357 /* Item search loop */
358 for (r = *rt; r != NULL; r = *rt)
363 dir = cmp(r, node, (void*)data);
364 stack[s++] = (uintptr_t)rt | dir;
374 if (l0 != NULL && l1 != NULL) /* two links case */
376 Eina_Rbtree *q, **t, **p;
379 stack[s++] = (uintptr_t)rt | 1;
380 ss = s; /* keep predecessor right link stack index */
382 /* find predecessor */
392 stack[s++] = (uintptr_t)p | 0;
396 /* detach predecessor */
402 /* replace entry by predecessor */
403 memcpy(q, node, sizeof(Eina_Rbtree));
406 if (c == EINA_RBTREE_RED)
409 /* fix stack for replaced entry */
411 stack[ss] = (uintptr_t)(q->son + 1) | 0;
413 else /* single link case */
420 if (node->color == EINA_RBTREE_RED)
421 goto end; /* removed red */
423 if (l0 != NULL && l0->color == EINA_RBTREE_RED)
425 /* red child replace removed black */
426 l0->color = EINA_RBTREE_BLACK;
435 uintptr_t st = stack[--s];
437 rt = (Eina_Rbtree**)(st & ~(uintptr_t)1);
442 if (q != NULL && q->color == EINA_RBTREE_RED)
444 *rt = _eina_rbtree_inline_single_rotation(*rt, dir);
446 rt = (*rt)->son + dir;
451 int r_color = r->color;
452 Eina_Rbtree *nd = q->son[dir ^ 1];
454 if (nd != NULL && nd->color == EINA_RBTREE_RED)
456 *rt = _eina_rbtree_inline_single_rotation(*rt, dir);
460 Eina_Rbtree *d = q->son[dir];
462 if (d != NULL && d->color == EINA_RBTREE_RED)
464 *rt = _eina_rbtree_inline_double_rotation(*rt, dir);
468 r->color = EINA_RBTREE_BLACK;
469 q->color = EINA_RBTREE_RED;
470 if (r_color == EINA_RBTREE_RED)
478 r->son[1]->color = r->son[0]->color = EINA_RBTREE_BLACK;
486 root->color = EINA_RBTREE_BLACK;
491 eina_rbtree_iterator_prefix(const Eina_Rbtree *root)
493 return _eina_rbtree_iterator_build(root, EINA_RBTREE_ITERATOR_PREFIX_MASK);
497 eina_rbtree_iterator_infix(const Eina_Rbtree *root)
499 return _eina_rbtree_iterator_build(root, EINA_RBTREE_ITERATOR_INFIX_MASK);
503 eina_rbtree_iterator_postfix(const Eina_Rbtree *root)
505 return _eina_rbtree_iterator_build(root, EINA_RBTREE_ITERATOR_POSTFIX_MASK);
509 eina_rbtree_delete(Eina_Rbtree *root, Eina_Rbtree_Free_Cb func, void *data)
514 EINA_SAFETY_ON_NULL_RETURN(func);
516 eina_rbtree_delete(root->son[0], func, data);
517 eina_rbtree_delete(root->son[1], func, data);