[asterisk-commits] rmudgett: trunk r384616 - /trunk/main/astobj2.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Apr 3 11:01:55 CDT 2013
Author: rmudgett
Date: Wed Apr 3 11:01:51 2013
New Revision: 384616
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=384616
Log:
astobj2: Fix rbtree duplicate handling.
OBJ_PARTIAL_KEY searching a rbtree did not find all possible matches if
the container did not accept duplicates.
Added matching node bias to indicate which matching node is being searched
for: first, last, any.
Modified:
trunk/main/astobj2.c
Modified: trunk/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/astobj2.c?view=diff&rev=384616&r1=384615&r2=384616
==============================================================================
--- trunk/main/astobj2.c (original)
+++ trunk/main/astobj2.c Wed Apr 3 11:01:51 2013
@@ -3468,6 +3468,15 @@
}
}
+enum equal_node_bias {
+ /*! Bias search toward first matching node in the container. */
+ BIAS_FIRST,
+ /*! Bias search toward any matching node. */
+ BIAS_EQUAL,
+ /*! Bias search toward last matching node in the container. */
+ BIAS_LAST,
+};
+
enum empty_node_direction {
GO_LEFT,
GO_RIGHT,
@@ -3485,10 +3494,11 @@
* OBJ_POINTER - if set, 'obj_right', is an object.
* OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
* OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
+ * \param bias How to bias search direction for duplicates
*
* \return enum empty_node_direction to proceed.
*/
-static enum empty_node_direction rb_find_empty_direction(struct rbtree_node *empty, ao2_sort_fn *sort_fn, void *obj_right, enum search_flags flags)
+static enum empty_node_direction rb_find_empty_direction(struct rbtree_node *empty, ao2_sort_fn *sort_fn, void *obj_right, enum search_flags flags, enum equal_node_bias bias)
{
int cmp;
struct rbtree_node *cur;
@@ -3505,6 +3515,9 @@
if (cmp < 0) {
return GO_RIGHT;
}
+ if (cmp == 0 && bias == BIAS_LAST) {
+ return GO_RIGHT;
+ }
return GO_LEFT;
}
@@ -3516,10 +3529,13 @@
cur = rb_node_most_left(empty->right);
if (cur->common.obj) {
cmp = sort_fn(cur->common.obj, obj_right, flags);
- if (cmp <= 0) {
- return GO_RIGHT;
- }
- return GO_LEFT;
+ if (cmp > 0) {
+ return GO_LEFT;
+ }
+ if (cmp == 0 && bias == BIAS_FIRST) {
+ return GO_LEFT;
+ }
+ return GO_RIGHT;
}
/*
@@ -3551,6 +3567,9 @@
if (cur->common.obj) {
cmp = sort_fn(cur->common.obj, obj_right, flags);
if (cmp < 0) {
+ return GO_RIGHT;
+ }
+ if (cmp == 0 && bias == BIAS_LAST) {
return GO_RIGHT;
}
return GO_LEFT;
@@ -4185,6 +4204,7 @@
struct rbtree_node *next;
ao2_sort_fn *sort_fn;
uint32_t options;
+ enum equal_node_bias bias;
if (!self->root) {
/* The tree is empty. */
@@ -4194,6 +4214,21 @@
sort_fn = self->common.sort_fn;
options = self->common.options;
+ switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
+ default:
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
+ if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
+ bias = BIAS_FIRST;
+ } else {
+ bias = BIAS_LAST;
+ }
+ break;
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
+ bias = BIAS_EQUAL;
+ break;
+ }
/*
* New nodes are always colored red when initially inserted into
@@ -4206,7 +4241,7 @@
for (;;) {
if (!cur->common.obj) {
/* Which direction do we go to insert this node? */
- if (rb_find_empty_direction(cur, sort_fn, node->common.obj, OBJ_POINTER)
+ if (rb_find_empty_direction(cur, sort_fn, node->common.obj, OBJ_POINTER, bias)
== GO_LEFT) {
if (cur->left) {
cur = cur->left;
@@ -4254,6 +4289,34 @@
rb_insert_fixup(self, node);
return AO2_CONTAINER_INSERT_NODE_INSERTED;
}
+ switch (bias) {
+ case BIAS_FIRST:
+ /* Duplicate nodes unconditionally accepted. */
+ if (cur->left) {
+ cur = cur->left;
+ continue;
+ }
+
+ /* Node becomes a left child */
+ cur->left = node;
+ node->parent = cur;
+ rb_insert_fixup(self, node);
+ return AO2_CONTAINER_INSERT_NODE_INSERTED;
+ case BIAS_EQUAL:
+ break;
+ case BIAS_LAST:
+ /* Duplicate nodes unconditionally accepted. */
+ if (cur->right) {
+ cur = cur->right;
+ continue;
+ }
+
+ /* Node becomes a right child */
+ cur->right = node;
+ node->parent = cur;
+ rb_insert_fixup(self, node);
+ return AO2_CONTAINER_INSERT_NODE_INSERTED;
+ }
break;
}
@@ -4262,50 +4325,8 @@
switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
default:
case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
- if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
- /* Find first duplicate node. */
- for (;;) {
- next = rb_node_prev_full(cur);
- if (!next) {
- break;
- }
- cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
- if (cmp) {
- break;
- }
- cur = next;
- }
- if (!cur->left) {
- /* Node becomes a left child */
- cur->left = node;
- } else {
- /* Node becomes a right child */
- cur = rb_node_most_right(cur->left);
- cur->right = node;
- }
- } else {
- /* Find last duplicate node. */
- for (;;) {
- next = rb_node_next_full(cur);
- if (!next) {
- break;
- }
- cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
- if (cmp) {
- break;
- }
- cur = next;
- }
- if (!cur->right) {
- /* Node becomes a right child */
- cur->right = node;
- } else {
- /* Node becomes a left child */
- cur = rb_node_most_left(cur->right);
- cur->left = node;
- }
- }
- break;
+ ast_assert(0);/* Case already handled by BIAS_FIRST/BIAS_LAST. */
+ return AO2_CONTAINER_INSERT_NODE_REJECTED;
case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
/* Reject all objects with the same key. */
return AO2_CONTAINER_INSERT_NODE_REJECTED;
@@ -4545,16 +4566,17 @@
* OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
* OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
* OBJ_CONTINUE - if set, return node right before or right after search key if not a match.
+ * \param bias How to bias search direction for duplicates
*
* \retval node on success.
* \retval NULL if not found.
*/
-static struct rbtree_node *rb_find_initial(struct ao2_container_rbtree *self, void *obj_right, enum search_flags flags)
+static struct rbtree_node *rb_find_initial(struct ao2_container_rbtree *self, void *obj_right, enum search_flags flags, enum equal_node_bias bias)
{
int cmp;
enum search_flags sort_flags;
struct rbtree_node *node;
- struct rbtree_node *next;
+ struct rbtree_node *next = NULL;
ao2_sort_fn *sort_fn;
sort_flags = flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY);
@@ -4568,13 +4590,34 @@
for (;;) {
if (!node->common.obj) {
/* Which direction do we go to find the node? */
- if (rb_find_empty_direction(node, sort_fn, obj_right, sort_flags)
+ if (rb_find_empty_direction(node, sort_fn, obj_right, sort_flags, bias)
== GO_LEFT) {
next = node->left;
} else {
next = node->right;
}
if (!next) {
+ switch (bias) {
+ case BIAS_FIRST:
+ /* Check successor node for match. */
+ next = rb_node_next_full(node);
+ break;
+ case BIAS_EQUAL:
+ break;
+ case BIAS_LAST:
+ /* Check previous node for match. */
+ next = rb_node_prev_full(node);
+ break;
+ }
+ if (next) {
+ cmp = sort_fn(next->common.obj, obj_right, sort_flags);
+ if (cmp == 0) {
+ /* Found the first/last matching node. */
+ return next;
+ }
+ next = NULL;
+ }
+
/* No match found. */
if (flags & OBJ_CONTINUE) {
next = rb_node_next_full(node);
@@ -4591,9 +4634,46 @@
} else if (cmp < 0) {
next = node->right;
} else {
- return node;
+ switch (bias) {
+ case BIAS_FIRST:
+ next = node->left;
+ break;
+ case BIAS_EQUAL:
+ return node;
+ case BIAS_LAST:
+ next = node->right;
+ break;
+ }
+ if (!next) {
+ /* Found the first/last matching node. */
+ return node;
+ }
}
if (!next) {
+ switch (bias) {
+ case BIAS_FIRST:
+ if (cmp < 0) {
+ /* Check successor node for match. */
+ next = rb_node_next_full(node);
+ }
+ break;
+ case BIAS_EQUAL:
+ break;
+ case BIAS_LAST:
+ if (cmp > 0) {
+ /* Check previous node for match. */
+ next = rb_node_prev_full(node);
+ }
+ break;
+ }
+ if (next) {
+ cmp = sort_fn(next->common.obj, obj_right, sort_flags);
+ if (cmp == 0) {
+ /* Found the first/last matching node. */
+ return next;
+ }
+ }
+
/* No match found. */
if (flags & OBJ_CONTINUE) {
return node;
@@ -4620,9 +4700,8 @@
*/
static struct rbtree_node *rb_ao2_find_first(struct ao2_container_rbtree *self, enum search_flags flags, void *arg, struct rbtree_traversal_state *state)
{
- struct rbtree_node *next;
struct rbtree_node *node;
- int cmp;
+ enum equal_node_bias bias;
if (self->common.destroying) {
/* Force traversal to be post order for tree destruction. */
@@ -4663,32 +4742,25 @@
}
/* Search for initial node. */
- node = rb_find_initial(self, arg, flags);
- if (!node) {
- return NULL;
- }
switch (self->common.options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
+ if ((flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) != OBJ_PARTIAL_KEY) {
+ /* There are no duplicates allowed. */
+ bias = BIAS_EQUAL;
+ break;
+ }
+ /* Fall through */
default:
case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
/* Find first duplicate node. */
- for (;;) {
- next = rb_node_prev_full(node);
- if (!next) {
- break;
- }
- cmp = state->sort_fn(next->common.obj, arg,
- flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
- if (cmp) {
- break;
- }
- node = next;
- }
+ bias = BIAS_FIRST;
break;
- case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
- case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
- /* There are no duplicates allowed. */
- break;
+ }
+ node = rb_find_initial(self, arg, flags, bias);
+ if (!node) {
+ return NULL;
}
break;
case OBJ_ORDER_DESCENDING:
@@ -4705,32 +4777,25 @@
}
/* Search for initial node. */
- node = rb_find_initial(self, arg, flags);
- if (!node) {
- return NULL;
- }
switch (self->common.options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
+ if ((flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) != OBJ_PARTIAL_KEY) {
+ /* There are no duplicates allowed. */
+ bias = BIAS_EQUAL;
+ break;
+ }
+ /* Fall through */
default:
case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
/* Find last duplicate node. */
- for (;;) {
- next = rb_node_next_full(node);
- if (!next) {
- break;
- }
- cmp = state->sort_fn(next->common.obj, arg,
- flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
- if (cmp) {
- break;
- }
- node = next;
- }
+ bias = BIAS_LAST;
break;
- case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
- case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
- /* There are no duplicates allowed. */
- break;
+ }
+ node = rb_find_initial(self, arg, flags, bias);
+ if (!node) {
+ return NULL;
}
break;
case OBJ_ORDER_PRE:
More information about the asterisk-commits
mailing list