2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
\r
5 * This software is available to you under the OpenIB.org BSD license
\r
8 * Redistribution and use in source and binary forms, with or
\r
9 * without modification, are permitted provided that the following
\r
10 * conditions are met:
\r
12 * - Redistributions of source code must retain the above
\r
13 * copyright notice, this list of conditions and the following
\r
16 * - Redistributions in binary form must reproduce the above
\r
17 * copyright notice, this list of conditions and the following
\r
18 * disclaimer in the documentation and/or other materials
\r
19 * provided with the distribution.
\r
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
25 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
26 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
37 * Implementation of quick map, a binary tree where the caller always provides
\r
38 * all necessary storage.
\r
47 /*****************************************************************************
\r
51 * Map is an associative array. By providing a key, the caller can retrieve
\r
52 * an object from the map. All objects in the map have an associated key,
\r
53 * as specified by the caller when the object was inserted into the map.
\r
54 * In addition to random access, the caller can traverse the map much like
\r
55 * a linked list, either forwards from the first object or backwards from
\r
56 * the last object. The objects in the map are always traversed in
\r
57 * order since the nodes are stored sorted.
\r
59 * This implementation of Map uses a red black tree verified against
\r
60 * Cormen-Leiserson-Rivest text, McGraw-Hill Edition, fourteenth
\r
63 *****************************************************************************/
\r
66 #include <complib/cl_qmap.h>
\r
67 #include <complib/cl_map.h>
\r
68 #include <complib/cl_fleximap.h>
\r
69 #include <complib/cl_memory.h>
\r
72 /******************************************************************************
\r
73 *******************************************************************************
\r
74 ************** ************
\r
75 ************** IMPLEMENTATION OF QUICK MAP ************
\r
76 ************** ************
\r
77 *******************************************************************************
\r
78 ******************************************************************************/
\r
83 static inline cl_map_item_t*
\r
85 IN const cl_qmap_t* const p_map )
\r
88 return( p_map->root.p_left );
\r
93 * Returns whether a given item is on the left of its parent.
\r
96 __cl_map_is_left_child(
\r
97 IN const cl_map_item_t* const p_item )
\r
99 CL_ASSERT( p_item );
\r
100 CL_ASSERT( p_item->p_up );
\r
101 CL_ASSERT( p_item->p_up != p_item );
\r
103 return( p_item->p_up->p_left == p_item );
\r
108 * Retrieve the pointer to the parent's pointer to an item.
\r
110 static cl_map_item_t**
\r
111 __cl_map_get_parent_ptr_to_item(
\r
112 IN cl_map_item_t* const p_item )
\r
114 CL_ASSERT( p_item );
\r
115 CL_ASSERT( p_item->p_up );
\r
116 CL_ASSERT( p_item->p_up != p_item );
\r
118 if( __cl_map_is_left_child( p_item ) )
\r
119 return( &p_item->p_up->p_left );
\r
121 CL_ASSERT( p_item->p_up->p_right == p_item );
\r
122 return( &p_item->p_up->p_right );
\r
127 * Rotate a node to the left. This rotation affects the least number of links
\r
128 * between nodes and brings the level of C up by one while increasing the depth
\r
129 * of A one. Note that the links to/from W, X, Y, and Z are not affected.
\r
143 IN cl_qmap_t* const p_map,
\r
144 IN cl_map_item_t* const p_item )
\r
146 cl_map_item_t **pp_root;
\r
148 CL_ASSERT( p_map );
\r
149 CL_ASSERT( p_item );
\r
150 CL_ASSERT( p_item->p_right != &p_map->nil );
\r
152 pp_root = __cl_map_get_parent_ptr_to_item( p_item );
\r
154 /* Point R to C instead of A. */
\r
155 *pp_root = p_item->p_right;
\r
156 /* Set C's parent to R. */
\r
157 (*pp_root)->p_up = p_item->p_up;
\r
159 /* Set A's right to B */
\r
160 p_item->p_right = (*pp_root)->p_left;
\r
162 * Set B's parent to A. We trap for B being NIL since the
\r
163 * caller may depend on NIL not changing.
\r
165 if( (*pp_root)->p_left != &p_map->nil )
\r
166 (*pp_root)->p_left->p_up = p_item;
\r
168 /* Set C's left to A. */
\r
169 (*pp_root)->p_left = p_item;
\r
170 /* Set A's parent to C. */
\r
171 p_item->p_up = *pp_root;
\r
176 * Rotate a node to the right. This rotation affects the least number of links
\r
177 * between nodes and brings the level of A up by one while increasing the depth
\r
178 * of C one. Note that the links to/from W, X, Y, and Z are not affected.
\r
191 __cl_map_rot_right(
\r
192 IN cl_qmap_t* const p_map,
\r
193 IN cl_map_item_t* const p_item )
\r
195 cl_map_item_t **pp_root;
\r
197 CL_ASSERT( p_map );
\r
198 CL_ASSERT( p_item );
\r
199 CL_ASSERT( p_item->p_left != &p_map->nil );
\r
201 /* Point R to A instead of C. */
\r
202 pp_root = __cl_map_get_parent_ptr_to_item( p_item );
\r
203 (*pp_root) = p_item->p_left;
\r
204 /* Set A's parent to R. */
\r
205 (*pp_root)->p_up = p_item->p_up;
\r
207 /* Set C's left to B */
\r
208 p_item->p_left = (*pp_root)->p_right;
\r
210 * Set B's parent to C. We trap for B being NIL since the
\r
211 * caller may depend on NIL not changing.
\r
213 if( (*pp_root)->p_right != &p_map->nil )
\r
214 (*pp_root)->p_right->p_up = p_item;
\r
216 /* Set A's right to C. */
\r
217 (*pp_root)->p_right = p_item;
\r
218 /* Set C's parent to A. */
\r
219 p_item->p_up = *pp_root;
\r
225 IN cl_qmap_t* const p_map )
\r
227 CL_ASSERT( p_map );
\r
229 cl_memclr( p_map, sizeof(cl_qmap_t) );
\r
231 /* special setup for the root node */
\r
232 p_map->root.p_up = &p_map->root;
\r
233 p_map->root.p_left = &p_map->nil;
\r
234 p_map->root.p_right = &p_map->nil;
\r
235 p_map->root.color = CL_MAP_BLACK;
\r
237 /* Setup the node used as terminator for all leaves. */
\r
238 p_map->nil.p_up = &p_map->nil;
\r
239 p_map->nil.p_left = &p_map->nil;
\r
240 p_map->nil.p_right = &p_map->nil;
\r
241 p_map->nil.color = CL_MAP_BLACK;
\r
244 p_map->root.p_map = p_map;
\r
245 p_map->nil.p_map = p_map;
\r
248 p_map->state = CL_INITIALIZED;
\r
250 cl_qmap_remove_all( p_map );
\r
256 IN const cl_qmap_t* const p_map,
\r
257 IN const uint64_t key )
\r
259 cl_map_item_t *p_item;
\r
261 CL_ASSERT( p_map );
\r
262 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
264 p_item = __cl_map_root( p_map );
\r
266 while( p_item != &p_map->nil )
\r
268 if( key == p_item->key )
\r
269 break; /* just right */
\r
271 if( key < p_item->key )
\r
272 p_item = p_item->p_left; /* too small */
\r
274 p_item = p_item->p_right; /* too big */
\r
282 cl_qmap_apply_func(
\r
283 IN const cl_qmap_t* const p_map,
\r
284 IN cl_pfn_qmap_apply_t pfn_func,
\r
285 IN const void* const context )
\r
287 cl_map_item_t* p_map_item;
\r
289 /* Note that context can have any arbitrary value. */
\r
290 CL_ASSERT( p_map );
\r
291 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
292 CL_ASSERT( pfn_func );
\r
294 p_map_item = cl_qmap_head( p_map );
\r
295 while( p_map_item != cl_qmap_end( p_map ) )
\r
297 pfn_func( p_map_item, (void*)context );
\r
298 p_map_item = cl_qmap_next( p_map_item );
\r
304 * Balance a tree starting at a given item back to the root.
\r
308 IN cl_qmap_t* const p_map,
\r
309 IN cl_map_item_t* p_item )
\r
311 cl_map_item_t* p_grand_uncle;
\r
313 CL_ASSERT( p_map );
\r
314 CL_ASSERT( p_item );
\r
315 CL_ASSERT( p_item != &p_map->root );
\r
317 while( p_item->p_up->color == CL_MAP_RED )
\r
319 if( __cl_map_is_left_child( p_item->p_up ) )
\r
321 p_grand_uncle = p_item->p_up->p_up->p_right;
\r
322 CL_ASSERT( p_grand_uncle );
\r
323 if( p_grand_uncle->color == CL_MAP_RED )
\r
325 p_grand_uncle->color = CL_MAP_BLACK;
\r
326 p_item->p_up->color = CL_MAP_BLACK;
\r
327 p_item->p_up->p_up->color = CL_MAP_RED;
\r
328 p_item = p_item->p_up->p_up;
\r
332 if( !__cl_map_is_left_child( p_item ) )
\r
334 p_item = p_item->p_up;
\r
335 __cl_map_rot_left( p_map, p_item );
\r
337 p_item->p_up->color = CL_MAP_BLACK;
\r
338 p_item->p_up->p_up->color = CL_MAP_RED;
\r
339 __cl_map_rot_right( p_map, p_item->p_up->p_up );
\r
343 p_grand_uncle = p_item->p_up->p_up->p_left;
\r
344 CL_ASSERT( p_grand_uncle );
\r
345 if( p_grand_uncle->color == CL_MAP_RED )
\r
347 p_grand_uncle->color = CL_MAP_BLACK;
\r
348 p_item->p_up->color = CL_MAP_BLACK;
\r
349 p_item->p_up->p_up->color = CL_MAP_RED;
\r
350 p_item = p_item->p_up->p_up;
\r
354 if( __cl_map_is_left_child( p_item ) )
\r
356 p_item = p_item->p_up;
\r
357 __cl_map_rot_right( p_map, p_item );
\r
359 p_item->p_up->color = CL_MAP_BLACK;
\r
360 p_item->p_up->p_up->color = CL_MAP_RED;
\r
361 __cl_map_rot_left( p_map, p_item->p_up->p_up );
\r
369 IN cl_qmap_t* const p_map,
\r
370 IN const uint64_t key,
\r
371 IN cl_map_item_t* const p_item )
\r
373 cl_map_item_t *p_insert_at, *p_comp_item;
\r
375 CL_ASSERT( p_map );
\r
376 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
377 CL_ASSERT( p_item );
\r
378 CL_ASSERT( p_map->root.p_up == &p_map->root );
\r
379 CL_ASSERT( p_map->root.color != CL_MAP_RED );
\r
380 CL_ASSERT( p_map->nil.color != CL_MAP_RED );
\r
382 p_item->p_left = &p_map->nil;
\r
383 p_item->p_right = &p_map->nil;
\r
385 p_item->color = CL_MAP_RED;
\r
387 /* Find the insertion location. */
\r
388 p_insert_at = &p_map->root;
\r
389 p_comp_item = __cl_map_root( p_map );
\r
391 while( p_comp_item != &p_map->nil )
\r
393 p_insert_at = p_comp_item;
\r
395 if( key == p_insert_at->key )
\r
396 return( p_insert_at );
\r
398 /* Traverse the tree until the correct insertion point is found. */
\r
399 if( key < p_insert_at->key )
\r
400 p_comp_item = p_insert_at->p_left;
\r
402 p_comp_item = p_insert_at->p_right;
\r
405 CL_ASSERT( p_insert_at != &p_map->nil );
\r
406 CL_ASSERT( p_comp_item == &p_map->nil );
\r
407 /* Insert the item. */
\r
408 if( p_insert_at == &p_map->root )
\r
410 p_insert_at->p_left = p_item;
\r
412 * Primitive insert places the new item in front of
\r
413 * the existing item.
\r
415 __cl_primitive_insert( &p_map->nil.pool_item.list_item,
\r
416 &p_item->pool_item.list_item );
\r
418 else if( key < p_insert_at->key )
\r
420 p_insert_at->p_left = p_item;
\r
422 * Primitive insert places the new item in front of
\r
423 * the existing item.
\r
425 __cl_primitive_insert( &p_insert_at->pool_item.list_item,
\r
426 &p_item->pool_item.list_item );
\r
430 p_insert_at->p_right = p_item;
\r
432 * Primitive insert places the new item in front of
\r
433 * the existing item.
\r
435 __cl_primitive_insert( p_insert_at->pool_item.list_item.p_next,
\r
436 &p_item->pool_item.list_item );
\r
438 /* Increase the count. */
\r
441 p_item->p_up = p_insert_at;
\r
444 * We have added depth to this section of the tree.
\r
445 * Rebalance as necessary as we retrace our path through the tree
\r
446 * and update colors.
\r
448 __cl_map_ins_bal( p_map, p_item );
\r
450 __cl_map_root( p_map )->color = CL_MAP_BLACK;
\r
453 * Note that it is not necessary to re-color the nil node black because all
\r
454 * red color assignments are made via the p_up pointer, and nil is never
\r
455 * set as the value of a p_up pointer.
\r
459 /* Set the pointer to the map in the map item for consistency checking. */
\r
460 p_item->p_map = p_map;
\r
469 IN cl_qmap_t* const p_map,
\r
470 IN cl_map_item_t* p_item )
\r
472 cl_map_item_t *p_uncle;
\r
474 while( (p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root) )
\r
476 if( __cl_map_is_left_child( p_item ) )
\r
478 p_uncle = p_item->p_up->p_right;
\r
480 if( p_uncle->color == CL_MAP_RED )
\r
482 p_uncle->color = CL_MAP_BLACK;
\r
483 p_item->p_up->color = CL_MAP_RED;
\r
484 __cl_map_rot_left( p_map, p_item->p_up );
\r
485 p_uncle = p_item->p_up->p_right;
\r
488 if( p_uncle->p_right->color != CL_MAP_RED )
\r
490 if( p_uncle->p_left->color != CL_MAP_RED )
\r
492 p_uncle->color = CL_MAP_RED;
\r
493 p_item = p_item->p_up;
\r
497 p_uncle->p_left->color = CL_MAP_BLACK;
\r
498 p_uncle->color = CL_MAP_RED;
\r
499 __cl_map_rot_right( p_map, p_uncle );
\r
500 p_uncle = p_item->p_up->p_right;
\r
502 p_uncle->color = p_item->p_up->color;
\r
503 p_item->p_up->color = CL_MAP_BLACK;
\r
504 p_uncle->p_right->color = CL_MAP_BLACK;
\r
505 __cl_map_rot_left( p_map, p_item->p_up );
\r
510 p_uncle = p_item->p_up->p_left;
\r
512 if( p_uncle->color == CL_MAP_RED )
\r
514 p_uncle->color = CL_MAP_BLACK;
\r
515 p_item->p_up->color = CL_MAP_RED;
\r
516 __cl_map_rot_right( p_map, p_item->p_up );
\r
517 p_uncle = p_item->p_up->p_left;
\r
520 if( p_uncle->p_left->color != CL_MAP_RED )
\r
522 if( p_uncle->p_right->color != CL_MAP_RED )
\r
524 p_uncle->color = CL_MAP_RED;
\r
525 p_item = p_item->p_up;
\r
529 p_uncle->p_right->color = CL_MAP_BLACK;
\r
530 p_uncle->color = CL_MAP_RED;
\r
531 __cl_map_rot_left( p_map, p_uncle );
\r
532 p_uncle = p_item->p_up->p_left;
\r
534 p_uncle->color = p_item->p_up->color;
\r
535 p_item->p_up->color = CL_MAP_BLACK;
\r
536 p_uncle->p_left->color = CL_MAP_BLACK;
\r
537 __cl_map_rot_right( p_map, p_item->p_up );
\r
541 p_item->color = CL_MAP_BLACK;
\r
546 cl_qmap_remove_item(
\r
547 IN cl_qmap_t* const p_map,
\r
548 IN cl_map_item_t* const p_item )
\r
550 cl_map_item_t *p_child, *p_del_item;
\r
552 CL_ASSERT( p_map );
\r
553 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
554 CL_ASSERT( p_item );
\r
555 CL_ASSERT( p_item->p_map == p_map );
\r
557 if( p_item == cl_qmap_end( p_map ) )
\r
560 if( (p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil ) )
\r
562 /* The item being removed has children on at most on side. */
\r
563 p_del_item = p_item;
\r
568 * The item being removed has children on both side.
\r
569 * We select the item that will replace it. After removing
\r
570 * the substitute item and rebalancing, the tree will have the
\r
571 * correct topology. Exchanging the substitute for the item
\r
572 * will finalize the removal.
\r
574 p_del_item = cl_qmap_next( p_item );
\r
575 CL_ASSERT( p_del_item != &p_map->nil );
\r
578 /* Remove the item from the list. */
\r
579 __cl_primitive_remove( &p_item->pool_item.list_item );
\r
580 /* Decrement the item count. */
\r
583 /* Get the pointer to the new root's child, if any. */
\r
584 if( p_del_item->p_left != &p_map->nil )
\r
585 p_child = p_del_item->p_left;
\r
587 p_child = p_del_item->p_right;
\r
590 * This assignment may modify the parent pointer of the nil node.
\r
591 * This is inconsequential.
\r
593 p_child->p_up = p_del_item->p_up;
\r
594 (*__cl_map_get_parent_ptr_to_item( p_del_item )) = p_child;
\r
596 if( p_del_item->color != CL_MAP_RED )
\r
597 __cl_map_del_bal( p_map, p_child );
\r
600 * Note that the splicing done below does not need to occur before
\r
601 * the tree is balanced, since the actual topology changes are made by the
\r
602 * preceding code. The topology is preserved by the color assignment made
\r
603 * below (reader should be reminded that p_del_item == p_item in some cases).
\r
605 if( p_del_item != p_item )
\r
608 * Finalize the removal of the specified item by exchanging it with
\r
609 * the substitute which we removed above.
\r
611 p_del_item->p_up = p_item->p_up;
\r
612 p_del_item->p_left = p_item->p_left;
\r
613 p_del_item->p_right = p_item->p_right;
\r
614 (*__cl_map_get_parent_ptr_to_item( p_item )) = p_del_item;
\r
615 p_item->p_right->p_up = p_del_item;
\r
616 p_item->p_left->p_up = p_del_item;
\r
617 p_del_item->color = p_item->color;
\r
620 CL_ASSERT( p_map->nil.color != CL_MAP_RED );
\r
623 /* Clear the pointer to the map since the item has been removed. */
\r
624 p_item->p_map = NULL;
\r
631 IN cl_qmap_t* const p_map,
\r
632 IN const uint64_t key )
\r
634 cl_map_item_t *p_item;
\r
636 CL_ASSERT( p_map );
\r
637 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
639 /* Seek the node with the specified key */
\r
640 p_item = cl_qmap_get( p_map, key );
\r
642 cl_qmap_remove_item( p_map, p_item );
\r
650 OUT cl_qmap_t* const p_dest_map,
\r
651 IN OUT cl_qmap_t* const p_src_map )
\r
653 cl_map_item_t *p_item, *p_item2, *p_next;
\r
655 CL_ASSERT( p_dest_map );
\r
656 CL_ASSERT( p_src_map );
\r
658 p_item = cl_qmap_head( p_src_map );
\r
660 while( p_item != cl_qmap_end( p_src_map ) )
\r
662 p_next = cl_qmap_next( p_item );
\r
664 /* Remove the item from its current map. */
\r
665 cl_qmap_remove_item( p_src_map, p_item );
\r
666 /* Insert the item into the destination map. */
\r
667 p_item2 = cl_qmap_insert( p_dest_map, cl_qmap_key( p_item ), p_item );
\r
668 /* Check that the item was successfully inserted. */
\r
669 if( p_item2 != p_item )
\r
671 /* Put the item in back in the source map. */
\r
673 cl_qmap_insert( p_src_map, cl_qmap_key( p_item ), p_item );
\r
674 CL_ASSERT( p_item2 == p_item );
\r
682 __cl_qmap_delta_move(
\r
683 IN OUT cl_qmap_t* const p_dest,
\r
684 IN OUT cl_qmap_t* const p_src,
\r
685 IN OUT cl_map_item_t** const pp_item )
\r
687 cl_map_item_t *p_temp, *p_next;
\r
690 * Get the next item so that we can ensure that pp_item points to
\r
691 * a valid item upon return from the function.
\r
693 p_next = cl_qmap_next( *pp_item );
\r
694 /* Move the old item from its current map the the old map. */
\r
695 cl_qmap_remove_item( p_src, *pp_item );
\r
696 p_temp = cl_qmap_insert( p_dest, cl_qmap_key( *pp_item ), *pp_item );
\r
697 /* We should never have duplicates. */
\r
698 CL_ASSERT( p_temp == *pp_item );
\r
699 /* Point pp_item to a valid item in the source map. */
\r
700 (*pp_item) = p_next;
\r
706 IN OUT cl_qmap_t* const p_map1,
\r
707 IN OUT cl_qmap_t* const p_map2,
\r
708 OUT cl_qmap_t* const p_new,
\r
709 OUT cl_qmap_t* const p_old )
\r
711 cl_map_item_t *p_item1, *p_item2;
\r
712 uint64_t key1, key2;
\r
714 CL_ASSERT( p_map1 );
\r
715 CL_ASSERT( p_map2 );
\r
716 CL_ASSERT( p_new );
\r
717 CL_ASSERT( p_old );
\r
718 CL_ASSERT( cl_is_qmap_empty( p_new ) );
\r
719 CL_ASSERT( cl_is_qmap_empty( p_old ) );
\r
721 p_item1 = cl_qmap_head( p_map1 );
\r
722 p_item2 = cl_qmap_head( p_map2 );
\r
724 while( p_item1 != cl_qmap_end( p_map1 ) &&
\r
725 p_item2 != cl_qmap_end( p_map2 ) )
\r
727 key1 = cl_qmap_key( p_item1 );
\r
728 key2 = cl_qmap_key( p_item2 );
\r
731 /* We found an old item. */
\r
732 __cl_qmap_delta_move( p_old, p_map1, &p_item1 );
\r
734 else if( key1 > key2 )
\r
736 /* We found a new item. */
\r
737 __cl_qmap_delta_move( p_new, p_map2, &p_item2 );
\r
741 /* Move both forward since they have the same key. */
\r
742 p_item1 = cl_qmap_next( p_item1 );
\r
743 p_item2 = cl_qmap_next( p_item2 );
\r
747 /* Process the remainder if the end of either source map was reached. */
\r
748 while( p_item2 != cl_qmap_end( p_map2 ) )
\r
749 __cl_qmap_delta_move( p_new, p_map2, &p_item2 );
\r
751 while( p_item1 != cl_qmap_end( p_map1 ) )
\r
752 __cl_qmap_delta_move( p_old, p_map1, &p_item1 );
\r
756 /******************************************************************************
\r
757 *******************************************************************************
\r
758 ************** ************
\r
759 ************** IMPLEMENTATION OF MAP ************
\r
760 ************** ************
\r
761 *******************************************************************************
\r
762 ******************************************************************************/
\r
765 #define MAP_GROW_SIZE 32
\r
770 IN cl_map_t* const p_map )
\r
772 CL_ASSERT( p_map );
\r
774 cl_qpool_construct( &p_map->pool );
\r
780 IN cl_map_t* const p_map,
\r
781 IN const size_t min_items )
\r
785 CL_ASSERT( p_map );
\r
787 cl_qmap_init( &p_map->qmap );
\r
790 * We will grow by min_items/8 items at a time, with a minimum of
\r
793 grow_size = min_items >> 3;
\r
794 if( grow_size < MAP_GROW_SIZE )
\r
795 grow_size = MAP_GROW_SIZE;
\r
797 return( cl_qpool_init( &p_map->pool, min_items, 0, grow_size,
\r
798 sizeof(cl_map_obj_t), NULL, NULL, NULL ) );
\r
804 IN cl_map_t* const p_map )
\r
806 CL_ASSERT( p_map );
\r
808 cl_qpool_destroy( &p_map->pool );
\r
814 IN cl_map_t* const p_map,
\r
815 IN const uint64_t key,
\r
816 IN const void* const p_object )
\r
818 cl_map_obj_t *p_map_obj, *p_obj_at_key;
\r
820 CL_ASSERT( p_map );
\r
822 p_map_obj = (cl_map_obj_t*)cl_qpool_get( &p_map->pool );
\r
827 cl_qmap_set_obj( p_map_obj, p_object );
\r
830 (cl_map_obj_t*)cl_qmap_insert( &p_map->qmap, key, &p_map_obj->item );
\r
832 /* Return the item to the pool if insertion failed. */
\r
833 if( p_obj_at_key != p_map_obj )
\r
834 cl_qpool_put( &p_map->pool, &p_map_obj->item.pool_item );
\r
836 return( cl_qmap_obj( p_obj_at_key ) );
\r
842 IN const cl_map_t* const p_map,
\r
843 IN const uint64_t key )
\r
845 cl_map_item_t *p_item;
\r
847 CL_ASSERT( p_map );
\r
849 p_item = cl_qmap_get( &p_map->qmap, key );
\r
851 if( p_item == cl_qmap_end( &p_map->qmap ) )
\r
854 return( cl_qmap_obj( PARENT_STRUCT( p_item, cl_map_obj_t, item ) ) );
\r
859 cl_map_remove_item(
\r
860 IN cl_map_t* const p_map,
\r
861 IN const cl_map_iterator_t itor )
\r
863 CL_ASSERT( itor->p_map == &p_map->qmap );
\r
865 if( itor == cl_map_end( p_map ) )
\r
868 cl_qmap_remove_item( &p_map->qmap, (cl_map_item_t*)itor );
\r
869 cl_qpool_put( &p_map->pool, &((cl_map_item_t*)itor)->pool_item );
\r
875 IN cl_map_t* const p_map,
\r
876 IN const uint64_t key )
\r
878 cl_map_item_t *p_item;
\r
880 CL_ASSERT( p_map );
\r
882 p_item = cl_qmap_remove( &p_map->qmap, key );
\r
884 if( p_item == cl_qmap_end( &p_map->qmap ) )
\r
887 cl_qpool_put( &p_map->pool, &p_item->pool_item );
\r
889 return( cl_qmap_obj( (cl_map_obj_t*)p_item ) );
\r
895 IN cl_map_t* const p_map )
\r
897 cl_map_item_t *p_item;
\r
899 CL_ASSERT( p_map );
\r
901 /* Return all map items to the pool. */
\r
902 while( !cl_is_qmap_empty( &p_map->qmap ) )
\r
904 p_item = cl_qmap_head( &p_map->qmap );
\r
905 cl_qmap_remove_item( &p_map->qmap, p_item );
\r
906 cl_qpool_put( &p_map->pool, &p_item->pool_item );
\r
908 if( !cl_is_qmap_empty( &p_map->qmap ) )
\r
910 p_item = cl_qmap_tail( &p_map->qmap );
\r
911 cl_qmap_remove_item( &p_map->qmap, p_item );
\r
912 cl_qpool_put( &p_map->pool, &p_item->pool_item );
\r
920 OUT cl_map_t* const p_dest_map,
\r
921 IN OUT cl_map_t* const p_src_map )
\r
923 cl_status_t status = CL_SUCCESS;
\r
924 cl_map_iterator_t itor, next;
\r
926 void *p_obj, *p_obj2;
\r
928 CL_ASSERT( p_dest_map );
\r
929 CL_ASSERT( p_src_map );
\r
931 itor = cl_map_head( p_src_map );
\r
932 while( itor != cl_map_end( p_src_map ) )
\r
934 next = cl_map_next( itor );
\r
936 p_obj = cl_map_obj( itor );
\r
937 key = cl_map_key( itor );
\r
939 cl_map_remove_item( p_src_map, itor );
\r
941 /* Insert the object into the destination map. */
\r
942 p_obj2 = cl_map_insert( p_dest_map, key, p_obj );
\r
943 /* Trap for failure. */
\r
944 if( p_obj != p_obj2 )
\r
947 status = CL_INSUFFICIENT_MEMORY;
\r
948 /* Put the object back in the source map. This must succeed. */
\r
949 p_obj2 = cl_map_insert( p_src_map, key, p_obj );
\r
950 CL_ASSERT( p_obj == p_obj2 );
\r
951 /* If the failure was due to insufficient memory, return. */
\r
952 if( status != CL_SUCCESS )
\r
958 return( CL_SUCCESS );
\r
964 IN OUT cl_map_t* const p_map1,
\r
965 IN OUT cl_map_t* const p_map2,
\r
966 IN OUT cl_map_t* const p_new,
\r
967 IN OUT cl_map_t* const p_old )
\r
969 cl_status_t status;
\r
971 /* Restore the initial state. */
\r
972 status = cl_map_merge( p_map1, p_old );
\r
973 CL_ASSERT( status == CL_SUCCESS );
\r
974 status = cl_map_merge( p_map2, p_new );
\r
975 CL_ASSERT( status == CL_SUCCESS );
\r
980 __cl_map_delta_move(
\r
981 OUT cl_map_t* const p_dest,
\r
982 IN OUT cl_map_t* const p_src,
\r
983 IN OUT cl_map_iterator_t* const p_itor )
\r
985 cl_map_iterator_t next;
\r
986 void *p_obj, *p_obj2;
\r
989 /* Get a valid iterator so we can continue the loop. */
\r
990 next = cl_map_next( *p_itor );
\r
991 /* Get the pointer to the object for insertion. */
\r
992 p_obj = cl_map_obj( *p_itor );
\r
993 /* Get the key for the object. */
\r
994 key = cl_map_key( *p_itor );
\r
995 /* Move the object. */
\r
996 cl_map_remove_item( p_src, *p_itor );
\r
997 p_obj2 = cl_map_insert( p_dest, key, p_obj );
\r
998 /* Check for failure. We should never get a duplicate. */
\r
1001 p_obj2 = cl_map_insert( p_src, key, p_obj );
\r
1002 CL_ASSERT( p_obj2 == p_obj );
\r
1003 return( CL_INSUFFICIENT_MEMORY );
\r
1006 /* We should never get a duplicate */
\r
1007 CL_ASSERT( p_obj == p_obj2 );
\r
1008 /* Update the iterator so that it is valid. */
\r
1011 return( CL_SUCCESS );
\r
1017 IN OUT cl_map_t* const p_map1,
\r
1018 IN OUT cl_map_t* const p_map2,
\r
1019 OUT cl_map_t* const p_new,
\r
1020 OUT cl_map_t* const p_old )
\r
1022 cl_map_iterator_t itor1, itor2;
\r
1023 uint64_t key1, key2;
\r
1024 cl_status_t status;
\r
1026 CL_ASSERT( p_map1 );
\r
1027 CL_ASSERT( p_map2 );
\r
1028 CL_ASSERT( p_new );
\r
1029 CL_ASSERT( p_old );
\r
1030 CL_ASSERT( cl_is_map_empty( p_new ) );
\r
1031 CL_ASSERT( cl_is_map_empty( p_old ) );
\r
1033 itor1 = cl_map_head( p_map1 );
\r
1034 itor2 = cl_map_head( p_map2 );
\r
1037 * Note that the check is for the end, since duplicate items will remain
\r
1038 * in their respective maps.
\r
1040 while( itor1 != cl_map_end( p_map1 ) &&
\r
1041 itor2 != cl_map_end( p_map2 ) )
\r
1043 key1 = cl_map_key( itor1 );
\r
1044 key2 = cl_map_key( itor2 );
\r
1047 status = __cl_map_delta_move( p_old, p_map1, &itor1 );
\r
1048 /* Check for failure. */
\r
1049 if( status != CL_SUCCESS )
\r
1051 /* Restore the initial state. */
\r
1052 __cl_map_revert( p_map1, p_map2, p_new, p_old );
\r
1053 /* Return the failure status. */
\r
1057 else if( key1 > key2 )
\r
1059 status = __cl_map_delta_move( p_new, p_map2, &itor2 );
\r
1060 if( status != CL_SUCCESS )
\r
1062 /* Restore the initial state. */
\r
1063 __cl_map_revert( p_map1, p_map2, p_new, p_old );
\r
1064 /* Return the failure status. */
\r
1070 /* Move both forward since they have the same key. */
\r
1071 itor1 = cl_map_next( itor1 );
\r
1072 itor2 = cl_map_next( itor2 );
\r
1076 /* Process the remainder if either source map is empty. */
\r
1077 while( itor2 != cl_map_end( p_map2 ) )
\r
1079 status = __cl_map_delta_move( p_new, p_map2, &itor2 );
\r
1080 if( status != CL_SUCCESS )
\r
1082 /* Restore the initial state. */
\r
1083 __cl_map_revert( p_map1, p_map2, p_new, p_old );
\r
1084 /* Return the failure status. */
\r
1089 while( itor1 != cl_map_end( p_map1 ) )
\r
1091 status = __cl_map_delta_move( p_old, p_map1, &itor1 );
\r
1092 if( status != CL_SUCCESS )
\r
1094 /* Restore the initial state. */
\r
1095 __cl_map_revert( p_map1, p_map2, p_new, p_old );
\r
1096 /* Return the failure status. */
\r
1101 return( CL_SUCCESS );
\r
1105 /******************************************************************************
\r
1106 *******************************************************************************
\r
1107 ************** ************
\r
1108 ************** IMPLEMENTATION OF FLEXI MAP ************
\r
1109 ************** ************
\r
1110 *******************************************************************************
\r
1111 ******************************************************************************/
\r
1116 static inline cl_fmap_item_t*
\r
1118 IN const cl_fmap_t* const p_map )
\r
1120 CL_ASSERT( p_map );
\r
1121 return( p_map->root.p_left );
\r
1126 * Returns whether a given item is on the left of its parent.
\r
1129 __cl_fmap_is_left_child(
\r
1130 IN const cl_fmap_item_t* const p_item )
\r
1132 CL_ASSERT( p_item );
\r
1133 CL_ASSERT( p_item->p_up );
\r
1134 CL_ASSERT( p_item->p_up != p_item );
\r
1136 return( p_item->p_up->p_left == p_item );
\r
1141 * Retrieve the pointer to the parent's pointer to an item.
\r
1143 static cl_fmap_item_t**
\r
1144 __cl_fmap_get_parent_ptr_to_item(
\r
1145 IN cl_fmap_item_t* const p_item )
\r
1147 CL_ASSERT( p_item );
\r
1148 CL_ASSERT( p_item->p_up );
\r
1149 CL_ASSERT( p_item->p_up != p_item );
\r
1151 if( __cl_fmap_is_left_child( p_item ) )
\r
1152 return( &p_item->p_up->p_left );
\r
1154 CL_ASSERT( p_item->p_up->p_right == p_item );
\r
1155 return( &p_item->p_up->p_right );
\r
1160 * Rotate a node to the left. This rotation affects the least number of links
\r
1161 * between nodes and brings the level of C up by one while increasing the depth
\r
1162 * of A one. Note that the links to/from W, X, Y, and Z are not affected.
\r
1175 __cl_fmap_rot_left(
\r
1176 IN cl_fmap_t* const p_map,
\r
1177 IN cl_fmap_item_t* const p_item )
\r
1179 cl_fmap_item_t **pp_root;
\r
1181 CL_ASSERT( p_map );
\r
1182 CL_ASSERT( p_item );
\r
1183 CL_ASSERT( p_item->p_right != &p_map->nil );
\r
1185 pp_root = __cl_fmap_get_parent_ptr_to_item( p_item );
\r
1187 /* Point R to C instead of A. */
\r
1188 *pp_root = p_item->p_right;
\r
1189 /* Set C's parent to R. */
\r
1190 (*pp_root)->p_up = p_item->p_up;
\r
1192 /* Set A's right to B */
\r
1193 p_item->p_right = (*pp_root)->p_left;
\r
1195 * Set B's parent to A. We trap for B being NIL since the
\r
1196 * caller may depend on NIL not changing.
\r
1198 if( (*pp_root)->p_left != &p_map->nil )
\r
1199 (*pp_root)->p_left->p_up = p_item;
\r
1201 /* Set C's left to A. */
\r
1202 (*pp_root)->p_left = p_item;
\r
1203 /* Set A's parent to C. */
\r
1204 p_item->p_up = *pp_root;
\r
1209 * Rotate a node to the right. This rotation affects the least number of links
\r
1210 * between nodes and brings the level of A up by one while increasing the depth
\r
1211 * of C one. Note that the links to/from W, X, Y, and Z are not affected.
\r
1224 __cl_fmap_rot_right(
\r
1225 IN cl_fmap_t* const p_map,
\r
1226 IN cl_fmap_item_t* const p_item )
\r
1228 cl_fmap_item_t **pp_root;
\r
1230 CL_ASSERT( p_map );
\r
1231 CL_ASSERT( p_item );
\r
1232 CL_ASSERT( p_item->p_left != &p_map->nil );
\r
1234 /* Point R to A instead of C. */
\r
1235 pp_root = __cl_fmap_get_parent_ptr_to_item( p_item );
\r
1236 (*pp_root) = p_item->p_left;
\r
1237 /* Set A's parent to R. */
\r
1238 (*pp_root)->p_up = p_item->p_up;
\r
1240 /* Set C's left to B */
\r
1241 p_item->p_left = (*pp_root)->p_right;
\r
1243 * Set B's parent to C. We trap for B being NIL since the
\r
1244 * caller may depend on NIL not changing.
\r
1246 if( (*pp_root)->p_right != &p_map->nil )
\r
1247 (*pp_root)->p_right->p_up = p_item;
\r
1249 /* Set A's right to C. */
\r
1250 (*pp_root)->p_right = p_item;
\r
1251 /* Set C's parent to A. */
\r
1252 p_item->p_up = *pp_root;
\r
1258 IN cl_fmap_t* const p_map,
\r
1259 IN cl_pfn_fmap_cmp_t pfn_compare )
\r
1261 CL_ASSERT( p_map );
\r
1262 CL_ASSERT( pfn_compare );
\r
1264 cl_memclr( p_map, sizeof(cl_fmap_t) );
\r
1266 /* special setup for the root node */
\r
1267 p_map->root.p_up = &p_map->root;
\r
1268 p_map->root.p_left = &p_map->nil;
\r
1269 p_map->root.p_right = &p_map->nil;
\r
1270 p_map->root.color = CL_MAP_BLACK;
\r
1272 /* Setup the node used as terminator for all leaves. */
\r
1273 p_map->nil.p_up = &p_map->nil;
\r
1274 p_map->nil.p_left = &p_map->nil;
\r
1275 p_map->nil.p_right = &p_map->nil;
\r
1276 p_map->nil.color = CL_MAP_BLACK;
\r
1278 /* Store the compare function pointer. */
\r
1279 p_map->pfn_compare = pfn_compare;
\r
1281 p_map->state = CL_INITIALIZED;
\r
1283 cl_fmap_remove_all( p_map );
\r
1289 IN const cl_fmap_t* const p_map,
\r
1290 IN const void* const p_key )
\r
1292 cl_fmap_item_t *p_item;
\r
1295 CL_ASSERT( p_map );
\r
1296 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1298 p_item = __cl_fmap_root( p_map );
\r
1300 while( p_item != &p_map->nil )
\r
1302 cmp = p_map->pfn_compare( p_key, p_item->p_key );
\r
1305 break; /* just right */
\r
1308 p_item = p_item->p_left; /* too small */
\r
1310 p_item = p_item->p_right; /* too big */
\r
1318 cl_fmap_apply_func(
\r
1319 IN const cl_fmap_t* const p_map,
\r
1320 IN cl_pfn_fmap_apply_t pfn_func,
\r
1321 IN const void* const context )
\r
1323 cl_fmap_item_t* p_fmap_item;
\r
1325 /* Note that context can have any arbitrary value. */
\r
1326 CL_ASSERT( p_map );
\r
1327 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1328 CL_ASSERT( pfn_func );
\r
1330 p_fmap_item = cl_fmap_head( p_map );
\r
1331 while( p_fmap_item != cl_fmap_end( p_map ) )
\r
1333 pfn_func( p_fmap_item, (void*)context );
\r
1334 p_fmap_item = cl_fmap_next( p_fmap_item );
\r
1340 * Balance a tree starting at a given item back to the root.
\r
1343 __cl_fmap_ins_bal(
\r
1344 IN cl_fmap_t* const p_map,
\r
1345 IN cl_fmap_item_t* p_item )
\r
1347 cl_fmap_item_t* p_grand_uncle;
\r
1349 CL_ASSERT( p_map );
\r
1350 CL_ASSERT( p_item );
\r
1351 CL_ASSERT( p_item != &p_map->root );
\r
1353 while( p_item->p_up->color == CL_MAP_RED )
\r
1355 if( __cl_fmap_is_left_child( p_item->p_up ) )
\r
1357 p_grand_uncle = p_item->p_up->p_up->p_right;
\r
1358 CL_ASSERT( p_grand_uncle );
\r
1359 if( p_grand_uncle->color == CL_MAP_RED )
\r
1361 p_grand_uncle->color = CL_MAP_BLACK;
\r
1362 p_item->p_up->color = CL_MAP_BLACK;
\r
1363 p_item->p_up->p_up->color = CL_MAP_RED;
\r
1364 p_item = p_item->p_up->p_up;
\r
1368 if( !__cl_fmap_is_left_child( p_item ) )
\r
1370 p_item = p_item->p_up;
\r
1371 __cl_fmap_rot_left( p_map, p_item );
\r
1373 p_item->p_up->color = CL_MAP_BLACK;
\r
1374 p_item->p_up->p_up->color = CL_MAP_RED;
\r
1375 __cl_fmap_rot_right( p_map, p_item->p_up->p_up );
\r
1379 p_grand_uncle = p_item->p_up->p_up->p_left;
\r
1380 CL_ASSERT( p_grand_uncle );
\r
1381 if( p_grand_uncle->color == CL_MAP_RED )
\r
1383 p_grand_uncle->color = CL_MAP_BLACK;
\r
1384 p_item->p_up->color = CL_MAP_BLACK;
\r
1385 p_item->p_up->p_up->color = CL_MAP_RED;
\r
1386 p_item = p_item->p_up->p_up;
\r
1390 if( __cl_fmap_is_left_child( p_item ) )
\r
1392 p_item = p_item->p_up;
\r
1393 __cl_fmap_rot_right( p_map, p_item );
\r
1395 p_item->p_up->color = CL_MAP_BLACK;
\r
1396 p_item->p_up->p_up->color = CL_MAP_RED;
\r
1397 __cl_fmap_rot_left( p_map, p_item->p_up->p_up );
\r
1405 IN cl_fmap_t* const p_map,
\r
1406 IN const void* const p_key,
\r
1407 IN cl_fmap_item_t* const p_item )
\r
1409 cl_fmap_item_t *p_insert_at, *p_comp_item;
\r
1412 CL_ASSERT( p_map );
\r
1413 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1414 CL_ASSERT( p_item );
\r
1415 CL_ASSERT( p_map->root.p_up == &p_map->root );
\r
1416 CL_ASSERT( p_map->root.color != CL_MAP_RED );
\r
1417 CL_ASSERT( p_map->nil.color != CL_MAP_RED );
\r
1419 p_item->p_left = &p_map->nil;
\r
1420 p_item->p_right = &p_map->nil;
\r
1421 p_item->p_key = p_key;
\r
1422 p_item->color = CL_MAP_RED;
\r
1424 /* Find the insertion location. */
\r
1425 p_insert_at = &p_map->root;
\r
1426 p_comp_item = __cl_fmap_root( p_map );
\r
1428 while( p_comp_item != &p_map->nil )
\r
1430 p_insert_at = p_comp_item;
\r
1432 cmp = p_map->pfn_compare( p_key, p_insert_at->p_key );
\r
1435 return( p_insert_at );
\r
1437 /* Traverse the tree until the correct insertion point is found. */
\r
1439 p_comp_item = p_insert_at->p_left;
\r
1441 p_comp_item = p_insert_at->p_right;
\r
1444 CL_ASSERT( p_insert_at != &p_map->nil );
\r
1445 CL_ASSERT( p_comp_item == &p_map->nil );
\r
1446 /* Insert the item. */
\r
1447 if( p_insert_at == &p_map->root )
\r
1449 p_insert_at->p_left = p_item;
\r
1451 * Primitive insert places the new item in front of
\r
1452 * the existing item.
\r
1454 __cl_primitive_insert( &p_map->nil.pool_item.list_item,
\r
1455 &p_item->pool_item.list_item );
\r
1457 else if( cmp < 0 )
\r
1459 p_insert_at->p_left = p_item;
\r
1461 * Primitive insert places the new item in front of
\r
1462 * the existing item.
\r
1464 __cl_primitive_insert( &p_insert_at->pool_item.list_item,
\r
1465 &p_item->pool_item.list_item );
\r
1469 p_insert_at->p_right = p_item;
\r
1471 * Primitive insert places the new item in front of
\r
1472 * the existing item.
\r
1474 __cl_primitive_insert( p_insert_at->pool_item.list_item.p_next,
\r
1475 &p_item->pool_item.list_item );
\r
1477 /* Increase the count. */
\r
1480 p_item->p_up = p_insert_at;
\r
1483 * We have added depth to this section of the tree.
\r
1484 * Rebalance as necessary as we retrace our path through the tree
\r
1485 * and update colors.
\r
1487 __cl_fmap_ins_bal( p_map, p_item );
\r
1489 __cl_fmap_root( p_map )->color = CL_MAP_BLACK;
\r
1492 * Note that it is not necessary to re-color the nil node black because all
\r
1493 * red color assignments are made via the p_up pointer, and nil is never
\r
1494 * set as the value of a p_up pointer.
\r
1498 /* Set the pointer to the map in the map item for consistency checking. */
\r
1499 p_item->p_map = p_map;
\r
1507 __cl_fmap_del_bal(
\r
1508 IN cl_fmap_t* const p_map,
\r
1509 IN cl_fmap_item_t* p_item )
\r
1511 cl_fmap_item_t *p_uncle;
\r
1513 while( (p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root) )
\r
1515 if( __cl_fmap_is_left_child( p_item ) )
\r
1517 p_uncle = p_item->p_up->p_right;
\r
1519 if( p_uncle->color == CL_MAP_RED )
\r
1521 p_uncle->color = CL_MAP_BLACK;
\r
1522 p_item->p_up->color = CL_MAP_RED;
\r
1523 __cl_fmap_rot_left( p_map, p_item->p_up );
\r
1524 p_uncle = p_item->p_up->p_right;
\r
1527 if( p_uncle->p_right->color != CL_MAP_RED )
\r
1529 if( p_uncle->p_left->color != CL_MAP_RED )
\r
1531 p_uncle->color = CL_MAP_RED;
\r
1532 p_item = p_item->p_up;
\r
1536 p_uncle->p_left->color = CL_MAP_BLACK;
\r
1537 p_uncle->color = CL_MAP_RED;
\r
1538 __cl_fmap_rot_right( p_map, p_uncle );
\r
1539 p_uncle = p_item->p_up->p_right;
\r
1541 p_uncle->color = p_item->p_up->color;
\r
1542 p_item->p_up->color = CL_MAP_BLACK;
\r
1543 p_uncle->p_right->color = CL_MAP_BLACK;
\r
1544 __cl_fmap_rot_left( p_map, p_item->p_up );
\r
1549 p_uncle = p_item->p_up->p_left;
\r
1551 if( p_uncle->color == CL_MAP_RED )
\r
1553 p_uncle->color = CL_MAP_BLACK;
\r
1554 p_item->p_up->color = CL_MAP_RED;
\r
1555 __cl_fmap_rot_right( p_map, p_item->p_up );
\r
1556 p_uncle = p_item->p_up->p_left;
\r
1559 if( p_uncle->p_left->color != CL_MAP_RED )
\r
1561 if( p_uncle->p_right->color != CL_MAP_RED )
\r
1563 p_uncle->color = CL_MAP_RED;
\r
1564 p_item = p_item->p_up;
\r
1568 p_uncle->p_right->color = CL_MAP_BLACK;
\r
1569 p_uncle->color = CL_MAP_RED;
\r
1570 __cl_fmap_rot_left( p_map, p_uncle );
\r
1571 p_uncle = p_item->p_up->p_left;
\r
1573 p_uncle->color = p_item->p_up->color;
\r
1574 p_item->p_up->color = CL_MAP_BLACK;
\r
1575 p_uncle->p_left->color = CL_MAP_BLACK;
\r
1576 __cl_fmap_rot_right( p_map, p_item->p_up );
\r
1580 p_item->color = CL_MAP_BLACK;
\r
1585 cl_fmap_remove_item(
\r
1586 IN cl_fmap_t* const p_map,
\r
1587 IN cl_fmap_item_t* const p_item )
\r
1589 cl_fmap_item_t *p_child, *p_del_item;
\r
1591 CL_ASSERT( p_map );
\r
1592 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1593 CL_ASSERT( p_item );
\r
1594 CL_ASSERT( p_item->p_map == p_map );
\r
1596 if( p_item == cl_fmap_end( p_map ) )
\r
1599 if( (p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil ) )
\r
1601 /* The item being removed has children on at most on side. */
\r
1602 p_del_item = p_item;
\r
1607 * The item being removed has children on both side.
\r
1608 * We select the item that will replace it. After removing
\r
1609 * the substitute item and rebalancing, the tree will have the
\r
1610 * correct topology. Exchanging the substitute for the item
\r
1611 * will finalize the removal.
\r
1613 p_del_item = cl_fmap_next( p_item );
\r
1614 CL_ASSERT( p_del_item != &p_map->nil );
\r
1617 /* Remove the item from the list. */
\r
1618 __cl_primitive_remove( &p_item->pool_item.list_item );
\r
1619 /* Decrement the item count. */
\r
1622 /* Get the pointer to the new root's child, if any. */
\r
1623 if( p_del_item->p_left != &p_map->nil )
\r
1624 p_child = p_del_item->p_left;
\r
1626 p_child = p_del_item->p_right;
\r
1629 * This assignment may modify the parent pointer of the nil node.
\r
1630 * This is inconsequential.
\r
1632 p_child->p_up = p_del_item->p_up;
\r
1633 (*__cl_fmap_get_parent_ptr_to_item( p_del_item )) = p_child;
\r
1635 if( p_del_item->color != CL_MAP_RED )
\r
1636 __cl_fmap_del_bal( p_map, p_child );
\r
1639 * Note that the splicing done below does not need to occur before
\r
1640 * the tree is balanced, since the actual topology changes are made by the
\r
1641 * preceding code. The topology is preserved by the color assignment made
\r
1642 * below (reader should be reminded that p_del_item == p_item in some cases).
\r
1644 if( p_del_item != p_item )
\r
1647 * Finalize the removal of the specified item by exchanging it with
\r
1648 * the substitute which we removed above.
\r
1650 p_del_item->p_up = p_item->p_up;
\r
1651 p_del_item->p_left = p_item->p_left;
\r
1652 p_del_item->p_right = p_item->p_right;
\r
1653 (*__cl_fmap_get_parent_ptr_to_item( p_item )) = p_del_item;
\r
1654 p_item->p_right->p_up = p_del_item;
\r
1655 p_item->p_left->p_up = p_del_item;
\r
1656 p_del_item->color = p_item->color;
\r
1659 CL_ASSERT( p_map->nil.color != CL_MAP_RED );
\r
1662 /* Clear the pointer to the map since the item has been removed. */
\r
1663 p_item->p_map = NULL;
\r
1670 IN cl_fmap_t* const p_map,
\r
1671 IN const void* const p_key )
\r
1673 cl_fmap_item_t *p_item;
\r
1675 CL_ASSERT( p_map );
\r
1676 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1678 /* Seek the node with the specified key */
\r
1679 p_item = cl_fmap_get( p_map, p_key );
\r
1681 cl_fmap_remove_item( p_map, p_item );
\r
1689 OUT cl_fmap_t* const p_dest_map,
\r
1690 IN OUT cl_fmap_t* const p_src_map )
\r
1692 cl_fmap_item_t *p_item, *p_item2, *p_next;
\r
1694 CL_ASSERT( p_dest_map );
\r
1695 CL_ASSERT( p_src_map );
\r
1697 p_item = cl_fmap_head( p_src_map );
\r
1699 while( p_item != cl_fmap_end( p_src_map ) )
\r
1701 p_next = cl_fmap_next( p_item );
\r
1703 /* Remove the item from its current map. */
\r
1704 cl_fmap_remove_item( p_src_map, p_item );
\r
1705 /* Insert the item into the destination map. */
\r
1706 p_item2 = cl_fmap_insert( p_dest_map, cl_fmap_key( p_item ), p_item );
\r
1707 /* Check that the item was successfully inserted. */
\r
1708 if( p_item2 != p_item )
\r
1710 /* Put the item in back in the source map. */
\r
1712 cl_fmap_insert( p_src_map, cl_fmap_key( p_item ), p_item );
\r
1713 CL_ASSERT( p_item2 == p_item );
\r
1721 __cl_fmap_delta_move(
\r
1722 IN OUT cl_fmap_t* const p_dest,
\r
1723 IN OUT cl_fmap_t* const p_src,
\r
1724 IN OUT cl_fmap_item_t** const pp_item )
\r
1726 cl_fmap_item_t *p_temp, *p_next;
\r
1729 * Get the next item so that we can ensure that pp_item points to
\r
1730 * a valid item upon return from the function.
\r
1732 p_next = cl_fmap_next( *pp_item );
\r
1733 /* Move the old item from its current map the the old map. */
\r
1734 cl_fmap_remove_item( p_src, *pp_item );
\r
1735 p_temp = cl_fmap_insert( p_dest, cl_fmap_key( *pp_item ), *pp_item );
\r
1736 /* We should never have duplicates. */
\r
1737 CL_ASSERT( p_temp == *pp_item );
\r
1738 /* Point pp_item to a valid item in the source map. */
\r
1739 (*pp_item) = p_next;
\r
1745 IN OUT cl_fmap_t* const p_map1,
\r
1746 IN OUT cl_fmap_t* const p_map2,
\r
1747 OUT cl_fmap_t* const p_new,
\r
1748 OUT cl_fmap_t* const p_old )
\r
1750 cl_fmap_item_t *p_item1, *p_item2;
\r
1753 CL_ASSERT( p_map1 );
\r
1754 CL_ASSERT( p_map2 );
\r
1755 CL_ASSERT( p_new );
\r
1756 CL_ASSERT( p_old );
\r
1757 CL_ASSERT( cl_is_fmap_empty( p_new ) );
\r
1758 CL_ASSERT( cl_is_fmap_empty( p_old ) );
\r
1760 p_item1 = cl_fmap_head( p_map1 );
\r
1761 p_item2 = cl_fmap_head( p_map2 );
\r
1763 while( p_item1 != cl_fmap_end( p_map1 ) &&
\r
1764 p_item2 != cl_fmap_end( p_map2 ) )
\r
1766 cmp = p_map1->pfn_compare( cl_fmap_key( p_item1 ),
\r
1767 cl_fmap_key( p_item2 ) );
\r
1770 /* We found an old item. */
\r
1771 __cl_fmap_delta_move( p_old, p_map1, &p_item1 );
\r
1773 else if( cmp > 0 )
\r
1775 /* We found a new item. */
\r
1776 __cl_fmap_delta_move( p_new, p_map2, &p_item2 );
\r
1780 /* Move both forward since they have the same key. */
\r
1781 p_item1 = cl_fmap_next( p_item1 );
\r
1782 p_item2 = cl_fmap_next( p_item2 );
\r
1786 /* Process the remainder if the end of either source map was reached. */
\r
1787 while( p_item2 != cl_fmap_end( p_map2 ) )
\r
1788 __cl_fmap_delta_move( p_new, p_map2, &p_item2 );
\r
1790 while( p_item1 != cl_fmap_end( p_map1 ) )
\r
1791 __cl_fmap_delta_move( p_old, p_map1, &p_item1 );
\r