Blame include/rbtree.c

Packit 961e70
/*
Packit 961e70
Packit 961e70
  This file is provided under a dual BSD/GPLv2 license.  When using or
Packit 961e70
  redistributing this file, you may do so under either license.
Packit 961e70
Packit 961e70
  GPL LICENSE SUMMARY
Packit 961e70
Packit 961e70
  Copyright(c) 2015 Intel Corporation.
Packit 961e70
Packit 961e70
  This program is free software; you can redistribute it and/or modify
Packit 961e70
  it under the terms of version 2 of the GNU General Public License as
Packit 961e70
  published by the Free Software Foundation.
Packit 961e70
Packit 961e70
  This program is distributed in the hope that it will be useful, but
Packit 961e70
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 961e70
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 961e70
  General Public License for more details.
Packit 961e70
Packit 961e70
  Contact Information:
Packit 961e70
  Intel Corporation, www.intel.com
Packit 961e70
Packit 961e70
  BSD LICENSE
Packit 961e70
Packit 961e70
  Copyright(c) 2015 Intel Corporation.
Packit 961e70
Packit 961e70
  Redistribution and use in source and binary forms, with or without
Packit 961e70
  modification, are permitted provided that the following conditions
Packit 961e70
  are met:
Packit 961e70
Packit 961e70
    * Redistributions of source code must retain the above copyright
Packit 961e70
      notice, this list of conditions and the following disclaimer.
Packit 961e70
    * Redistributions in binary form must reproduce the above copyright
Packit 961e70
      notice, this list of conditions and the following disclaimer in
Packit 961e70
      the documentation and/or other materials provided with the
Packit 961e70
      distribution.
Packit 961e70
    * Neither the name of Intel Corporation nor the names of its
Packit 961e70
      contributors may be used to endorse or promote products derived
Packit 961e70
      from this software without specific prior written permission.
Packit 961e70
Packit 961e70
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 961e70
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 961e70
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 961e70
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 961e70
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 961e70
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 961e70
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 961e70
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 961e70
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 961e70
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 961e70
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 961e70
Packit 961e70
*/
Packit 961e70
Packit 961e70
/* Copyright (c) 2003-2015 Intel Corporation. All rights reserved. */
Packit 961e70
Packit 961e70
/*
Packit 961e70
 * Abstract:
Packit 961e70
 *	Implementation of quick map, a binary tree where the caller always provides
Packit 961e70
 *	all necessary storage.
Packit 961e70
 *
Packit 961e70
 * Environment:
Packit 961e70
 *	All
Packit 961e70
 *
Packit 961e70
 * $Revision$
Packit 961e70
 */
Packit 961e70
Packit 961e70
Packit 961e70
/*****************************************************************************
Packit 961e70
*
Packit 961e70
* Map
Packit 961e70
*
Packit 961e70
* Map is an associative array.  By providing a key, the caller can retrieve
Packit 961e70
* an object from the map.  All objects in the map have an associated key,
Packit 961e70
* as specified by the caller when the object was inserted into the map.
Packit 961e70
* In addition to random access, the caller can traverse the map much like
Packit 961e70
* a linked list, either forwards from the first object or backwards from
Packit 961e70
* the last object.  The objects in the map are always traversed in
Packit 961e70
* order since the nodes are stored sorted.
Packit 961e70
*
Packit 961e70
* This implementation of Map uses a red black tree verified against
Packit 961e70
* Cormen-Leiserson-Rivest text, McGraw-Hill Edition, fourteenth
Packit 961e70
* printing, 1994.
Packit 961e70
*
Packit 961e70
*****************************************************************************/
Packit 961e70
Packit 961e70
#include <string.h> /* for memset declaration */
Packit 961e70
Packit Service 7ed5cc
// RBTREE_CMP should be a comparator, i.e. RBTREE_CMP(a, b) should evaluate to
Packit Service 7ed5cc
// -1, 0, or 1 depending on if a < b, a == b, or a > b, respectively.
Packit Service 7ed5cc
#ifdef RBTREE_CMP
Packit Service 7ed5cc
Packit Service 7ed5cc
#if defined(RBTREE_GET_LEFTMOST) || defined(RBTREE_GET_RIGHTMOST)
Packit Service 7ed5cc
#error Cannot define both RBTREE_CMP and RBTREE_GET_(LEFT|RIGHT)MOST
Packit Service 7ed5cc
#endif
Packit Service 7ed5cc
Packit Service 7ed5cc
#elif !defined ( RBTREE_GET_LEFTMOST )       || \
Packit 961e70
	! defined ( RBTREE_GET_RIGHTMOST ) || \
Packit 961e70
	! defined ( RBTREE_MAP_COUNT )     || \
Packit 961e70
	! defined ( RBTREE_ASSERT )
Packit 961e70
#error "You must define RBTREE_GET_LEFTMOST and RBTREE_GET_RIGHTMOST and \
Packit 961e70
        RBTREE_MAP_COUNT and RBTREE_ASSERT before including rbtree.c"
Packit Service 7ed5cc
Packit Service 7ed5cc
#endif /* RBTREE_CMP */
Packit 961e70
Packit 961e70
#define IN /* nothing */
Packit 961e70
Packit 961e70
/******************************************************************************
Packit 961e70
*******************************************************************************
Packit 961e70
**************                                                     ************
Packit 961e70
**************			 IMPLEMENTATION OF QUICK MAP       ************
Packit 961e70
**************                                                     ************
Packit 961e70
*******************************************************************************
Packit 961e70
******************************************************************************/
Packit 961e70
Packit 961e70
/* Forward declarations: */
Packit 961e70
static void ips_cl_qmap_init(
Packit 961e70
				IN	cl_qmap_t		*p_map,
Packit 961e70
				IN	cl_map_item_t* const	root,
Packit 961e70
				IN	cl_map_item_t* const	nil);
Packit 961e70
static void ips_cl_qmap_insert_item(
Packit 961e70
				IN	cl_qmap_t* const	p_map,
Packit 961e70
				IN	cl_map_item_t* const	p_item);
Packit 961e70
static void ips_cl_qmap_remove_item(
Packit 961e70
				IN	cl_qmap_t* const	p_map,
Packit 961e70
				IN	cl_map_item_t* const	p_item);
Packit 961e70
static cl_map_item_t* ips_cl_qmap_successor(
Packit 961e70
				IN	cl_qmap_t* const	p_map,
Packit 961e70
				IN	const cl_map_item_t*	p_item);
Packit Service 7ed5cc
Packit Service 7ed5cc
Packit Service 7ed5cc
#ifndef RBTREE_NO_EMIT_IPS_CL_QMAP_PREDECESSOR
Packit 961e70
static cl_map_item_t* ips_cl_qmap_predecessor(
Packit 961e70
				IN	cl_qmap_t* const	p_map,
Packit 961e70
				IN	const cl_map_item_t*	p_item);
Packit Service 7ed5cc
#endif
Packit Service 7ed5cc
Packit Service 7ed5cc
#if defined(RBTREE_GET_LEFTMOST)
Packit 961e70
static cl_map_item_t* ips_cl_qmap_search(
Packit 961e70
				IN	cl_qmap_t* const	p_map,
Packit 961e70
				IN	unsigned long		start,
Packit 961e70
				IN	unsigned long		end);
Packit Service 7ed5cc
#else
Packit Service 7ed5cc
static cl_map_item_t* ips_cl_qmap_searchv(
Packit Service 7ed5cc
				cl_qmap_t* const	p_map,
Packit Service 7ed5cc
				const RBTREE_MI_PL *key);
Packit Service 7ed5cc
#endif
Packit 961e70
Packit 961e70
/*
Packit 961e70
 * Get the root.
Packit 961e70
 */
Packit 961e70
static inline cl_map_item_t*
Packit 961e70
__cl_map_root(
Packit 961e70
	IN	const cl_qmap_t* const	p_map )
Packit 961e70
{
Packit 961e70
	RBTREE_ASSERT( p_map );
Packit 961e70
	return( p_map->root->p_left );
Packit 961e70
}
Packit 961e70
Packit 961e70
Packit 961e70
/*
Packit 961e70
 * Returns whether a given item is on the left of its parent.
Packit 961e70
 */
Packit 961e70
static int
Packit 961e70
__cl_map_is_left_child(
Packit 961e70
	IN	const cl_map_item_t* const	p_item )
Packit 961e70
{
Packit 961e70
	RBTREE_ASSERT( p_item );
Packit 961e70
	RBTREE_ASSERT( p_item->p_up );
Packit 961e70
	RBTREE_ASSERT( p_item->p_up != p_item );
Packit 961e70
Packit 961e70
	return( p_item->p_up->p_left == p_item );
Packit 961e70
}
Packit 961e70
Packit 961e70
Packit 961e70
/*
Packit 961e70
 * Retrieve the pointer to the parent's pointer to an item.
Packit 961e70
 */
Packit 961e70
static cl_map_item_t**
Packit 961e70
__cl_map_get_parent_ptr_to_item(
Packit 961e70
	IN	cl_map_item_t* const	p_item )
Packit 961e70
{
Packit 961e70
	RBTREE_ASSERT( p_item );
Packit 961e70
	RBTREE_ASSERT( p_item->p_up );
Packit 961e70
	RBTREE_ASSERT( p_item->p_up != p_item );
Packit 961e70
Packit 961e70
	if( __cl_map_is_left_child( p_item ) )
Packit 961e70
		return( &p_item->p_up->p_left );
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_item->p_up->p_right == p_item );
Packit 961e70
	return( &p_item->p_up->p_right );
Packit 961e70
}
Packit 961e70
Packit 961e70
Packit 961e70
/*
Packit 961e70
 * Rotate a node to the left.  This rotation affects the least number of links
Packit 961e70
 * between nodes and brings the level of C up by one while increasing the depth
Packit 961e70
 * of A one.  Note that the links to/from W, X, Y, and Z are not affected.
Packit 961e70
 *
Packit 961e70
 *	    R				      R
Packit 961e70
 *	    |				      |
Packit 961e70
 *	    A				      C
Packit 961e70
 *	  /   \			        /   \
Packit 961e70
 *	W       C			  A       Z
Packit 961e70
 *	       / \			 / \
Packit 961e70
 *	      B   Z			W   B
Packit 961e70
 *	     / \			   / \
Packit 961e70
 *	    X   Y			  X   Y
Packit 961e70
 */
Packit 961e70
static void
Packit 961e70
__cl_map_rot_left(
Packit 961e70
	IN	cl_qmap_t* const		p_map,
Packit 961e70
	IN	cl_map_item_t* const	p_item )
Packit 961e70
{
Packit 961e70
	cl_map_item_t	**pp_root;
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_map );
Packit 961e70
	RBTREE_ASSERT( p_item );
Packit 961e70
	RBTREE_ASSERT( p_item->p_right != p_map->nil_item );
Packit 961e70
Packit 961e70
	pp_root = __cl_map_get_parent_ptr_to_item( p_item );
Packit 961e70
Packit 961e70
	/* Point R to C instead of A. */
Packit 961e70
	*pp_root = p_item->p_right;
Packit 961e70
	/* Set C's parent to R. */
Packit 961e70
	(*pp_root)->p_up = p_item->p_up;
Packit 961e70
Packit 961e70
	/* Set A's right to B */
Packit 961e70
	p_item->p_right = (*pp_root)->p_left;
Packit 961e70
	/*
Packit 961e70
	 * Set B's parent to A.  We trap for B being NIL since the
Packit 961e70
	 * caller may depend on NIL not changing.
Packit 961e70
	 */
Packit 961e70
	if( (*pp_root)->p_left != p_map->nil_item )
Packit 961e70
		(*pp_root)->p_left->p_up = p_item;
Packit 961e70
Packit 961e70
	/* Set C's left to A. */
Packit 961e70
	(*pp_root)->p_left = p_item;
Packit 961e70
	/* Set A's parent to C. */
Packit 961e70
	p_item->p_up = *pp_root;
Packit 961e70
}
Packit 961e70
Packit 961e70
Packit 961e70
/*
Packit 961e70
 * Rotate a node to the right.  This rotation affects the least number of links
Packit 961e70
 * between nodes and brings the level of A up by one while increasing the depth
Packit 961e70
 * of C one.  Note that the links to/from W, X, Y, and Z are not affected.
Packit 961e70
 *
Packit 961e70
 *	        R				     R
Packit 961e70
 *	        |				     |
Packit 961e70
 *	        C				     A
Packit 961e70
 *	      /   \				   /   \
Packit 961e70
 *	    A       Z			 W       C
Packit 961e70
 *	   / \    				        / \
Packit 961e70
 *	  W   B   				       B   Z
Packit 961e70
 *	     / \				      / \
Packit 961e70
 *	    X   Y				     X   Y
Packit 961e70
 */
Packit 961e70
static void
Packit 961e70
__cl_map_rot_right(
Packit 961e70
	IN	cl_qmap_t* const		p_map,
Packit 961e70
	IN	cl_map_item_t* const	p_item )
Packit 961e70
{
Packit 961e70
	cl_map_item_t	**pp_root;
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_map );
Packit 961e70
	RBTREE_ASSERT( p_item );
Packit 961e70
	RBTREE_ASSERT( p_item->p_left != p_map->nil_item );
Packit 961e70
Packit 961e70
	/* Point R to A instead of C. */
Packit 961e70
	pp_root = __cl_map_get_parent_ptr_to_item( p_item );
Packit 961e70
	(*pp_root) = p_item->p_left;
Packit 961e70
	/* Set A's parent to R. */
Packit 961e70
	(*pp_root)->p_up = p_item->p_up;
Packit 961e70
Packit 961e70
	/* Set C's left to B */
Packit 961e70
	p_item->p_left = (*pp_root)->p_right;
Packit 961e70
	/*
Packit 961e70
	 * Set B's parent to C.  We trap for B being NIL since the
Packit 961e70
	 * caller may depend on NIL not changing.
Packit 961e70
	 */
Packit 961e70
	if( (*pp_root)->p_right != p_map->nil_item )
Packit 961e70
		(*pp_root)->p_right->p_up = p_item;
Packit 961e70
Packit 961e70
	/* Set A's right to C. */
Packit 961e70
	(*pp_root)->p_right = p_item;
Packit 961e70
	/* Set C's parent to A. */
Packit 961e70
	p_item->p_up = *pp_root;
Packit 961e70
}
Packit 961e70
Packit 961e70
/*
Packit 961e70
 * Balance a tree starting at a given item back to the root.
Packit 961e70
 */
Packit 961e70
static void
Packit 961e70
__cl_map_ins_bal(
Packit 961e70
	IN	cl_qmap_t* const	p_map,
Packit 961e70
	IN	cl_map_item_t*		p_item )
Packit 961e70
{
Packit 961e70
	cl_map_item_t*		p_grand_uncle;
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_map );
Packit 961e70
	RBTREE_ASSERT( p_item );
Packit 961e70
	RBTREE_ASSERT( p_item != p_map->root );
Packit 961e70
Packit 961e70
	while( p_item->p_up->color == CL_MAP_RED )
Packit 961e70
	{
Packit 961e70
		if( __cl_map_is_left_child( p_item->p_up ) )
Packit 961e70
		{
Packit 961e70
			p_grand_uncle = p_item->p_up->p_up->p_right;
Packit 961e70
			RBTREE_ASSERT( p_grand_uncle );
Packit 961e70
			if( p_grand_uncle->color == CL_MAP_RED )
Packit 961e70
			{
Packit 961e70
				p_grand_uncle->color = CL_MAP_BLACK;
Packit 961e70
				p_item->p_up->color = CL_MAP_BLACK;
Packit 961e70
				p_item->p_up->p_up->color = CL_MAP_RED;
Packit 961e70
				p_item = p_item->p_up->p_up;
Packit 961e70
				continue;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			if( !__cl_map_is_left_child( p_item ) )
Packit 961e70
			{
Packit 961e70
				p_item = p_item->p_up;
Packit 961e70
				__cl_map_rot_left( p_map, p_item );
Packit 961e70
			}
Packit 961e70
			p_item->p_up->color = CL_MAP_BLACK;
Packit 961e70
			p_item->p_up->p_up->color = CL_MAP_RED;
Packit 961e70
			__cl_map_rot_right( p_map, p_item->p_up->p_up );
Packit 961e70
		}
Packit 961e70
		else
Packit 961e70
		{
Packit 961e70
			p_grand_uncle = p_item->p_up->p_up->p_left;
Packit 961e70
			RBTREE_ASSERT( p_grand_uncle );
Packit 961e70
			if( p_grand_uncle->color == CL_MAP_RED )
Packit 961e70
			{
Packit 961e70
				p_grand_uncle->color = CL_MAP_BLACK;
Packit 961e70
				p_item->p_up->color = CL_MAP_BLACK;
Packit 961e70
				p_item->p_up->p_up->color = CL_MAP_RED;
Packit 961e70
				p_item = p_item->p_up->p_up;
Packit 961e70
				continue;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			if( __cl_map_is_left_child( p_item ) )
Packit 961e70
			{
Packit 961e70
				p_item = p_item->p_up;
Packit 961e70
				__cl_map_rot_right( p_map, p_item );
Packit 961e70
			}
Packit 961e70
			p_item->p_up->color = CL_MAP_BLACK;
Packit 961e70
			p_item->p_up->p_up->color = CL_MAP_RED;
Packit 961e70
			__cl_map_rot_left( p_map, p_item->p_up->p_up );
Packit 961e70
		}
Packit 961e70
	}
Packit 961e70
}
Packit 961e70
Packit 961e70
static void ips_cl_qmap_init(
Packit 961e70
				IN	cl_qmap_t		*p_map,
Packit 961e70
				IN	cl_map_item_t* const	root,
Packit 961e70
				IN	cl_map_item_t* const	nil_item)
Packit 961e70
{
Packit 961e70
	RBTREE_ASSERT( p_map );
Packit 961e70
	RBTREE_ASSERT( root );
Packit 961e70
	RBTREE_ASSERT( nil_item );
Packit 961e70
Packit 961e70
	memset(p_map,0,sizeof(cl_qmap_t));
Packit 961e70
Packit 961e70
	p_map->root = root;
Packit 961e70
Packit 961e70
	/* setup the RB tree map */
Packit 961e70
	p_map->nil_item = nil_item;
Packit 961e70
Packit 961e70
	p_map->root->p_up = p_map->root;
Packit 961e70
	p_map->root->p_left = p_map->nil_item;
Packit 961e70
	p_map->root->p_right = p_map->nil_item;
Packit 961e70
	p_map->root->color = CL_MAP_BLACK;
Packit 961e70
Packit 961e70
	p_map->nil_item->p_up = p_map->nil_item;
Packit 961e70
	p_map->nil_item->p_left = p_map->nil_item;
Packit 961e70
	p_map->nil_item->p_right = p_map->nil_item;
Packit 961e70
	p_map->nil_item->color = CL_MAP_BLACK;
Packit 961e70
}
Packit 961e70
Packit 961e70
static void
Packit 961e70
ips_cl_qmap_insert_item(
Packit 961e70
	IN	cl_qmap_t* const		p_map,
Packit 961e70
	IN	cl_map_item_t* const	p_item )
Packit 961e70
{
Packit 961e70
	cl_map_item_t	*p_insert_at, *p_comp_item;
Packit 961e70
	int compare_res = 0;
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_map );
Packit 961e70
	RBTREE_ASSERT( p_item );
Packit 961e70
	RBTREE_ASSERT( p_map->root->p_up == p_map->root );
Packit 961e70
	RBTREE_ASSERT( p_map->root->color != CL_MAP_RED );
Packit 961e70
	RBTREE_ASSERT( p_map->nil_item->color != CL_MAP_RED );
Packit 961e70
Packit 961e70
	/* Find the insertion location. */
Packit 961e70
	p_insert_at = p_map->root;
Packit 961e70
	p_comp_item = __cl_map_root( p_map );
Packit 961e70
Packit 961e70
	while( p_comp_item != p_map->nil_item )
Packit 961e70
	{
Packit 961e70
		p_insert_at = p_comp_item;
Packit 961e70
Packit 961e70
		/* Traverse the tree until the correct insertion point is found. */
Packit Service 7ed5cc
#ifdef RBTREE_GET_LEFTMOST
Packit 961e70
		if( RBTREE_GET_LEFTMOST(&p_item->payload) < RBTREE_GET_LEFTMOST(&p_insert_at->payload) )
Packit Service 7ed5cc
#else
Packit Service 7ed5cc
		if(RBTREE_CMP(&p_item->payload, &p_insert_at->payload) < 0)
Packit Service 7ed5cc
#endif
Packit 961e70
		{
Packit 961e70
			p_comp_item = p_insert_at->p_left;
Packit 961e70
			compare_res = 1;
Packit 961e70
		} else {
Packit 961e70
			p_comp_item = p_insert_at->p_right;
Packit 961e70
			compare_res = -1;
Packit 961e70
		}
Packit 961e70
	}
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_insert_at != p_map->nil_item );
Packit 961e70
	RBTREE_ASSERT( p_comp_item == p_map->nil_item );
Packit 961e70
Packit 961e70
	/* Insert the item. */
Packit 961e70
	p_item->p_left = p_map->nil_item;
Packit 961e70
	p_item->p_right = p_map->nil_item;
Packit 961e70
	p_item->color = CL_MAP_RED;
Packit 961e70
	if( p_insert_at == p_map->root )
Packit 961e70
	{
Packit 961e70
		p_insert_at->p_left = p_item;
Packit 961e70
	}
Packit 961e70
	else if( compare_res > 0 ) /* key < p_insert_at->key */
Packit 961e70
	{
Packit 961e70
		p_insert_at->p_left = p_item;
Packit 961e70
	}
Packit 961e70
	else
Packit 961e70
	{
Packit 961e70
		p_insert_at->p_right = p_item;
Packit 961e70
	}
Packit 961e70
	/* Increase the count. */
Packit 961e70
	RBTREE_MAP_COUNT(&p_map->payload)++;
Packit 961e70
Packit 961e70
	p_item->p_up = p_insert_at;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * We have added depth to this section of the tree.
Packit 961e70
	 * Rebalance as necessary as we retrace our path through the tree
Packit 961e70
	 * and update colors.
Packit 961e70
	 */
Packit 961e70
	__cl_map_ins_bal( p_map, p_item );
Packit 961e70
Packit 961e70
	__cl_map_root( p_map )->color = CL_MAP_BLACK;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Note that it is not necessary to re-color the nil node black because all
Packit 961e70
	 * red color assignments are made via the p_up pointer, and nil is never
Packit 961e70
	 * set as the value of a p_up pointer.
Packit 961e70
	 */
Packit 961e70
}
Packit 961e70
Packit 961e70
static void
Packit 961e70
__cl_map_del_bal(
Packit 961e70
	IN	cl_qmap_t* const	p_map,
Packit 961e70
	IN	cl_map_item_t*		p_item )
Packit 961e70
{
Packit 961e70
	cl_map_item_t		*p_uncle;
Packit 961e70
Packit 961e70
	while( (p_item->color != CL_MAP_RED) && (p_item->p_up != p_map->root) )
Packit 961e70
	{
Packit 961e70
		if( __cl_map_is_left_child( p_item ) )
Packit 961e70
		{
Packit 961e70
			p_uncle = p_item->p_up->p_right;
Packit 961e70
Packit 961e70
			if( p_uncle->color == CL_MAP_RED )
Packit 961e70
			{
Packit 961e70
				p_uncle->color = CL_MAP_BLACK;
Packit 961e70
				p_item->p_up->color = CL_MAP_RED;
Packit 961e70
				__cl_map_rot_left( p_map, p_item->p_up );
Packit 961e70
				p_uncle = p_item->p_up->p_right;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			if( p_uncle->p_right->color != CL_MAP_RED )
Packit 961e70
			{
Packit 961e70
				if( p_uncle->p_left->color != CL_MAP_RED )
Packit 961e70
				{
Packit 961e70
					p_uncle->color = CL_MAP_RED;
Packit 961e70
					p_item = p_item->p_up;
Packit 961e70
					continue;
Packit 961e70
				}
Packit 961e70
Packit 961e70
				p_uncle->p_left->color = CL_MAP_BLACK;
Packit 961e70
				p_uncle->color = CL_MAP_RED;
Packit 961e70
				__cl_map_rot_right( p_map, p_uncle );
Packit 961e70
				p_uncle = p_item->p_up->p_right;
Packit 961e70
			}
Packit 961e70
			p_uncle->color = p_item->p_up->color;
Packit 961e70
			p_item->p_up->color = CL_MAP_BLACK;
Packit 961e70
			p_uncle->p_right->color = CL_MAP_BLACK;
Packit 961e70
			__cl_map_rot_left( p_map, p_item->p_up );
Packit 961e70
			break;
Packit 961e70
		}
Packit 961e70
		else
Packit 961e70
		{
Packit 961e70
			p_uncle = p_item->p_up->p_left;
Packit 961e70
Packit 961e70
			if( p_uncle->color == CL_MAP_RED )
Packit 961e70
			{
Packit 961e70
				p_uncle->color = CL_MAP_BLACK;
Packit 961e70
				p_item->p_up->color = CL_MAP_RED;
Packit 961e70
				__cl_map_rot_right( p_map, p_item->p_up );
Packit 961e70
				p_uncle = p_item->p_up->p_left;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			if( p_uncle->p_left->color != CL_MAP_RED )
Packit 961e70
			{
Packit 961e70
				if( p_uncle->p_right->color != CL_MAP_RED )
Packit 961e70
				{
Packit 961e70
					p_uncle->color = CL_MAP_RED;
Packit 961e70
					p_item = p_item->p_up;
Packit 961e70
					continue;
Packit 961e70
				}
Packit 961e70
Packit 961e70
				p_uncle->p_right->color = CL_MAP_BLACK;
Packit 961e70
				p_uncle->color = CL_MAP_RED;
Packit 961e70
				__cl_map_rot_left( p_map, p_uncle );
Packit 961e70
				p_uncle = p_item->p_up->p_left;
Packit 961e70
			}
Packit 961e70
			p_uncle->color = p_item->p_up->color;
Packit 961e70
			p_item->p_up->color = CL_MAP_BLACK;
Packit 961e70
			p_uncle->p_left->color = CL_MAP_BLACK;
Packit 961e70
			__cl_map_rot_right( p_map, p_item->p_up );
Packit 961e70
			break;
Packit 961e70
		}
Packit 961e70
	}
Packit 961e70
	p_item->color = CL_MAP_BLACK;
Packit 961e70
}
Packit 961e70
Packit 961e70
static void
Packit 961e70
ips_cl_qmap_remove_item(
Packit 961e70
	IN	cl_qmap_t* const		p_map,
Packit 961e70
	IN	cl_map_item_t* const	p_item )
Packit 961e70
{
Packit 961e70
	cl_map_item_t	*p_child, *p_del_item;
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_map );
Packit 961e70
	RBTREE_ASSERT( p_item );
Packit 961e70
Packit 961e70
	if( p_item == p_map->nil_item )
Packit 961e70
		return;
Packit 961e70
Packit 961e70
	if( (p_item->p_right == p_map->nil_item) || (p_item->p_left == p_map->nil_item ) )
Packit 961e70
	{
Packit 961e70
		/* The item being removed has children on at most on side. */
Packit 961e70
		p_del_item = p_item;
Packit 961e70
	}
Packit 961e70
	else
Packit 961e70
	{
Packit 961e70
		/*
Packit 961e70
		 * The item being removed has children on both side.
Packit 961e70
		 * We select the item that will replace it.  After removing
Packit 961e70
		 * the substitute item and rebalancing, the tree will have the
Packit 961e70
		 * correct topology.  Exchanging the substitute for the item
Packit 961e70
		 * will finalize the removal.
Packit 961e70
		 */
Packit 961e70
		p_del_item = ips_cl_qmap_successor(p_map, p_item);
Packit 961e70
		RBTREE_ASSERT( p_del_item != p_map->nil_item );
Packit 961e70
	}
Packit 961e70
Packit 961e70
	RBTREE_MAP_COUNT(&p_map->payload)--;
Packit 961e70
Packit 961e70
	/* Get the pointer to the new root's child, if any. */
Packit 961e70
	if( p_del_item->p_left != p_map->nil_item )
Packit 961e70
		p_child = p_del_item->p_left;
Packit 961e70
	else
Packit 961e70
		p_child = p_del_item->p_right;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * This assignment may modify the parent pointer of the nil node.
Packit 961e70
	 * This is inconsequential.
Packit 961e70
	 */
Packit 961e70
	p_child->p_up = p_del_item->p_up;
Packit 961e70
	(*__cl_map_get_parent_ptr_to_item( p_del_item )) = p_child;
Packit 961e70
Packit 961e70
	if( p_del_item->color != CL_MAP_RED )
Packit 961e70
		__cl_map_del_bal( p_map, p_child );
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Note that the splicing done below does not need to occur before
Packit 961e70
	 * the tree is balanced, since the actual topology changes are made by the
Packit 961e70
	 * preceding code.  The topology is preserved by the color assignment made
Packit 961e70
	 * below (reader should be reminded that p_del_item == p_item in some cases).
Packit 961e70
	 */
Packit 961e70
	if( p_del_item != p_item )
Packit 961e70
	{
Packit 961e70
		/*
Packit 961e70
		 * Finalize the removal of the specified item by exchanging it with
Packit 961e70
		 * the substitute which we removed above.
Packit 961e70
		 */
Packit 961e70
		p_del_item->p_up = p_item->p_up;
Packit 961e70
		p_del_item->p_left = p_item->p_left;
Packit 961e70
		p_del_item->p_right = p_item->p_right;
Packit 961e70
		(*__cl_map_get_parent_ptr_to_item( p_item )) = p_del_item;
Packit 961e70
		p_item->p_right->p_up = p_del_item;
Packit 961e70
		p_item->p_left->p_up = p_del_item;
Packit 961e70
		p_del_item->color = p_item->color;
Packit 961e70
	}
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_map->nil_item->color != CL_MAP_RED );
Packit 961e70
}
Packit 961e70
Packit 961e70
static cl_map_item_t *
Packit 961e70
ips_cl_qmap_successor(
Packit 961e70
	IN	cl_qmap_t* const		p_map,
Packit 961e70
	IN	const cl_map_item_t*		p_item )
Packit 961e70
{
Packit 961e70
	cl_map_item_t	*p_tmp;
Packit 961e70
Packit 961e70
	p_tmp = p_item->p_right;
Packit 961e70
	if (p_tmp != p_map->nil_item) {
Packit 961e70
		while (p_tmp->p_left != p_map->nil_item)
Packit 961e70
			p_tmp = p_tmp->p_left;
Packit 961e70
		return p_tmp;
Packit 961e70
	} else {
Packit 961e70
		p_tmp = p_item->p_up;
Packit 961e70
		while (p_tmp->p_right == p_item) {
Packit 961e70
			p_item = p_tmp;
Packit 961e70
			p_tmp = p_tmp->p_up;
Packit 961e70
		}
Packit 961e70
		if (p_tmp == p_map->root)
Packit 961e70
			return p_map->nil_item;
Packit 961e70
		return p_tmp;
Packit 961e70
	}
Packit 961e70
}
Packit 961e70
Packit Service 7ed5cc
// When includer defines RBTREE_CMP, ips_cl_qmap_search() is not emitted.
Packit Service 7ed5cc
// When this happens, ips_cl_qmap_predecessor() may not be called.
Packit Service 7ed5cc
// Combined with -Werror -Wunused-function, libpsm2 fails to build.
Packit Service 7ed5cc
// So provide macro to control emitting this function
Packit Service 7ed5cc
#ifndef RBTREE_NO_EMIT_IPS_CL_QMAP_PREDECESSOR
Packit 961e70
static cl_map_item_t *
Packit 961e70
ips_cl_qmap_predecessor(
Packit 961e70
	IN	cl_qmap_t* const		p_map,
Packit 961e70
	IN	const cl_map_item_t*		p_item )
Packit 961e70
{
Packit 961e70
	cl_map_item_t	*p_tmp;
Packit 961e70
Packit 961e70
	p_tmp = p_item->p_left;
Packit 961e70
	if (p_tmp != p_map->nil_item) {
Packit 961e70
		while (p_tmp->p_right != p_map->nil_item)
Packit 961e70
			p_tmp = p_tmp->p_right;
Packit 961e70
		return p_tmp;
Packit 961e70
	} else {
Packit 961e70
		p_tmp = p_item->p_up;
Packit 961e70
		while (p_tmp->p_left == p_item) {
Packit 961e70
			p_item = p_tmp;
Packit 961e70
			p_tmp = p_tmp->p_up;
Packit 961e70
		}
Packit 961e70
		if (p_tmp == p_map->root)
Packit 961e70
			return p_map->nil_item;
Packit 961e70
		return p_tmp;
Packit 961e70
	}
Packit 961e70
}
Packit Service 7ed5cc
#endif /* RBTREE_NO_EMIT_IPS_CL_QMAP_PREDECESSOR */
Packit 961e70
Packit Service 7ed5cc
#if defined(RBTREE_GET_LEFTMOST)
Packit 961e70
/*
Packit 961e70
 * return the first node with buffer overlapping or zero.
Packit 961e70
 */
Packit 961e70
static cl_map_item_t *
Packit 961e70
ips_cl_qmap_search(cl_qmap_t * const p_map,
Packit 961e70
		unsigned long start, unsigned long end)
Packit 961e70
{
Packit 961e70
	cl_map_item_t *p_item, *p_tmp;
Packit 961e70
Packit 961e70
	RBTREE_ASSERT( p_map );
Packit 961e70
	p_item = __cl_map_root(p_map);
Packit 961e70
Packit 961e70
	while (p_item != p_map->nil_item) {
Packit 961e70
		if (start > RBTREE_GET_LEFTMOST(&p_item->payload)) {
Packit 961e70
			p_tmp = p_item->p_right;
Packit 961e70
			if (p_tmp != p_map->nil_item) {
Packit 961e70
				p_item = p_tmp;
Packit 961e70
				continue;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			/*
Packit 961e70
			 * p_item is on immediate left side of 'start'.
Packit 961e70
			 */
Packit 961e70
			if (start >= RBTREE_GET_RIGHTMOST(&p_item->payload)) {
Packit 961e70
				/*
Packit 961e70
				 * p_item is on immediate right
Packit 961e70
				 * side of 'start'.
Packit 961e70
				 */
Packit 961e70
				p_item = ips_cl_qmap_successor(p_map, p_item);
Packit 961e70
				if (p_item != p_map->nil_item &&
Packit 961e70
				    end <= RBTREE_GET_LEFTMOST(&p_item->payload))
Packit 961e70
					p_item = p_map->nil_item;
Packit 961e70
			}
Packit 961e70
		} else if (start < RBTREE_GET_LEFTMOST(&p_item->payload)) {
Packit 961e70
			p_tmp = p_item->p_left;
Packit 961e70
			if (p_tmp != p_map->nil_item) {
Packit 961e70
				p_item = p_tmp;
Packit 961e70
				continue;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			/*
Packit 961e70
			 * p_tmp is on immediate left side of 'start'.
Packit 961e70
			 */
Packit 961e70
			p_tmp = ips_cl_qmap_predecessor(p_map, p_item);
Packit 961e70
			if (p_tmp == p_map->nil_item ||
Packit 961e70
			    (start >= RBTREE_GET_RIGHTMOST(&p_tmp->payload))) {
Packit 961e70
				/*
Packit 961e70
				 * p_item is on immediate right
Packit 961e70
				 * side of 'start'.
Packit 961e70
				 */
Packit 961e70
				if (end <= RBTREE_GET_LEFTMOST(&p_item->payload))
Packit 961e70
					p_item = p_map->nil_item;
Packit 961e70
			} else
Packit 961e70
				p_item = p_tmp;
Packit 961e70
		}
Packit 961e70
Packit 961e70
		break;
Packit 961e70
	}
Packit 961e70
Packit 961e70
Packit 961e70
	return p_item;
Packit 961e70
}
Packit Service 7ed5cc
#else /* defined(...LEFTMOST) || defined(...RIGHTMOST) */
Packit Service 7ed5cc
static cl_map_item_t *
Packit Service 7ed5cc
ips_cl_qmap_searchv(cl_qmap_t * const p_map, const RBTREE_MI_PL *key)
Packit Service 7ed5cc
{
Packit Service 7ed5cc
	RBTREE_ASSERT( p_map );
Packit Service 7ed5cc
	cl_map_item_t *p_item = __cl_map_root(p_map);
Packit Service 7ed5cc
Packit Service 7ed5cc
	while (p_item != p_map->nil_item) {
Packit Service 7ed5cc
		if (RBTREE_CMP(key, &p_item->payload) > 0) {
Packit Service 7ed5cc
			p_item = p_item->p_right;
Packit Service 7ed5cc
		} else if (RBTREE_CMP(key, &p_item->payload) < 0) {
Packit Service 7ed5cc
			p_item = p_item->p_left;
Packit Service 7ed5cc
		} else {
Packit Service 7ed5cc
			break;
Packit Service 7ed5cc
		}
Packit Service 7ed5cc
	}
Packit Service 7ed5cc
Packit Service 7ed5cc
	return p_item;
Packit Service 7ed5cc
}
Packit Service 7ed5cc
#endif /* defined(...LEFTMOST) || defined(...RIGHTMOST) */