mirror of
				https://github.com/nextepc/nextepc-oss.git
				synced 2025-11-04 05:43:13 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			435 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			435 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
 | 
						|
 *
 | 
						|
 * This file is part of Open5GS.
 | 
						|
 *
 | 
						|
 * This program is free software: you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU Affero General Public License as published by
 | 
						|
 * the Free Software Foundation, either version 3 of the License, or
 | 
						|
 * (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
#include "ogs-core.h"
 | 
						|
 | 
						|
static ogs_inline void rb_change_child(ogs_rbtree_t *tree,
 | 
						|
        ogs_rbnode_t *old, ogs_rbnode_t *new, ogs_rbnode_t *parent)
 | 
						|
{
 | 
						|
    if (parent) {
 | 
						|
        if (old == parent->left)
 | 
						|
            parent->left = new;
 | 
						|
        else
 | 
						|
            parent->right = new;
 | 
						|
    } else {
 | 
						|
        tree->root = new;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static ogs_inline void rb_replace_node(ogs_rbtree_t *tree,
 | 
						|
        ogs_rbnode_t *old, ogs_rbnode_t *new, ogs_rbnode_t *parent)
 | 
						|
{
 | 
						|
    rb_change_child(tree, old, new, parent);
 | 
						|
 | 
						|
    if (new)
 | 
						|
        new->parent = parent;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Example - Left rotate at A
 | 
						|
 *
 | 
						|
 *       A            B 
 | 
						|
 *      / \          / \
 | 
						|
 *     B   C  <--   D   A
 | 
						|
 *    / \ / \      / \ / \
 | 
						|
 *   D  3 4  5    1  2 3  C
 | 
						|
 *  / \                  / \
 | 
						|
 * 1   2                1   2
 | 
						|
 */
 | 
						|
static void rb_rotate_left(ogs_rbtree_t *tree, ogs_rbnode_t *node)
 | 
						|
{
 | 
						|
    ogs_rbnode_t *right = node->right;
 | 
						|
    node->right = right->left;
 | 
						|
    if (right->left)
 | 
						|
        right->left->parent = node;
 | 
						|
 | 
						|
    rb_replace_node(tree, node, right, node->parent);
 | 
						|
 | 
						|
    right->left = node;
 | 
						|
    node->parent = right;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Example - right rotate at A
 | 
						|
 *
 | 
						|
 *       A            B 
 | 
						|
 *      / \          / \
 | 
						|
 *     B   C  -->   D   A
 | 
						|
 *    / \ / \      / \ / \
 | 
						|
 *   D  3 4  5    1  2 3  C
 | 
						|
 *  / \                  / \
 | 
						|
 * 1   2                1   2
 | 
						|
 */
 | 
						|
static void rb_rotate_right(ogs_rbtree_t *tree, ogs_rbnode_t *node)
 | 
						|
{
 | 
						|
    ogs_rbnode_t *left = node->left;
 | 
						|
    node->left = left->right;
 | 
						|
    if (left->right)
 | 
						|
        left->right->parent = node;
 | 
						|
 | 
						|
    rb_replace_node(tree, node, left, node->parent);
 | 
						|
 | 
						|
    left->right = node;
 | 
						|
    node->parent = left;
 | 
						|
}
 | 
						|
 | 
						|
void ogs_rbtree_insert_color(ogs_rbtree_t *tree, void *rb_node)
 | 
						|
{
 | 
						|
    ogs_rbnode_t *node = rb_node;
 | 
						|
    ogs_rbnode_t *parent;
 | 
						|
    ogs_assert(tree);
 | 
						|
    ogs_assert(node);
 | 
						|
 | 
						|
    while ((parent = node->parent) && parent->color == OGS_RBTREE_RED) {
 | 
						|
        ogs_rbnode_t *gparent = parent->parent;
 | 
						|
        ogs_assert(gparent);
 | 
						|
 | 
						|
        /* parent == grandparent's left child */
 | 
						|
        if (parent == gparent->left) {
 | 
						|
            ogs_rbnode_t *uncle = gparent->right;
 | 
						|
 | 
						|
            if (uncle && uncle->color == OGS_RBTREE_RED) {
 | 
						|
                /*
 | 
						|
                 * node's uncle == red (color flips)
 | 
						|
                 *
 | 
						|
                 *       G            g
 | 
						|
                 *      / \          / \
 | 
						|
                 *     p   u  -->   P   U
 | 
						|
                 *    /            /
 | 
						|
                 *   n            n
 | 
						|
                 */
 | 
						|
                uncle->color = OGS_RBTREE_BLACK;
 | 
						|
                parent->color = OGS_RBTREE_BLACK;
 | 
						|
 | 
						|
                gparent->color = OGS_RBTREE_RED;
 | 
						|
 | 
						|
                node = gparent;
 | 
						|
            } else {
 | 
						|
                /* node's uncle == black */
 | 
						|
                if (node == parent->right) {
 | 
						|
                    /*
 | 
						|
                     * node == the parent's right child,
 | 
						|
                     * (left rotate at parent)
 | 
						|
                     *
 | 
						|
                     *      G             G
 | 
						|
                     *     / \           / \
 | 
						|
                     *    p   U  -->    p   U
 | 
						|
                     *     \           /
 | 
						|
                     *      n         n
 | 
						|
                     */
 | 
						|
                    node = node->parent;
 | 
						|
                    rb_rotate_left(tree, node);
 | 
						|
                }
 | 
						|
 | 
						|
                /*
 | 
						|
                 * Now we're the left child
 | 
						|
                 * (right rotate at grand parent)
 | 
						|
                 *
 | 
						|
                 *      g           P
 | 
						|
                 *     / \         / \
 | 
						|
                 *    P   U  -->  n   g
 | 
						|
                 *   /                 \
 | 
						|
                 *  n                   U
 | 
						|
                 */
 | 
						|
                node->parent->color = OGS_RBTREE_BLACK;
 | 
						|
                gparent->color = OGS_RBTREE_RED;
 | 
						|
                rb_rotate_right(tree, gparent);
 | 
						|
            }
 | 
						|
        /* parent  == grandparent's right child */
 | 
						|
        } else {
 | 
						|
            ogs_rbnode_t *uncle = gparent->left;
 | 
						|
 | 
						|
            if (uncle && uncle->color == OGS_RBTREE_RED) {
 | 
						|
                /*
 | 
						|
                 * node's uncle == red (color flips)
 | 
						|
                 *
 | 
						|
                 *       G            g
 | 
						|
                 *      / \          / \
 | 
						|
                 *     u   p  -->   U   P
 | 
						|
                 *          \            \
 | 
						|
                 *           n            n
 | 
						|
                 */
 | 
						|
                uncle->color = OGS_RBTREE_BLACK;
 | 
						|
                parent->color = OGS_RBTREE_BLACK;
 | 
						|
 | 
						|
                gparent->color = OGS_RBTREE_RED;
 | 
						|
 | 
						|
                node = gparent;
 | 
						|
            } else {
 | 
						|
                /* node's uncle == black */
 | 
						|
                if (node == parent->left) {
 | 
						|
                    /*
 | 
						|
                     * node == the parent's left child,
 | 
						|
                     * (right rotate at parent)
 | 
						|
                     *
 | 
						|
                     *      G             G
 | 
						|
                     *     / \           / \
 | 
						|
                     *    p   U  -->    p   U
 | 
						|
                     *   /               \
 | 
						|
                     *  n                 n
 | 
						|
                     */
 | 
						|
                    node = node->parent;
 | 
						|
                    rb_rotate_right(tree, node);
 | 
						|
                }
 | 
						|
 | 
						|
                /*
 | 
						|
                 * Now we're the right child,
 | 
						|
                 * (left rotate at grand parent)
 | 
						|
                 *
 | 
						|
                 *      g           P
 | 
						|
                 *     / \         / \
 | 
						|
                 *    P   U  -->  n   g
 | 
						|
                 *     \               \
 | 
						|
                 *      n               U
 | 
						|
                 */
 | 
						|
                node->parent->color = OGS_RBTREE_BLACK;
 | 
						|
                gparent->color = OGS_RBTREE_RED;
 | 
						|
                rb_rotate_left(tree, gparent);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    ogs_assert(tree->root);
 | 
						|
    tree->root->color = OGS_RBTREE_BLACK;
 | 
						|
}
 | 
						|
 | 
						|
static void rb_delete_color(
 | 
						|
    ogs_rbtree_t *tree, ogs_rbnode_t *node, ogs_rbnode_t *parent)
 | 
						|
{
 | 
						|
    ogs_rbnode_t *sibling;
 | 
						|
    ogs_assert(tree);
 | 
						|
 | 
						|
#define rb_is_black(r) ((!r) || (r)->color == OGS_RBTREE_BLACK)
 | 
						|
    while (node != tree->root && rb_is_black(node)) {
 | 
						|
        if (node == parent->left) {
 | 
						|
            sibling = parent->right;
 | 
						|
            if (sibling->color == OGS_RBTREE_RED) {
 | 
						|
                /*
 | 
						|
                 * Case 1 - left rotate at parent
 | 
						|
                 *
 | 
						|
                 *     P               S
 | 
						|
                 *    / \             / \
 | 
						|
                 *   N   s    -->    p   Sr
 | 
						|
                 *      / \         / \
 | 
						|
                 *     Sl  Sr      N   Sl
 | 
						|
                 */
 | 
						|
                sibling->color = OGS_RBTREE_BLACK;
 | 
						|
                parent->color = OGS_RBTREE_RED;
 | 
						|
                rb_rotate_left(tree, parent);
 | 
						|
                sibling = parent->right;
 | 
						|
            }
 | 
						|
            if (rb_is_black(sibling->left) && rb_is_black(sibling->right)) {
 | 
						|
                /*
 | 
						|
                 * Case 2 - sibling color flip
 | 
						|
                 * (p could be either color here)
 | 
						|
                 *
 | 
						|
                 *    (p)           (p)
 | 
						|
                 *    / \           / \
 | 
						|
                 *   N   S    -->  N   s
 | 
						|
                 *      / \           / \
 | 
						|
                 *     Sl  Sr        Sl  Sr
 | 
						|
                 */
 | 
						|
                sibling->color = OGS_RBTREE_RED;
 | 
						|
                node = parent;
 | 
						|
                parent = node->parent;
 | 
						|
            } else {
 | 
						|
                if (rb_is_black(sibling->right)) {
 | 
						|
                    /*
 | 
						|
                     * Case 3 - right rotate at sibling
 | 
						|
                     * (p could be either color here)
 | 
						|
                     *
 | 
						|
                     *   (p)           (p)
 | 
						|
                     *   / \           / \
 | 
						|
                     *  N   S    -->  N   Sl
 | 
						|
                     *     / \             \
 | 
						|
                     *    sl  Sr            s
 | 
						|
                     *                       \
 | 
						|
                     *                        Sr
 | 
						|
                     */
 | 
						|
                    sibling->left->color = OGS_RBTREE_BLACK;
 | 
						|
                    sibling->color = OGS_RBTREE_RED;
 | 
						|
                    rb_rotate_right(tree, sibling);
 | 
						|
                    sibling = parent->right;
 | 
						|
                }
 | 
						|
                /*
 | 
						|
                 * Case 4 - left rotate at parent + color flips
 | 
						|
                 * (p and sl could be either color here.
 | 
						|
                 *  After rotation, p becomes black, s acquires
 | 
						|
                 *  p's color, and sl keeps its color)
 | 
						|
                 *
 | 
						|
                 *      (p)             (s)
 | 
						|
                 *      / \             / \
 | 
						|
                 *     N   S     -->   P   Sr
 | 
						|
                 *        / \         / \
 | 
						|
                 *      (sl) sr      N  (sl)
 | 
						|
                 */
 | 
						|
                sibling->color = parent->color;
 | 
						|
                parent->color = OGS_RBTREE_BLACK;
 | 
						|
                sibling->right->color = OGS_RBTREE_BLACK;
 | 
						|
                rb_rotate_left(tree, parent);
 | 
						|
                node = tree->root;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            sibling = parent->left;
 | 
						|
            if (sibling->color == OGS_RBTREE_RED) {
 | 
						|
                sibling->color = OGS_RBTREE_BLACK;
 | 
						|
                parent->color = OGS_RBTREE_RED;
 | 
						|
                /* Case 1 - right rotate at parent */
 | 
						|
                rb_rotate_right(tree, parent);
 | 
						|
                sibling = parent->left;
 | 
						|
            }
 | 
						|
            if (rb_is_black(sibling->left) && rb_is_black(sibling->right)) {
 | 
						|
                /* Case 2 - sibling color flip */
 | 
						|
                sibling->color = OGS_RBTREE_RED;
 | 
						|
                node = parent;
 | 
						|
                parent = node->parent;
 | 
						|
            } else {
 | 
						|
                if (rb_is_black(sibling->left)) {
 | 
						|
                    sibling->right->color = OGS_RBTREE_BLACK;
 | 
						|
                    sibling->color = OGS_RBTREE_RED;
 | 
						|
                    /* Case 3 - left rotate at sibling */
 | 
						|
                    rb_rotate_left(tree, sibling);
 | 
						|
                    sibling = parent->left;
 | 
						|
                }
 | 
						|
                /* Case 4 - right rotate at parent + color flips */
 | 
						|
                sibling->color = parent->color;
 | 
						|
                parent->color = OGS_RBTREE_BLACK;
 | 
						|
                sibling->left->color = OGS_RBTREE_BLACK;
 | 
						|
                rb_rotate_right(tree, parent);
 | 
						|
                node = tree->root;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (node)
 | 
						|
        node->color = OGS_RBTREE_BLACK;
 | 
						|
}
 | 
						|
 | 
						|
void ogs_rbtree_delete(ogs_rbtree_t *tree, void *rb_node)
 | 
						|
{
 | 
						|
    ogs_rbnode_t *node = rb_node;
 | 
						|
    ogs_rbnode_t *child, *parent;
 | 
						|
    ogs_rbtree_color_e color;
 | 
						|
    ogs_assert(tree);
 | 
						|
    ogs_assert(node);
 | 
						|
 | 
						|
    if (!node->left) {
 | 
						|
        child = node->right;
 | 
						|
        parent = node->parent;
 | 
						|
        color = node->color;
 | 
						|
 | 
						|
        rb_replace_node(tree, node, child, parent);
 | 
						|
    } else if (!node->right) {
 | 
						|
        child = node->left;
 | 
						|
        parent = node->parent;
 | 
						|
        color = node->color;
 | 
						|
 | 
						|
        rb_replace_node(tree, node, child, parent);
 | 
						|
    } else {
 | 
						|
        ogs_rbnode_t *new = ogs_rbtree_min(node->right);
 | 
						|
 | 
						|
        child = new->right;
 | 
						|
        parent = new->parent;
 | 
						|
        color = new->color;
 | 
						|
 | 
						|
        new->left = node->left;
 | 
						|
        node->left->parent = new;
 | 
						|
 | 
						|
        if (parent == node) {
 | 
						|
            parent = new;
 | 
						|
        } else {
 | 
						|
            if (child) {
 | 
						|
                child->parent = parent;
 | 
						|
            }
 | 
						|
            parent->left = child;
 | 
						|
 | 
						|
            new->right = node->right;
 | 
						|
            node->right->parent = new;
 | 
						|
        }
 | 
						|
 | 
						|
        new->color = node->color;
 | 
						|
 | 
						|
        rb_replace_node(tree, node, new, node->parent);
 | 
						|
    }
 | 
						|
 | 
						|
    if (color == OGS_RBTREE_BLACK)
 | 
						|
        rb_delete_color(tree, child, parent);
 | 
						|
}
 | 
						|
 | 
						|
void *ogs_rbtree_first(const ogs_rbtree_t *tree)
 | 
						|
{
 | 
						|
    ogs_rbnode_t *node;
 | 
						|
    ogs_assert(tree);
 | 
						|
 | 
						|
    node = tree->root;
 | 
						|
    if (!node)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    return ogs_rbtree_min(node);
 | 
						|
}
 | 
						|
 | 
						|
void *ogs_rbtree_last(const ogs_rbtree_t *tree)
 | 
						|
{
 | 
						|
    ogs_rbnode_t *node;
 | 
						|
    ogs_assert(tree);
 | 
						|
 | 
						|
    node = tree->root;
 | 
						|
    if (!node)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    return ogs_rbtree_max(node);
 | 
						|
}
 | 
						|
 | 
						|
#define rb_empty_node(node) ((node)->parent == (node))
 | 
						|
 | 
						|
void *ogs_rbtree_next(const void *rb_node)
 | 
						|
{
 | 
						|
    const ogs_rbnode_t *node = rb_node;
 | 
						|
    ogs_rbnode_t *parent;
 | 
						|
    ogs_assert(node);
 | 
						|
 | 
						|
    if (rb_empty_node(node))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    if (node->right)
 | 
						|
        return ogs_rbtree_min(node->right);
 | 
						|
 | 
						|
    while ((parent = node->parent) && node == parent->right)
 | 
						|
        node = parent;
 | 
						|
 | 
						|
    return parent;
 | 
						|
}
 | 
						|
 | 
						|
void *ogs_rbtree_prev(const void *rb_node)
 | 
						|
{
 | 
						|
    const ogs_rbnode_t *node = rb_node;
 | 
						|
    ogs_rbnode_t *parent;
 | 
						|
    ogs_assert(node);
 | 
						|
 | 
						|
    if (rb_empty_node(node))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    if (node->left)
 | 
						|
        return ogs_rbtree_max(node->left);
 | 
						|
 | 
						|
    while ((parent = node->parent) && node == parent->left)
 | 
						|
        node = parent;
 | 
						|
 | 
						|
    return parent;
 | 
						|
}
 |