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