/* Balanced binary trees using treaps. | |

Copyright (C) 2000-2020 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); | |

} |