static int silc_avl_tree_rot_left(SilcTree *tree, SilcTreeHeader *h) { SilcTreeHeader *right, *parent; int hc; SILC_ASSERT(h); SILC_ASSERT(h->right); right = h->right; h->right = right->left; if (right->left) right->left->parent = h; parent = h->parent; right->parent = parent; if (parent) { if (parent->left == h) parent->left = right; else parent->right = right; } else { tree->root = right; } right->left = h; h->parent = right; hc = right->t != 0; h->t -= 1 + SILC_MAX(right->t, 0); right->t -= 1 - SILC_MIN(h->t, 0); return hc; }
static int silc_avl_tree_rot_right(SilcTree *tree, SilcTreeHeader *h) { SilcTreeHeader *left, *parent; int hc; SILC_ASSERT(h); SILC_ASSERT(h->left); left = h->left; h->left = left->right; if (left->right) left->right->parent = h; parent = h->parent; left->parent = parent; if (parent) { if (parent->left == h) parent->left = left; else parent->right = left; } else { tree->root = left; } left->right = h; h->parent = left; hc = left->t != 0; h->t += 1 - SILC_MIN(left->t, 0); left->t += 1 + SILC_MAX(h->t, 0); return hc; }
void silc_mutex_assert_locked(SilcMutex mutex) { #ifdef SILC_THREADS if (mutex) SILC_ASSERT(mutex->locked); #endif /* SILC_THREADS */ }
void silc_mutex_unlock(SilcMutex mutex) { #ifdef SILC_THREADS if (mutex) { SILC_ASSERT(mutex->locked == TRUE); mutex->locked = FALSE; LeaveCriticalSection(&mutex->mutex); } #endif /* SILC_THREADS */ }
void silc_mutex_lock(SilcMutex mutex) { #ifdef SILC_THREADS if (mutex) { EnterCriticalSection(&mutex->mutex); SILC_ASSERT(mutex->locked == FALSE); mutex->locked = TRUE; } #endif /* SILC_THREADS */ }
SilcBool silc_avl_tree_del(SilcTree *tree, void *entry) { SilcTreeHeader *h, *q, *out, *parent = NULL, tmp; int left; SILC_TREE_DEBUG(("AVL tree %p, delete %p", tree, entry)); if (!tree->root || !entry) { silc_set_errno_nofail(SILC_ERR_INVALID_ARGUMENT); return FALSE; } /* Unless the incoming entry is already the one to be deleted find it from the tree first. */ q = h = SILC_TREE_GET_HEADER(tree, entry); if (!h->parent && !h->left && !h->right && !h->t) { entry = silc_avl_tree_find(tree, entry, NULL, NULL); if (!entry) return FALSE; q = h = SILC_TREE_GET_HEADER(tree, entry); } /* If entry has duplicates, replace this with one of them */ if (h->dup) { h->dup->duplicate = FALSE; h->dup->parent = h->parent; h->dup->left = h->left; h->dup->right = h->right; h->dup->t = h->t; /* Update parent */ if (h->parent) { if (h->parent->left == h) h->parent->left = h->dup; else h->parent->right = h->dup; } else { tree->root = h->dup; } /* Update leafs */ if (h->left) h->left->parent = h->dup; if (h->right) h->right->parent = h->dup; /* Cleanup the deleted entry */ SILC_TREE_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h))); h->parent = h->left = h->right = h->dup = NULL; h->t = 0; tree->count--; return TRUE; } /* If the entry is not a leaf, swap with the smallest from right side */ if (h->left && h->right) { for (q = out = h->right; out->left; q = out = out->left) ; tmp = *h; *h = *out; *out = tmp; /* Update node's parent with the replaced node */ if (out->parent) { if (out->parent->left == h) out->parent->left = out; else out->parent->right = out; } else { tree->root = out; } /* Update parents and leafs */ if (h->parent == h) h->parent = out; if (out->left == out) out->left = h; else if (out->right == out) out->right = h; out->left->parent = out; out->right->parent = out; } parent = h->parent; out = h->left ? h->left : h->right; if (out) out->parent = parent; /* Cleanup the deleted entry */ SILC_TREE_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h))); h->parent = h->left = h->right = h->dup = NULL; h->t = 0; if (!parent) { tree->root = out; tree->count--; return TRUE; } /* Update parent */ left = parent->left == q; if (left) parent->left = out; else parent->right = out; /* Balance */ for (;;) { if (left) { if (++parent->t == 0) { h = parent; goto higher; } if (parent->t == 2) { SILC_ASSERT(parent->right); if (parent->right->t < 0) { silc_avl_tree_rot_right(tree, parent->right); silc_avl_tree_rot_left(tree, parent); } else { SILC_ASSERT(parent->right->right); if (silc_avl_tree_rot_left(tree, parent) == 0) break; } } else { break; } } else { if (--parent->t == 0) { h = parent; goto higher; } if (parent->t == (-2)) { SILC_ASSERT(parent->left); if (parent->left->t > 0) { silc_avl_tree_rot_left(tree, parent->left); silc_avl_tree_rot_right(tree, parent); } else { SILC_ASSERT(parent->left->left); if (silc_avl_tree_rot_right(tree, parent) == 0) break; } } else { break; } } /* Only get here on double rotations or single rotations that changed subtree height - in either event, `parent->parent' is positioned where `parent' was positioned before any rotations. */ h = parent->parent; higher: if ((parent = h->parent) == NULL) break; left = parent->left == h; } tree->count--; return TRUE; }
SilcBool silc_avl_tree_add(SilcTree *tree, void *entry) { SilcTreeHeader *h, *parent = NULL, *q = NULL; int ret = 0; SILC_TREE_DEBUG(("AVL tree %p, adding %p", tree, entry)); /* If tree is empty, add to root */ if (!tree->root) { h = SILC_TREE_GET_HEADER(tree, entry); h->parent = h->left = h->right = h->dup = NULL; h->t = 0; tree->root = h; SILC_TREE_DEBUG(("Entry %p added as root", entry)); SILC_ASSERT(!tree->count); tree->count = 1; return TRUE; } /* Find the spot to add the new entry */ h = tree->root; while (h) { /* Same entry context must not be in tree */ if (entry == SILC_TREE_GET_ENTRY(tree, h)) { silc_set_errno_nofail(SILC_ERR_ALREADY_EXISTS); return FALSE; } ret = tree->compare(entry, SILC_TREE_GET_ENTRY(tree, h), tree->context); if (!tree->duplicates && ret == SILC_COMPARE_EQUAL_TO) { silc_set_errno_nofail(SILC_ERR_ALREADY_EXISTS); return FALSE; } /* Duplicate entry, add to list */ if (ret == SILC_COMPARE_EQUAL_TO) { q = SILC_TREE_GET_HEADER(tree, entry); q->duplicate = TRUE; q->parent = h; if (h->dup) h->dup->parent = q; q->dup = h->dup; h->dup = q; SILC_TREE_DEBUG(("Entry %p is duplicate to %p", entry, SILC_TREE_GET_ENTRY(tree, h))); tree->count++; return TRUE; } parent = h; if (parent->t) q = parent; h = ret > 0 ? h->right : h->left; } /* Update parent */ h = SILC_TREE_GET_HEADER(tree, entry); if (ret < 0) parent->left = h; else parent->right = h; SILC_TREE_DEBUG(("Entry %p added, parent %p", entry, SILC_TREE_GET_ENTRY(tree, parent))); /* Update the new entry */ h->parent = parent; h->left = h->right = h->dup = NULL; h->t = 0; /* Balance */ while (parent != q) { parent->t = (parent->right == h) * 2 - 1; h = parent; parent = h->parent; } if (q) { if (q->left == h) { if (--q->t == (-2)) { if (q->left->t > 0) silc_avl_tree_rot_left(tree, q->left); silc_avl_tree_rot_right(tree, q); } } else { if (++q->t == 2) { if (q->right->t < 0) silc_avl_tree_rot_right(tree, q->right); silc_avl_tree_rot_left(tree, q); } } } tree->count++; return TRUE; }