xref: /freebsd/contrib/ofed/opensm/complib/cl_map.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3*d6b92ffaSHans Petter Selasky  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4*d6b92ffaSHans Petter Selasky  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5*d6b92ffaSHans Petter Selasky  *
6*d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
7*d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
8*d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
9*d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
10*d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
11*d6b92ffaSHans Petter Selasky  *
12*d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
13*d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
14*d6b92ffaSHans Petter Selasky  *     conditions are met:
15*d6b92ffaSHans Petter Selasky  *
16*d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
17*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
18*d6b92ffaSHans Petter Selasky  *        disclaimer.
19*d6b92ffaSHans Petter Selasky  *
20*d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
21*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
22*d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
23*d6b92ffaSHans Petter Selasky  *        provided with the distribution.
24*d6b92ffaSHans Petter Selasky  *
25*d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26*d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27*d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28*d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29*d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30*d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31*d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32*d6b92ffaSHans Petter Selasky  * SOFTWARE.
33*d6b92ffaSHans Petter Selasky  *
34*d6b92ffaSHans Petter Selasky  */
35*d6b92ffaSHans Petter Selasky 
36*d6b92ffaSHans Petter Selasky /*
37*d6b92ffaSHans Petter Selasky  * Abstract:
38*d6b92ffaSHans Petter Selasky  *	Implementation of quick map, a binary tree where the caller always
39*d6b92ffaSHans Petter Selasky  *	provides all necessary storage.
40*d6b92ffaSHans Petter Selasky  *
41*d6b92ffaSHans Petter Selasky  */
42*d6b92ffaSHans Petter Selasky 
43*d6b92ffaSHans Petter Selasky /*****************************************************************************
44*d6b92ffaSHans Petter Selasky *
45*d6b92ffaSHans Petter Selasky * Map
46*d6b92ffaSHans Petter Selasky *
47*d6b92ffaSHans Petter Selasky * Map is an associative array.  By providing a key, the caller can retrieve
48*d6b92ffaSHans Petter Selasky * an object from the map.  All objects in the map have an associated key,
49*d6b92ffaSHans Petter Selasky * as specified by the caller when the object was inserted into the map.
50*d6b92ffaSHans Petter Selasky * In addition to random access, the caller can traverse the map much like
51*d6b92ffaSHans Petter Selasky * a linked list, either forwards from the first object or backwards from
52*d6b92ffaSHans Petter Selasky * the last object.  The objects in the map are always traversed in
53*d6b92ffaSHans Petter Selasky * order since the nodes are stored sorted.
54*d6b92ffaSHans Petter Selasky *
55*d6b92ffaSHans Petter Selasky * This implementation of Map uses a red black tree verified against
56*d6b92ffaSHans Petter Selasky * Cormen-Leiserson-Rivest text, McGraw-Hill Edition, fourteenth
57*d6b92ffaSHans Petter Selasky * printing, 1994.
58*d6b92ffaSHans Petter Selasky *
59*d6b92ffaSHans Petter Selasky *****************************************************************************/
60*d6b92ffaSHans Petter Selasky 
61*d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
62*d6b92ffaSHans Petter Selasky #  include <config.h>
63*d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
64*d6b92ffaSHans Petter Selasky 
65*d6b92ffaSHans Petter Selasky #include <string.h>
66*d6b92ffaSHans Petter Selasky #include <complib/cl_qmap.h>
67*d6b92ffaSHans Petter Selasky #include <complib/cl_map.h>
68*d6b92ffaSHans Petter Selasky #include <complib/cl_fleximap.h>
69*d6b92ffaSHans Petter Selasky 
70*d6b92ffaSHans Petter Selasky /******************************************************************************
71*d6b92ffaSHans Petter Selasky  IMPLEMENTATION OF QUICK MAP
72*d6b92ffaSHans Petter Selasky ******************************************************************************/
73*d6b92ffaSHans Petter Selasky 
74*d6b92ffaSHans Petter Selasky /*
75*d6b92ffaSHans Petter Selasky  * Get the root.
76*d6b92ffaSHans Petter Selasky  */
__cl_map_root(IN const cl_qmap_t * const p_map)77*d6b92ffaSHans Petter Selasky static inline cl_map_item_t *__cl_map_root(IN const cl_qmap_t * const p_map)
78*d6b92ffaSHans Petter Selasky {
79*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
80*d6b92ffaSHans Petter Selasky 	return (p_map->root.p_left);
81*d6b92ffaSHans Petter Selasky }
82*d6b92ffaSHans Petter Selasky 
83*d6b92ffaSHans Petter Selasky /*
84*d6b92ffaSHans Petter Selasky  * Returns whether a given item is on the left of its parent.
85*d6b92ffaSHans Petter Selasky  */
__cl_map_is_left_child(IN const cl_map_item_t * const p_item)86*d6b92ffaSHans Petter Selasky static boolean_t __cl_map_is_left_child(IN const cl_map_item_t * const p_item)
87*d6b92ffaSHans Petter Selasky {
88*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
89*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up);
90*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up != p_item);
91*d6b92ffaSHans Petter Selasky 
92*d6b92ffaSHans Petter Selasky 	return (p_item->p_up->p_left == p_item);
93*d6b92ffaSHans Petter Selasky }
94*d6b92ffaSHans Petter Selasky 
95*d6b92ffaSHans Petter Selasky /*
96*d6b92ffaSHans Petter Selasky  * Retrieve the pointer to the parent's pointer to an item.
97*d6b92ffaSHans Petter Selasky  */
__cl_map_get_parent_ptr_to_item(IN cl_map_item_t * const p_item)98*d6b92ffaSHans Petter Selasky static cl_map_item_t **__cl_map_get_parent_ptr_to_item(IN cl_map_item_t *
99*d6b92ffaSHans Petter Selasky 						       const p_item)
100*d6b92ffaSHans Petter Selasky {
101*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
102*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up);
103*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up != p_item);
104*d6b92ffaSHans Petter Selasky 
105*d6b92ffaSHans Petter Selasky 	if (__cl_map_is_left_child(p_item))
106*d6b92ffaSHans Petter Selasky 		return (&p_item->p_up->p_left);
107*d6b92ffaSHans Petter Selasky 
108*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up->p_right == p_item);
109*d6b92ffaSHans Petter Selasky 	return (&p_item->p_up->p_right);
110*d6b92ffaSHans Petter Selasky }
111*d6b92ffaSHans Petter Selasky 
112*d6b92ffaSHans Petter Selasky /*
113*d6b92ffaSHans Petter Selasky  * Rotate a node to the left.  This rotation affects the least number of links
114*d6b92ffaSHans Petter Selasky  * between nodes and brings the level of C up by one while increasing the depth
115*d6b92ffaSHans Petter Selasky  * of A one.  Note that the links to/from W, X, Y, and Z are not affected.
116*d6b92ffaSHans Petter Selasky  *
117*d6b92ffaSHans Petter Selasky  *	    R				      R
118*d6b92ffaSHans Petter Selasky  *	    |				      |
119*d6b92ffaSHans Petter Selasky  *	    A				      C
120*d6b92ffaSHans Petter Selasky  *	  /   \			        /   \
121*d6b92ffaSHans Petter Selasky  *	W       C			  A       Z
122*d6b92ffaSHans Petter Selasky  *	       / \			 / \
123*d6b92ffaSHans Petter Selasky  *	      B   Z			W   B
124*d6b92ffaSHans Petter Selasky  *	     / \			   / \
125*d6b92ffaSHans Petter Selasky  *	    X   Y			  X   Y
126*d6b92ffaSHans Petter Selasky  */
__cl_map_rot_left(IN cl_qmap_t * const p_map,IN cl_map_item_t * const p_item)127*d6b92ffaSHans Petter Selasky static void __cl_map_rot_left(IN cl_qmap_t * const p_map,
128*d6b92ffaSHans Petter Selasky 			      IN cl_map_item_t * const p_item)
129*d6b92ffaSHans Petter Selasky {
130*d6b92ffaSHans Petter Selasky 	cl_map_item_t **pp_root;
131*d6b92ffaSHans Petter Selasky 
132*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
133*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
134*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_right != &p_map->nil);
135*d6b92ffaSHans Petter Selasky 
136*d6b92ffaSHans Petter Selasky 	pp_root = __cl_map_get_parent_ptr_to_item(p_item);
137*d6b92ffaSHans Petter Selasky 
138*d6b92ffaSHans Petter Selasky 	/* Point R to C instead of A. */
139*d6b92ffaSHans Petter Selasky 	*pp_root = p_item->p_right;
140*d6b92ffaSHans Petter Selasky 	/* Set C's parent to R. */
141*d6b92ffaSHans Petter Selasky 	(*pp_root)->p_up = p_item->p_up;
142*d6b92ffaSHans Petter Selasky 
143*d6b92ffaSHans Petter Selasky 	/* Set A's right to B */
144*d6b92ffaSHans Petter Selasky 	p_item->p_right = (*pp_root)->p_left;
145*d6b92ffaSHans Petter Selasky 	/*
146*d6b92ffaSHans Petter Selasky 	 * Set B's parent to A.  We trap for B being NIL since the
147*d6b92ffaSHans Petter Selasky 	 * caller may depend on NIL not changing.
148*d6b92ffaSHans Petter Selasky 	 */
149*d6b92ffaSHans Petter Selasky 	if ((*pp_root)->p_left != &p_map->nil)
150*d6b92ffaSHans Petter Selasky 		(*pp_root)->p_left->p_up = p_item;
151*d6b92ffaSHans Petter Selasky 
152*d6b92ffaSHans Petter Selasky 	/* Set C's left to A. */
153*d6b92ffaSHans Petter Selasky 	(*pp_root)->p_left = p_item;
154*d6b92ffaSHans Petter Selasky 	/* Set A's parent to C. */
155*d6b92ffaSHans Petter Selasky 	p_item->p_up = *pp_root;
156*d6b92ffaSHans Petter Selasky }
157*d6b92ffaSHans Petter Selasky 
158*d6b92ffaSHans Petter Selasky /*
159*d6b92ffaSHans Petter Selasky  * Rotate a node to the right.  This rotation affects the least number of links
160*d6b92ffaSHans Petter Selasky  * between nodes and brings the level of A up by one while increasing the depth
161*d6b92ffaSHans Petter Selasky  * of C one.  Note that the links to/from W, X, Y, and Z are not affected.
162*d6b92ffaSHans Petter Selasky  *
163*d6b92ffaSHans Petter Selasky  *	        R				     R
164*d6b92ffaSHans Petter Selasky  *	        |				     |
165*d6b92ffaSHans Petter Selasky  *	        C				     A
166*d6b92ffaSHans Petter Selasky  *	      /   \				   /   \
167*d6b92ffaSHans Petter Selasky  *	    A       Z			 W       C
168*d6b92ffaSHans Petter Selasky  *	   / \    				        / \
169*d6b92ffaSHans Petter Selasky  *	  W   B   				       B   Z
170*d6b92ffaSHans Petter Selasky  *	     / \				      / \
171*d6b92ffaSHans Petter Selasky  *	    X   Y				     X   Y
172*d6b92ffaSHans Petter Selasky  */
__cl_map_rot_right(IN cl_qmap_t * const p_map,IN cl_map_item_t * const p_item)173*d6b92ffaSHans Petter Selasky static void __cl_map_rot_right(IN cl_qmap_t * const p_map,
174*d6b92ffaSHans Petter Selasky 			       IN cl_map_item_t * const p_item)
175*d6b92ffaSHans Petter Selasky {
176*d6b92ffaSHans Petter Selasky 	cl_map_item_t **pp_root;
177*d6b92ffaSHans Petter Selasky 
178*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
179*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
180*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_left != &p_map->nil);
181*d6b92ffaSHans Petter Selasky 
182*d6b92ffaSHans Petter Selasky 	/* Point R to A instead of C. */
183*d6b92ffaSHans Petter Selasky 	pp_root = __cl_map_get_parent_ptr_to_item(p_item);
184*d6b92ffaSHans Petter Selasky 	(*pp_root) = p_item->p_left;
185*d6b92ffaSHans Petter Selasky 	/* Set A's parent to R. */
186*d6b92ffaSHans Petter Selasky 	(*pp_root)->p_up = p_item->p_up;
187*d6b92ffaSHans Petter Selasky 
188*d6b92ffaSHans Petter Selasky 	/* Set C's left to B */
189*d6b92ffaSHans Petter Selasky 	p_item->p_left = (*pp_root)->p_right;
190*d6b92ffaSHans Petter Selasky 	/*
191*d6b92ffaSHans Petter Selasky 	 * Set B's parent to C.  We trap for B being NIL since the
192*d6b92ffaSHans Petter Selasky 	 * caller may depend on NIL not changing.
193*d6b92ffaSHans Petter Selasky 	 */
194*d6b92ffaSHans Petter Selasky 	if ((*pp_root)->p_right != &p_map->nil)
195*d6b92ffaSHans Petter Selasky 		(*pp_root)->p_right->p_up = p_item;
196*d6b92ffaSHans Petter Selasky 
197*d6b92ffaSHans Petter Selasky 	/* Set A's right to C. */
198*d6b92ffaSHans Petter Selasky 	(*pp_root)->p_right = p_item;
199*d6b92ffaSHans Petter Selasky 	/* Set C's parent to A. */
200*d6b92ffaSHans Petter Selasky 	p_item->p_up = *pp_root;
201*d6b92ffaSHans Petter Selasky }
202*d6b92ffaSHans Petter Selasky 
cl_qmap_init(IN cl_qmap_t * const p_map)203*d6b92ffaSHans Petter Selasky void cl_qmap_init(IN cl_qmap_t * const p_map)
204*d6b92ffaSHans Petter Selasky {
205*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
206*d6b92ffaSHans Petter Selasky 
207*d6b92ffaSHans Petter Selasky 	memset(p_map, 0, sizeof(cl_qmap_t));
208*d6b92ffaSHans Petter Selasky 
209*d6b92ffaSHans Petter Selasky 	/* special setup for the root node */
210*d6b92ffaSHans Petter Selasky 	p_map->root.p_up = &p_map->root;
211*d6b92ffaSHans Petter Selasky 	p_map->root.p_left = &p_map->nil;
212*d6b92ffaSHans Petter Selasky 	p_map->root.p_right = &p_map->nil;
213*d6b92ffaSHans Petter Selasky 	p_map->root.color = CL_MAP_BLACK;
214*d6b92ffaSHans Petter Selasky 
215*d6b92ffaSHans Petter Selasky 	/* Setup the node used as terminator for all leaves. */
216*d6b92ffaSHans Petter Selasky 	p_map->nil.p_up = &p_map->nil;
217*d6b92ffaSHans Petter Selasky 	p_map->nil.p_left = &p_map->nil;
218*d6b92ffaSHans Petter Selasky 	p_map->nil.p_right = &p_map->nil;
219*d6b92ffaSHans Petter Selasky 	p_map->nil.color = CL_MAP_BLACK;
220*d6b92ffaSHans Petter Selasky 
221*d6b92ffaSHans Petter Selasky 	p_map->state = CL_INITIALIZED;
222*d6b92ffaSHans Petter Selasky 
223*d6b92ffaSHans Petter Selasky 	cl_qmap_remove_all(p_map);
224*d6b92ffaSHans Petter Selasky }
225*d6b92ffaSHans Petter Selasky 
cl_qmap_get(IN const cl_qmap_t * const p_map,IN const uint64_t key)226*d6b92ffaSHans Petter Selasky cl_map_item_t *cl_qmap_get(IN const cl_qmap_t * const p_map,
227*d6b92ffaSHans Petter Selasky 			   IN const uint64_t key)
228*d6b92ffaSHans Petter Selasky {
229*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item;
230*d6b92ffaSHans Petter Selasky 
231*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
232*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
233*d6b92ffaSHans Petter Selasky 
234*d6b92ffaSHans Petter Selasky 	p_item = __cl_map_root(p_map);
235*d6b92ffaSHans Petter Selasky 
236*d6b92ffaSHans Petter Selasky 	while (p_item != &p_map->nil) {
237*d6b92ffaSHans Petter Selasky 		if (key == p_item->key)
238*d6b92ffaSHans Petter Selasky 			break;	/* just right */
239*d6b92ffaSHans Petter Selasky 
240*d6b92ffaSHans Petter Selasky 		if (key < p_item->key)
241*d6b92ffaSHans Petter Selasky 			p_item = p_item->p_left;	/* too small */
242*d6b92ffaSHans Petter Selasky 		else
243*d6b92ffaSHans Petter Selasky 			p_item = p_item->p_right;	/* too big */
244*d6b92ffaSHans Petter Selasky 	}
245*d6b92ffaSHans Petter Selasky 
246*d6b92ffaSHans Petter Selasky 	return (p_item);
247*d6b92ffaSHans Petter Selasky }
248*d6b92ffaSHans Petter Selasky 
cl_qmap_get_next(IN const cl_qmap_t * const p_map,IN const uint64_t key)249*d6b92ffaSHans Petter Selasky cl_map_item_t *cl_qmap_get_next(IN const cl_qmap_t * const p_map,
250*d6b92ffaSHans Petter Selasky 				IN const uint64_t key)
251*d6b92ffaSHans Petter Selasky {
252*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item;
253*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item_found;
254*d6b92ffaSHans Petter Selasky 
255*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
256*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
257*d6b92ffaSHans Petter Selasky 
258*d6b92ffaSHans Petter Selasky 	p_item = __cl_map_root(p_map);
259*d6b92ffaSHans Petter Selasky 	p_item_found = (cl_map_item_t *) & p_map->nil;
260*d6b92ffaSHans Petter Selasky 
261*d6b92ffaSHans Petter Selasky 	while (p_item != &p_map->nil) {
262*d6b92ffaSHans Petter Selasky 		if (key < p_item->key) {
263*d6b92ffaSHans Petter Selasky 			p_item_found = p_item;
264*d6b92ffaSHans Petter Selasky 			p_item = p_item->p_left;
265*d6b92ffaSHans Petter Selasky 		} else {
266*d6b92ffaSHans Petter Selasky 			p_item = p_item->p_right;
267*d6b92ffaSHans Petter Selasky 		}
268*d6b92ffaSHans Petter Selasky 	}
269*d6b92ffaSHans Petter Selasky 
270*d6b92ffaSHans Petter Selasky 	return (p_item_found);
271*d6b92ffaSHans Petter Selasky }
272*d6b92ffaSHans Petter Selasky 
cl_qmap_apply_func(IN const cl_qmap_t * const p_map,IN cl_pfn_qmap_apply_t pfn_func,IN const void * const context)273*d6b92ffaSHans Petter Selasky void cl_qmap_apply_func(IN const cl_qmap_t * const p_map,
274*d6b92ffaSHans Petter Selasky 			IN cl_pfn_qmap_apply_t pfn_func,
275*d6b92ffaSHans Petter Selasky 			IN const void *const context)
276*d6b92ffaSHans Petter Selasky {
277*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_map_item;
278*d6b92ffaSHans Petter Selasky 
279*d6b92ffaSHans Petter Selasky 	/* Note that context can have any arbitrary value. */
280*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
281*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
282*d6b92ffaSHans Petter Selasky 	CL_ASSERT(pfn_func);
283*d6b92ffaSHans Petter Selasky 
284*d6b92ffaSHans Petter Selasky 	p_map_item = cl_qmap_head(p_map);
285*d6b92ffaSHans Petter Selasky 	while (p_map_item != cl_qmap_end(p_map)) {
286*d6b92ffaSHans Petter Selasky 		pfn_func(p_map_item, (void *)context);
287*d6b92ffaSHans Petter Selasky 		p_map_item = cl_qmap_next(p_map_item);
288*d6b92ffaSHans Petter Selasky 	}
289*d6b92ffaSHans Petter Selasky }
290*d6b92ffaSHans Petter Selasky 
291*d6b92ffaSHans Petter Selasky /*
292*d6b92ffaSHans Petter Selasky  * Balance a tree starting at a given item back to the root.
293*d6b92ffaSHans Petter Selasky  */
__cl_map_ins_bal(IN cl_qmap_t * const p_map,IN cl_map_item_t * p_item)294*d6b92ffaSHans Petter Selasky static void __cl_map_ins_bal(IN cl_qmap_t * const p_map,
295*d6b92ffaSHans Petter Selasky 			     IN cl_map_item_t * p_item)
296*d6b92ffaSHans Petter Selasky {
297*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_grand_uncle;
298*d6b92ffaSHans Petter Selasky 
299*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
300*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
301*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item != &p_map->root);
302*d6b92ffaSHans Petter Selasky 
303*d6b92ffaSHans Petter Selasky 	while (p_item->p_up->color == CL_MAP_RED) {
304*d6b92ffaSHans Petter Selasky 		if (__cl_map_is_left_child(p_item->p_up)) {
305*d6b92ffaSHans Petter Selasky 			p_grand_uncle = p_item->p_up->p_up->p_right;
306*d6b92ffaSHans Petter Selasky 			CL_ASSERT(p_grand_uncle);
307*d6b92ffaSHans Petter Selasky 			if (p_grand_uncle->color == CL_MAP_RED) {
308*d6b92ffaSHans Petter Selasky 				p_grand_uncle->color = CL_MAP_BLACK;
309*d6b92ffaSHans Petter Selasky 				p_item->p_up->color = CL_MAP_BLACK;
310*d6b92ffaSHans Petter Selasky 				p_item->p_up->p_up->color = CL_MAP_RED;
311*d6b92ffaSHans Petter Selasky 				p_item = p_item->p_up->p_up;
312*d6b92ffaSHans Petter Selasky 				continue;
313*d6b92ffaSHans Petter Selasky 			}
314*d6b92ffaSHans Petter Selasky 
315*d6b92ffaSHans Petter Selasky 			if (!__cl_map_is_left_child(p_item)) {
316*d6b92ffaSHans Petter Selasky 				p_item = p_item->p_up;
317*d6b92ffaSHans Petter Selasky 				__cl_map_rot_left(p_map, p_item);
318*d6b92ffaSHans Petter Selasky 			}
319*d6b92ffaSHans Petter Selasky 			p_item->p_up->color = CL_MAP_BLACK;
320*d6b92ffaSHans Petter Selasky 			p_item->p_up->p_up->color = CL_MAP_RED;
321*d6b92ffaSHans Petter Selasky 			__cl_map_rot_right(p_map, p_item->p_up->p_up);
322*d6b92ffaSHans Petter Selasky 		} else {
323*d6b92ffaSHans Petter Selasky 			p_grand_uncle = p_item->p_up->p_up->p_left;
324*d6b92ffaSHans Petter Selasky 			CL_ASSERT(p_grand_uncle);
325*d6b92ffaSHans Petter Selasky 			if (p_grand_uncle->color == CL_MAP_RED) {
326*d6b92ffaSHans Petter Selasky 				p_grand_uncle->color = CL_MAP_BLACK;
327*d6b92ffaSHans Petter Selasky 				p_item->p_up->color = CL_MAP_BLACK;
328*d6b92ffaSHans Petter Selasky 				p_item->p_up->p_up->color = CL_MAP_RED;
329*d6b92ffaSHans Petter Selasky 				p_item = p_item->p_up->p_up;
330*d6b92ffaSHans Petter Selasky 				continue;
331*d6b92ffaSHans Petter Selasky 			}
332*d6b92ffaSHans Petter Selasky 
333*d6b92ffaSHans Petter Selasky 			if (__cl_map_is_left_child(p_item)) {
334*d6b92ffaSHans Petter Selasky 				p_item = p_item->p_up;
335*d6b92ffaSHans Petter Selasky 				__cl_map_rot_right(p_map, p_item);
336*d6b92ffaSHans Petter Selasky 			}
337*d6b92ffaSHans Petter Selasky 			p_item->p_up->color = CL_MAP_BLACK;
338*d6b92ffaSHans Petter Selasky 			p_item->p_up->p_up->color = CL_MAP_RED;
339*d6b92ffaSHans Petter Selasky 			__cl_map_rot_left(p_map, p_item->p_up->p_up);
340*d6b92ffaSHans Petter Selasky 		}
341*d6b92ffaSHans Petter Selasky 	}
342*d6b92ffaSHans Petter Selasky }
343*d6b92ffaSHans Petter Selasky 
cl_qmap_insert(IN cl_qmap_t * const p_map,IN const uint64_t key,IN cl_map_item_t * const p_item)344*d6b92ffaSHans Petter Selasky cl_map_item_t *cl_qmap_insert(IN cl_qmap_t * const p_map,
345*d6b92ffaSHans Petter Selasky 			      IN const uint64_t key,
346*d6b92ffaSHans Petter Selasky 			      IN cl_map_item_t * const p_item)
347*d6b92ffaSHans Petter Selasky {
348*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_insert_at, *p_comp_item;
349*d6b92ffaSHans Petter Selasky 
350*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
351*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
352*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
353*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->root.p_up == &p_map->root);
354*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->root.color != CL_MAP_RED);
355*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->nil.color != CL_MAP_RED);
356*d6b92ffaSHans Petter Selasky 
357*d6b92ffaSHans Petter Selasky 	p_item->p_left = &p_map->nil;
358*d6b92ffaSHans Petter Selasky 	p_item->p_right = &p_map->nil;
359*d6b92ffaSHans Petter Selasky 	p_item->key = key;
360*d6b92ffaSHans Petter Selasky 	p_item->color = CL_MAP_RED;
361*d6b92ffaSHans Petter Selasky 
362*d6b92ffaSHans Petter Selasky 	/* Find the insertion location. */
363*d6b92ffaSHans Petter Selasky 	p_insert_at = &p_map->root;
364*d6b92ffaSHans Petter Selasky 	p_comp_item = __cl_map_root(p_map);
365*d6b92ffaSHans Petter Selasky 
366*d6b92ffaSHans Petter Selasky 	while (p_comp_item != &p_map->nil) {
367*d6b92ffaSHans Petter Selasky 		p_insert_at = p_comp_item;
368*d6b92ffaSHans Petter Selasky 
369*d6b92ffaSHans Petter Selasky 		if (key == p_insert_at->key)
370*d6b92ffaSHans Petter Selasky 			return (p_insert_at);
371*d6b92ffaSHans Petter Selasky 
372*d6b92ffaSHans Petter Selasky 		/* Traverse the tree until the correct insertion point is found. */
373*d6b92ffaSHans Petter Selasky 		if (key < p_insert_at->key)
374*d6b92ffaSHans Petter Selasky 			p_comp_item = p_insert_at->p_left;
375*d6b92ffaSHans Petter Selasky 		else
376*d6b92ffaSHans Petter Selasky 			p_comp_item = p_insert_at->p_right;
377*d6b92ffaSHans Petter Selasky 	}
378*d6b92ffaSHans Petter Selasky 
379*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_insert_at != &p_map->nil);
380*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_comp_item == &p_map->nil);
381*d6b92ffaSHans Petter Selasky 	/* Insert the item. */
382*d6b92ffaSHans Petter Selasky 	if (p_insert_at == &p_map->root) {
383*d6b92ffaSHans Petter Selasky 		p_insert_at->p_left = p_item;
384*d6b92ffaSHans Petter Selasky 		/*
385*d6b92ffaSHans Petter Selasky 		 * Primitive insert places the new item in front of
386*d6b92ffaSHans Petter Selasky 		 * the existing item.
387*d6b92ffaSHans Petter Selasky 		 */
388*d6b92ffaSHans Petter Selasky 		__cl_primitive_insert(&p_map->nil.pool_item.list_item,
389*d6b92ffaSHans Petter Selasky 				      &p_item->pool_item.list_item);
390*d6b92ffaSHans Petter Selasky 	} else if (key < p_insert_at->key) {
391*d6b92ffaSHans Petter Selasky 		p_insert_at->p_left = p_item;
392*d6b92ffaSHans Petter Selasky 		/*
393*d6b92ffaSHans Petter Selasky 		 * Primitive insert places the new item in front of
394*d6b92ffaSHans Petter Selasky 		 * the existing item.
395*d6b92ffaSHans Petter Selasky 		 */
396*d6b92ffaSHans Petter Selasky 		__cl_primitive_insert(&p_insert_at->pool_item.list_item,
397*d6b92ffaSHans Petter Selasky 				      &p_item->pool_item.list_item);
398*d6b92ffaSHans Petter Selasky 	} else {
399*d6b92ffaSHans Petter Selasky 		p_insert_at->p_right = p_item;
400*d6b92ffaSHans Petter Selasky 		/*
401*d6b92ffaSHans Petter Selasky 		 * Primitive insert places the new item in front of
402*d6b92ffaSHans Petter Selasky 		 * the existing item.
403*d6b92ffaSHans Petter Selasky 		 */
404*d6b92ffaSHans Petter Selasky 		__cl_primitive_insert(p_insert_at->pool_item.list_item.p_next,
405*d6b92ffaSHans Petter Selasky 				      &p_item->pool_item.list_item);
406*d6b92ffaSHans Petter Selasky 	}
407*d6b92ffaSHans Petter Selasky 	/* Increase the count. */
408*d6b92ffaSHans Petter Selasky 	p_map->count++;
409*d6b92ffaSHans Petter Selasky 
410*d6b92ffaSHans Petter Selasky 	p_item->p_up = p_insert_at;
411*d6b92ffaSHans Petter Selasky 
412*d6b92ffaSHans Petter Selasky 	/*
413*d6b92ffaSHans Petter Selasky 	 * We have added depth to this section of the tree.
414*d6b92ffaSHans Petter Selasky 	 * Rebalance as necessary as we retrace our path through the tree
415*d6b92ffaSHans Petter Selasky 	 * and update colors.
416*d6b92ffaSHans Petter Selasky 	 */
417*d6b92ffaSHans Petter Selasky 	__cl_map_ins_bal(p_map, p_item);
418*d6b92ffaSHans Petter Selasky 
419*d6b92ffaSHans Petter Selasky 	__cl_map_root(p_map)->color = CL_MAP_BLACK;
420*d6b92ffaSHans Petter Selasky 
421*d6b92ffaSHans Petter Selasky 	/*
422*d6b92ffaSHans Petter Selasky 	 * Note that it is not necessary to re-color the nil node black because all
423*d6b92ffaSHans Petter Selasky 	 * red color assignments are made via the p_up pointer, and nil is never
424*d6b92ffaSHans Petter Selasky 	 * set as the value of a p_up pointer.
425*d6b92ffaSHans Petter Selasky 	 */
426*d6b92ffaSHans Petter Selasky 
427*d6b92ffaSHans Petter Selasky #ifdef _DEBUG_
428*d6b92ffaSHans Petter Selasky 	/* Set the pointer to the map in the map item for consistency checking. */
429*d6b92ffaSHans Petter Selasky 	p_item->p_map = p_map;
430*d6b92ffaSHans Petter Selasky #endif
431*d6b92ffaSHans Petter Selasky 
432*d6b92ffaSHans Petter Selasky 	return (p_item);
433*d6b92ffaSHans Petter Selasky }
434*d6b92ffaSHans Petter Selasky 
__cl_map_del_bal(IN cl_qmap_t * const p_map,IN cl_map_item_t * p_item)435*d6b92ffaSHans Petter Selasky static void __cl_map_del_bal(IN cl_qmap_t * const p_map,
436*d6b92ffaSHans Petter Selasky 			     IN cl_map_item_t * p_item)
437*d6b92ffaSHans Petter Selasky {
438*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_uncle;
439*d6b92ffaSHans Petter Selasky 
440*d6b92ffaSHans Petter Selasky 	while ((p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root)) {
441*d6b92ffaSHans Petter Selasky 		if (__cl_map_is_left_child(p_item)) {
442*d6b92ffaSHans Petter Selasky 			p_uncle = p_item->p_up->p_right;
443*d6b92ffaSHans Petter Selasky 
444*d6b92ffaSHans Petter Selasky 			if (p_uncle->color == CL_MAP_RED) {
445*d6b92ffaSHans Petter Selasky 				p_uncle->color = CL_MAP_BLACK;
446*d6b92ffaSHans Petter Selasky 				p_item->p_up->color = CL_MAP_RED;
447*d6b92ffaSHans Petter Selasky 				__cl_map_rot_left(p_map, p_item->p_up);
448*d6b92ffaSHans Petter Selasky 				p_uncle = p_item->p_up->p_right;
449*d6b92ffaSHans Petter Selasky 			}
450*d6b92ffaSHans Petter Selasky 
451*d6b92ffaSHans Petter Selasky 			if (p_uncle->p_right->color != CL_MAP_RED) {
452*d6b92ffaSHans Petter Selasky 				if (p_uncle->p_left->color != CL_MAP_RED) {
453*d6b92ffaSHans Petter Selasky 					p_uncle->color = CL_MAP_RED;
454*d6b92ffaSHans Petter Selasky 					p_item = p_item->p_up;
455*d6b92ffaSHans Petter Selasky 					continue;
456*d6b92ffaSHans Petter Selasky 				}
457*d6b92ffaSHans Petter Selasky 
458*d6b92ffaSHans Petter Selasky 				p_uncle->p_left->color = CL_MAP_BLACK;
459*d6b92ffaSHans Petter Selasky 				p_uncle->color = CL_MAP_RED;
460*d6b92ffaSHans Petter Selasky 				__cl_map_rot_right(p_map, p_uncle);
461*d6b92ffaSHans Petter Selasky 				p_uncle = p_item->p_up->p_right;
462*d6b92ffaSHans Petter Selasky 			}
463*d6b92ffaSHans Petter Selasky 			p_uncle->color = p_item->p_up->color;
464*d6b92ffaSHans Petter Selasky 			p_item->p_up->color = CL_MAP_BLACK;
465*d6b92ffaSHans Petter Selasky 			p_uncle->p_right->color = CL_MAP_BLACK;
466*d6b92ffaSHans Petter Selasky 			__cl_map_rot_left(p_map, p_item->p_up);
467*d6b92ffaSHans Petter Selasky 			break;
468*d6b92ffaSHans Petter Selasky 		} else {
469*d6b92ffaSHans Petter Selasky 			p_uncle = p_item->p_up->p_left;
470*d6b92ffaSHans Petter Selasky 
471*d6b92ffaSHans Petter Selasky 			if (p_uncle->color == CL_MAP_RED) {
472*d6b92ffaSHans Petter Selasky 				p_uncle->color = CL_MAP_BLACK;
473*d6b92ffaSHans Petter Selasky 				p_item->p_up->color = CL_MAP_RED;
474*d6b92ffaSHans Petter Selasky 				__cl_map_rot_right(p_map, p_item->p_up);
475*d6b92ffaSHans Petter Selasky 				p_uncle = p_item->p_up->p_left;
476*d6b92ffaSHans Petter Selasky 			}
477*d6b92ffaSHans Petter Selasky 
478*d6b92ffaSHans Petter Selasky 			if (p_uncle->p_left->color != CL_MAP_RED) {
479*d6b92ffaSHans Petter Selasky 				if (p_uncle->p_right->color != CL_MAP_RED) {
480*d6b92ffaSHans Petter Selasky 					p_uncle->color = CL_MAP_RED;
481*d6b92ffaSHans Petter Selasky 					p_item = p_item->p_up;
482*d6b92ffaSHans Petter Selasky 					continue;
483*d6b92ffaSHans Petter Selasky 				}
484*d6b92ffaSHans Petter Selasky 
485*d6b92ffaSHans Petter Selasky 				p_uncle->p_right->color = CL_MAP_BLACK;
486*d6b92ffaSHans Petter Selasky 				p_uncle->color = CL_MAP_RED;
487*d6b92ffaSHans Petter Selasky 				__cl_map_rot_left(p_map, p_uncle);
488*d6b92ffaSHans Petter Selasky 				p_uncle = p_item->p_up->p_left;
489*d6b92ffaSHans Petter Selasky 			}
490*d6b92ffaSHans Petter Selasky 			p_uncle->color = p_item->p_up->color;
491*d6b92ffaSHans Petter Selasky 			p_item->p_up->color = CL_MAP_BLACK;
492*d6b92ffaSHans Petter Selasky 			p_uncle->p_left->color = CL_MAP_BLACK;
493*d6b92ffaSHans Petter Selasky 			__cl_map_rot_right(p_map, p_item->p_up);
494*d6b92ffaSHans Petter Selasky 			break;
495*d6b92ffaSHans Petter Selasky 		}
496*d6b92ffaSHans Petter Selasky 	}
497*d6b92ffaSHans Petter Selasky 	p_item->color = CL_MAP_BLACK;
498*d6b92ffaSHans Petter Selasky }
499*d6b92ffaSHans Petter Selasky 
cl_qmap_remove_item(IN cl_qmap_t * const p_map,IN cl_map_item_t * const p_item)500*d6b92ffaSHans Petter Selasky void cl_qmap_remove_item(IN cl_qmap_t * const p_map,
501*d6b92ffaSHans Petter Selasky 			 IN cl_map_item_t * const p_item)
502*d6b92ffaSHans Petter Selasky {
503*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_child, *p_del_item;
504*d6b92ffaSHans Petter Selasky 
505*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
506*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
507*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
508*d6b92ffaSHans Petter Selasky 
509*d6b92ffaSHans Petter Selasky 	if (p_item == cl_qmap_end(p_map))
510*d6b92ffaSHans Petter Selasky 		return;
511*d6b92ffaSHans Petter Selasky 
512*d6b92ffaSHans Petter Selasky 	/* must be checked after comparing to cl_qmap_end, since
513*d6b92ffaSHans Petter Selasky 	   the end is not a valid item. */
514*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_map == p_map);
515*d6b92ffaSHans Petter Selasky 
516*d6b92ffaSHans Petter Selasky 	if ((p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil)) {
517*d6b92ffaSHans Petter Selasky 		/* The item being removed has children on at most on side. */
518*d6b92ffaSHans Petter Selasky 		p_del_item = p_item;
519*d6b92ffaSHans Petter Selasky 	} else {
520*d6b92ffaSHans Petter Selasky 		/*
521*d6b92ffaSHans Petter Selasky 		 * The item being removed has children on both side.
522*d6b92ffaSHans Petter Selasky 		 * We select the item that will replace it.  After removing
523*d6b92ffaSHans Petter Selasky 		 * the substitute item and rebalancing, the tree will have the
524*d6b92ffaSHans Petter Selasky 		 * correct topology.  Exchanging the substitute for the item
525*d6b92ffaSHans Petter Selasky 		 * will finalize the removal.
526*d6b92ffaSHans Petter Selasky 		 */
527*d6b92ffaSHans Petter Selasky 		p_del_item = cl_qmap_next(p_item);
528*d6b92ffaSHans Petter Selasky 		CL_ASSERT(p_del_item != &p_map->nil);
529*d6b92ffaSHans Petter Selasky 	}
530*d6b92ffaSHans Petter Selasky 
531*d6b92ffaSHans Petter Selasky 	/* Remove the item from the list. */
532*d6b92ffaSHans Petter Selasky 	__cl_primitive_remove(&p_item->pool_item.list_item);
533*d6b92ffaSHans Petter Selasky 	/* Decrement the item count. */
534*d6b92ffaSHans Petter Selasky 	p_map->count--;
535*d6b92ffaSHans Petter Selasky 
536*d6b92ffaSHans Petter Selasky 	/* Get the pointer to the new root's child, if any. */
537*d6b92ffaSHans Petter Selasky 	if (p_del_item->p_left != &p_map->nil)
538*d6b92ffaSHans Petter Selasky 		p_child = p_del_item->p_left;
539*d6b92ffaSHans Petter Selasky 	else
540*d6b92ffaSHans Petter Selasky 		p_child = p_del_item->p_right;
541*d6b92ffaSHans Petter Selasky 
542*d6b92ffaSHans Petter Selasky 	/*
543*d6b92ffaSHans Petter Selasky 	 * This assignment may modify the parent pointer of the nil node.
544*d6b92ffaSHans Petter Selasky 	 * This is inconsequential.
545*d6b92ffaSHans Petter Selasky 	 */
546*d6b92ffaSHans Petter Selasky 	p_child->p_up = p_del_item->p_up;
547*d6b92ffaSHans Petter Selasky 	(*__cl_map_get_parent_ptr_to_item(p_del_item)) = p_child;
548*d6b92ffaSHans Petter Selasky 
549*d6b92ffaSHans Petter Selasky 	if (p_del_item->color != CL_MAP_RED)
550*d6b92ffaSHans Petter Selasky 		__cl_map_del_bal(p_map, p_child);
551*d6b92ffaSHans Petter Selasky 
552*d6b92ffaSHans Petter Selasky 	/*
553*d6b92ffaSHans Petter Selasky 	 * Note that the splicing done below does not need to occur before
554*d6b92ffaSHans Petter Selasky 	 * the tree is balanced, since the actual topology changes are made by the
555*d6b92ffaSHans Petter Selasky 	 * preceding code.  The topology is preserved by the color assignment made
556*d6b92ffaSHans Petter Selasky 	 * below (reader should be reminded that p_del_item == p_item in some cases).
557*d6b92ffaSHans Petter Selasky 	 */
558*d6b92ffaSHans Petter Selasky 	if (p_del_item != p_item) {
559*d6b92ffaSHans Petter Selasky 		/*
560*d6b92ffaSHans Petter Selasky 		 * Finalize the removal of the specified item by exchanging it with
561*d6b92ffaSHans Petter Selasky 		 * the substitute which we removed above.
562*d6b92ffaSHans Petter Selasky 		 */
563*d6b92ffaSHans Petter Selasky 		p_del_item->p_up = p_item->p_up;
564*d6b92ffaSHans Petter Selasky 		p_del_item->p_left = p_item->p_left;
565*d6b92ffaSHans Petter Selasky 		p_del_item->p_right = p_item->p_right;
566*d6b92ffaSHans Petter Selasky 		(*__cl_map_get_parent_ptr_to_item(p_item)) = p_del_item;
567*d6b92ffaSHans Petter Selasky 		p_item->p_right->p_up = p_del_item;
568*d6b92ffaSHans Petter Selasky 		p_item->p_left->p_up = p_del_item;
569*d6b92ffaSHans Petter Selasky 		p_del_item->color = p_item->color;
570*d6b92ffaSHans Petter Selasky 	}
571*d6b92ffaSHans Petter Selasky 
572*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->nil.color != CL_MAP_RED);
573*d6b92ffaSHans Petter Selasky 
574*d6b92ffaSHans Petter Selasky #ifdef _DEBUG_
575*d6b92ffaSHans Petter Selasky 	/* Clear the pointer to the map since the item has been removed. */
576*d6b92ffaSHans Petter Selasky 	p_item->p_map = NULL;
577*d6b92ffaSHans Petter Selasky #endif
578*d6b92ffaSHans Petter Selasky }
579*d6b92ffaSHans Petter Selasky 
cl_qmap_remove(IN cl_qmap_t * const p_map,IN const uint64_t key)580*d6b92ffaSHans Petter Selasky cl_map_item_t *cl_qmap_remove(IN cl_qmap_t * const p_map, IN const uint64_t key)
581*d6b92ffaSHans Petter Selasky {
582*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item;
583*d6b92ffaSHans Petter Selasky 
584*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
585*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
586*d6b92ffaSHans Petter Selasky 
587*d6b92ffaSHans Petter Selasky 	/* Seek the node with the specified key */
588*d6b92ffaSHans Petter Selasky 	p_item = cl_qmap_get(p_map, key);
589*d6b92ffaSHans Petter Selasky 
590*d6b92ffaSHans Petter Selasky 	cl_qmap_remove_item(p_map, p_item);
591*d6b92ffaSHans Petter Selasky 
592*d6b92ffaSHans Petter Selasky 	return (p_item);
593*d6b92ffaSHans Petter Selasky }
594*d6b92ffaSHans Petter Selasky 
cl_qmap_merge(OUT cl_qmap_t * const p_dest_map,IN OUT cl_qmap_t * const p_src_map)595*d6b92ffaSHans Petter Selasky void cl_qmap_merge(OUT cl_qmap_t * const p_dest_map,
596*d6b92ffaSHans Petter Selasky 		   IN OUT cl_qmap_t * const p_src_map)
597*d6b92ffaSHans Petter Selasky {
598*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item, *p_item2, *p_next;
599*d6b92ffaSHans Petter Selasky 
600*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_dest_map);
601*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_src_map);
602*d6b92ffaSHans Petter Selasky 
603*d6b92ffaSHans Petter Selasky 	p_item = cl_qmap_head(p_src_map);
604*d6b92ffaSHans Petter Selasky 
605*d6b92ffaSHans Petter Selasky 	while (p_item != cl_qmap_end(p_src_map)) {
606*d6b92ffaSHans Petter Selasky 		p_next = cl_qmap_next(p_item);
607*d6b92ffaSHans Petter Selasky 
608*d6b92ffaSHans Petter Selasky 		/* Remove the item from its current map. */
609*d6b92ffaSHans Petter Selasky 		cl_qmap_remove_item(p_src_map, p_item);
610*d6b92ffaSHans Petter Selasky 		/* Insert the item into the destination map. */
611*d6b92ffaSHans Petter Selasky 		p_item2 =
612*d6b92ffaSHans Petter Selasky 		    cl_qmap_insert(p_dest_map, cl_qmap_key(p_item), p_item);
613*d6b92ffaSHans Petter Selasky 		/* Check that the item was successfully inserted. */
614*d6b92ffaSHans Petter Selasky 		if (p_item2 != p_item) {
615*d6b92ffaSHans Petter Selasky 			/* Put the item in back in the source map. */
616*d6b92ffaSHans Petter Selasky 			p_item2 =
617*d6b92ffaSHans Petter Selasky 			    cl_qmap_insert(p_src_map, cl_qmap_key(p_item),
618*d6b92ffaSHans Petter Selasky 					   p_item);
619*d6b92ffaSHans Petter Selasky 			CL_ASSERT(p_item2 == p_item);
620*d6b92ffaSHans Petter Selasky 		}
621*d6b92ffaSHans Petter Selasky 		p_item = p_next;
622*d6b92ffaSHans Petter Selasky 	}
623*d6b92ffaSHans Petter Selasky }
624*d6b92ffaSHans Petter Selasky 
__cl_qmap_delta_move(IN OUT cl_qmap_t * const p_dest,IN OUT cl_qmap_t * const p_src,IN OUT cl_map_item_t ** const pp_item)625*d6b92ffaSHans Petter Selasky static void __cl_qmap_delta_move(IN OUT cl_qmap_t * const p_dest,
626*d6b92ffaSHans Petter Selasky 				 IN OUT cl_qmap_t * const p_src,
627*d6b92ffaSHans Petter Selasky 				 IN OUT cl_map_item_t ** const pp_item)
628*d6b92ffaSHans Petter Selasky {
629*d6b92ffaSHans Petter Selasky 	cl_map_item_t __attribute__((__unused__)) *p_temp;
630*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_next;
631*d6b92ffaSHans Petter Selasky 
632*d6b92ffaSHans Petter Selasky 	/*
633*d6b92ffaSHans Petter Selasky 	 * Get the next item so that we can ensure that pp_item points to
634*d6b92ffaSHans Petter Selasky 	 * a valid item upon return from the function.
635*d6b92ffaSHans Petter Selasky 	 */
636*d6b92ffaSHans Petter Selasky 	p_next = cl_qmap_next(*pp_item);
637*d6b92ffaSHans Petter Selasky 	/* Move the old item from its current map the the old map. */
638*d6b92ffaSHans Petter Selasky 	cl_qmap_remove_item(p_src, *pp_item);
639*d6b92ffaSHans Petter Selasky 	p_temp = cl_qmap_insert(p_dest, cl_qmap_key(*pp_item), *pp_item);
640*d6b92ffaSHans Petter Selasky 	/* We should never have duplicates. */
641*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_temp == *pp_item);
642*d6b92ffaSHans Petter Selasky 	/* Point pp_item to a valid item in the source map. */
643*d6b92ffaSHans Petter Selasky 	(*pp_item) = p_next;
644*d6b92ffaSHans Petter Selasky }
645*d6b92ffaSHans Petter Selasky 
cl_qmap_delta(IN OUT cl_qmap_t * const p_map1,IN OUT cl_qmap_t * const p_map2,OUT cl_qmap_t * const p_new,OUT cl_qmap_t * const p_old)646*d6b92ffaSHans Petter Selasky void cl_qmap_delta(IN OUT cl_qmap_t * const p_map1,
647*d6b92ffaSHans Petter Selasky 		   IN OUT cl_qmap_t * const p_map2,
648*d6b92ffaSHans Petter Selasky 		   OUT cl_qmap_t * const p_new, OUT cl_qmap_t * const p_old)
649*d6b92ffaSHans Petter Selasky {
650*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item1, *p_item2;
651*d6b92ffaSHans Petter Selasky 	uint64_t key1, key2;
652*d6b92ffaSHans Petter Selasky 
653*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map1);
654*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map2);
655*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_new);
656*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_old);
657*d6b92ffaSHans Petter Selasky 	CL_ASSERT(cl_is_qmap_empty(p_new));
658*d6b92ffaSHans Petter Selasky 	CL_ASSERT(cl_is_qmap_empty(p_old));
659*d6b92ffaSHans Petter Selasky 
660*d6b92ffaSHans Petter Selasky 	p_item1 = cl_qmap_head(p_map1);
661*d6b92ffaSHans Petter Selasky 	p_item2 = cl_qmap_head(p_map2);
662*d6b92ffaSHans Petter Selasky 
663*d6b92ffaSHans Petter Selasky 	while (p_item1 != cl_qmap_end(p_map1) && p_item2 != cl_qmap_end(p_map2)) {
664*d6b92ffaSHans Petter Selasky 		key1 = cl_qmap_key(p_item1);
665*d6b92ffaSHans Petter Selasky 		key2 = cl_qmap_key(p_item2);
666*d6b92ffaSHans Petter Selasky 		if (key1 < key2) {
667*d6b92ffaSHans Petter Selasky 			/* We found an old item. */
668*d6b92ffaSHans Petter Selasky 			__cl_qmap_delta_move(p_old, p_map1, &p_item1);
669*d6b92ffaSHans Petter Selasky 		} else if (key1 > key2) {
670*d6b92ffaSHans Petter Selasky 			/* We found a new item. */
671*d6b92ffaSHans Petter Selasky 			__cl_qmap_delta_move(p_new, p_map2, &p_item2);
672*d6b92ffaSHans Petter Selasky 		} else {
673*d6b92ffaSHans Petter Selasky 			/* Move both forward since they have the same key. */
674*d6b92ffaSHans Petter Selasky 			p_item1 = cl_qmap_next(p_item1);
675*d6b92ffaSHans Petter Selasky 			p_item2 = cl_qmap_next(p_item2);
676*d6b92ffaSHans Petter Selasky 		}
677*d6b92ffaSHans Petter Selasky 	}
678*d6b92ffaSHans Petter Selasky 
679*d6b92ffaSHans Petter Selasky 	/* Process the remainder if the end of either source map was reached. */
680*d6b92ffaSHans Petter Selasky 	while (p_item2 != cl_qmap_end(p_map2))
681*d6b92ffaSHans Petter Selasky 		__cl_qmap_delta_move(p_new, p_map2, &p_item2);
682*d6b92ffaSHans Petter Selasky 
683*d6b92ffaSHans Petter Selasky 	while (p_item1 != cl_qmap_end(p_map1))
684*d6b92ffaSHans Petter Selasky 		__cl_qmap_delta_move(p_old, p_map1, &p_item1);
685*d6b92ffaSHans Petter Selasky }
686*d6b92ffaSHans Petter Selasky 
687*d6b92ffaSHans Petter Selasky /******************************************************************************
688*d6b92ffaSHans Petter Selasky  IMPLEMENTATION OF MAP
689*d6b92ffaSHans Petter Selasky ******************************************************************************/
690*d6b92ffaSHans Petter Selasky 
691*d6b92ffaSHans Petter Selasky #define MAP_GROW_SIZE 32
692*d6b92ffaSHans Petter Selasky 
cl_map_construct(IN cl_map_t * const p_map)693*d6b92ffaSHans Petter Selasky void cl_map_construct(IN cl_map_t * const p_map)
694*d6b92ffaSHans Petter Selasky {
695*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
696*d6b92ffaSHans Petter Selasky 
697*d6b92ffaSHans Petter Selasky 	cl_qpool_construct(&p_map->pool);
698*d6b92ffaSHans Petter Selasky }
699*d6b92ffaSHans Petter Selasky 
cl_map_init(IN cl_map_t * const p_map,IN const uint32_t min_items)700*d6b92ffaSHans Petter Selasky cl_status_t cl_map_init(IN cl_map_t * const p_map, IN const uint32_t min_items)
701*d6b92ffaSHans Petter Selasky {
702*d6b92ffaSHans Petter Selasky 	uint32_t grow_size;
703*d6b92ffaSHans Petter Selasky 
704*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
705*d6b92ffaSHans Petter Selasky 
706*d6b92ffaSHans Petter Selasky 	cl_qmap_init(&p_map->qmap);
707*d6b92ffaSHans Petter Selasky 
708*d6b92ffaSHans Petter Selasky 	/*
709*d6b92ffaSHans Petter Selasky 	 * We will grow by min_items/8 items at a time, with a minimum of
710*d6b92ffaSHans Petter Selasky 	 * MAP_GROW_SIZE.
711*d6b92ffaSHans Petter Selasky 	 */
712*d6b92ffaSHans Petter Selasky 	grow_size = min_items >> 3;
713*d6b92ffaSHans Petter Selasky 	if (grow_size < MAP_GROW_SIZE)
714*d6b92ffaSHans Petter Selasky 		grow_size = MAP_GROW_SIZE;
715*d6b92ffaSHans Petter Selasky 
716*d6b92ffaSHans Petter Selasky 	return (cl_qpool_init(&p_map->pool, min_items, 0, grow_size,
717*d6b92ffaSHans Petter Selasky 			      sizeof(cl_map_obj_t), NULL, NULL, NULL));
718*d6b92ffaSHans Petter Selasky }
719*d6b92ffaSHans Petter Selasky 
cl_map_destroy(IN cl_map_t * const p_map)720*d6b92ffaSHans Petter Selasky void cl_map_destroy(IN cl_map_t * const p_map)
721*d6b92ffaSHans Petter Selasky {
722*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
723*d6b92ffaSHans Petter Selasky 
724*d6b92ffaSHans Petter Selasky 	cl_qpool_destroy(&p_map->pool);
725*d6b92ffaSHans Petter Selasky }
726*d6b92ffaSHans Petter Selasky 
cl_map_insert(IN cl_map_t * const p_map,IN const uint64_t key,IN const void * const p_object)727*d6b92ffaSHans Petter Selasky void *cl_map_insert(IN cl_map_t * const p_map,
728*d6b92ffaSHans Petter Selasky 		    IN const uint64_t key, IN const void *const p_object)
729*d6b92ffaSHans Petter Selasky {
730*d6b92ffaSHans Petter Selasky 	cl_map_obj_t *p_map_obj, *p_obj_at_key;
731*d6b92ffaSHans Petter Selasky 
732*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
733*d6b92ffaSHans Petter Selasky 
734*d6b92ffaSHans Petter Selasky 	p_map_obj = (cl_map_obj_t *) cl_qpool_get(&p_map->pool);
735*d6b92ffaSHans Petter Selasky 
736*d6b92ffaSHans Petter Selasky 	if (!p_map_obj)
737*d6b92ffaSHans Petter Selasky 		return (NULL);
738*d6b92ffaSHans Petter Selasky 
739*d6b92ffaSHans Petter Selasky 	cl_qmap_set_obj(p_map_obj, p_object);
740*d6b92ffaSHans Petter Selasky 
741*d6b92ffaSHans Petter Selasky 	p_obj_at_key =
742*d6b92ffaSHans Petter Selasky 	    (cl_map_obj_t *) cl_qmap_insert(&p_map->qmap, key,
743*d6b92ffaSHans Petter Selasky 					    &p_map_obj->item);
744*d6b92ffaSHans Petter Selasky 
745*d6b92ffaSHans Petter Selasky 	/* Return the item to the pool if insertion failed. */
746*d6b92ffaSHans Petter Selasky 	if (p_obj_at_key != p_map_obj)
747*d6b92ffaSHans Petter Selasky 		cl_qpool_put(&p_map->pool, &p_map_obj->item.pool_item);
748*d6b92ffaSHans Petter Selasky 
749*d6b92ffaSHans Petter Selasky 	return (cl_qmap_obj(p_obj_at_key));
750*d6b92ffaSHans Petter Selasky }
751*d6b92ffaSHans Petter Selasky 
cl_map_get(IN const cl_map_t * const p_map,IN const uint64_t key)752*d6b92ffaSHans Petter Selasky void *cl_map_get(IN const cl_map_t * const p_map, IN const uint64_t key)
753*d6b92ffaSHans Petter Selasky {
754*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item;
755*d6b92ffaSHans Petter Selasky 
756*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
757*d6b92ffaSHans Petter Selasky 
758*d6b92ffaSHans Petter Selasky 	p_item = cl_qmap_get(&p_map->qmap, key);
759*d6b92ffaSHans Petter Selasky 
760*d6b92ffaSHans Petter Selasky 	if (p_item == cl_qmap_end(&p_map->qmap))
761*d6b92ffaSHans Petter Selasky 		return (NULL);
762*d6b92ffaSHans Petter Selasky 
763*d6b92ffaSHans Petter Selasky 	return (cl_qmap_obj(PARENT_STRUCT(p_item, cl_map_obj_t, item)));
764*d6b92ffaSHans Petter Selasky }
765*d6b92ffaSHans Petter Selasky 
cl_map_get_next(IN const cl_map_t * const p_map,IN const uint64_t key)766*d6b92ffaSHans Petter Selasky void *cl_map_get_next(IN const cl_map_t * const p_map, IN const uint64_t key)
767*d6b92ffaSHans Petter Selasky {
768*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item;
769*d6b92ffaSHans Petter Selasky 
770*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
771*d6b92ffaSHans Petter Selasky 
772*d6b92ffaSHans Petter Selasky 	p_item = cl_qmap_get_next(&p_map->qmap, key);
773*d6b92ffaSHans Petter Selasky 
774*d6b92ffaSHans Petter Selasky 	if (p_item == cl_qmap_end(&p_map->qmap))
775*d6b92ffaSHans Petter Selasky 		return (NULL);
776*d6b92ffaSHans Petter Selasky 
777*d6b92ffaSHans Petter Selasky 	return (cl_qmap_obj(PARENT_STRUCT(p_item, cl_map_obj_t, item)));
778*d6b92ffaSHans Petter Selasky }
779*d6b92ffaSHans Petter Selasky 
cl_map_remove_item(IN cl_map_t * const p_map,IN const cl_map_iterator_t itor)780*d6b92ffaSHans Petter Selasky void cl_map_remove_item(IN cl_map_t * const p_map,
781*d6b92ffaSHans Petter Selasky 			IN const cl_map_iterator_t itor)
782*d6b92ffaSHans Petter Selasky {
783*d6b92ffaSHans Petter Selasky 	CL_ASSERT(itor->p_map == &p_map->qmap);
784*d6b92ffaSHans Petter Selasky 
785*d6b92ffaSHans Petter Selasky 	if (itor == cl_map_end(p_map))
786*d6b92ffaSHans Petter Selasky 		return;
787*d6b92ffaSHans Petter Selasky 
788*d6b92ffaSHans Petter Selasky 	cl_qmap_remove_item(&p_map->qmap, (cl_map_item_t *) itor);
789*d6b92ffaSHans Petter Selasky 	cl_qpool_put(&p_map->pool, &((cl_map_item_t *) itor)->pool_item);
790*d6b92ffaSHans Petter Selasky }
791*d6b92ffaSHans Petter Selasky 
cl_map_remove(IN cl_map_t * const p_map,IN const uint64_t key)792*d6b92ffaSHans Petter Selasky void *cl_map_remove(IN cl_map_t * const p_map, IN const uint64_t key)
793*d6b92ffaSHans Petter Selasky {
794*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item;
795*d6b92ffaSHans Petter Selasky 	void *p_obj;
796*d6b92ffaSHans Petter Selasky 
797*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
798*d6b92ffaSHans Petter Selasky 
799*d6b92ffaSHans Petter Selasky 	p_item = cl_qmap_remove(&p_map->qmap, key);
800*d6b92ffaSHans Petter Selasky 
801*d6b92ffaSHans Petter Selasky 	if (p_item == cl_qmap_end(&p_map->qmap))
802*d6b92ffaSHans Petter Selasky 		return (NULL);
803*d6b92ffaSHans Petter Selasky 
804*d6b92ffaSHans Petter Selasky 	p_obj = cl_qmap_obj((cl_map_obj_t *) p_item);
805*d6b92ffaSHans Petter Selasky 	cl_qpool_put(&p_map->pool, &p_item->pool_item);
806*d6b92ffaSHans Petter Selasky 
807*d6b92ffaSHans Petter Selasky 	return (p_obj);
808*d6b92ffaSHans Petter Selasky }
809*d6b92ffaSHans Petter Selasky 
cl_map_remove_all(IN cl_map_t * const p_map)810*d6b92ffaSHans Petter Selasky void cl_map_remove_all(IN cl_map_t * const p_map)
811*d6b92ffaSHans Petter Selasky {
812*d6b92ffaSHans Petter Selasky 	cl_map_item_t *p_item;
813*d6b92ffaSHans Petter Selasky 
814*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
815*d6b92ffaSHans Petter Selasky 
816*d6b92ffaSHans Petter Selasky 	/* Return all map items to the pool. */
817*d6b92ffaSHans Petter Selasky 	while (!cl_is_qmap_empty(&p_map->qmap)) {
818*d6b92ffaSHans Petter Selasky 		p_item = cl_qmap_head(&p_map->qmap);
819*d6b92ffaSHans Petter Selasky 		cl_qmap_remove_item(&p_map->qmap, p_item);
820*d6b92ffaSHans Petter Selasky 		cl_qpool_put(&p_map->pool, &p_item->pool_item);
821*d6b92ffaSHans Petter Selasky 
822*d6b92ffaSHans Petter Selasky 		if (!cl_is_qmap_empty(&p_map->qmap)) {
823*d6b92ffaSHans Petter Selasky 			p_item = cl_qmap_tail(&p_map->qmap);
824*d6b92ffaSHans Petter Selasky 			cl_qmap_remove_item(&p_map->qmap, p_item);
825*d6b92ffaSHans Petter Selasky 			cl_qpool_put(&p_map->pool, &p_item->pool_item);
826*d6b92ffaSHans Petter Selasky 		}
827*d6b92ffaSHans Petter Selasky 	}
828*d6b92ffaSHans Petter Selasky }
829*d6b92ffaSHans Petter Selasky 
cl_map_merge(OUT cl_map_t * const p_dest_map,IN OUT cl_map_t * const p_src_map)830*d6b92ffaSHans Petter Selasky cl_status_t cl_map_merge(OUT cl_map_t * const p_dest_map,
831*d6b92ffaSHans Petter Selasky 			 IN OUT cl_map_t * const p_src_map)
832*d6b92ffaSHans Petter Selasky {
833*d6b92ffaSHans Petter Selasky 	cl_status_t status = CL_SUCCESS;
834*d6b92ffaSHans Petter Selasky 	cl_map_iterator_t itor, next;
835*d6b92ffaSHans Petter Selasky 	uint64_t key;
836*d6b92ffaSHans Petter Selasky 	void *p_obj, *p_obj2;
837*d6b92ffaSHans Petter Selasky 
838*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_dest_map);
839*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_src_map);
840*d6b92ffaSHans Petter Selasky 
841*d6b92ffaSHans Petter Selasky 	itor = cl_map_head(p_src_map);
842*d6b92ffaSHans Petter Selasky 	while (itor != cl_map_end(p_src_map)) {
843*d6b92ffaSHans Petter Selasky 		next = cl_map_next(itor);
844*d6b92ffaSHans Petter Selasky 
845*d6b92ffaSHans Petter Selasky 		p_obj = cl_map_obj(itor);
846*d6b92ffaSHans Petter Selasky 		key = cl_map_key(itor);
847*d6b92ffaSHans Petter Selasky 
848*d6b92ffaSHans Petter Selasky 		cl_map_remove_item(p_src_map, itor);
849*d6b92ffaSHans Petter Selasky 
850*d6b92ffaSHans Petter Selasky 		/* Insert the object into the destination map. */
851*d6b92ffaSHans Petter Selasky 		p_obj2 = cl_map_insert(p_dest_map, key, p_obj);
852*d6b92ffaSHans Petter Selasky 		/* Trap for failure. */
853*d6b92ffaSHans Petter Selasky 		if (p_obj != p_obj2) {
854*d6b92ffaSHans Petter Selasky 			if (!p_obj2)
855*d6b92ffaSHans Petter Selasky 				status = CL_INSUFFICIENT_MEMORY;
856*d6b92ffaSHans Petter Selasky 			/* Put the object back in the source map.  This must succeed. */
857*d6b92ffaSHans Petter Selasky 			p_obj2 = cl_map_insert(p_src_map, key, p_obj);
858*d6b92ffaSHans Petter Selasky 			CL_ASSERT(p_obj == p_obj2);
859*d6b92ffaSHans Petter Selasky 			/* If the failure was due to insufficient memory, return. */
860*d6b92ffaSHans Petter Selasky 			if (status != CL_SUCCESS)
861*d6b92ffaSHans Petter Selasky 				return (status);
862*d6b92ffaSHans Petter Selasky 		}
863*d6b92ffaSHans Petter Selasky 		itor = next;
864*d6b92ffaSHans Petter Selasky 	}
865*d6b92ffaSHans Petter Selasky 
866*d6b92ffaSHans Petter Selasky 	return (CL_SUCCESS);
867*d6b92ffaSHans Petter Selasky }
868*d6b92ffaSHans Petter Selasky 
__cl_map_revert(IN OUT cl_map_t * const p_map1,IN OUT cl_map_t * const p_map2,IN OUT cl_map_t * const p_new,IN OUT cl_map_t * const p_old)869*d6b92ffaSHans Petter Selasky static void __cl_map_revert(IN OUT cl_map_t * const p_map1,
870*d6b92ffaSHans Petter Selasky 			    IN OUT cl_map_t * const p_map2,
871*d6b92ffaSHans Petter Selasky 			    IN OUT cl_map_t * const p_new,
872*d6b92ffaSHans Petter Selasky 			    IN OUT cl_map_t * const p_old)
873*d6b92ffaSHans Petter Selasky {
874*d6b92ffaSHans Petter Selasky 	cl_status_t __attribute__((__unused__)) status;
875*d6b92ffaSHans Petter Selasky 
876*d6b92ffaSHans Petter Selasky 	/* Restore the initial state. */
877*d6b92ffaSHans Petter Selasky 	status = cl_map_merge(p_map1, p_old);
878*d6b92ffaSHans Petter Selasky 	CL_ASSERT(status == CL_SUCCESS);
879*d6b92ffaSHans Petter Selasky 	status = cl_map_merge(p_map2, p_new);
880*d6b92ffaSHans Petter Selasky 	CL_ASSERT(status == CL_SUCCESS);
881*d6b92ffaSHans Petter Selasky }
882*d6b92ffaSHans Petter Selasky 
__cl_map_delta_move(OUT cl_map_t * const p_dest,IN OUT cl_map_t * const p_src,IN OUT cl_map_iterator_t * const p_itor)883*d6b92ffaSHans Petter Selasky static cl_status_t __cl_map_delta_move(OUT cl_map_t * const p_dest,
884*d6b92ffaSHans Petter Selasky 				       IN OUT cl_map_t * const p_src,
885*d6b92ffaSHans Petter Selasky 				       IN OUT cl_map_iterator_t * const p_itor)
886*d6b92ffaSHans Petter Selasky {
887*d6b92ffaSHans Petter Selasky 	cl_map_iterator_t next;
888*d6b92ffaSHans Petter Selasky 	void *p_obj, *p_obj2;
889*d6b92ffaSHans Petter Selasky 	uint64_t key;
890*d6b92ffaSHans Petter Selasky 
891*d6b92ffaSHans Petter Selasky 	/* Get a valid iterator so we can continue the loop. */
892*d6b92ffaSHans Petter Selasky 	next = cl_map_next(*p_itor);
893*d6b92ffaSHans Petter Selasky 	/* Get the pointer to the object for insertion. */
894*d6b92ffaSHans Petter Selasky 	p_obj = cl_map_obj(*p_itor);
895*d6b92ffaSHans Petter Selasky 	/* Get the key for the object. */
896*d6b92ffaSHans Petter Selasky 	key = cl_map_key(*p_itor);
897*d6b92ffaSHans Petter Selasky 	/* Move the object. */
898*d6b92ffaSHans Petter Selasky 	cl_map_remove_item(p_src, *p_itor);
899*d6b92ffaSHans Petter Selasky 	p_obj2 = cl_map_insert(p_dest, key, p_obj);
900*d6b92ffaSHans Petter Selasky 	/* Check for failure. We should never get a duplicate. */
901*d6b92ffaSHans Petter Selasky 	if (!p_obj2) {
902*d6b92ffaSHans Petter Selasky 		p_obj2 = cl_map_insert(p_src, key, p_obj);
903*d6b92ffaSHans Petter Selasky 		CL_ASSERT(p_obj2 == p_obj);
904*d6b92ffaSHans Petter Selasky 		return (CL_INSUFFICIENT_MEMORY);
905*d6b92ffaSHans Petter Selasky 	}
906*d6b92ffaSHans Petter Selasky 
907*d6b92ffaSHans Petter Selasky 	/* We should never get a duplicate */
908*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_obj == p_obj2);
909*d6b92ffaSHans Petter Selasky 	/* Update the iterator so that it is valid. */
910*d6b92ffaSHans Petter Selasky 	(*p_itor) = next;
911*d6b92ffaSHans Petter Selasky 
912*d6b92ffaSHans Petter Selasky 	return (CL_SUCCESS);
913*d6b92ffaSHans Petter Selasky }
914*d6b92ffaSHans Petter Selasky 
cl_map_delta(IN OUT cl_map_t * const p_map1,IN OUT cl_map_t * const p_map2,OUT cl_map_t * const p_new,OUT cl_map_t * const p_old)915*d6b92ffaSHans Petter Selasky cl_status_t cl_map_delta(IN OUT cl_map_t * const p_map1,
916*d6b92ffaSHans Petter Selasky 			 IN OUT cl_map_t * const p_map2,
917*d6b92ffaSHans Petter Selasky 			 OUT cl_map_t * const p_new, OUT cl_map_t * const p_old)
918*d6b92ffaSHans Petter Selasky {
919*d6b92ffaSHans Petter Selasky 	cl_map_iterator_t itor1, itor2;
920*d6b92ffaSHans Petter Selasky 	uint64_t key1, key2;
921*d6b92ffaSHans Petter Selasky 	cl_status_t status;
922*d6b92ffaSHans Petter Selasky 
923*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map1);
924*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map2);
925*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_new);
926*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_old);
927*d6b92ffaSHans Petter Selasky 	CL_ASSERT(cl_is_map_empty(p_new));
928*d6b92ffaSHans Petter Selasky 	CL_ASSERT(cl_is_map_empty(p_old));
929*d6b92ffaSHans Petter Selasky 
930*d6b92ffaSHans Petter Selasky 	itor1 = cl_map_head(p_map1);
931*d6b92ffaSHans Petter Selasky 	itor2 = cl_map_head(p_map2);
932*d6b92ffaSHans Petter Selasky 
933*d6b92ffaSHans Petter Selasky 	/*
934*d6b92ffaSHans Petter Selasky 	 * Note that the check is for the end, since duplicate items will remain
935*d6b92ffaSHans Petter Selasky 	 * in their respective maps.
936*d6b92ffaSHans Petter Selasky 	 */
937*d6b92ffaSHans Petter Selasky 	while (itor1 != cl_map_end(p_map1) && itor2 != cl_map_end(p_map2)) {
938*d6b92ffaSHans Petter Selasky 		key1 = cl_map_key(itor1);
939*d6b92ffaSHans Petter Selasky 		key2 = cl_map_key(itor2);
940*d6b92ffaSHans Petter Selasky 		if (key1 < key2) {
941*d6b92ffaSHans Petter Selasky 			status = __cl_map_delta_move(p_old, p_map1, &itor1);
942*d6b92ffaSHans Petter Selasky 			/* Check for failure. */
943*d6b92ffaSHans Petter Selasky 			if (status != CL_SUCCESS) {
944*d6b92ffaSHans Petter Selasky 				/* Restore the initial state. */
945*d6b92ffaSHans Petter Selasky 				__cl_map_revert(p_map1, p_map2, p_new, p_old);
946*d6b92ffaSHans Petter Selasky 				/* Return the failure status. */
947*d6b92ffaSHans Petter Selasky 				return (status);
948*d6b92ffaSHans Petter Selasky 			}
949*d6b92ffaSHans Petter Selasky 		} else if (key1 > key2) {
950*d6b92ffaSHans Petter Selasky 			status = __cl_map_delta_move(p_new, p_map2, &itor2);
951*d6b92ffaSHans Petter Selasky 			if (status != CL_SUCCESS) {
952*d6b92ffaSHans Petter Selasky 				/* Restore the initial state. */
953*d6b92ffaSHans Petter Selasky 				__cl_map_revert(p_map1, p_map2, p_new, p_old);
954*d6b92ffaSHans Petter Selasky 				/* Return the failure status. */
955*d6b92ffaSHans Petter Selasky 				return (status);
956*d6b92ffaSHans Petter Selasky 			}
957*d6b92ffaSHans Petter Selasky 		} else {
958*d6b92ffaSHans Petter Selasky 			/* Move both forward since they have the same key. */
959*d6b92ffaSHans Petter Selasky 			itor1 = cl_map_next(itor1);
960*d6b92ffaSHans Petter Selasky 			itor2 = cl_map_next(itor2);
961*d6b92ffaSHans Petter Selasky 		}
962*d6b92ffaSHans Petter Selasky 	}
963*d6b92ffaSHans Petter Selasky 
964*d6b92ffaSHans Petter Selasky 	/* Process the remainder if either source map is empty. */
965*d6b92ffaSHans Petter Selasky 	while (itor2 != cl_map_end(p_map2)) {
966*d6b92ffaSHans Petter Selasky 		status = __cl_map_delta_move(p_new, p_map2, &itor2);
967*d6b92ffaSHans Petter Selasky 		if (status != CL_SUCCESS) {
968*d6b92ffaSHans Petter Selasky 			/* Restore the initial state. */
969*d6b92ffaSHans Petter Selasky 			__cl_map_revert(p_map1, p_map2, p_new, p_old);
970*d6b92ffaSHans Petter Selasky 			/* Return the failure status. */
971*d6b92ffaSHans Petter Selasky 			return (status);
972*d6b92ffaSHans Petter Selasky 		}
973*d6b92ffaSHans Petter Selasky 	}
974*d6b92ffaSHans Petter Selasky 
975*d6b92ffaSHans Petter Selasky 	while (itor1 != cl_map_end(p_map1)) {
976*d6b92ffaSHans Petter Selasky 		status = __cl_map_delta_move(p_old, p_map1, &itor1);
977*d6b92ffaSHans Petter Selasky 		if (status != CL_SUCCESS) {
978*d6b92ffaSHans Petter Selasky 			/* Restore the initial state. */
979*d6b92ffaSHans Petter Selasky 			__cl_map_revert(p_map1, p_map2, p_new, p_old);
980*d6b92ffaSHans Petter Selasky 			/* Return the failure status. */
981*d6b92ffaSHans Petter Selasky 			return (status);
982*d6b92ffaSHans Petter Selasky 		}
983*d6b92ffaSHans Petter Selasky 	}
984*d6b92ffaSHans Petter Selasky 
985*d6b92ffaSHans Petter Selasky 	return (CL_SUCCESS);
986*d6b92ffaSHans Petter Selasky }
987*d6b92ffaSHans Petter Selasky 
988*d6b92ffaSHans Petter Selasky /******************************************************************************
989*d6b92ffaSHans Petter Selasky  IMPLEMENTATION OF FLEXI MAP
990*d6b92ffaSHans Petter Selasky ******************************************************************************/
991*d6b92ffaSHans Petter Selasky 
992*d6b92ffaSHans Petter Selasky /*
993*d6b92ffaSHans Petter Selasky  * Get the root.
994*d6b92ffaSHans Petter Selasky  */
__cl_fmap_root(IN const cl_fmap_t * const p_map)995*d6b92ffaSHans Petter Selasky static inline cl_fmap_item_t *__cl_fmap_root(IN const cl_fmap_t * const p_map)
996*d6b92ffaSHans Petter Selasky {
997*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
998*d6b92ffaSHans Petter Selasky 	return (p_map->root.p_left);
999*d6b92ffaSHans Petter Selasky }
1000*d6b92ffaSHans Petter Selasky 
1001*d6b92ffaSHans Petter Selasky /*
1002*d6b92ffaSHans Petter Selasky  * Returns whether a given item is on the left of its parent.
1003*d6b92ffaSHans Petter Selasky  */
__cl_fmap_is_left_child(IN const cl_fmap_item_t * const p_item)1004*d6b92ffaSHans Petter Selasky static boolean_t __cl_fmap_is_left_child(IN const cl_fmap_item_t * const p_item)
1005*d6b92ffaSHans Petter Selasky {
1006*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
1007*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up);
1008*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up != p_item);
1009*d6b92ffaSHans Petter Selasky 
1010*d6b92ffaSHans Petter Selasky 	return (p_item->p_up->p_left == p_item);
1011*d6b92ffaSHans Petter Selasky }
1012*d6b92ffaSHans Petter Selasky 
1013*d6b92ffaSHans Petter Selasky /*
1014*d6b92ffaSHans Petter Selasky  * Retrieve the pointer to the parent's pointer to an item.
1015*d6b92ffaSHans Petter Selasky  */
__cl_fmap_get_parent_ptr_to_item(IN cl_fmap_item_t * const p_item)1016*d6b92ffaSHans Petter Selasky static cl_fmap_item_t **__cl_fmap_get_parent_ptr_to_item(IN cl_fmap_item_t *
1017*d6b92ffaSHans Petter Selasky 							 const p_item)
1018*d6b92ffaSHans Petter Selasky {
1019*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
1020*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up);
1021*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up != p_item);
1022*d6b92ffaSHans Petter Selasky 
1023*d6b92ffaSHans Petter Selasky 	if (__cl_fmap_is_left_child(p_item))
1024*d6b92ffaSHans Petter Selasky 		return (&p_item->p_up->p_left);
1025*d6b92ffaSHans Petter Selasky 
1026*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_up->p_right == p_item);
1027*d6b92ffaSHans Petter Selasky 	return (&p_item->p_up->p_right);
1028*d6b92ffaSHans Petter Selasky }
1029*d6b92ffaSHans Petter Selasky 
1030*d6b92ffaSHans Petter Selasky /*
1031*d6b92ffaSHans Petter Selasky  * Rotate a node to the left.  This rotation affects the least number of links
1032*d6b92ffaSHans Petter Selasky  * between nodes and brings the level of C up by one while increasing the depth
1033*d6b92ffaSHans Petter Selasky  * of A one.  Note that the links to/from W, X, Y, and Z are not affected.
1034*d6b92ffaSHans Petter Selasky  *
1035*d6b92ffaSHans Petter Selasky  *	    R				      R
1036*d6b92ffaSHans Petter Selasky  *	    |				      |
1037*d6b92ffaSHans Petter Selasky  *	    A				      C
1038*d6b92ffaSHans Petter Selasky  *	  /   \			        /   \
1039*d6b92ffaSHans Petter Selasky  *	W       C			  A       Z
1040*d6b92ffaSHans Petter Selasky  *	       / \			 / \
1041*d6b92ffaSHans Petter Selasky  *	      B   Z			W   B
1042*d6b92ffaSHans Petter Selasky  *	     / \			   / \
1043*d6b92ffaSHans Petter Selasky  *	    X   Y			  X   Y
1044*d6b92ffaSHans Petter Selasky  */
__cl_fmap_rot_left(IN cl_fmap_t * const p_map,IN cl_fmap_item_t * const p_item)1045*d6b92ffaSHans Petter Selasky static void __cl_fmap_rot_left(IN cl_fmap_t * const p_map,
1046*d6b92ffaSHans Petter Selasky 			       IN cl_fmap_item_t * const p_item)
1047*d6b92ffaSHans Petter Selasky {
1048*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t **pp_root;
1049*d6b92ffaSHans Petter Selasky 
1050*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1051*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
1052*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_right != &p_map->nil);
1053*d6b92ffaSHans Petter Selasky 
1054*d6b92ffaSHans Petter Selasky 	pp_root = __cl_fmap_get_parent_ptr_to_item(p_item);
1055*d6b92ffaSHans Petter Selasky 
1056*d6b92ffaSHans Petter Selasky 	/* Point R to C instead of A. */
1057*d6b92ffaSHans Petter Selasky 	*pp_root = p_item->p_right;
1058*d6b92ffaSHans Petter Selasky 	/* Set C's parent to R. */
1059*d6b92ffaSHans Petter Selasky 	(*pp_root)->p_up = p_item->p_up;
1060*d6b92ffaSHans Petter Selasky 
1061*d6b92ffaSHans Petter Selasky 	/* Set A's right to B */
1062*d6b92ffaSHans Petter Selasky 	p_item->p_right = (*pp_root)->p_left;
1063*d6b92ffaSHans Petter Selasky 	/*
1064*d6b92ffaSHans Petter Selasky 	 * Set B's parent to A.  We trap for B being NIL since the
1065*d6b92ffaSHans Petter Selasky 	 * caller may depend on NIL not changing.
1066*d6b92ffaSHans Petter Selasky 	 */
1067*d6b92ffaSHans Petter Selasky 	if ((*pp_root)->p_left != &p_map->nil)
1068*d6b92ffaSHans Petter Selasky 		(*pp_root)->p_left->p_up = p_item;
1069*d6b92ffaSHans Petter Selasky 
1070*d6b92ffaSHans Petter Selasky 	/* Set C's left to A. */
1071*d6b92ffaSHans Petter Selasky 	(*pp_root)->p_left = p_item;
1072*d6b92ffaSHans Petter Selasky 	/* Set A's parent to C. */
1073*d6b92ffaSHans Petter Selasky 	p_item->p_up = *pp_root;
1074*d6b92ffaSHans Petter Selasky }
1075*d6b92ffaSHans Petter Selasky 
1076*d6b92ffaSHans Petter Selasky /*
1077*d6b92ffaSHans Petter Selasky  * Rotate a node to the right.  This rotation affects the least number of links
1078*d6b92ffaSHans Petter Selasky  * between nodes and brings the level of A up by one while increasing the depth
1079*d6b92ffaSHans Petter Selasky  * of C one.  Note that the links to/from W, X, Y, and Z are not affected.
1080*d6b92ffaSHans Petter Selasky  *
1081*d6b92ffaSHans Petter Selasky  *	        R				     R
1082*d6b92ffaSHans Petter Selasky  *	        |				     |
1083*d6b92ffaSHans Petter Selasky  *	        C				     A
1084*d6b92ffaSHans Petter Selasky  *	      /   \				   /   \
1085*d6b92ffaSHans Petter Selasky  *	    A       Z			 W       C
1086*d6b92ffaSHans Petter Selasky  *	   / \    				        / \
1087*d6b92ffaSHans Petter Selasky  *	  W   B   				       B   Z
1088*d6b92ffaSHans Petter Selasky  *	     / \				      / \
1089*d6b92ffaSHans Petter Selasky  *	    X   Y				     X   Y
1090*d6b92ffaSHans Petter Selasky  */
__cl_fmap_rot_right(IN cl_fmap_t * const p_map,IN cl_fmap_item_t * const p_item)1091*d6b92ffaSHans Petter Selasky static void __cl_fmap_rot_right(IN cl_fmap_t * const p_map,
1092*d6b92ffaSHans Petter Selasky 				IN cl_fmap_item_t * const p_item)
1093*d6b92ffaSHans Petter Selasky {
1094*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t **pp_root;
1095*d6b92ffaSHans Petter Selasky 
1096*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1097*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
1098*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_left != &p_map->nil);
1099*d6b92ffaSHans Petter Selasky 
1100*d6b92ffaSHans Petter Selasky 	/* Point R to A instead of C. */
1101*d6b92ffaSHans Petter Selasky 	pp_root = __cl_fmap_get_parent_ptr_to_item(p_item);
1102*d6b92ffaSHans Petter Selasky 	(*pp_root) = p_item->p_left;
1103*d6b92ffaSHans Petter Selasky 	/* Set A's parent to R. */
1104*d6b92ffaSHans Petter Selasky 	(*pp_root)->p_up = p_item->p_up;
1105*d6b92ffaSHans Petter Selasky 
1106*d6b92ffaSHans Petter Selasky 	/* Set C's left to B */
1107*d6b92ffaSHans Petter Selasky 	p_item->p_left = (*pp_root)->p_right;
1108*d6b92ffaSHans Petter Selasky 	/*
1109*d6b92ffaSHans Petter Selasky 	 * Set B's parent to C.  We trap for B being NIL since the
1110*d6b92ffaSHans Petter Selasky 	 * caller may depend on NIL not changing.
1111*d6b92ffaSHans Petter Selasky 	 */
1112*d6b92ffaSHans Petter Selasky 	if ((*pp_root)->p_right != &p_map->nil)
1113*d6b92ffaSHans Petter Selasky 		(*pp_root)->p_right->p_up = p_item;
1114*d6b92ffaSHans Petter Selasky 
1115*d6b92ffaSHans Petter Selasky 	/* Set A's right to C. */
1116*d6b92ffaSHans Petter Selasky 	(*pp_root)->p_right = p_item;
1117*d6b92ffaSHans Petter Selasky 	/* Set C's parent to A. */
1118*d6b92ffaSHans Petter Selasky 	p_item->p_up = *pp_root;
1119*d6b92ffaSHans Petter Selasky }
1120*d6b92ffaSHans Petter Selasky 
cl_fmap_init(IN cl_fmap_t * const p_map,IN cl_pfn_fmap_cmp_t pfn_compare)1121*d6b92ffaSHans Petter Selasky void cl_fmap_init(IN cl_fmap_t * const p_map, IN cl_pfn_fmap_cmp_t pfn_compare)
1122*d6b92ffaSHans Petter Selasky {
1123*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1124*d6b92ffaSHans Petter Selasky 	CL_ASSERT(pfn_compare);
1125*d6b92ffaSHans Petter Selasky 
1126*d6b92ffaSHans Petter Selasky 	memset(p_map, 0, sizeof(cl_fmap_t));
1127*d6b92ffaSHans Petter Selasky 
1128*d6b92ffaSHans Petter Selasky 	/* special setup for the root node */
1129*d6b92ffaSHans Petter Selasky 	p_map->root.p_up = &p_map->root;
1130*d6b92ffaSHans Petter Selasky 	p_map->root.p_left = &p_map->nil;
1131*d6b92ffaSHans Petter Selasky 	p_map->root.p_right = &p_map->nil;
1132*d6b92ffaSHans Petter Selasky 	p_map->root.color = CL_MAP_BLACK;
1133*d6b92ffaSHans Petter Selasky 
1134*d6b92ffaSHans Petter Selasky 	/* Setup the node used as terminator for all leaves. */
1135*d6b92ffaSHans Petter Selasky 	p_map->nil.p_up = &p_map->nil;
1136*d6b92ffaSHans Petter Selasky 	p_map->nil.p_left = &p_map->nil;
1137*d6b92ffaSHans Petter Selasky 	p_map->nil.p_right = &p_map->nil;
1138*d6b92ffaSHans Petter Selasky 	p_map->nil.color = CL_MAP_BLACK;
1139*d6b92ffaSHans Petter Selasky 
1140*d6b92ffaSHans Petter Selasky 	/* Store the compare function pointer. */
1141*d6b92ffaSHans Petter Selasky 	p_map->pfn_compare = pfn_compare;
1142*d6b92ffaSHans Petter Selasky 
1143*d6b92ffaSHans Petter Selasky 	p_map->state = CL_INITIALIZED;
1144*d6b92ffaSHans Petter Selasky 
1145*d6b92ffaSHans Petter Selasky 	cl_fmap_remove_all(p_map);
1146*d6b92ffaSHans Petter Selasky }
1147*d6b92ffaSHans Petter Selasky 
cl_fmap_match(IN const cl_fmap_t * const p_map,IN const void * const p_key,IN cl_pfn_fmap_cmp_t pfn_compare)1148*d6b92ffaSHans Petter Selasky cl_fmap_item_t *cl_fmap_match(IN const cl_fmap_t * const p_map,
1149*d6b92ffaSHans Petter Selasky 			      IN const void *const p_key,
1150*d6b92ffaSHans Petter Selasky 			      IN cl_pfn_fmap_cmp_t pfn_compare)
1151*d6b92ffaSHans Petter Selasky {
1152*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_item;
1153*d6b92ffaSHans Petter Selasky 	int cmp;
1154*d6b92ffaSHans Petter Selasky 
1155*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1156*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
1157*d6b92ffaSHans Petter Selasky 
1158*d6b92ffaSHans Petter Selasky 	p_item = __cl_fmap_root(p_map);
1159*d6b92ffaSHans Petter Selasky 
1160*d6b92ffaSHans Petter Selasky 	while (p_item != &p_map->nil) {
1161*d6b92ffaSHans Petter Selasky 		cmp = pfn_compare ? pfn_compare(p_key, p_item->p_key) :
1162*d6b92ffaSHans Petter Selasky 			p_map->pfn_compare(p_key, p_item->p_key);
1163*d6b92ffaSHans Petter Selasky 
1164*d6b92ffaSHans Petter Selasky 		if (!cmp)
1165*d6b92ffaSHans Petter Selasky 			break;	/* just right */
1166*d6b92ffaSHans Petter Selasky 
1167*d6b92ffaSHans Petter Selasky 		if (cmp < 0)
1168*d6b92ffaSHans Petter Selasky 			p_item = p_item->p_left;	/* too small */
1169*d6b92ffaSHans Petter Selasky 		else
1170*d6b92ffaSHans Petter Selasky 			p_item = p_item->p_right;	/* too big */
1171*d6b92ffaSHans Petter Selasky 	}
1172*d6b92ffaSHans Petter Selasky 
1173*d6b92ffaSHans Petter Selasky 	return (p_item);
1174*d6b92ffaSHans Petter Selasky }
1175*d6b92ffaSHans Petter Selasky 
cl_fmap_get(IN const cl_fmap_t * const p_map,IN const void * const p_key)1176*d6b92ffaSHans Petter Selasky cl_fmap_item_t *cl_fmap_get(IN const cl_fmap_t * const p_map,
1177*d6b92ffaSHans Petter Selasky 			    IN const void *const p_key)
1178*d6b92ffaSHans Petter Selasky {
1179*d6b92ffaSHans Petter Selasky 	return cl_fmap_match(p_map, p_key, p_map->pfn_compare);
1180*d6b92ffaSHans Petter Selasky }
1181*d6b92ffaSHans Petter Selasky 
cl_fmap_get_next(IN const cl_fmap_t * const p_map,IN const void * const p_key)1182*d6b92ffaSHans Petter Selasky cl_fmap_item_t *cl_fmap_get_next(IN const cl_fmap_t * const p_map,
1183*d6b92ffaSHans Petter Selasky 				 IN const void *const p_key)
1184*d6b92ffaSHans Petter Selasky {
1185*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_item;
1186*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_item_found;
1187*d6b92ffaSHans Petter Selasky 	int cmp;
1188*d6b92ffaSHans Petter Selasky 
1189*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1190*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
1191*d6b92ffaSHans Petter Selasky 
1192*d6b92ffaSHans Petter Selasky 	p_item = __cl_fmap_root(p_map);
1193*d6b92ffaSHans Petter Selasky 	p_item_found = (cl_fmap_item_t *) & p_map->nil;
1194*d6b92ffaSHans Petter Selasky 
1195*d6b92ffaSHans Petter Selasky 	while (p_item != &p_map->nil) {
1196*d6b92ffaSHans Petter Selasky 		cmp = p_map->pfn_compare(p_key, p_item->p_key);
1197*d6b92ffaSHans Petter Selasky 
1198*d6b92ffaSHans Petter Selasky 		if (cmp < 0) {
1199*d6b92ffaSHans Petter Selasky 			p_item_found = p_item;
1200*d6b92ffaSHans Petter Selasky 			p_item = p_item->p_left;	/* too small */
1201*d6b92ffaSHans Petter Selasky 		} else {
1202*d6b92ffaSHans Petter Selasky 			p_item = p_item->p_right;	/* too big or match */
1203*d6b92ffaSHans Petter Selasky 		}
1204*d6b92ffaSHans Petter Selasky 	}
1205*d6b92ffaSHans Petter Selasky 
1206*d6b92ffaSHans Petter Selasky 	return (p_item_found);
1207*d6b92ffaSHans Petter Selasky }
1208*d6b92ffaSHans Petter Selasky 
cl_fmap_apply_func(IN const cl_fmap_t * const p_map,IN cl_pfn_fmap_apply_t pfn_func,IN const void * const context)1209*d6b92ffaSHans Petter Selasky void cl_fmap_apply_func(IN const cl_fmap_t * const p_map,
1210*d6b92ffaSHans Petter Selasky 			IN cl_pfn_fmap_apply_t pfn_func,
1211*d6b92ffaSHans Petter Selasky 			IN const void *const context)
1212*d6b92ffaSHans Petter Selasky {
1213*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_fmap_item;
1214*d6b92ffaSHans Petter Selasky 
1215*d6b92ffaSHans Petter Selasky 	/* Note that context can have any arbitrary value. */
1216*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1217*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
1218*d6b92ffaSHans Petter Selasky 	CL_ASSERT(pfn_func);
1219*d6b92ffaSHans Petter Selasky 
1220*d6b92ffaSHans Petter Selasky 	p_fmap_item = cl_fmap_head(p_map);
1221*d6b92ffaSHans Petter Selasky 	while (p_fmap_item != cl_fmap_end(p_map)) {
1222*d6b92ffaSHans Petter Selasky 		pfn_func(p_fmap_item, (void *)context);
1223*d6b92ffaSHans Petter Selasky 		p_fmap_item = cl_fmap_next(p_fmap_item);
1224*d6b92ffaSHans Petter Selasky 	}
1225*d6b92ffaSHans Petter Selasky }
1226*d6b92ffaSHans Petter Selasky 
1227*d6b92ffaSHans Petter Selasky /*
1228*d6b92ffaSHans Petter Selasky  * Balance a tree starting at a given item back to the root.
1229*d6b92ffaSHans Petter Selasky  */
__cl_fmap_ins_bal(IN cl_fmap_t * const p_map,IN cl_fmap_item_t * p_item)1230*d6b92ffaSHans Petter Selasky static void __cl_fmap_ins_bal(IN cl_fmap_t * const p_map,
1231*d6b92ffaSHans Petter Selasky 			      IN cl_fmap_item_t * p_item)
1232*d6b92ffaSHans Petter Selasky {
1233*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_grand_uncle;
1234*d6b92ffaSHans Petter Selasky 
1235*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1236*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
1237*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item != &p_map->root);
1238*d6b92ffaSHans Petter Selasky 
1239*d6b92ffaSHans Petter Selasky 	while (p_item->p_up->color == CL_MAP_RED) {
1240*d6b92ffaSHans Petter Selasky 		if (__cl_fmap_is_left_child(p_item->p_up)) {
1241*d6b92ffaSHans Petter Selasky 			p_grand_uncle = p_item->p_up->p_up->p_right;
1242*d6b92ffaSHans Petter Selasky 			CL_ASSERT(p_grand_uncle);
1243*d6b92ffaSHans Petter Selasky 			if (p_grand_uncle->color == CL_MAP_RED) {
1244*d6b92ffaSHans Petter Selasky 				p_grand_uncle->color = CL_MAP_BLACK;
1245*d6b92ffaSHans Petter Selasky 				p_item->p_up->color = CL_MAP_BLACK;
1246*d6b92ffaSHans Petter Selasky 				p_item->p_up->p_up->color = CL_MAP_RED;
1247*d6b92ffaSHans Petter Selasky 				p_item = p_item->p_up->p_up;
1248*d6b92ffaSHans Petter Selasky 				continue;
1249*d6b92ffaSHans Petter Selasky 			}
1250*d6b92ffaSHans Petter Selasky 
1251*d6b92ffaSHans Petter Selasky 			if (!__cl_fmap_is_left_child(p_item)) {
1252*d6b92ffaSHans Petter Selasky 				p_item = p_item->p_up;
1253*d6b92ffaSHans Petter Selasky 				__cl_fmap_rot_left(p_map, p_item);
1254*d6b92ffaSHans Petter Selasky 			}
1255*d6b92ffaSHans Petter Selasky 			p_item->p_up->color = CL_MAP_BLACK;
1256*d6b92ffaSHans Petter Selasky 			p_item->p_up->p_up->color = CL_MAP_RED;
1257*d6b92ffaSHans Petter Selasky 			__cl_fmap_rot_right(p_map, p_item->p_up->p_up);
1258*d6b92ffaSHans Petter Selasky 		} else {
1259*d6b92ffaSHans Petter Selasky 			p_grand_uncle = p_item->p_up->p_up->p_left;
1260*d6b92ffaSHans Petter Selasky 			CL_ASSERT(p_grand_uncle);
1261*d6b92ffaSHans Petter Selasky 			if (p_grand_uncle->color == CL_MAP_RED) {
1262*d6b92ffaSHans Petter Selasky 				p_grand_uncle->color = CL_MAP_BLACK;
1263*d6b92ffaSHans Petter Selasky 				p_item->p_up->color = CL_MAP_BLACK;
1264*d6b92ffaSHans Petter Selasky 				p_item->p_up->p_up->color = CL_MAP_RED;
1265*d6b92ffaSHans Petter Selasky 				p_item = p_item->p_up->p_up;
1266*d6b92ffaSHans Petter Selasky 				continue;
1267*d6b92ffaSHans Petter Selasky 			}
1268*d6b92ffaSHans Petter Selasky 
1269*d6b92ffaSHans Petter Selasky 			if (__cl_fmap_is_left_child(p_item)) {
1270*d6b92ffaSHans Petter Selasky 				p_item = p_item->p_up;
1271*d6b92ffaSHans Petter Selasky 				__cl_fmap_rot_right(p_map, p_item);
1272*d6b92ffaSHans Petter Selasky 			}
1273*d6b92ffaSHans Petter Selasky 			p_item->p_up->color = CL_MAP_BLACK;
1274*d6b92ffaSHans Petter Selasky 			p_item->p_up->p_up->color = CL_MAP_RED;
1275*d6b92ffaSHans Petter Selasky 			__cl_fmap_rot_left(p_map, p_item->p_up->p_up);
1276*d6b92ffaSHans Petter Selasky 		}
1277*d6b92ffaSHans Petter Selasky 	}
1278*d6b92ffaSHans Petter Selasky }
1279*d6b92ffaSHans Petter Selasky 
cl_fmap_insert(IN cl_fmap_t * const p_map,IN const void * const p_key,IN cl_fmap_item_t * const p_item)1280*d6b92ffaSHans Petter Selasky cl_fmap_item_t *cl_fmap_insert(IN cl_fmap_t * const p_map,
1281*d6b92ffaSHans Petter Selasky 			       IN const void *const p_key,
1282*d6b92ffaSHans Petter Selasky 			       IN cl_fmap_item_t * const p_item)
1283*d6b92ffaSHans Petter Selasky {
1284*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_insert_at, *p_comp_item;
1285*d6b92ffaSHans Petter Selasky 	int cmp = 0;
1286*d6b92ffaSHans Petter Selasky 
1287*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1288*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
1289*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
1290*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->root.p_up == &p_map->root);
1291*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->root.color != CL_MAP_RED);
1292*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->nil.color != CL_MAP_RED);
1293*d6b92ffaSHans Petter Selasky 
1294*d6b92ffaSHans Petter Selasky 	p_item->p_left = &p_map->nil;
1295*d6b92ffaSHans Petter Selasky 	p_item->p_right = &p_map->nil;
1296*d6b92ffaSHans Petter Selasky 	p_item->p_key = p_key;
1297*d6b92ffaSHans Petter Selasky 	p_item->color = CL_MAP_RED;
1298*d6b92ffaSHans Petter Selasky 
1299*d6b92ffaSHans Petter Selasky 	/* Find the insertion location. */
1300*d6b92ffaSHans Petter Selasky 	p_insert_at = &p_map->root;
1301*d6b92ffaSHans Petter Selasky 	p_comp_item = __cl_fmap_root(p_map);
1302*d6b92ffaSHans Petter Selasky 
1303*d6b92ffaSHans Petter Selasky 	while (p_comp_item != &p_map->nil) {
1304*d6b92ffaSHans Petter Selasky 		p_insert_at = p_comp_item;
1305*d6b92ffaSHans Petter Selasky 
1306*d6b92ffaSHans Petter Selasky 		cmp = p_map->pfn_compare(p_key, p_insert_at->p_key);
1307*d6b92ffaSHans Petter Selasky 
1308*d6b92ffaSHans Petter Selasky 		if (!cmp)
1309*d6b92ffaSHans Petter Selasky 			return (p_insert_at);
1310*d6b92ffaSHans Petter Selasky 
1311*d6b92ffaSHans Petter Selasky 		/* Traverse the tree until the correct insertion point is found. */
1312*d6b92ffaSHans Petter Selasky 		if (cmp < 0)
1313*d6b92ffaSHans Petter Selasky 			p_comp_item = p_insert_at->p_left;
1314*d6b92ffaSHans Petter Selasky 		else
1315*d6b92ffaSHans Petter Selasky 			p_comp_item = p_insert_at->p_right;
1316*d6b92ffaSHans Petter Selasky 	}
1317*d6b92ffaSHans Petter Selasky 
1318*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_insert_at != &p_map->nil);
1319*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_comp_item == &p_map->nil);
1320*d6b92ffaSHans Petter Selasky 	/* Insert the item. */
1321*d6b92ffaSHans Petter Selasky 	if (p_insert_at == &p_map->root) {
1322*d6b92ffaSHans Petter Selasky 		p_insert_at->p_left = p_item;
1323*d6b92ffaSHans Petter Selasky 		/*
1324*d6b92ffaSHans Petter Selasky 		 * Primitive insert places the new item in front of
1325*d6b92ffaSHans Petter Selasky 		 * the existing item.
1326*d6b92ffaSHans Petter Selasky 		 */
1327*d6b92ffaSHans Petter Selasky 		__cl_primitive_insert(&p_map->nil.pool_item.list_item,
1328*d6b92ffaSHans Petter Selasky 				      &p_item->pool_item.list_item);
1329*d6b92ffaSHans Petter Selasky 	} else if (cmp < 0) {
1330*d6b92ffaSHans Petter Selasky 		p_insert_at->p_left = p_item;
1331*d6b92ffaSHans Petter Selasky 		/*
1332*d6b92ffaSHans Petter Selasky 		 * Primitive insert places the new item in front of
1333*d6b92ffaSHans Petter Selasky 		 * the existing item.
1334*d6b92ffaSHans Petter Selasky 		 */
1335*d6b92ffaSHans Petter Selasky 		__cl_primitive_insert(&p_insert_at->pool_item.list_item,
1336*d6b92ffaSHans Petter Selasky 				      &p_item->pool_item.list_item);
1337*d6b92ffaSHans Petter Selasky 	} else {
1338*d6b92ffaSHans Petter Selasky 		p_insert_at->p_right = p_item;
1339*d6b92ffaSHans Petter Selasky 		/*
1340*d6b92ffaSHans Petter Selasky 		 * Primitive insert places the new item in front of
1341*d6b92ffaSHans Petter Selasky 		 * the existing item.
1342*d6b92ffaSHans Petter Selasky 		 */
1343*d6b92ffaSHans Petter Selasky 		__cl_primitive_insert(p_insert_at->pool_item.list_item.p_next,
1344*d6b92ffaSHans Petter Selasky 				      &p_item->pool_item.list_item);
1345*d6b92ffaSHans Petter Selasky 	}
1346*d6b92ffaSHans Petter Selasky 	/* Increase the count. */
1347*d6b92ffaSHans Petter Selasky 	p_map->count++;
1348*d6b92ffaSHans Petter Selasky 
1349*d6b92ffaSHans Petter Selasky 	p_item->p_up = p_insert_at;
1350*d6b92ffaSHans Petter Selasky 
1351*d6b92ffaSHans Petter Selasky 	/*
1352*d6b92ffaSHans Petter Selasky 	 * We have added depth to this section of the tree.
1353*d6b92ffaSHans Petter Selasky 	 * Rebalance as necessary as we retrace our path through the tree
1354*d6b92ffaSHans Petter Selasky 	 * and update colors.
1355*d6b92ffaSHans Petter Selasky 	 */
1356*d6b92ffaSHans Petter Selasky 	__cl_fmap_ins_bal(p_map, p_item);
1357*d6b92ffaSHans Petter Selasky 
1358*d6b92ffaSHans Petter Selasky 	__cl_fmap_root(p_map)->color = CL_MAP_BLACK;
1359*d6b92ffaSHans Petter Selasky 
1360*d6b92ffaSHans Petter Selasky 	/*
1361*d6b92ffaSHans Petter Selasky 	 * Note that it is not necessary to re-color the nil node black because all
1362*d6b92ffaSHans Petter Selasky 	 * red color assignments are made via the p_up pointer, and nil is never
1363*d6b92ffaSHans Petter Selasky 	 * set as the value of a p_up pointer.
1364*d6b92ffaSHans Petter Selasky 	 */
1365*d6b92ffaSHans Petter Selasky 
1366*d6b92ffaSHans Petter Selasky #ifdef _DEBUG_
1367*d6b92ffaSHans Petter Selasky 	/* Set the pointer to the map in the map item for consistency checking. */
1368*d6b92ffaSHans Petter Selasky 	p_item->p_map = p_map;
1369*d6b92ffaSHans Petter Selasky #endif
1370*d6b92ffaSHans Petter Selasky 
1371*d6b92ffaSHans Petter Selasky 	return (p_item);
1372*d6b92ffaSHans Petter Selasky }
1373*d6b92ffaSHans Petter Selasky 
__cl_fmap_del_bal(IN cl_fmap_t * const p_map,IN cl_fmap_item_t * p_item)1374*d6b92ffaSHans Petter Selasky static void __cl_fmap_del_bal(IN cl_fmap_t * const p_map,
1375*d6b92ffaSHans Petter Selasky 			      IN cl_fmap_item_t * p_item)
1376*d6b92ffaSHans Petter Selasky {
1377*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_uncle;
1378*d6b92ffaSHans Petter Selasky 
1379*d6b92ffaSHans Petter Selasky 	while ((p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root)) {
1380*d6b92ffaSHans Petter Selasky 		if (__cl_fmap_is_left_child(p_item)) {
1381*d6b92ffaSHans Petter Selasky 			p_uncle = p_item->p_up->p_right;
1382*d6b92ffaSHans Petter Selasky 
1383*d6b92ffaSHans Petter Selasky 			if (p_uncle->color == CL_MAP_RED) {
1384*d6b92ffaSHans Petter Selasky 				p_uncle->color = CL_MAP_BLACK;
1385*d6b92ffaSHans Petter Selasky 				p_item->p_up->color = CL_MAP_RED;
1386*d6b92ffaSHans Petter Selasky 				__cl_fmap_rot_left(p_map, p_item->p_up);
1387*d6b92ffaSHans Petter Selasky 				p_uncle = p_item->p_up->p_right;
1388*d6b92ffaSHans Petter Selasky 			}
1389*d6b92ffaSHans Petter Selasky 
1390*d6b92ffaSHans Petter Selasky 			if (p_uncle->p_right->color != CL_MAP_RED) {
1391*d6b92ffaSHans Petter Selasky 				if (p_uncle->p_left->color != CL_MAP_RED) {
1392*d6b92ffaSHans Petter Selasky 					p_uncle->color = CL_MAP_RED;
1393*d6b92ffaSHans Petter Selasky 					p_item = p_item->p_up;
1394*d6b92ffaSHans Petter Selasky 					continue;
1395*d6b92ffaSHans Petter Selasky 				}
1396*d6b92ffaSHans Petter Selasky 
1397*d6b92ffaSHans Petter Selasky 				p_uncle->p_left->color = CL_MAP_BLACK;
1398*d6b92ffaSHans Petter Selasky 				p_uncle->color = CL_MAP_RED;
1399*d6b92ffaSHans Petter Selasky 				__cl_fmap_rot_right(p_map, p_uncle);
1400*d6b92ffaSHans Petter Selasky 				p_uncle = p_item->p_up->p_right;
1401*d6b92ffaSHans Petter Selasky 			}
1402*d6b92ffaSHans Petter Selasky 			p_uncle->color = p_item->p_up->color;
1403*d6b92ffaSHans Petter Selasky 			p_item->p_up->color = CL_MAP_BLACK;
1404*d6b92ffaSHans Petter Selasky 			p_uncle->p_right->color = CL_MAP_BLACK;
1405*d6b92ffaSHans Petter Selasky 			__cl_fmap_rot_left(p_map, p_item->p_up);
1406*d6b92ffaSHans Petter Selasky 			break;
1407*d6b92ffaSHans Petter Selasky 		} else {
1408*d6b92ffaSHans Petter Selasky 			p_uncle = p_item->p_up->p_left;
1409*d6b92ffaSHans Petter Selasky 
1410*d6b92ffaSHans Petter Selasky 			if (p_uncle->color == CL_MAP_RED) {
1411*d6b92ffaSHans Petter Selasky 				p_uncle->color = CL_MAP_BLACK;
1412*d6b92ffaSHans Petter Selasky 				p_item->p_up->color = CL_MAP_RED;
1413*d6b92ffaSHans Petter Selasky 				__cl_fmap_rot_right(p_map, p_item->p_up);
1414*d6b92ffaSHans Petter Selasky 				p_uncle = p_item->p_up->p_left;
1415*d6b92ffaSHans Petter Selasky 			}
1416*d6b92ffaSHans Petter Selasky 
1417*d6b92ffaSHans Petter Selasky 			if (p_uncle->p_left->color != CL_MAP_RED) {
1418*d6b92ffaSHans Petter Selasky 				if (p_uncle->p_right->color != CL_MAP_RED) {
1419*d6b92ffaSHans Petter Selasky 					p_uncle->color = CL_MAP_RED;
1420*d6b92ffaSHans Petter Selasky 					p_item = p_item->p_up;
1421*d6b92ffaSHans Petter Selasky 					continue;
1422*d6b92ffaSHans Petter Selasky 				}
1423*d6b92ffaSHans Petter Selasky 
1424*d6b92ffaSHans Petter Selasky 				p_uncle->p_right->color = CL_MAP_BLACK;
1425*d6b92ffaSHans Petter Selasky 				p_uncle->color = CL_MAP_RED;
1426*d6b92ffaSHans Petter Selasky 				__cl_fmap_rot_left(p_map, p_uncle);
1427*d6b92ffaSHans Petter Selasky 				p_uncle = p_item->p_up->p_left;
1428*d6b92ffaSHans Petter Selasky 			}
1429*d6b92ffaSHans Petter Selasky 			p_uncle->color = p_item->p_up->color;
1430*d6b92ffaSHans Petter Selasky 			p_item->p_up->color = CL_MAP_BLACK;
1431*d6b92ffaSHans Petter Selasky 			p_uncle->p_left->color = CL_MAP_BLACK;
1432*d6b92ffaSHans Petter Selasky 			__cl_fmap_rot_right(p_map, p_item->p_up);
1433*d6b92ffaSHans Petter Selasky 			break;
1434*d6b92ffaSHans Petter Selasky 		}
1435*d6b92ffaSHans Petter Selasky 	}
1436*d6b92ffaSHans Petter Selasky 	p_item->color = CL_MAP_BLACK;
1437*d6b92ffaSHans Petter Selasky }
1438*d6b92ffaSHans Petter Selasky 
cl_fmap_remove_item(IN cl_fmap_t * const p_map,IN cl_fmap_item_t * const p_item)1439*d6b92ffaSHans Petter Selasky void cl_fmap_remove_item(IN cl_fmap_t * const p_map,
1440*d6b92ffaSHans Petter Selasky 			 IN cl_fmap_item_t * const p_item)
1441*d6b92ffaSHans Petter Selasky {
1442*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_child, *p_del_item;
1443*d6b92ffaSHans Petter Selasky 
1444*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1445*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
1446*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item);
1447*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_item->p_map == p_map);
1448*d6b92ffaSHans Petter Selasky 
1449*d6b92ffaSHans Petter Selasky 	if (p_item == cl_fmap_end(p_map))
1450*d6b92ffaSHans Petter Selasky 		return;
1451*d6b92ffaSHans Petter Selasky 
1452*d6b92ffaSHans Petter Selasky 	if ((p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil)) {
1453*d6b92ffaSHans Petter Selasky 		/* The item being removed has children on at most on side. */
1454*d6b92ffaSHans Petter Selasky 		p_del_item = p_item;
1455*d6b92ffaSHans Petter Selasky 	} else {
1456*d6b92ffaSHans Petter Selasky 		/*
1457*d6b92ffaSHans Petter Selasky 		 * The item being removed has children on both side.
1458*d6b92ffaSHans Petter Selasky 		 * We select the item that will replace it.  After removing
1459*d6b92ffaSHans Petter Selasky 		 * the substitute item and rebalancing, the tree will have the
1460*d6b92ffaSHans Petter Selasky 		 * correct topology.  Exchanging the substitute for the item
1461*d6b92ffaSHans Petter Selasky 		 * will finalize the removal.
1462*d6b92ffaSHans Petter Selasky 		 */
1463*d6b92ffaSHans Petter Selasky 		p_del_item = cl_fmap_next(p_item);
1464*d6b92ffaSHans Petter Selasky 		CL_ASSERT(p_del_item != &p_map->nil);
1465*d6b92ffaSHans Petter Selasky 	}
1466*d6b92ffaSHans Petter Selasky 
1467*d6b92ffaSHans Petter Selasky 	/* Remove the item from the list. */
1468*d6b92ffaSHans Petter Selasky 	__cl_primitive_remove(&p_item->pool_item.list_item);
1469*d6b92ffaSHans Petter Selasky 	/* Decrement the item count. */
1470*d6b92ffaSHans Petter Selasky 	p_map->count--;
1471*d6b92ffaSHans Petter Selasky 
1472*d6b92ffaSHans Petter Selasky 	/* Get the pointer to the new root's child, if any. */
1473*d6b92ffaSHans Petter Selasky 	if (p_del_item->p_left != &p_map->nil)
1474*d6b92ffaSHans Petter Selasky 		p_child = p_del_item->p_left;
1475*d6b92ffaSHans Petter Selasky 	else
1476*d6b92ffaSHans Petter Selasky 		p_child = p_del_item->p_right;
1477*d6b92ffaSHans Petter Selasky 
1478*d6b92ffaSHans Petter Selasky 	/*
1479*d6b92ffaSHans Petter Selasky 	 * This assignment may modify the parent pointer of the nil node.
1480*d6b92ffaSHans Petter Selasky 	 * This is inconsequential.
1481*d6b92ffaSHans Petter Selasky 	 */
1482*d6b92ffaSHans Petter Selasky 	p_child->p_up = p_del_item->p_up;
1483*d6b92ffaSHans Petter Selasky 	(*__cl_fmap_get_parent_ptr_to_item(p_del_item)) = p_child;
1484*d6b92ffaSHans Petter Selasky 
1485*d6b92ffaSHans Petter Selasky 	if (p_del_item->color != CL_MAP_RED)
1486*d6b92ffaSHans Petter Selasky 		__cl_fmap_del_bal(p_map, p_child);
1487*d6b92ffaSHans Petter Selasky 
1488*d6b92ffaSHans Petter Selasky 	/*
1489*d6b92ffaSHans Petter Selasky 	 * Note that the splicing done below does not need to occur before
1490*d6b92ffaSHans Petter Selasky 	 * the tree is balanced, since the actual topology changes are made by the
1491*d6b92ffaSHans Petter Selasky 	 * preceding code.  The topology is preserved by the color assignment made
1492*d6b92ffaSHans Petter Selasky 	 * below (reader should be reminded that p_del_item == p_item in some cases).
1493*d6b92ffaSHans Petter Selasky 	 */
1494*d6b92ffaSHans Petter Selasky 	if (p_del_item != p_item) {
1495*d6b92ffaSHans Petter Selasky 		/*
1496*d6b92ffaSHans Petter Selasky 		 * Finalize the removal of the specified item by exchanging it with
1497*d6b92ffaSHans Petter Selasky 		 * the substitute which we removed above.
1498*d6b92ffaSHans Petter Selasky 		 */
1499*d6b92ffaSHans Petter Selasky 		p_del_item->p_up = p_item->p_up;
1500*d6b92ffaSHans Petter Selasky 		p_del_item->p_left = p_item->p_left;
1501*d6b92ffaSHans Petter Selasky 		p_del_item->p_right = p_item->p_right;
1502*d6b92ffaSHans Petter Selasky 		(*__cl_fmap_get_parent_ptr_to_item(p_item)) = p_del_item;
1503*d6b92ffaSHans Petter Selasky 		p_item->p_right->p_up = p_del_item;
1504*d6b92ffaSHans Petter Selasky 		p_item->p_left->p_up = p_del_item;
1505*d6b92ffaSHans Petter Selasky 		p_del_item->color = p_item->color;
1506*d6b92ffaSHans Petter Selasky 	}
1507*d6b92ffaSHans Petter Selasky 
1508*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->nil.color != CL_MAP_RED);
1509*d6b92ffaSHans Petter Selasky 
1510*d6b92ffaSHans Petter Selasky #ifdef _DEBUG_
1511*d6b92ffaSHans Petter Selasky 	/* Clear the pointer to the map since the item has been removed. */
1512*d6b92ffaSHans Petter Selasky 	p_item->p_map = NULL;
1513*d6b92ffaSHans Petter Selasky #endif
1514*d6b92ffaSHans Petter Selasky }
1515*d6b92ffaSHans Petter Selasky 
cl_fmap_remove(IN cl_fmap_t * const p_map,IN const void * const p_key)1516*d6b92ffaSHans Petter Selasky cl_fmap_item_t *cl_fmap_remove(IN cl_fmap_t * const p_map,
1517*d6b92ffaSHans Petter Selasky 			       IN const void *const p_key)
1518*d6b92ffaSHans Petter Selasky {
1519*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_item;
1520*d6b92ffaSHans Petter Selasky 
1521*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map);
1522*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map->state == CL_INITIALIZED);
1523*d6b92ffaSHans Petter Selasky 
1524*d6b92ffaSHans Petter Selasky 	/* Seek the node with the specified key */
1525*d6b92ffaSHans Petter Selasky 	p_item = cl_fmap_get(p_map, p_key);
1526*d6b92ffaSHans Petter Selasky 
1527*d6b92ffaSHans Petter Selasky 	cl_fmap_remove_item(p_map, p_item);
1528*d6b92ffaSHans Petter Selasky 
1529*d6b92ffaSHans Petter Selasky 	return (p_item);
1530*d6b92ffaSHans Petter Selasky }
1531*d6b92ffaSHans Petter Selasky 
cl_fmap_merge(OUT cl_fmap_t * const p_dest_map,IN OUT cl_fmap_t * const p_src_map)1532*d6b92ffaSHans Petter Selasky void cl_fmap_merge(OUT cl_fmap_t * const p_dest_map,
1533*d6b92ffaSHans Petter Selasky 		   IN OUT cl_fmap_t * const p_src_map)
1534*d6b92ffaSHans Petter Selasky {
1535*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_item, *p_item2, *p_next;
1536*d6b92ffaSHans Petter Selasky 
1537*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_dest_map);
1538*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_src_map);
1539*d6b92ffaSHans Petter Selasky 
1540*d6b92ffaSHans Petter Selasky 	p_item = cl_fmap_head(p_src_map);
1541*d6b92ffaSHans Petter Selasky 
1542*d6b92ffaSHans Petter Selasky 	while (p_item != cl_fmap_end(p_src_map)) {
1543*d6b92ffaSHans Petter Selasky 		p_next = cl_fmap_next(p_item);
1544*d6b92ffaSHans Petter Selasky 
1545*d6b92ffaSHans Petter Selasky 		/* Remove the item from its current map. */
1546*d6b92ffaSHans Petter Selasky 		cl_fmap_remove_item(p_src_map, p_item);
1547*d6b92ffaSHans Petter Selasky 		/* Insert the item into the destination map. */
1548*d6b92ffaSHans Petter Selasky 		p_item2 =
1549*d6b92ffaSHans Petter Selasky 		    cl_fmap_insert(p_dest_map, cl_fmap_key(p_item), p_item);
1550*d6b92ffaSHans Petter Selasky 		/* Check that the item was successfully inserted. */
1551*d6b92ffaSHans Petter Selasky 		if (p_item2 != p_item) {
1552*d6b92ffaSHans Petter Selasky 			/* Put the item in back in the source map. */
1553*d6b92ffaSHans Petter Selasky 			p_item2 =
1554*d6b92ffaSHans Petter Selasky 			    cl_fmap_insert(p_src_map, cl_fmap_key(p_item),
1555*d6b92ffaSHans Petter Selasky 					   p_item);
1556*d6b92ffaSHans Petter Selasky 			CL_ASSERT(p_item2 == p_item);
1557*d6b92ffaSHans Petter Selasky 		}
1558*d6b92ffaSHans Petter Selasky 		p_item = p_next;
1559*d6b92ffaSHans Petter Selasky 	}
1560*d6b92ffaSHans Petter Selasky }
1561*d6b92ffaSHans Petter Selasky 
__cl_fmap_delta_move(IN OUT cl_fmap_t * const p_dest,IN OUT cl_fmap_t * const p_src,IN OUT cl_fmap_item_t ** const pp_item)1562*d6b92ffaSHans Petter Selasky static void __cl_fmap_delta_move(IN OUT cl_fmap_t * const p_dest,
1563*d6b92ffaSHans Petter Selasky 				 IN OUT cl_fmap_t * const p_src,
1564*d6b92ffaSHans Petter Selasky 				 IN OUT cl_fmap_item_t ** const pp_item)
1565*d6b92ffaSHans Petter Selasky {
1566*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t __attribute__((__unused__)) *p_temp;
1567*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_next;
1568*d6b92ffaSHans Petter Selasky 
1569*d6b92ffaSHans Petter Selasky 	/*
1570*d6b92ffaSHans Petter Selasky 	 * Get the next item so that we can ensure that pp_item points to
1571*d6b92ffaSHans Petter Selasky 	 * a valid item upon return from the function.
1572*d6b92ffaSHans Petter Selasky 	 */
1573*d6b92ffaSHans Petter Selasky 	p_next = cl_fmap_next(*pp_item);
1574*d6b92ffaSHans Petter Selasky 	/* Move the old item from its current map the the old map. */
1575*d6b92ffaSHans Petter Selasky 	cl_fmap_remove_item(p_src, *pp_item);
1576*d6b92ffaSHans Petter Selasky 	p_temp = cl_fmap_insert(p_dest, cl_fmap_key(*pp_item), *pp_item);
1577*d6b92ffaSHans Petter Selasky 	/* We should never have duplicates. */
1578*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_temp == *pp_item);
1579*d6b92ffaSHans Petter Selasky 	/* Point pp_item to a valid item in the source map. */
1580*d6b92ffaSHans Petter Selasky 	(*pp_item) = p_next;
1581*d6b92ffaSHans Petter Selasky }
1582*d6b92ffaSHans Petter Selasky 
cl_fmap_delta(IN OUT cl_fmap_t * const p_map1,IN OUT cl_fmap_t * const p_map2,OUT cl_fmap_t * const p_new,OUT cl_fmap_t * const p_old)1583*d6b92ffaSHans Petter Selasky void cl_fmap_delta(IN OUT cl_fmap_t * const p_map1,
1584*d6b92ffaSHans Petter Selasky 		   IN OUT cl_fmap_t * const p_map2,
1585*d6b92ffaSHans Petter Selasky 		   OUT cl_fmap_t * const p_new, OUT cl_fmap_t * const p_old)
1586*d6b92ffaSHans Petter Selasky {
1587*d6b92ffaSHans Petter Selasky 	cl_fmap_item_t *p_item1, *p_item2;
1588*d6b92ffaSHans Petter Selasky 	int cmp;
1589*d6b92ffaSHans Petter Selasky 
1590*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map1);
1591*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_map2);
1592*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_new);
1593*d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_old);
1594*d6b92ffaSHans Petter Selasky 	CL_ASSERT(cl_is_fmap_empty(p_new));
1595*d6b92ffaSHans Petter Selasky 	CL_ASSERT(cl_is_fmap_empty(p_old));
1596*d6b92ffaSHans Petter Selasky 
1597*d6b92ffaSHans Petter Selasky 	p_item1 = cl_fmap_head(p_map1);
1598*d6b92ffaSHans Petter Selasky 	p_item2 = cl_fmap_head(p_map2);
1599*d6b92ffaSHans Petter Selasky 
1600*d6b92ffaSHans Petter Selasky 	while (p_item1 != cl_fmap_end(p_map1) && p_item2 != cl_fmap_end(p_map2)) {
1601*d6b92ffaSHans Petter Selasky 		cmp = p_map1->pfn_compare(cl_fmap_key(p_item1),
1602*d6b92ffaSHans Petter Selasky 					  cl_fmap_key(p_item2));
1603*d6b92ffaSHans Petter Selasky 		if (cmp < 0) {
1604*d6b92ffaSHans Petter Selasky 			/* We found an old item. */
1605*d6b92ffaSHans Petter Selasky 			__cl_fmap_delta_move(p_old, p_map1, &p_item1);
1606*d6b92ffaSHans Petter Selasky 		} else if (cmp > 0) {
1607*d6b92ffaSHans Petter Selasky 			/* We found a new item. */
1608*d6b92ffaSHans Petter Selasky 			__cl_fmap_delta_move(p_new, p_map2, &p_item2);
1609*d6b92ffaSHans Petter Selasky 		} else {
1610*d6b92ffaSHans Petter Selasky 			/* Move both forward since they have the same key. */
1611*d6b92ffaSHans Petter Selasky 			p_item1 = cl_fmap_next(p_item1);
1612*d6b92ffaSHans Petter Selasky 			p_item2 = cl_fmap_next(p_item2);
1613*d6b92ffaSHans Petter Selasky 		}
1614*d6b92ffaSHans Petter Selasky 	}
1615*d6b92ffaSHans Petter Selasky 
1616*d6b92ffaSHans Petter Selasky 	/* Process the remainder if the end of either source map was reached. */
1617*d6b92ffaSHans Petter Selasky 	while (p_item2 != cl_fmap_end(p_map2))
1618*d6b92ffaSHans Petter Selasky 		__cl_fmap_delta_move(p_new, p_map2, &p_item2);
1619*d6b92ffaSHans Petter Selasky 
1620*d6b92ffaSHans Petter Selasky 	while (p_item1 != cl_fmap_end(p_map1))
1621*d6b92ffaSHans Petter Selasky 		__cl_fmap_delta_move(p_old, p_map1, &p_item1);
1622*d6b92ffaSHans Petter Selasky }
1623