/* internal insert routine */ static void g_tree_insert_internal (GTree *tree, gpointer key, gpointer value, gboolean replace) { GTreeNode *node; GTreeNode *path[MAX_GTREE_HEIGHT]; int idx; g_return_if_fail (tree != NULL); if (!tree->root) { tree->root = g_tree_node_new (key, value); tree->nnodes++; return; } idx = 0; path[idx++] = NULL; node = tree->root; while (1) { int cmp = tree->key_compare (key, node->key, tree->key_compare_data); if (cmp == 0) { if (tree->value_destroy_func) tree->value_destroy_func (node->value); node->value = value; if (replace) { if (tree->key_destroy_func) tree->key_destroy_func (node->key); node->key = key; } else { /* free the passed key */ if (tree->key_destroy_func) tree->key_destroy_func (key); } return; } else if (cmp < 0) { if (node->left_child) { path[idx++] = node; node = node->left; } else { GTreeNode *child = g_tree_node_new (key, value); child->left = node->left; child->right = node; node->left = child; node->left_child = TRUE; node->balance -= 1; tree->nnodes++; break; } } else { if (node->right_child) { path[idx++] = node; node = node->right; } else { GTreeNode *child = g_tree_node_new (key, value); child->right = node->right; child->left = node; node->right = child; node->right_child = TRUE; node->balance += 1; tree->nnodes++; break; } } } /* Restore balance. This is the goodness of a non-recursive * implementation, when we are done with balancing we 'break' * the loop and we are done. */ while (1) { GTreeNode *bparent = path[--idx]; gboolean left_node = (bparent && node == bparent->left); g_assert (!bparent || bparent->left == node || bparent->right == node); if (node->balance < -1 || node->balance > 1) { node = g_tree_node_balance (node); if (bparent == NULL) tree->root = node; else if (left_node) bparent->left = node; else bparent->right = node; } if (node->balance == 0 || bparent == NULL) break; if (left_node) bparent->balance -= 1; else bparent->balance += 1; node = bparent; } }
static GTreeNode* g_tree_node_insert (GTree *tree, GTreeNode *node, gpointer key, gpointer value, gboolean replace, gboolean *inserted) { gint old_balance; gint cmp; if (!node) { *inserted = TRUE; return g_tree_node_new (key, value); } cmp = tree->key_compare (key, node->key, tree->key_compare_data); if (cmp == 0) { *inserted = FALSE; if (tree->value_destroy_func) tree->value_destroy_func (node->value); node->value = value; if (replace) { if (tree->key_destroy_func) tree->key_destroy_func (node->key); node->key = key; } else { /* free the passed key */ if (tree->key_destroy_func) tree->key_destroy_func (key); } return node; } if (cmp < 0) { if (node->left) { old_balance = node->left->balance; node->left = g_tree_node_insert (tree, node->left, key, value, replace, inserted); if ((old_balance != node->left->balance) && node->left->balance) node->balance -= 1; } else { *inserted = TRUE; node->left = g_tree_node_new (key, value); node->balance -= 1; } } else if (cmp > 0) { if (node->right) { old_balance = node->right->balance; node->right = g_tree_node_insert (tree, node->right, key, value, replace, inserted); if ((old_balance != node->right->balance) && node->right->balance) node->balance += 1; } else { *inserted = TRUE; node->right = g_tree_node_new (key, value); node->balance += 1; } } if (*inserted) { if ((node->balance < -1) || (node->balance > 1)) node = g_tree_node_balance (node); } return node; }