/* * Copyright (c) 2015 Cray Inc. All rights reserved. * Copyright (c) 2018 Intel Corp, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * Copied from http://oopweb.com/Algorithms/Documents/Sman/VolumeFrames.html?/Algorithms/Documents/Sman/Volume/RedBlackTrees_files/s_rbt.htm * * Disclosure from the author's main page: * (http://oopweb.com/Algorithms/Documents/Sman/VolumeFrames.html?/Algorithms/Documents/Sman/Volume/RedBlackTrees_files/s_rbt.htm) * * Source code when part of a software project may be used freely * without reference to the author. * */ // reentrant red-black tree #include #include #include #include static struct ofi_rbnode *ofi_rbnode_alloc(struct ofi_rbmap *map) { struct ofi_rbnode *node; if (!map->free_list) return malloc(sizeof(*node)); node = map->free_list; map->free_list = node->right; return node; } static void ofi_rbnode_free(struct ofi_rbmap *map, struct ofi_rbnode *node) { node->right = map->free_list ? map->free_list : NULL; map->free_list = node; } void ofi_rbmap_init(struct ofi_rbmap *map, int (*compare)(struct ofi_rbmap *map, void *key, void *data)) { map->compare = compare; map->root = &map->sentinel; map->sentinel.left = &map->sentinel; map->sentinel.right = &map->sentinel; map->sentinel.parent = NULL; map->sentinel.color = BLACK; map->sentinel.data = NULL; } struct ofi_rbmap * ofi_rbmap_create(int (*compare)(struct ofi_rbmap *map, void *key, void *data)) { struct ofi_rbmap *map; map = calloc(1, sizeof *map); if (map) ofi_rbmap_init(map, compare); return map; } static void ofi_delete_tree(struct ofi_rbmap *map, struct ofi_rbnode *node) { if (node == &map->sentinel) return; ofi_delete_tree(map, node->left); ofi_delete_tree(map, node->right); free(node); } void ofi_rbmap_cleanup(struct ofi_rbmap *map) { struct ofi_rbnode *node; ofi_delete_tree(map, map->root); while (map->free_list) { node = map->free_list; map->free_list = node->right; free(node); } } void ofi_rbmap_destroy(struct ofi_rbmap *map) { ofi_rbmap_cleanup(map); free(map); } int ofi_rbmap_empty(struct ofi_rbmap *map) { return map->root == &map->sentinel; } static void ofi_rotate_left(struct ofi_rbmap *map, struct ofi_rbnode *node) { struct ofi_rbnode *y = node->right; node->right = y->left; if (y->left != &map->sentinel) y->left->parent = node; if (y != &map->sentinel) y->parent = node->parent; if (node->parent) { if (node== node->parent->left) node->parent->left = y; else node->parent->right = y; } else { map->root = y; } y->left = node; if (node != &map->sentinel) node->parent = y; } static void ofi_rotate_right(struct ofi_rbmap *map, struct ofi_rbnode *node) { struct ofi_rbnode *y = node->left; node->left = y->right; if (y->right != &map->sentinel) y->right->parent = node; if (y != &map->sentinel) y->parent = node->parent; if (node->parent) { if (node == node->parent->right) node->parent->right = y; else node->parent->left = y; } else { map->root = y; } y->right = node; if (node != &map->sentinel) node->parent = y; } static void ofi_insert_rebalance(struct ofi_rbmap *map, struct ofi_rbnode *x) { struct ofi_rbnode *y; while (x != map->root && x->parent->color == RED) { if (x->parent == x->parent->parent->left) { y = x->parent->parent->right; if (y->color == RED) { x->parent->color = BLACK; y->color = BLACK; x->parent->parent->color = RED; x = x->parent->parent; } else { if (x == x->parent->right) { x = x->parent; ofi_rotate_left(map, x); } x->parent->color = BLACK; x->parent->parent->color = RED; ofi_rotate_right(map, x->parent->parent); } } else { y = x->parent->parent->left; if (y->color == RED) { x->parent->color = BLACK; y->color = BLACK; x->parent->parent->color = RED; x = x->parent->parent; } else { if (x == x->parent->left) { x = x->parent; ofi_rotate_right(map, x); } x->parent->color = BLACK; x->parent->parent->color = RED; ofi_rotate_left(map, x->parent->parent); } } } map->root->color = BLACK; } int ofi_rbmap_insert(struct ofi_rbmap *map, void *key, void *data, struct ofi_rbnode **ret_node) { struct ofi_rbnode *current, *parent, *node; int ret; current = map->root; parent = NULL; while (current != &map->sentinel) { ret = map->compare(map, key, current->data); if (ret == 0) { if (ret_node) *ret_node = current; return -FI_EALREADY; } parent = current; current = (ret < 0) ? current->left : current->right; } node = ofi_rbnode_alloc(map); if (!node) return -FI_ENOMEM; node->parent = parent; node->left = &map->sentinel; node->right = &map->sentinel; node->color = RED; node->data = data; if (parent) { if (map->compare(map, key, parent->data) < 0) parent->left = node; else parent->right = node; } else { map->root = node; } ofi_insert_rebalance(map, node); if (ret_node) *ret_node = node; return 0; } static void ofi_delete_rebalance(struct ofi_rbmap *map, struct ofi_rbnode *node) { struct ofi_rbnode *w; while (node != map->root && node->color == BLACK) { if (node == node->parent->left) { w = node->parent->right; if (w->color == RED) { w->color = BLACK; node->parent->color = RED; ofi_rotate_left(map, node->parent); w = node->parent->right; } if (w->left->color == BLACK && w->right->color == BLACK) { w->color = RED; node = node->parent; } else { if (w->right->color == BLACK) { w->left->color = BLACK; w->color = RED; ofi_rotate_right(map, w); w = node->parent->right; } w->color = node->parent->color; node->parent->color = BLACK; w->right->color = BLACK; ofi_rotate_left(map, node->parent); node = map->root; } } else { w = node->parent->left; if (w->color == RED) { w->color = BLACK; node->parent->color = RED; ofi_rotate_right(map, node->parent); w = node->parent->left; } if (w->right->color == BLACK && w->left->color == BLACK) { w->color = RED; node = node->parent; } else { if (w->left->color == BLACK) { w->right->color = BLACK; w->color = RED; ofi_rotate_left(map, w); w = node->parent->left; } w->color = node->parent->color; node->parent->color = BLACK; w->left->color = BLACK; ofi_rotate_right(map, node->parent); node = map->root; } } } node->color = BLACK; } static void ofi_rbmap_replace_node_ptr(struct ofi_rbmap *map, struct ofi_rbnode *old_node, struct ofi_rbnode *new_node) { if (new_node == old_node) return; *new_node = *old_node; if (!old_node->parent) map->root = new_node; else if (old_node == old_node->parent->left) old_node->parent->left = new_node; else old_node->parent->right = new_node; if (old_node->left != &map->sentinel) old_node->left->parent = new_node; if (old_node->right != &map->sentinel) old_node->right->parent = new_node; } void ofi_rbmap_delete(struct ofi_rbmap *map, struct ofi_rbnode *node) { struct ofi_rbnode *x, *y; if (node->left == &map->sentinel) { y = node; x = y->right; } else if (node->right == &map->sentinel) { y = node; x = y->left; } else { y = node->right; while (y->left != &map->sentinel) y = y->left; x = y->right; } x->parent = y->parent; if (y->parent) { if (y == y->parent->left) y->parent->left = x; else y->parent->right = x; } else { map->root = x; } if (y != node) node->data = y->data; if (y->color == BLACK) ofi_delete_rebalance(map, x); /* swap y in for node, so we can free node */ ofi_rbmap_replace_node_ptr(map, node, y); ofi_rbnode_free(map, node); } struct ofi_rbnode *ofi_rbmap_get_root(struct ofi_rbmap *map) { if (ofi_rbmap_empty(map)) return NULL; return map->root; } struct ofi_rbnode *ofi_rbmap_find(struct ofi_rbmap *map, void *key) { struct ofi_rbnode *node; int ret; node = map->root; while (node != &map->sentinel) { ret = map->compare(map, key, node->data); if (ret == 0) return node; node = (ret < 0) ? node->left : node->right; } return NULL; } int ofi_rbmap_find_delete(struct ofi_rbmap *map, void *key) { struct ofi_rbnode *node; node = ofi_rbmap_find(map, key); if (!node) return -FI_ENODATA; ofi_rbmap_delete(map, node); return 0; } struct ofi_rbnode *ofi_rbmap_search(struct ofi_rbmap *map, void *key, int (*compare)(struct ofi_rbmap *map, void *key, void *data)) { struct ofi_rbnode *node; int ret; node = map->root; while (node != &map->sentinel) { ret = compare(map, key, node->data); if (ret == 0) return node; node = (ret < 0) ? node->left : node->right; } return NULL; }