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
45 /*****************************************************************************
\r
49 * Map is an associative array. By providing a key, the caller can retrieve
\r
50 * an object from the map. All objects in the map have an associated key,
\r
51 * as specified by the caller when the object was inserted into the map.
\r
52 * In addition to random access, the caller can traverse the map much like
\r
53 * a linked list, either forwards from the first object or backwards from
\r
54 * the last object. The objects in the map are always traversed in
\r
55 * order since the nodes are stored sorted.
\r
57 * This implementation of Map uses a red black tree verified against
\r
58 * Cormen-Leiserson-Rivest text, McGraw-Hill Edition, fourteenth
\r
61 *****************************************************************************/
\r
64 #include <complib/cl_qmap.h>
\r
65 #include <complib/cl_map.h>
\r
66 #include <complib/cl_fleximap.h>
\r
67 #include <complib/cl_memory.h>
\r
70 /******************************************************************************
\r
71 *******************************************************************************
\r
72 ************** ************
\r
73 ************** IMPLEMENTATION OF QUICK MAP ************
\r
74 ************** ************
\r
75 *******************************************************************************
\r
76 ******************************************************************************/
\r
81 static inline cl_map_item_t*
\r
83 IN const cl_qmap_t* const p_map )
\r
86 return( p_map->root.p_left );
\r
91 * Returns whether a given item is on the left of its parent.
\r
94 __cl_map_is_left_child(
\r
95 IN const cl_map_item_t* const p_item )
\r
97 CL_ASSERT( p_item );
\r
98 CL_ASSERT( p_item->p_up );
\r
99 CL_ASSERT( p_item->p_up != p_item );
\r
101 return( p_item->p_up->p_left == p_item );
\r
106 * Retrieve the pointer to the parent's pointer to an item.
\r
108 static cl_map_item_t**
\r
109 __cl_map_get_parent_ptr_to_item(
\r
110 IN cl_map_item_t* const p_item )
\r
112 CL_ASSERT( p_item );
\r
113 CL_ASSERT( p_item->p_up );
\r
114 CL_ASSERT( p_item->p_up != p_item );
\r
116 if( __cl_map_is_left_child( p_item ) )
\r
117 return( &p_item->p_up->p_left );
\r
119 CL_ASSERT( p_item->p_up->p_right == p_item );
\r
120 return( &p_item->p_up->p_right );
\r
125 * Rotate a node to the left. This rotation affects the least number of links
\r
126 * between nodes and brings the level of C up by one while increasing the depth
\r
127 * of A one. Note that the links to/from W, X, Y, and Z are not affected.
\r
141 IN cl_qmap_t* const p_map,
\r
142 IN cl_map_item_t* const p_item )
\r
144 cl_map_item_t **pp_root;
\r
146 CL_ASSERT( p_map );
\r
147 CL_ASSERT( p_item );
\r
148 CL_ASSERT( p_item->p_right != &p_map->nil );
\r
150 pp_root = __cl_map_get_parent_ptr_to_item( p_item );
\r
152 /* Point R to C instead of A. */
\r
153 *pp_root = p_item->p_right;
\r
154 /* Set C's parent to R. */
\r
155 (*pp_root)->p_up = p_item->p_up;
\r
157 /* Set A's right to B */
\r
158 p_item->p_right = (*pp_root)->p_left;
\r
160 * Set B's parent to A. We trap for B being NIL since the
\r
161 * caller may depend on NIL not changing.
\r
163 if( (*pp_root)->p_left != &p_map->nil )
\r
164 (*pp_root)->p_left->p_up = p_item;
\r
166 /* Set C's left to A. */
\r
167 (*pp_root)->p_left = p_item;
\r
168 /* Set A's parent to C. */
\r
169 p_item->p_up = *pp_root;
\r
174 * Rotate a node to the right. This rotation affects the least number of links
\r
175 * between nodes and brings the level of A up by one while increasing the depth
\r
176 * of C one. Note that the links to/from W, X, Y, and Z are not affected.
\r
189 __cl_map_rot_right(
\r
190 IN cl_qmap_t* const p_map,
\r
191 IN cl_map_item_t* const p_item )
\r
193 cl_map_item_t **pp_root;
\r
195 CL_ASSERT( p_map );
\r
196 CL_ASSERT( p_item );
\r
197 CL_ASSERT( p_item->p_left != &p_map->nil );
\r
199 /* Point R to A instead of C. */
\r
200 pp_root = __cl_map_get_parent_ptr_to_item( p_item );
\r
201 (*pp_root) = p_item->p_left;
\r
202 /* Set A's parent to R. */
\r
203 (*pp_root)->p_up = p_item->p_up;
\r
205 /* Set C's left to B */
\r
206 p_item->p_left = (*pp_root)->p_right;
\r
208 * Set B's parent to C. We trap for B being NIL since the
\r
209 * caller may depend on NIL not changing.
\r
211 if( (*pp_root)->p_right != &p_map->nil )
\r
212 (*pp_root)->p_right->p_up = p_item;
\r
214 /* Set A's right to C. */
\r
215 (*pp_root)->p_right = p_item;
\r
216 /* Set C's parent to A. */
\r
217 p_item->p_up = *pp_root;
\r
223 IN cl_qmap_t* const p_map )
\r
225 CL_ASSERT( p_map );
\r
227 cl_memclr( p_map, sizeof(cl_qmap_t) );
\r
229 /* special setup for the root node */
\r
230 p_map->root.p_up = &p_map->root;
\r
231 p_map->root.p_left = &p_map->nil;
\r
232 p_map->root.p_right = &p_map->nil;
\r
233 p_map->root.color = CL_MAP_BLACK;
\r
235 /* Setup the node used as terminator for all leaves. */
\r
236 p_map->nil.p_up = &p_map->nil;
\r
237 p_map->nil.p_left = &p_map->nil;
\r
238 p_map->nil.p_right = &p_map->nil;
\r
239 p_map->nil.color = CL_MAP_BLACK;
\r
242 p_map->root.p_map = p_map;
\r
243 p_map->nil.p_map = p_map;
\r
246 p_map->state = CL_INITIALIZED;
\r
248 cl_qmap_remove_all( p_map );
\r
254 IN const cl_qmap_t* const p_map,
\r
255 IN const uint64_t key )
\r
257 cl_map_item_t *p_item;
\r
259 CL_ASSERT( p_map );
\r
260 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
262 p_item = __cl_map_root( p_map );
\r
264 while( p_item != &p_map->nil )
\r
266 if( key == p_item->key )
\r
267 break; /* just right */
\r
269 if( key < p_item->key )
\r
270 p_item = p_item->p_left; /* too small */
\r
272 p_item = p_item->p_right; /* too big */
\r
280 cl_qmap_apply_func(
\r
281 IN const cl_qmap_t* const p_map,
\r
282 IN cl_pfn_qmap_apply_t pfn_func,
\r
283 IN const void* const context )
\r
285 cl_map_item_t* p_map_item;
\r
287 /* Note that context can have any arbitrary value. */
\r
288 CL_ASSERT( p_map );
\r
289 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
290 CL_ASSERT( pfn_func );
\r
292 p_map_item = cl_qmap_head( p_map );
\r
293 while( p_map_item != cl_qmap_end( p_map ) )
\r
295 pfn_func( p_map_item, (void*)context );
\r
296 p_map_item = cl_qmap_next( p_map_item );
\r
302 * Balance a tree starting at a given item back to the root.
\r
306 IN cl_qmap_t* const p_map,
\r
307 IN cl_map_item_t* p_item )
\r
309 cl_map_item_t* p_grand_uncle;
\r
311 CL_ASSERT( p_map );
\r
312 CL_ASSERT( p_item );
\r
313 CL_ASSERT( p_item != &p_map->root );
\r
315 while( p_item->p_up->color == CL_MAP_RED )
\r
317 if( __cl_map_is_left_child( p_item->p_up ) )
\r
319 p_grand_uncle = p_item->p_up->p_up->p_right;
\r
320 CL_ASSERT( p_grand_uncle );
\r
321 if( p_grand_uncle->color == CL_MAP_RED )
\r
323 p_grand_uncle->color = CL_MAP_BLACK;
\r
324 p_item->p_up->color = CL_MAP_BLACK;
\r
325 p_item->p_up->p_up->color = CL_MAP_RED;
\r
326 p_item = p_item->p_up->p_up;
\r
330 if( !__cl_map_is_left_child( p_item ) )
\r
332 p_item = p_item->p_up;
\r
333 __cl_map_rot_left( p_map, p_item );
\r
335 p_item->p_up->color = CL_MAP_BLACK;
\r
336 p_item->p_up->p_up->color = CL_MAP_RED;
\r
337 __cl_map_rot_right( p_map, p_item->p_up->p_up );
\r
341 p_grand_uncle = p_item->p_up->p_up->p_left;
\r
342 CL_ASSERT( p_grand_uncle );
\r
343 if( p_grand_uncle->color == CL_MAP_RED )
\r
345 p_grand_uncle->color = CL_MAP_BLACK;
\r
346 p_item->p_up->color = CL_MAP_BLACK;
\r
347 p_item->p_up->p_up->color = CL_MAP_RED;
\r
348 p_item = p_item->p_up->p_up;
\r
352 if( __cl_map_is_left_child( p_item ) )
\r
354 p_item = p_item->p_up;
\r
355 __cl_map_rot_right( p_map, p_item );
\r
357 p_item->p_up->color = CL_MAP_BLACK;
\r
358 p_item->p_up->p_up->color = CL_MAP_RED;
\r
359 __cl_map_rot_left( p_map, p_item->p_up->p_up );
\r
367 IN cl_qmap_t* const p_map,
\r
368 IN const uint64_t key,
\r
369 IN cl_map_item_t* const p_item )
\r
371 cl_map_item_t *p_insert_at, *p_comp_item;
\r
373 CL_ASSERT( p_map );
\r
374 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
375 CL_ASSERT( p_item );
\r
376 CL_ASSERT( p_map->root.p_up == &p_map->root );
\r
377 CL_ASSERT( p_map->root.color != CL_MAP_RED );
\r
378 CL_ASSERT( p_map->nil.color != CL_MAP_RED );
\r
380 p_item->p_left = &p_map->nil;
\r
381 p_item->p_right = &p_map->nil;
\r
383 p_item->color = CL_MAP_RED;
\r
385 /* Find the insertion location. */
\r
386 p_insert_at = &p_map->root;
\r
387 p_comp_item = __cl_map_root( p_map );
\r
389 while( p_comp_item != &p_map->nil )
\r
391 p_insert_at = p_comp_item;
\r
393 if( key == p_insert_at->key )
\r
394 return( p_insert_at );
\r
396 /* Traverse the tree until the correct insertion point is found. */
\r
397 if( key < p_insert_at->key )
\r
398 p_comp_item = p_insert_at->p_left;
\r
400 p_comp_item = p_insert_at->p_right;
\r
403 CL_ASSERT( p_insert_at != &p_map->nil );
\r
404 CL_ASSERT( p_comp_item == &p_map->nil );
\r
405 /* Insert the item. */
\r
406 if( p_insert_at == &p_map->root )
\r
408 p_insert_at->p_left = p_item;
\r
410 * Primitive insert places the new item in front of
\r
411 * the existing item.
\r
413 __cl_primitive_insert( &p_map->nil.pool_item.list_item,
\r
414 &p_item->pool_item.list_item );
\r
416 else if( key < p_insert_at->key )
\r
418 p_insert_at->p_left = p_item;
\r
420 * Primitive insert places the new item in front of
\r
421 * the existing item.
\r
423 __cl_primitive_insert( &p_insert_at->pool_item.list_item,
\r
424 &p_item->pool_item.list_item );
\r
428 p_insert_at->p_right = p_item;
\r
430 * Primitive insert places the new item in front of
\r
431 * the existing item.
\r
433 __cl_primitive_insert( p_insert_at->pool_item.list_item.p_next,
\r
434 &p_item->pool_item.list_item );
\r
436 /* Increase the count. */
\r
439 p_item->p_up = p_insert_at;
\r
442 * We have added depth to this section of the tree.
\r
443 * Rebalance as necessary as we retrace our path through the tree
\r
444 * and update colors.
\r
446 __cl_map_ins_bal( p_map, p_item );
\r
448 __cl_map_root( p_map )->color = CL_MAP_BLACK;
\r
451 * Note that it is not necessary to re-color the nil node black because all
\r
452 * red color assignments are made via the p_up pointer, and nil is never
\r
453 * set as the value of a p_up pointer.
\r
457 /* Set the pointer to the map in the map item for consistency checking. */
\r
458 p_item->p_map = p_map;
\r
467 IN cl_qmap_t* const p_map,
\r
468 IN cl_map_item_t* p_item )
\r
470 cl_map_item_t *p_uncle;
\r
472 while( (p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root) )
\r
474 if( __cl_map_is_left_child( p_item ) )
\r
476 p_uncle = p_item->p_up->p_right;
\r
478 if( p_uncle->color == CL_MAP_RED )
\r
480 p_uncle->color = CL_MAP_BLACK;
\r
481 p_item->p_up->color = CL_MAP_RED;
\r
482 __cl_map_rot_left( p_map, p_item->p_up );
\r
483 p_uncle = p_item->p_up->p_right;
\r
486 if( p_uncle->p_right->color != CL_MAP_RED )
\r
488 if( p_uncle->p_left->color != CL_MAP_RED )
\r
490 p_uncle->color = CL_MAP_RED;
\r
491 p_item = p_item->p_up;
\r
495 p_uncle->p_left->color = CL_MAP_BLACK;
\r
496 p_uncle->color = CL_MAP_RED;
\r
497 __cl_map_rot_right( p_map, p_uncle );
\r
498 p_uncle = p_item->p_up->p_right;
\r
500 p_uncle->color = p_item->p_up->color;
\r
501 p_item->p_up->color = CL_MAP_BLACK;
\r
502 p_uncle->p_right->color = CL_MAP_BLACK;
\r
503 __cl_map_rot_left( p_map, p_item->p_up );
\r
508 p_uncle = p_item->p_up->p_left;
\r
510 if( p_uncle->color == CL_MAP_RED )
\r
512 p_uncle->color = CL_MAP_BLACK;
\r
513 p_item->p_up->color = CL_MAP_RED;
\r
514 __cl_map_rot_right( p_map, p_item->p_up );
\r
515 p_uncle = p_item->p_up->p_left;
\r
518 if( p_uncle->p_left->color != CL_MAP_RED )
\r
520 if( p_uncle->p_right->color != CL_MAP_RED )
\r
522 p_uncle->color = CL_MAP_RED;
\r
523 p_item = p_item->p_up;
\r
527 p_uncle->p_right->color = CL_MAP_BLACK;
\r
528 p_uncle->color = CL_MAP_RED;
\r
529 __cl_map_rot_left( p_map, p_uncle );
\r
530 p_uncle = p_item->p_up->p_left;
\r
532 p_uncle->color = p_item->p_up->color;
\r
533 p_item->p_up->color = CL_MAP_BLACK;
\r
534 p_uncle->p_left->color = CL_MAP_BLACK;
\r
535 __cl_map_rot_right( p_map, p_item->p_up );
\r
539 p_item->color = CL_MAP_BLACK;
\r
544 cl_qmap_remove_item(
\r
545 IN cl_qmap_t* const p_map,
\r
546 IN cl_map_item_t* const p_item )
\r
548 cl_map_item_t *p_child, *p_del_item;
\r
550 CL_ASSERT( p_map );
\r
551 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
552 CL_ASSERT( p_item );
\r
553 CL_ASSERT( p_item->p_map == p_map );
\r
555 if( p_item == cl_qmap_end( p_map ) )
\r
558 if( (p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil ) )
\r
560 /* The item being removed has children on at most on side. */
\r
561 p_del_item = p_item;
\r
566 * The item being removed has children on both side.
\r
567 * We select the item that will replace it. After removing
\r
568 * the substitute item and rebalancing, the tree will have the
\r
569 * correct topology. Exchanging the substitute for the item
\r
570 * will finalize the removal.
\r
572 p_del_item = cl_qmap_next( p_item );
\r
573 CL_ASSERT( p_del_item != &p_map->nil );
\r
576 /* Remove the item from the list. */
\r
577 __cl_primitive_remove( &p_item->pool_item.list_item );
\r
578 /* Decrement the item count. */
\r
581 /* Get the pointer to the new root's child, if any. */
\r
582 if( p_del_item->p_left != &p_map->nil )
\r
583 p_child = p_del_item->p_left;
\r
585 p_child = p_del_item->p_right;
\r
588 * This assignment may modify the parent pointer of the nil node.
\r
589 * This is inconsequential.
\r
591 p_child->p_up = p_del_item->p_up;
\r
592 (*__cl_map_get_parent_ptr_to_item( p_del_item )) = p_child;
\r
594 if( p_del_item->color != CL_MAP_RED )
\r
595 __cl_map_del_bal( p_map, p_child );
\r
598 * Note that the splicing done below does not need to occur before
\r
599 * the tree is balanced, since the actual topology changes are made by the
\r
600 * preceding code. The topology is preserved by the color assignment made
\r
601 * below (reader should be reminded that p_del_item == p_item in some cases).
\r
603 if( p_del_item != p_item )
\r
606 * Finalize the removal of the specified item by exchanging it with
\r
607 * the substitute which we removed above.
\r
609 p_del_item->p_up = p_item->p_up;
\r
610 p_del_item->p_left = p_item->p_left;
\r
611 p_del_item->p_right = p_item->p_right;
\r
612 (*__cl_map_get_parent_ptr_to_item( p_item )) = p_del_item;
\r
613 p_item->p_right->p_up = p_del_item;
\r
614 p_item->p_left->p_up = p_del_item;
\r
615 p_del_item->color = p_item->color;
\r
618 CL_ASSERT( p_map->nil.color != CL_MAP_RED );
\r
621 /* Clear the pointer to the map since the item has been removed. */
\r
622 p_item->p_map = NULL;
\r
629 IN cl_qmap_t* const p_map,
\r
630 IN const uint64_t key )
\r
632 cl_map_item_t *p_item;
\r
634 CL_ASSERT( p_map );
\r
635 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
637 /* Seek the node with the specified key */
\r
638 p_item = cl_qmap_get( p_map, key );
\r
640 cl_qmap_remove_item( p_map, p_item );
\r
648 OUT cl_qmap_t* const p_dest_map,
\r
649 IN OUT cl_qmap_t* const p_src_map )
\r
651 cl_map_item_t *p_item, *p_item2, *p_next;
\r
653 CL_ASSERT( p_dest_map );
\r
654 CL_ASSERT( p_src_map );
\r
656 p_item = cl_qmap_head( p_src_map );
\r
658 while( p_item != cl_qmap_end( p_src_map ) )
\r
660 p_next = cl_qmap_next( p_item );
\r
662 /* Remove the item from its current map. */
\r
663 cl_qmap_remove_item( p_src_map, p_item );
\r
664 /* Insert the item into the destination map. */
\r
665 p_item2 = cl_qmap_insert( p_dest_map, cl_qmap_key( p_item ), p_item );
\r
666 /* Check that the item was successfully inserted. */
\r
667 if( p_item2 != p_item )
\r
669 /* Put the item in back in the source map. */
\r
671 cl_qmap_insert( p_src_map, cl_qmap_key( p_item ), p_item );
\r
672 CL_ASSERT( p_item2 == p_item );
\r
680 __cl_qmap_delta_move(
\r
681 IN OUT cl_qmap_t* const p_dest,
\r
682 IN OUT cl_qmap_t* const p_src,
\r
683 IN OUT cl_map_item_t** const pp_item )
\r
685 cl_map_item_t *p_temp, *p_next;
\r
688 * Get the next item so that we can ensure that pp_item points to
\r
689 * a valid item upon return from the function.
\r
691 p_next = cl_qmap_next( *pp_item );
\r
692 /* Move the old item from its current map the the old map. */
\r
693 cl_qmap_remove_item( p_src, *pp_item );
\r
694 p_temp = cl_qmap_insert( p_dest, cl_qmap_key( *pp_item ), *pp_item );
\r
695 /* We should never have duplicates. */
\r
696 CL_ASSERT( p_temp == *pp_item );
\r
697 /* Point pp_item to a valid item in the source map. */
\r
698 (*pp_item) = p_next;
\r
704 IN OUT cl_qmap_t* const p_map1,
\r
705 IN OUT cl_qmap_t* const p_map2,
\r
706 OUT cl_qmap_t* const p_new,
\r
707 OUT cl_qmap_t* const p_old )
\r
709 cl_map_item_t *p_item1, *p_item2;
\r
710 uint64_t key1, key2;
\r
712 CL_ASSERT( p_map1 );
\r
713 CL_ASSERT( p_map2 );
\r
714 CL_ASSERT( p_new );
\r
715 CL_ASSERT( p_old );
\r
716 CL_ASSERT( cl_is_qmap_empty( p_new ) );
\r
717 CL_ASSERT( cl_is_qmap_empty( p_old ) );
\r
719 p_item1 = cl_qmap_head( p_map1 );
\r
720 p_item2 = cl_qmap_head( p_map2 );
\r
722 while( p_item1 != cl_qmap_end( p_map1 ) &&
\r
723 p_item2 != cl_qmap_end( p_map2 ) )
\r
725 key1 = cl_qmap_key( p_item1 );
\r
726 key2 = cl_qmap_key( p_item2 );
\r
729 /* We found an old item. */
\r
730 __cl_qmap_delta_move( p_old, p_map1, &p_item1 );
\r
732 else if( key1 > key2 )
\r
734 /* We found a new item. */
\r
735 __cl_qmap_delta_move( p_new, p_map2, &p_item2 );
\r
739 /* Move both forward since they have the same key. */
\r
740 p_item1 = cl_qmap_next( p_item1 );
\r
741 p_item2 = cl_qmap_next( p_item2 );
\r
745 /* Process the remainder if the end of either source map was reached. */
\r
746 while( p_item2 != cl_qmap_end( p_map2 ) )
\r
747 __cl_qmap_delta_move( p_new, p_map2, &p_item2 );
\r
749 while( p_item1 != cl_qmap_end( p_map1 ) )
\r
750 __cl_qmap_delta_move( p_old, p_map1, &p_item1 );
\r
754 /******************************************************************************
\r
755 *******************************************************************************
\r
756 ************** ************
\r
757 ************** IMPLEMENTATION OF MAP ************
\r
758 ************** ************
\r
759 *******************************************************************************
\r
760 ******************************************************************************/
\r
763 #define MAP_GROW_SIZE 32
\r
768 IN cl_map_t* const p_map )
\r
770 CL_ASSERT( p_map );
\r
772 cl_qpool_construct( &p_map->pool );
\r
778 IN cl_map_t* const p_map,
\r
779 IN const size_t min_items )
\r
783 CL_ASSERT( p_map );
\r
785 cl_qmap_init( &p_map->qmap );
\r
788 * We will grow by min_items/8 items at a time, with a minimum of
\r
791 grow_size = min_items >> 3;
\r
792 if( grow_size < MAP_GROW_SIZE )
\r
793 grow_size = MAP_GROW_SIZE;
\r
795 return( cl_qpool_init( &p_map->pool, min_items, 0, grow_size,
\r
796 sizeof(cl_map_obj_t), NULL, NULL, NULL ) );
\r
802 IN cl_map_t* const p_map )
\r
804 CL_ASSERT( p_map );
\r
806 cl_qpool_destroy( &p_map->pool );
\r
812 IN cl_map_t* const p_map,
\r
813 IN const uint64_t key,
\r
814 IN const void* const p_object )
\r
816 cl_map_obj_t *p_map_obj, *p_obj_at_key;
\r
818 CL_ASSERT( p_map );
\r
820 p_map_obj = (cl_map_obj_t*)cl_qpool_get( &p_map->pool );
\r
825 cl_qmap_set_obj( p_map_obj, p_object );
\r
828 (cl_map_obj_t*)cl_qmap_insert( &p_map->qmap, key, &p_map_obj->item );
\r
830 /* Return the item to the pool if insertion failed. */
\r
831 if( p_obj_at_key != p_map_obj )
\r
832 cl_qpool_put( &p_map->pool, &p_map_obj->item.pool_item );
\r
834 return( cl_qmap_obj( p_obj_at_key ) );
\r
840 IN const cl_map_t* const p_map,
\r
841 IN const uint64_t key )
\r
843 cl_map_item_t *p_item;
\r
845 CL_ASSERT( p_map );
\r
847 p_item = cl_qmap_get( &p_map->qmap, key );
\r
849 if( p_item == cl_qmap_end( &p_map->qmap ) )
\r
852 return( cl_qmap_obj( PARENT_STRUCT( p_item, cl_map_obj_t, item ) ) );
\r
857 cl_map_remove_item(
\r
858 IN cl_map_t* const p_map,
\r
859 IN const cl_map_iterator_t itor )
\r
861 CL_ASSERT( itor->p_map == &p_map->qmap );
\r
863 if( itor == cl_map_end( p_map ) )
\r
866 cl_qmap_remove_item( &p_map->qmap, (cl_map_item_t*)itor );
\r
867 cl_qpool_put( &p_map->pool, &((cl_map_item_t*)itor)->pool_item );
\r
873 IN cl_map_t* const p_map,
\r
874 IN const uint64_t key )
\r
876 cl_map_item_t *p_item;
\r
878 CL_ASSERT( p_map );
\r
880 p_item = cl_qmap_remove( &p_map->qmap, key );
\r
882 if( p_item == cl_qmap_end( &p_map->qmap ) )
\r
885 cl_qpool_put( &p_map->pool, &p_item->pool_item );
\r
887 return( cl_qmap_obj( (cl_map_obj_t*)p_item ) );
\r
893 IN cl_map_t* const p_map )
\r
895 cl_map_item_t *p_item;
\r
897 CL_ASSERT( p_map );
\r
899 /* Return all map items to the pool. */
\r
900 while( !cl_is_qmap_empty( &p_map->qmap ) )
\r
902 p_item = cl_qmap_head( &p_map->qmap );
\r
903 cl_qmap_remove_item( &p_map->qmap, p_item );
\r
904 cl_qpool_put( &p_map->pool, &p_item->pool_item );
\r
906 if( !cl_is_qmap_empty( &p_map->qmap ) )
\r
908 p_item = cl_qmap_tail( &p_map->qmap );
\r
909 cl_qmap_remove_item( &p_map->qmap, p_item );
\r
910 cl_qpool_put( &p_map->pool, &p_item->pool_item );
\r
918 OUT cl_map_t* const p_dest_map,
\r
919 IN OUT cl_map_t* const p_src_map )
\r
921 cl_status_t status = CL_SUCCESS;
\r
922 cl_map_iterator_t itor, next;
\r
924 void *p_obj, *p_obj2;
\r
926 CL_ASSERT( p_dest_map );
\r
927 CL_ASSERT( p_src_map );
\r
929 itor = cl_map_head( p_src_map );
\r
930 while( itor != cl_map_end( p_src_map ) )
\r
932 next = cl_map_next( itor );
\r
934 p_obj = cl_map_obj( itor );
\r
935 key = cl_map_key( itor );
\r
937 cl_map_remove_item( p_src_map, itor );
\r
939 /* Insert the object into the destination map. */
\r
940 p_obj2 = cl_map_insert( p_dest_map, key, p_obj );
\r
941 /* Trap for failure. */
\r
942 if( p_obj != p_obj2 )
\r
945 status = CL_INSUFFICIENT_MEMORY;
\r
946 /* Put the object back in the source map. This must succeed. */
\r
947 p_obj2 = cl_map_insert( p_src_map, key, p_obj );
\r
948 CL_ASSERT( p_obj == p_obj2 );
\r
949 /* If the failure was due to insufficient memory, return. */
\r
950 if( status != CL_SUCCESS )
\r
956 return( CL_SUCCESS );
\r
962 IN OUT cl_map_t* const p_map1,
\r
963 IN OUT cl_map_t* const p_map2,
\r
964 IN OUT cl_map_t* const p_new,
\r
965 IN OUT cl_map_t* const p_old )
\r
967 cl_status_t status;
\r
969 /* Restore the initial state. */
\r
970 status = cl_map_merge( p_map1, p_old );
\r
971 CL_ASSERT( status == CL_SUCCESS );
\r
972 status = cl_map_merge( p_map2, p_new );
\r
973 CL_ASSERT( status == CL_SUCCESS );
\r
978 __cl_map_delta_move(
\r
979 OUT cl_map_t* const p_dest,
\r
980 IN OUT cl_map_t* const p_src,
\r
981 IN OUT cl_map_iterator_t* const p_itor )
\r
983 cl_map_iterator_t next;
\r
984 void *p_obj, *p_obj2;
\r
987 /* Get a valid iterator so we can continue the loop. */
\r
988 next = cl_map_next( *p_itor );
\r
989 /* Get the pointer to the object for insertion. */
\r
990 p_obj = cl_map_obj( *p_itor );
\r
991 /* Get the key for the object. */
\r
992 key = cl_map_key( *p_itor );
\r
993 /* Move the object. */
\r
994 cl_map_remove_item( p_src, *p_itor );
\r
995 p_obj2 = cl_map_insert( p_dest, key, p_obj );
\r
996 /* Check for failure. We should never get a duplicate. */
\r
999 p_obj2 = cl_map_insert( p_src, key, p_obj );
\r
1000 CL_ASSERT( p_obj2 == p_obj );
\r
1001 return( CL_INSUFFICIENT_MEMORY );
\r
1004 /* We should never get a duplicate */
\r
1005 CL_ASSERT( p_obj == p_obj2 );
\r
1006 /* Update the iterator so that it is valid. */
\r
1009 return( CL_SUCCESS );
\r
1015 IN OUT cl_map_t* const p_map1,
\r
1016 IN OUT cl_map_t* const p_map2,
\r
1017 OUT cl_map_t* const p_new,
\r
1018 OUT cl_map_t* const p_old )
\r
1020 cl_map_iterator_t itor1, itor2;
\r
1021 uint64_t key1, key2;
\r
1022 cl_status_t status;
\r
1024 CL_ASSERT( p_map1 );
\r
1025 CL_ASSERT( p_map2 );
\r
1026 CL_ASSERT( p_new );
\r
1027 CL_ASSERT( p_old );
\r
1028 CL_ASSERT( cl_is_map_empty( p_new ) );
\r
1029 CL_ASSERT( cl_is_map_empty( p_old ) );
\r
1031 itor1 = cl_map_head( p_map1 );
\r
1032 itor2 = cl_map_head( p_map2 );
\r
1035 * Note that the check is for the end, since duplicate items will remain
\r
1036 * in their respective maps.
\r
1038 while( itor1 != cl_map_end( p_map1 ) &&
\r
1039 itor2 != cl_map_end( p_map2 ) )
\r
1041 key1 = cl_map_key( itor1 );
\r
1042 key2 = cl_map_key( itor2 );
\r
1045 status = __cl_map_delta_move( p_old, p_map1, &itor1 );
\r
1046 /* Check for failure. */
\r
1047 if( status != CL_SUCCESS )
\r
1049 /* Restore the initial state. */
\r
1050 __cl_map_revert( p_map1, p_map2, p_new, p_old );
\r
1051 /* Return the failure status. */
\r
1055 else if( key1 > key2 )
\r
1057 status = __cl_map_delta_move( p_new, p_map2, &itor2 );
\r
1058 if( status != CL_SUCCESS )
\r
1060 /* Restore the initial state. */
\r
1061 __cl_map_revert( p_map1, p_map2, p_new, p_old );
\r
1062 /* Return the failure status. */
\r
1068 /* Move both forward since they have the same key. */
\r
1069 itor1 = cl_map_next( itor1 );
\r
1070 itor2 = cl_map_next( itor2 );
\r
1074 /* Process the remainder if either source map is empty. */
\r
1075 while( itor2 != cl_map_end( p_map2 ) )
\r
1077 status = __cl_map_delta_move( p_new, p_map2, &itor2 );
\r
1078 if( status != CL_SUCCESS )
\r
1080 /* Restore the initial state. */
\r
1081 __cl_map_revert( p_map1, p_map2, p_new, p_old );
\r
1082 /* Return the failure status. */
\r
1087 while( itor1 != cl_map_end( p_map1 ) )
\r
1089 status = __cl_map_delta_move( p_old, p_map1, &itor1 );
\r
1090 if( status != CL_SUCCESS )
\r
1092 /* Restore the initial state. */
\r
1093 __cl_map_revert( p_map1, p_map2, p_new, p_old );
\r
1094 /* Return the failure status. */
\r
1099 return( CL_SUCCESS );
\r
1103 /******************************************************************************
\r
1104 *******************************************************************************
\r
1105 ************** ************
\r
1106 ************** IMPLEMENTATION OF FLEXI MAP ************
\r
1107 ************** ************
\r
1108 *******************************************************************************
\r
1109 ******************************************************************************/
\r
1114 static inline cl_fmap_item_t*
\r
1116 IN const cl_fmap_t* const p_map )
\r
1118 CL_ASSERT( p_map );
\r
1119 return( p_map->root.p_left );
\r
1124 * Returns whether a given item is on the left of its parent.
\r
1127 __cl_fmap_is_left_child(
\r
1128 IN const cl_fmap_item_t* const p_item )
\r
1130 CL_ASSERT( p_item );
\r
1131 CL_ASSERT( p_item->p_up );
\r
1132 CL_ASSERT( p_item->p_up != p_item );
\r
1134 return( p_item->p_up->p_left == p_item );
\r
1139 * Retrieve the pointer to the parent's pointer to an item.
\r
1141 static cl_fmap_item_t**
\r
1142 __cl_fmap_get_parent_ptr_to_item(
\r
1143 IN cl_fmap_item_t* const p_item )
\r
1145 CL_ASSERT( p_item );
\r
1146 CL_ASSERT( p_item->p_up );
\r
1147 CL_ASSERT( p_item->p_up != p_item );
\r
1149 if( __cl_fmap_is_left_child( p_item ) )
\r
1150 return( &p_item->p_up->p_left );
\r
1152 CL_ASSERT( p_item->p_up->p_right == p_item );
\r
1153 return( &p_item->p_up->p_right );
\r
1158 * Rotate a node to the left. This rotation affects the least number of links
\r
1159 * between nodes and brings the level of C up by one while increasing the depth
\r
1160 * of A one. Note that the links to/from W, X, Y, and Z are not affected.
\r
1173 __cl_fmap_rot_left(
\r
1174 IN cl_fmap_t* const p_map,
\r
1175 IN cl_fmap_item_t* const p_item )
\r
1177 cl_fmap_item_t **pp_root;
\r
1179 CL_ASSERT( p_map );
\r
1180 CL_ASSERT( p_item );
\r
1181 CL_ASSERT( p_item->p_right != &p_map->nil );
\r
1183 pp_root = __cl_fmap_get_parent_ptr_to_item( p_item );
\r
1185 /* Point R to C instead of A. */
\r
1186 *pp_root = p_item->p_right;
\r
1187 /* Set C's parent to R. */
\r
1188 (*pp_root)->p_up = p_item->p_up;
\r
1190 /* Set A's right to B */
\r
1191 p_item->p_right = (*pp_root)->p_left;
\r
1193 * Set B's parent to A. We trap for B being NIL since the
\r
1194 * caller may depend on NIL not changing.
\r
1196 if( (*pp_root)->p_left != &p_map->nil )
\r
1197 (*pp_root)->p_left->p_up = p_item;
\r
1199 /* Set C's left to A. */
\r
1200 (*pp_root)->p_left = p_item;
\r
1201 /* Set A's parent to C. */
\r
1202 p_item->p_up = *pp_root;
\r
1207 * Rotate a node to the right. This rotation affects the least number of links
\r
1208 * between nodes and brings the level of A up by one while increasing the depth
\r
1209 * of C one. Note that the links to/from W, X, Y, and Z are not affected.
\r
1222 __cl_fmap_rot_right(
\r
1223 IN cl_fmap_t* const p_map,
\r
1224 IN cl_fmap_item_t* const p_item )
\r
1226 cl_fmap_item_t **pp_root;
\r
1228 CL_ASSERT( p_map );
\r
1229 CL_ASSERT( p_item );
\r
1230 CL_ASSERT( p_item->p_left != &p_map->nil );
\r
1232 /* Point R to A instead of C. */
\r
1233 pp_root = __cl_fmap_get_parent_ptr_to_item( p_item );
\r
1234 (*pp_root) = p_item->p_left;
\r
1235 /* Set A's parent to R. */
\r
1236 (*pp_root)->p_up = p_item->p_up;
\r
1238 /* Set C's left to B */
\r
1239 p_item->p_left = (*pp_root)->p_right;
\r
1241 * Set B's parent to C. We trap for B being NIL since the
\r
1242 * caller may depend on NIL not changing.
\r
1244 if( (*pp_root)->p_right != &p_map->nil )
\r
1245 (*pp_root)->p_right->p_up = p_item;
\r
1247 /* Set A's right to C. */
\r
1248 (*pp_root)->p_right = p_item;
\r
1249 /* Set C's parent to A. */
\r
1250 p_item->p_up = *pp_root;
\r
1256 IN cl_fmap_t* const p_map,
\r
1257 IN cl_pfn_fmap_cmp_t pfn_compare )
\r
1259 CL_ASSERT( p_map );
\r
1260 CL_ASSERT( pfn_compare );
\r
1262 cl_memclr( p_map, sizeof(cl_fmap_t) );
\r
1264 /* special setup for the root node */
\r
1265 p_map->root.p_up = &p_map->root;
\r
1266 p_map->root.p_left = &p_map->nil;
\r
1267 p_map->root.p_right = &p_map->nil;
\r
1268 p_map->root.color = CL_MAP_BLACK;
\r
1270 /* Setup the node used as terminator for all leaves. */
\r
1271 p_map->nil.p_up = &p_map->nil;
\r
1272 p_map->nil.p_left = &p_map->nil;
\r
1273 p_map->nil.p_right = &p_map->nil;
\r
1274 p_map->nil.color = CL_MAP_BLACK;
\r
1276 /* Store the compare function pointer. */
\r
1277 p_map->pfn_compare = pfn_compare;
\r
1279 p_map->state = CL_INITIALIZED;
\r
1281 cl_fmap_remove_all( p_map );
\r
1287 IN const cl_fmap_t* const p_map,
\r
1288 IN const void* const p_key )
\r
1290 cl_fmap_item_t *p_item;
\r
1293 CL_ASSERT( p_map );
\r
1294 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1296 p_item = __cl_fmap_root( p_map );
\r
1298 while( p_item != &p_map->nil )
\r
1300 cmp = p_map->pfn_compare( p_key, p_item->p_key );
\r
1303 break; /* just right */
\r
1306 p_item = p_item->p_left; /* too small */
\r
1308 p_item = p_item->p_right; /* too big */
\r
1316 cl_fmap_apply_func(
\r
1317 IN const cl_fmap_t* const p_map,
\r
1318 IN cl_pfn_fmap_apply_t pfn_func,
\r
1319 IN const void* const context )
\r
1321 cl_fmap_item_t* p_fmap_item;
\r
1323 /* Note that context can have any arbitrary value. */
\r
1324 CL_ASSERT( p_map );
\r
1325 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1326 CL_ASSERT( pfn_func );
\r
1328 p_fmap_item = cl_fmap_head( p_map );
\r
1329 while( p_fmap_item != cl_fmap_end( p_map ) )
\r
1331 pfn_func( p_fmap_item, (void*)context );
\r
1332 p_fmap_item = cl_fmap_next( p_fmap_item );
\r
1338 * Balance a tree starting at a given item back to the root.
\r
1341 __cl_fmap_ins_bal(
\r
1342 IN cl_fmap_t* const p_map,
\r
1343 IN cl_fmap_item_t* p_item )
\r
1345 cl_fmap_item_t* p_grand_uncle;
\r
1347 CL_ASSERT( p_map );
\r
1348 CL_ASSERT( p_item );
\r
1349 CL_ASSERT( p_item != &p_map->root );
\r
1351 while( p_item->p_up->color == CL_MAP_RED )
\r
1353 if( __cl_fmap_is_left_child( p_item->p_up ) )
\r
1355 p_grand_uncle = p_item->p_up->p_up->p_right;
\r
1356 CL_ASSERT( p_grand_uncle );
\r
1357 if( p_grand_uncle->color == CL_MAP_RED )
\r
1359 p_grand_uncle->color = CL_MAP_BLACK;
\r
1360 p_item->p_up->color = CL_MAP_BLACK;
\r
1361 p_item->p_up->p_up->color = CL_MAP_RED;
\r
1362 p_item = p_item->p_up->p_up;
\r
1366 if( !__cl_fmap_is_left_child( p_item ) )
\r
1368 p_item = p_item->p_up;
\r
1369 __cl_fmap_rot_left( p_map, p_item );
\r
1371 p_item->p_up->color = CL_MAP_BLACK;
\r
1372 p_item->p_up->p_up->color = CL_MAP_RED;
\r
1373 __cl_fmap_rot_right( p_map, p_item->p_up->p_up );
\r
1377 p_grand_uncle = p_item->p_up->p_up->p_left;
\r
1378 CL_ASSERT( p_grand_uncle );
\r
1379 if( p_grand_uncle->color == CL_MAP_RED )
\r
1381 p_grand_uncle->color = CL_MAP_BLACK;
\r
1382 p_item->p_up->color = CL_MAP_BLACK;
\r
1383 p_item->p_up->p_up->color = CL_MAP_RED;
\r
1384 p_item = p_item->p_up->p_up;
\r
1388 if( __cl_fmap_is_left_child( p_item ) )
\r
1390 p_item = p_item->p_up;
\r
1391 __cl_fmap_rot_right( p_map, p_item );
\r
1393 p_item->p_up->color = CL_MAP_BLACK;
\r
1394 p_item->p_up->p_up->color = CL_MAP_RED;
\r
1395 __cl_fmap_rot_left( p_map, p_item->p_up->p_up );
\r
1403 IN cl_fmap_t* const p_map,
\r
1404 IN const void* const p_key,
\r
1405 IN cl_fmap_item_t* const p_item )
\r
1407 cl_fmap_item_t *p_insert_at, *p_comp_item;
\r
1410 CL_ASSERT( p_map );
\r
1411 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1412 CL_ASSERT( p_item );
\r
1413 CL_ASSERT( p_map->root.p_up == &p_map->root );
\r
1414 CL_ASSERT( p_map->root.color != CL_MAP_RED );
\r
1415 CL_ASSERT( p_map->nil.color != CL_MAP_RED );
\r
1417 p_item->p_left = &p_map->nil;
\r
1418 p_item->p_right = &p_map->nil;
\r
1419 p_item->p_key = p_key;
\r
1420 p_item->color = CL_MAP_RED;
\r
1422 /* Find the insertion location. */
\r
1423 p_insert_at = &p_map->root;
\r
1424 p_comp_item = __cl_fmap_root( p_map );
\r
1426 while( p_comp_item != &p_map->nil )
\r
1428 p_insert_at = p_comp_item;
\r
1430 cmp = p_map->pfn_compare( p_key, p_insert_at->p_key );
\r
1433 return( p_insert_at );
\r
1435 /* Traverse the tree until the correct insertion point is found. */
\r
1437 p_comp_item = p_insert_at->p_left;
\r
1439 p_comp_item = p_insert_at->p_right;
\r
1442 CL_ASSERT( p_insert_at != &p_map->nil );
\r
1443 CL_ASSERT( p_comp_item == &p_map->nil );
\r
1444 /* Insert the item. */
\r
1445 if( p_insert_at == &p_map->root )
\r
1447 p_insert_at->p_left = p_item;
\r
1449 * Primitive insert places the new item in front of
\r
1450 * the existing item.
\r
1452 __cl_primitive_insert( &p_map->nil.pool_item.list_item,
\r
1453 &p_item->pool_item.list_item );
\r
1455 else if( cmp < 0 )
\r
1457 p_insert_at->p_left = p_item;
\r
1459 * Primitive insert places the new item in front of
\r
1460 * the existing item.
\r
1462 __cl_primitive_insert( &p_insert_at->pool_item.list_item,
\r
1463 &p_item->pool_item.list_item );
\r
1467 p_insert_at->p_right = p_item;
\r
1469 * Primitive insert places the new item in front of
\r
1470 * the existing item.
\r
1472 __cl_primitive_insert( p_insert_at->pool_item.list_item.p_next,
\r
1473 &p_item->pool_item.list_item );
\r
1475 /* Increase the count. */
\r
1478 p_item->p_up = p_insert_at;
\r
1481 * We have added depth to this section of the tree.
\r
1482 * Rebalance as necessary as we retrace our path through the tree
\r
1483 * and update colors.
\r
1485 __cl_fmap_ins_bal( p_map, p_item );
\r
1487 __cl_fmap_root( p_map )->color = CL_MAP_BLACK;
\r
1490 * Note that it is not necessary to re-color the nil node black because all
\r
1491 * red color assignments are made via the p_up pointer, and nil is never
\r
1492 * set as the value of a p_up pointer.
\r
1496 /* Set the pointer to the map in the map item for consistency checking. */
\r
1497 p_item->p_map = p_map;
\r
1505 __cl_fmap_del_bal(
\r
1506 IN cl_fmap_t* const p_map,
\r
1507 IN cl_fmap_item_t* p_item )
\r
1509 cl_fmap_item_t *p_uncle;
\r
1511 while( (p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root) )
\r
1513 if( __cl_fmap_is_left_child( p_item ) )
\r
1515 p_uncle = p_item->p_up->p_right;
\r
1517 if( p_uncle->color == CL_MAP_RED )
\r
1519 p_uncle->color = CL_MAP_BLACK;
\r
1520 p_item->p_up->color = CL_MAP_RED;
\r
1521 __cl_fmap_rot_left( p_map, p_item->p_up );
\r
1522 p_uncle = p_item->p_up->p_right;
\r
1525 if( p_uncle->p_right->color != CL_MAP_RED )
\r
1527 if( p_uncle->p_left->color != CL_MAP_RED )
\r
1529 p_uncle->color = CL_MAP_RED;
\r
1530 p_item = p_item->p_up;
\r
1534 p_uncle->p_left->color = CL_MAP_BLACK;
\r
1535 p_uncle->color = CL_MAP_RED;
\r
1536 __cl_fmap_rot_right( p_map, p_uncle );
\r
1537 p_uncle = p_item->p_up->p_right;
\r
1539 p_uncle->color = p_item->p_up->color;
\r
1540 p_item->p_up->color = CL_MAP_BLACK;
\r
1541 p_uncle->p_right->color = CL_MAP_BLACK;
\r
1542 __cl_fmap_rot_left( p_map, p_item->p_up );
\r
1547 p_uncle = p_item->p_up->p_left;
\r
1549 if( p_uncle->color == CL_MAP_RED )
\r
1551 p_uncle->color = CL_MAP_BLACK;
\r
1552 p_item->p_up->color = CL_MAP_RED;
\r
1553 __cl_fmap_rot_right( p_map, p_item->p_up );
\r
1554 p_uncle = p_item->p_up->p_left;
\r
1557 if( p_uncle->p_left->color != CL_MAP_RED )
\r
1559 if( p_uncle->p_right->color != CL_MAP_RED )
\r
1561 p_uncle->color = CL_MAP_RED;
\r
1562 p_item = p_item->p_up;
\r
1566 p_uncle->p_right->color = CL_MAP_BLACK;
\r
1567 p_uncle->color = CL_MAP_RED;
\r
1568 __cl_fmap_rot_left( p_map, p_uncle );
\r
1569 p_uncle = p_item->p_up->p_left;
\r
1571 p_uncle->color = p_item->p_up->color;
\r
1572 p_item->p_up->color = CL_MAP_BLACK;
\r
1573 p_uncle->p_left->color = CL_MAP_BLACK;
\r
1574 __cl_fmap_rot_right( p_map, p_item->p_up );
\r
1578 p_item->color = CL_MAP_BLACK;
\r
1583 cl_fmap_remove_item(
\r
1584 IN cl_fmap_t* const p_map,
\r
1585 IN cl_fmap_item_t* const p_item )
\r
1587 cl_fmap_item_t *p_child, *p_del_item;
\r
1589 CL_ASSERT( p_map );
\r
1590 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1591 CL_ASSERT( p_item );
\r
1592 CL_ASSERT( p_item->p_map == p_map );
\r
1594 if( p_item == cl_fmap_end( p_map ) )
\r
1597 if( (p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil ) )
\r
1599 /* The item being removed has children on at most on side. */
\r
1600 p_del_item = p_item;
\r
1605 * The item being removed has children on both side.
\r
1606 * We select the item that will replace it. After removing
\r
1607 * the substitute item and rebalancing, the tree will have the
\r
1608 * correct topology. Exchanging the substitute for the item
\r
1609 * will finalize the removal.
\r
1611 p_del_item = cl_fmap_next( p_item );
\r
1612 CL_ASSERT( p_del_item != &p_map->nil );
\r
1615 /* Remove the item from the list. */
\r
1616 __cl_primitive_remove( &p_item->pool_item.list_item );
\r
1617 /* Decrement the item count. */
\r
1620 /* Get the pointer to the new root's child, if any. */
\r
1621 if( p_del_item->p_left != &p_map->nil )
\r
1622 p_child = p_del_item->p_left;
\r
1624 p_child = p_del_item->p_right;
\r
1627 * This assignment may modify the parent pointer of the nil node.
\r
1628 * This is inconsequential.
\r
1630 p_child->p_up = p_del_item->p_up;
\r
1631 (*__cl_fmap_get_parent_ptr_to_item( p_del_item )) = p_child;
\r
1633 if( p_del_item->color != CL_MAP_RED )
\r
1634 __cl_fmap_del_bal( p_map, p_child );
\r
1637 * Note that the splicing done below does not need to occur before
\r
1638 * the tree is balanced, since the actual topology changes are made by the
\r
1639 * preceding code. The topology is preserved by the color assignment made
\r
1640 * below (reader should be reminded that p_del_item == p_item in some cases).
\r
1642 if( p_del_item != p_item )
\r
1645 * Finalize the removal of the specified item by exchanging it with
\r
1646 * the substitute which we removed above.
\r
1648 p_del_item->p_up = p_item->p_up;
\r
1649 p_del_item->p_left = p_item->p_left;
\r
1650 p_del_item->p_right = p_item->p_right;
\r
1651 (*__cl_fmap_get_parent_ptr_to_item( p_item )) = p_del_item;
\r
1652 p_item->p_right->p_up = p_del_item;
\r
1653 p_item->p_left->p_up = p_del_item;
\r
1654 p_del_item->color = p_item->color;
\r
1657 CL_ASSERT( p_map->nil.color != CL_MAP_RED );
\r
1660 /* Clear the pointer to the map since the item has been removed. */
\r
1661 p_item->p_map = NULL;
\r
1668 IN cl_fmap_t* const p_map,
\r
1669 IN const void* const p_key )
\r
1671 cl_fmap_item_t *p_item;
\r
1673 CL_ASSERT( p_map );
\r
1674 CL_ASSERT( p_map->state == CL_INITIALIZED );
\r
1676 /* Seek the node with the specified key */
\r
1677 p_item = cl_fmap_get( p_map, p_key );
\r
1679 cl_fmap_remove_item( p_map, p_item );
\r
1687 OUT cl_fmap_t* const p_dest_map,
\r
1688 IN OUT cl_fmap_t* const p_src_map )
\r
1690 cl_fmap_item_t *p_item, *p_item2, *p_next;
\r
1692 CL_ASSERT( p_dest_map );
\r
1693 CL_ASSERT( p_src_map );
\r
1695 p_item = cl_fmap_head( p_src_map );
\r
1697 while( p_item != cl_fmap_end( p_src_map ) )
\r
1699 p_next = cl_fmap_next( p_item );
\r
1701 /* Remove the item from its current map. */
\r
1702 cl_fmap_remove_item( p_src_map, p_item );
\r
1703 /* Insert the item into the destination map. */
\r
1704 p_item2 = cl_fmap_insert( p_dest_map, cl_fmap_key( p_item ), p_item );
\r
1705 /* Check that the item was successfully inserted. */
\r
1706 if( p_item2 != p_item )
\r
1708 /* Put the item in back in the source map. */
\r
1710 cl_fmap_insert( p_src_map, cl_fmap_key( p_item ), p_item );
\r
1711 CL_ASSERT( p_item2 == p_item );
\r
1719 __cl_fmap_delta_move(
\r
1720 IN OUT cl_fmap_t* const p_dest,
\r
1721 IN OUT cl_fmap_t* const p_src,
\r
1722 IN OUT cl_fmap_item_t** const pp_item )
\r
1724 cl_fmap_item_t *p_temp, *p_next;
\r
1727 * Get the next item so that we can ensure that pp_item points to
\r
1728 * a valid item upon return from the function.
\r
1730 p_next = cl_fmap_next( *pp_item );
\r
1731 /* Move the old item from its current map the the old map. */
\r
1732 cl_fmap_remove_item( p_src, *pp_item );
\r
1733 p_temp = cl_fmap_insert( p_dest, cl_fmap_key( *pp_item ), *pp_item );
\r
1734 /* We should never have duplicates. */
\r
1735 CL_ASSERT( p_temp == *pp_item );
\r
1736 /* Point pp_item to a valid item in the source map. */
\r
1737 (*pp_item) = p_next;
\r
1743 IN OUT cl_fmap_t* const p_map1,
\r
1744 IN OUT cl_fmap_t* const p_map2,
\r
1745 OUT cl_fmap_t* const p_new,
\r
1746 OUT cl_fmap_t* const p_old )
\r
1748 cl_fmap_item_t *p_item1, *p_item2;
\r
1751 CL_ASSERT( p_map1 );
\r
1752 CL_ASSERT( p_map2 );
\r
1753 CL_ASSERT( p_new );
\r
1754 CL_ASSERT( p_old );
\r
1755 CL_ASSERT( cl_is_fmap_empty( p_new ) );
\r
1756 CL_ASSERT( cl_is_fmap_empty( p_old ) );
\r
1758 p_item1 = cl_fmap_head( p_map1 );
\r
1759 p_item2 = cl_fmap_head( p_map2 );
\r
1761 while( p_item1 != cl_fmap_end( p_map1 ) &&
\r
1762 p_item2 != cl_fmap_end( p_map2 ) )
\r
1764 cmp = p_map1->pfn_compare( cl_fmap_key( p_item1 ),
\r
1765 cl_fmap_key( p_item2 ) );
\r
1768 /* We found an old item. */
\r
1769 __cl_fmap_delta_move( p_old, p_map1, &p_item1 );
\r
1771 else if( cmp > 0 )
\r
1773 /* We found a new item. */
\r
1774 __cl_fmap_delta_move( p_new, p_map2, &p_item2 );
\r
1778 /* Move both forward since they have the same key. */
\r
1779 p_item1 = cl_fmap_next( p_item1 );
\r
1780 p_item2 = cl_fmap_next( p_item2 );
\r
1784 /* Process the remainder if the end of either source map was reached. */
\r
1785 while( p_item2 != cl_fmap_end( p_map2 ) )
\r
1786 __cl_fmap_delta_move( p_new, p_map2, &p_item2 );
\r
1788 while( p_item1 != cl_fmap_end( p_map1 ) )
\r
1789 __cl_fmap_delta_move( p_old, p_map1, &p_item1 );
\r