| /* Balanced binary trees using treaps. |
| Copyright (C) 2000-2022 Free Software Foundation, Inc. |
| Contributed by Andy Vaught |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* The idea is to balance the tree using pseudorandom numbers. The |
| main constraint on this implementation is that we have several |
| distinct structures that have to be arranged in a binary tree. |
| These structures all contain a BBT_HEADER() in front that gives the |
| treap-related information. The key and value are assumed to reside |
| in the rest of the structure. |
| |
| When calling, we are also passed a comparison function that |
| compares two nodes. We don't implement a separate 'find' function |
| here, but rather use separate functions for each variety of tree. |
| We are also restricted to not copy treap structures, which most |
| implementations find convenient, because we otherwise would need to |
| know how long the structure is. |
| |
| This implementation is based on Stefan Nilsson's article in the |
| July 1997 Doctor Dobb's Journal, "Treaps in Java". */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "gfortran.h" |
| |
| typedef struct gfc_treap |
| { |
| BBT_HEADER (gfc_treap); |
| } |
| gfc_bbt; |
| |
| /* Simple linear congruential pseudorandom number generator. The |
| period of this generator is 44071, which is plenty for our |
| purposes. */ |
| |
| static int |
| pseudo_random (void) |
| { |
| static int x0 = 5341; |
| |
| x0 = (22611 * x0 + 10) % 44071; |
| return x0; |
| } |
| |
| |
| /* Rotate the treap left. */ |
| |
| static gfc_bbt * |
| rotate_left (gfc_bbt *t) |
| { |
| gfc_bbt *temp; |
| |
| temp = t->right; |
| t->right = t->right->left; |
| temp->left = t; |
| |
| return temp; |
| } |
| |
| |
| /* Rotate the treap right. */ |
| |
| static gfc_bbt * |
| rotate_right (gfc_bbt *t) |
| { |
| gfc_bbt *temp; |
| |
| temp = t->left; |
| t->left = t->left->right; |
| temp->right = t; |
| |
| return temp; |
| } |
| |
| |
| /* Recursive insertion function. Returns the updated treap, or |
| aborts if we find a duplicate key. */ |
| |
| static gfc_bbt * |
| insert (gfc_bbt *new_bbt, gfc_bbt *t, compare_fn compare) |
| { |
| int c; |
| |
| if (t == NULL) |
| return new_bbt; |
| |
| c = (*compare) (new_bbt, t); |
| |
| if (c < 0) |
| { |
| t->left = insert (new_bbt, t->left, compare); |
| if (t->priority < t->left->priority) |
| t = rotate_right (t); |
| } |
| else if (c > 0) |
| { |
| t->right = insert (new_bbt, t->right, compare); |
| if (t->priority < t->right->priority) |
| t = rotate_left (t); |
| } |
| else /* if (c == 0) */ |
| gfc_internal_error("insert_bbt(): Duplicate key found"); |
| |
| return t; |
| } |
| |
| |
| /* Given root pointer, a new node and a comparison function, insert |
| the new node into the treap. It is an error to insert a key that |
| already exists. */ |
| |
| void |
| gfc_insert_bbt (void *root, void *new_node, compare_fn compare) |
| { |
| gfc_bbt **r, *n; |
| |
| r = (gfc_bbt **) root; |
| n = (gfc_bbt *) new_node; |
| n->priority = pseudo_random (); |
| *r = insert (n, *r, compare); |
| } |
| |
| static gfc_bbt * |
| delete_root (gfc_bbt *t) |
| { |
| gfc_bbt *temp; |
| |
| if (t->left == NULL) |
| return t->right; |
| if (t->right == NULL) |
| return t->left; |
| |
| if (t->left->priority > t->right->priority) |
| { |
| temp = rotate_right (t); |
| temp->right = delete_root (t); |
| } |
| else |
| { |
| temp = rotate_left (t); |
| temp->left = delete_root (t); |
| } |
| |
| return temp; |
| } |
| |
| |
| /* Delete an element from a tree. The 'old' value does not |
| necessarily have to point to the element to be deleted, it must |
| just point to a treap structure with the key to be deleted. |
| Returns the new root node of the tree. */ |
| |
| static gfc_bbt * |
| delete_treap (gfc_bbt *old, gfc_bbt *t, compare_fn compare) |
| { |
| int c; |
| |
| if (t == NULL) |
| return NULL; |
| |
| c = (*compare) (old, t); |
| |
| if (c < 0) |
| t->left = delete_treap (old, t->left, compare); |
| if (c > 0) |
| t->right = delete_treap (old, t->right, compare); |
| if (c == 0) |
| t = delete_root (t); |
| |
| return t; |
| } |
| |
| |
| void |
| gfc_delete_bbt (void *root, void *old, compare_fn compare) |
| { |
| gfc_bbt **t; |
| |
| t = (gfc_bbt **) root; |
| *t = delete_treap ((gfc_bbt *) old, *t, compare); |
| } |