numbers ? AUTHORS++
Vincent On Mon, Feb 27, 2012 at 2:29 PM, Enlightenment SVN <no-re...@enlightenment.org> wrote: > Log: > eina: faster implementation of Eina_Rbtree by Alexandre Becoulet. > > > Author: cedric > Date: 2012-02-27 05:29:47 -0800 (Mon, 27 Feb 2012) > New Revision: 68474 > Trac: http://trac.enlightenment.org/e/changeset/68474 > > Modified: > trunk/eina/ChangeLog trunk/eina/NEWS trunk/eina/src/lib/eina_rbtree.c > > Modified: trunk/eina/ChangeLog > =================================================================== > --- trunk/eina/ChangeLog 2012-02-27 13:20:05 UTC (rev 68473) > +++ trunk/eina/ChangeLog 2012-02-27 13:29:47 UTC (rev 68474) > @@ -225,3 +225,7 @@ > 2012-02-22 Cedric Bail > > * Add eina_file_stat. > + > +2012-02-27 Alexandre Becoulet > + > + * Add faster implementation of Eina_Rbtree. > > Modified: trunk/eina/NEWS > =================================================================== > --- trunk/eina/NEWS 2012-02-27 13:20:05 UTC (rev 68473) > +++ trunk/eina/NEWS 2012-02-27 13:29:47 UTC (rev 68474) > @@ -21,7 +21,10 @@ > > * compilation errors in Eina_RWLock code when building code on Windows > > XP > > +Improvements: > > + * faster implementation of Eina_Rbtree. > + > Eina 1.1.0 (2011-12-02) > > Changes since Eina 1.0.0: > > Modified: trunk/eina/src/lib/eina_rbtree.c > =================================================================== > --- trunk/eina/src/lib/eina_rbtree.c 2012-02-27 13:20:05 UTC (rev 68473) > +++ trunk/eina/src/lib/eina_rbtree.c 2012-02-27 13:29:47 UTC (rev 68474) > @@ -1,5 +1,6 @@ > /* EINA - EFL data type library > * Copyright (C) 2008 Cedric Bail > + * Copyright (C) 2011 Alexandre Becoulet > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -23,6 +24,7 @@ > #include <stdlib.h> > #include <stdio.h> > #include <string.h> > +#include <stdint.h> > > #include "eina_config.h" > #include "eina_private.h" > @@ -244,9 +246,9 @@ > _eina_rbtree_inline_single_rotation(Eina_Rbtree *node, > Eina_Rbtree_Direction dir) > { > - Eina_Rbtree *save = node->son[!dir]; > + Eina_Rbtree *save = node->son[dir ^ 1]; > > - node->son[!dir] = save->son[dir]; > + node->son[dir ^ 1] = save->son[dir]; > save->son[dir] = node; > > node->color = EINA_RBTREE_RED; > @@ -259,7 +261,7 @@ > _eina_rbtree_inline_double_rotation(Eina_Rbtree *node, > Eina_Rbtree_Direction dir) > { > - node->son[!dir] = _eina_rbtree_inline_single_rotation(node->son[!dir], > !dir); > + node->son[dir ^ 1] = _eina_rbtree_inline_single_rotation(node->son[dir ^ > 1], dir ^ 1); > return _eina_rbtree_inline_single_rotation(node, dir); > } > > @@ -277,87 +279,64 @@ > Eina_Rbtree_Cmp_Node_Cb cmp, > const void *data) > { > - Eina_Rbtree head; > - Eina_Rbtree *g, *t; /* Grandparent & parent */ > - Eina_Rbtree *p, *q; /* Iterator & parent */ > - /* WARNING: > - Compiler is not able to understand the underlying algorithm and don't > know that > - first top node is always black, so it will never use last before > running the loop > - one time. > - */ > - Eina_Rbtree_Direction dir, last; > + Eina_Rbtree **r = &root; > + Eina_Rbtree *q = root; > + uintptr_t stack[48]; > + unsigned int s = 0; > > EINA_SAFETY_ON_NULL_RETURN_VAL(node, root); > EINA_SAFETY_ON_NULL_RETURN_VAL( cmp, root); > > - if (!node) > - return root; > + /* Find insertion leaf */ > + while (q != NULL) > + { > + Eina_Rbtree_Direction dir = cmp(q, node, (void *)data); > > - _eina_rbtree_node_init(node); > + /* Keep path in stack */ > + stack[s++] = (uintptr_t)r | dir; > > - if (!root) > - { > - root = node; > - goto end_add; > - } > + r = q->son + dir; > + q = *r; > + } > > - memset(&head, 0, sizeof (Eina_Rbtree)); > - last = dir = EINA_RBTREE_LEFT; > + /* Insert */ > + *r = node; > + _eina_rbtree_node_init(node); > > - /* Set up helpers */ > - t = &head; > - g = p = NULL; > - q = t->son[1] = root; > + /* Rebalance */ > + while (s > 0) > + { > + Eina_Rbtree *a, *b; > + uintptr_t top = stack[--s]; /* Pop link pointer and direction */ > + Eina_Rbtree_Direction dir = top & 1; > > - /* Search down the tree */ > - for (;; ) > - { > - if (!q) > - /* Insert new node at the bottom */ > - p->son[dir] = q = node; > - else if (_eina_rbtree_is_red(q->son[0]) > - && _eina_rbtree_is_red(q->son[1])) > - { > - /* Color flip */ > - q->color = EINA_RBTREE_RED; > - q->son[0]->color = EINA_RBTREE_BLACK; > - q->son[1]->color = EINA_RBTREE_BLACK; > - } > + r = (Eina_Rbtree **)(top & ~1ULL); > + q = *r; > > - /* Fix red violation */ > - if (_eina_rbtree_is_red(q) && _eina_rbtree_is_red(p)) > - { > - Eina_Rbtree_Direction dir2; > + a = q->son[dir]; > + /* Rebalance done ? */ > + if (a == NULL || a->color == EINA_RBTREE_BLACK) > + break; > > - dir2 = (t->son[1] == g) ? EINA_RBTREE_RIGHT : EINA_RBTREE_LEFT; > + b = q->son[dir ^ 1]; > + if (b != NULL && b->color == EINA_RBTREE_RED) > + { > + q->color = EINA_RBTREE_RED; > + b->color = a->color = EINA_RBTREE_BLACK; > + } > + else > + { > + Eina_Rbtree *c = a->son[dir]; > + Eina_Rbtree *d = a->son[dir ^ 1]; > > - if (q == p->son[last]) > - t->son[dir2] = _eina_rbtree_inline_single_rotation(g, !last); > - else > - t->son[dir2] = _eina_rbtree_inline_double_rotation(g, !last); > - } > + if (c != NULL && c->color == EINA_RBTREE_RED) > + *r = _eina_rbtree_inline_single_rotation(*r, dir ^ 1); > + else if (d != NULL && d->color == EINA_RBTREE_RED) > + *r = _eina_rbtree_inline_double_rotation(*r, dir ^ 1); > + } > + } > > - /* Stop if found */ > - if (q == node) > - break; > - > - last = dir; > - dir = cmp(q, node, (void *)data); > - > - /* Update helpers */ > - if ( g ) > - t = g; > - > - g = p, p = q; > - q = q->son[dir]; > - } > - > - root = head.son[1]; > - > -end_add: > - /* Make root black */ > root->color = EINA_RBTREE_BLACK; > - > return root; > } > > @@ -367,122 +346,144 @@ > Eina_Rbtree_Cmp_Node_Cb cmp, > const void *data) > { > - Eina_Rbtree head; > - Eina_Rbtree *q, *p; > - Eina_Rbtree *f = NULL; > + Eina_Rbtree *l0, *l1, *r, **rt = &root; > Eina_Rbtree_Direction dir; > + uintptr_t stack[48]; > + unsigned int s = 0; > > EINA_SAFETY_ON_NULL_RETURN_VAL(node, root); > EINA_SAFETY_ON_NULL_RETURN_VAL( cmp, root); > > - if (!root || !node) > - return root; > + /* Item search loop */ > + for (r = *rt; r != NULL; r = *rt) > + { > + if (r == node) > + goto found; > > - memset(&head, 0, sizeof(Eina_Rbtree)); > + dir = cmp(r, node, (void*)data); > + stack[s++] = (uintptr_t)rt | dir; > + rt = r->son + dir; > + } > + return root; > > - dir = EINA_RBTREE_RIGHT; > - q = &head; > - p = NULL; > - q->son[EINA_RBTREE_RIGHT] = root; > + found: > + /* remove entry */ > + l0 = node->son[0]; > + l1 = node->son[1]; > > - /* Search and push a red down */ > - while (q->son[dir]) > - { > - Eina_Rbtree_Direction last = dir; > - Eina_Rbtree *g; > + if (l0 != NULL && l1 != NULL) /* two links case */ > + { > + Eina_Rbtree *q, **t, **p; > + uintptr_t ss; > > - /* Update helpers */ > - g = p; p = q; > - q = q->son[dir]; > - dir = cmp(q, node, (void *)data); > + stack[s++] = (uintptr_t)rt | 1; > + ss = s; /* keep predecessor right link stack index */ > > - /* Save parent node found */ > - if (q == node) > - f = p; > + /* find predecessor */ > + p = node->son + 1; > + q = *p; > > - /* Push the red node down */ > - if (!_eina_rbtree_is_red(q) > - && !_eina_rbtree_is_red(q->son[dir])) > - { > - if (_eina_rbtree_is_red(q->son[!dir])) > - q = p->son[last] = _eina_rbtree_inline_single_rotation(q, > dir); > - else if (!_eina_rbtree_is_red(q->son[!dir])) > - { > - Eina_Rbtree *s = p->son[!last]; > + while (1) > + { > + t = q->son; > + q = *t; > + if (q == NULL) > + break; > + stack[s++] = (uintptr_t)p | 0; > + p = t; > + } > > - if (s) > - { > - if (!_eina_rbtree_is_red(s->son[EINA_RBTREE_LEFT]) > - && > !_eina_rbtree_is_red(s->son[EINA_RBTREE_RIGHT])) > - { > -/* Color flip */ > - p->color = EINA_RBTREE_BLACK; > - p->son[EINA_RBTREE_LEFT]->color = > EINA_RBTREE_RED; > - p->son[EINA_RBTREE_RIGHT]->color = > EINA_RBTREE_RED; > - } > - else > - { > - Eina_Rbtree_Direction dir2; > + /* detach predecessor */ > + q = *p; > + *p = q->son[1]; > > - dir2 = g->son[1] == > - p ? EINA_RBTREE_RIGHT : EINA_RBTREE_LEFT; > + int c = q->color; > > - if (_eina_rbtree_is_red(s->son[last])) > - { > - g->son[dir2] = > - _eina_rbtree_inline_double_rotation(p, > last); > - if (f == g) > - { > - p = g->son[dir2]->son[last]; > - f = g->son[dir2]; > - } > - } > - else if (_eina_rbtree_is_red(s->son[!last])) > - { > - g->son[dir2] = > - _eina_rbtree_inline_single_rotation(p, > last); > - if (f == g) > - { > - p = g->son[dir2]->son[last]; > - f = g->son[dir2]; > - } > - } > + /* replace entry by predecessor */ > + memcpy(q, node, sizeof(Eina_Rbtree)); > + *rt = q; > > -/* Ensure correct coloring */ > - q->color = g->son[dir2]->color = EINA_RBTREE_RED; > - g->son[dir2]->son[EINA_RBTREE_LEFT]->color = > - EINA_RBTREE_BLACK; > - g->son[dir2]->son[EINA_RBTREE_RIGHT]->color = > - EINA_RBTREE_BLACK; > - } > - } > - } > - } > - } > + if (c == EINA_RBTREE_RED) > + goto end; > > - /* Replace and remove if found */ > - if (f) > - { > - /* 'q' should take the place of 'node' parent */ > - f->son[f->son[1] == node] = q; > + /* fix stack for replaced entry */ > + if (s > ss) > + stack[ss] = (uintptr_t)(q->son + 1) | 0; > + } > + else /* single link case */ > + { > + if (l0 == NULL) > + l0 = l1; > > - /* Switch the link from the parent to q's son */ > - p->son[p->son[1] == q] = q->son[!q->son[0]]; > + *rt = l0; > > - /* Put q at the place of node */ > - q->son[0] = node->son[0]; > - q->son[1] = node->son[1]; > - q->color = node->color; > + if (node->color == EINA_RBTREE_RED) > + goto end; /* removed red */ > > - /* Reset node link */ > - node->son[0] = NULL; > - node->son[1] = NULL; > - } > + if (l0 != NULL && l0->color == EINA_RBTREE_RED) > + { > + /* red child replace removed black */ > + l0->color = EINA_RBTREE_BLACK; > + goto end; > + } > + } > > - root = head.son[1]; > - if (root) > + /* rebalance */ > + while (s > 0) > + { > + Eina_Rbtree *q; > + uintptr_t st = stack[--s]; > + > + rt = (Eina_Rbtree**)(st & ~1ULL); > + dir = st & 1; > + r = *rt; > + q = r->son[dir ^ 1]; > + > + if (q != NULL && q->color == EINA_RBTREE_RED) > + { > + *rt = _eina_rbtree_inline_single_rotation(*rt, dir); > + q = r->son[dir ^ 1]; > + rt = (*rt)->son + dir; > + } > + > + if (q != NULL) > + { > + int r_color = r->color; > + Eina_Rbtree *nd = q->son[dir ^ 1]; > + > + if (nd != NULL && nd->color == EINA_RBTREE_RED) > + { > + *rt = _eina_rbtree_inline_single_rotation(*rt, dir); > + } > + else > + { > + Eina_Rbtree *d = q->son[dir]; > + > + if (d != NULL && d->color == EINA_RBTREE_RED) > + { > + *rt = _eina_rbtree_inline_double_rotation(*rt, > dir); > + } > + else > + { > + r->color = EINA_RBTREE_BLACK; > + q->color = EINA_RBTREE_RED; > + if (r_color == EINA_RBTREE_RED) > + break; > + continue; > + } > + } > + > + r = *rt; > + r->color = r_color; > + r->son[1]->color = r->son[0]->color = EINA_RBTREE_BLACK; > + > + break; > + } > + } > + > + end: > + if (root != NULL) > root->color = EINA_RBTREE_BLACK; > - > return root; > } > > > > ------------------------------------------------------------------------------ > Try before you buy = See our experts in action! > The most comprehensive online learning library for Microsoft developers > is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3, > Metro Style Apps, more. Free future releases when you subscribe now! > http://p.sf.net/sfu/learndevnow-dev2 > _______________________________________________ > enlightenment-svn mailing list > enlightenment-...@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/enlightenment-svn ------------------------------------------------------------------------------ Try before you buy = See our experts in action! The most comprehensive online learning library for Microsoft developers is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3, Metro Style Apps, more. Free future releases when you subscribe now! http://p.sf.net/sfu/learndevnow-dev2 _______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel