int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order, int (*callback)(void *, void *), void *context);
/*
+ * Find a matching data item in an rbtree and, if one is found,
+ * perform a callback on it.
+ *
+ * The callback is similar to rbtree_walk above, except that a
+ * positive return code from the callback will cause the found node
+ * to be deleted from the tree. If the tree was created with
+ * RBTREE_FLAG_LOCK, then the entire find/callback/delete/rebalance
+ * sequence happens while the lock is held.
+ *
+ * Note that the callback MUST NOT alter any of the data which
+ * is used as the rbtree key, nor attempt to alter the rest of
+ * the rbtree in any way.
+ *
+ * Returns a pointer to the user data in the found node, or NULL if the
+ * item was not found, or NULL if the item was deleted and the tree was
+ * created with a freeNode garbage collection routine.
+ */
+void *rbtree_callbydata(rbtree_t *tree, void const *Data, int (*callback)(void *, void *), void *context);
+
+/*
* FIFOs
*/
typedef struct fr_fifo_t fr_fifo_t;
/*
* Delete an element from the tree.
*/
-void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
+static void rbtree_delete_internal(rbtree_t *tree, rbnode_t *Z, int skiplock)
{
rbnode_t *X, *Y;
rbnode_t *Parent;
if (!Z || Z == NIL) return;
- PTHREAD_MUTEX_LOCK(tree);
+ if (!skiplock) {
+ PTHREAD_MUTEX_LOCK(tree);
+ }
if (Z->Left == NIL || Z->Right == NIL) {
/* Y has a NIL node as a child */
}
tree->num_elements--;
- PTHREAD_MUTEX_UNLOCK(tree);
+ if (!skiplock) {
+ PTHREAD_MUTEX_UNLOCK(tree);
+ }
+}
+void rbtree_delete(rbtree_t *tree, rbnode_t *Z) {
+ rbtree_delete_internal(tree, Z, 0);
}
/*
}
/*
+ * Find a node by data, perform a callback, and perhaps delete the node.
+ */
+void *rbtree_callbydata(rbtree_t *tree, void const *Data,
+ int (*callback)(void *, void *), void *context) {
+
+ /*******************************
+ * find node containing Data *
+ *******************************/
+
+ rbnode_t *Current;
+
+
+ PTHREAD_MUTEX_LOCK(tree);
+ Current = tree->Root;
+
+ while (Current != NIL) {
+ int result = tree->Compare(Data, Current->Data);
+
+ if (result == 0) {
+ void *data = Current->Data;
+
+ if (callback(context, data) > 0) {
+ rbtree_delete_internal(tree, Current, 1);
+ if (tree->freeNode) {
+ data = NULL;
+ }
+ }
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return data;
+ } else {
+ Current = (result < 0) ?
+ Current->Left : Current->Right;
+ }
+ }
+
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return NULL;
+}
+
+/*
* Walk the tree, Pre-order
*
* We call ourselves recursively for each function, but that's OK,