2 #include "libbenchmark_datastructure_btree_au_internal.h"
4 /***** private prototypes *****/
5 static void libbenchmark_datastructure_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus, struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue );
6 static void libbenchmark_datastructure_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus, struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue );
12 /****************************************************************************/
13 void libbenchmark_datastructure_btree_au_pthread_rwlock_init( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus,
14 int (*key_compare_function)(void const *new_key, void const *existing_key),
15 enum libbenchmark_datastructure_btree_au_pthread_rwlock_existing_key existing_key,
18 LFDS710_PAL_ASSERT( baus != NULL );
19 LFDS710_PAL_ASSERT( key_compare_function != NULL );
20 // TRD : existing_key can be any value in its range
21 // TRD : user_state can be NULL
24 baus->key_compare_function = key_compare_function;
25 baus->existing_key = existing_key;
26 baus->user_state = user_state;
28 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_CREATE( baus->lock );
30 LFDS710_MISC_BARRIER_STORE;
32 lfds710_misc_force_store();
41 /****************************************************************************/
42 void libbenchmark_datastructure_btree_au_pthread_rwlock_cleanup( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus,
43 void (*element_cleanup_callback)(struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus, struct libbenchmark_datastructure_btree_au_pthread_rwlock_element *baue) )
45 enum libbenchmark_datastructure_btree_au_delete_action
46 delete_action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_SELF; // TRD : to remove compiler warning
48 struct libbenchmark_datastructure_btree_au_pthread_rwlock_element
52 LFDS710_PAL_ASSERT( baus != NULL );
53 // TRD : element_delete_function can be NULL
55 if( element_cleanup_callback != NULL )
57 libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_absolute_position_for_read( baus, &baue, LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_ABSOLUTE_POSITION_ROOT );
61 if( baue->left == NULL and baue->right == NULL )
62 delete_action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_SELF;
64 if( baue->left != NULL and baue->right == NULL )
65 delete_action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD;
67 if( baue->left == NULL and baue->right != NULL )
68 delete_action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD;
70 if( baue->left != NULL and baue->right != NULL )
71 delete_action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_MOVE_LEFT;
73 switch( delete_action )
75 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_SELF:
76 // TRD : if we have a parent (we could be root) set his point to us to NULL
77 if( baue->up != NULL )
79 if( baue->up->left == baue )
80 baue->up->left = NULL;
81 if( baue->up->right == baue )
82 baue->up->right = NULL;
86 libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_relative_position_for_read( baus, &baue, LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_UP );
87 element_cleanup_callback( baus, temp );
90 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD:
91 baue->left->up = baue->up;
92 if( baue->up != NULL )
94 if( baue->up->left == baue )
95 baue->up->left = baue->left;
96 if( baue->up->right == baue )
97 baue->up->right = baue->left;
101 libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_relative_position_for_read( baus, &baue, LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_LEFT );
102 element_cleanup_callback( baus, temp );
105 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD:
106 baue->right->up = baue->up;
107 if( baue->up != NULL )
109 if( baue->up->left == baue )
110 baue->up->left = baue->right;
111 if( baue->up->right == baue )
112 baue->up->right = baue->right;
116 libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_relative_position_for_read( baus, &baue, LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_RIGHT );
117 element_cleanup_callback( baus, temp );
120 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_DELETE_MOVE_LEFT:
121 libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_relative_position_for_read( baus, &baue, LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_LEFT );
127 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_DESTROY( baus->lock );
136 /****************************************************************************/
137 enum libbenchmark_datastructure_btree_au_pthread_rwlock_insert_result libbenchmark_datastructure_btree_au_pthread_rwlock_insert( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus,
138 struct libbenchmark_datastructure_btree_au_pthread_rwlock_element *baue,
139 struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **existing_baue )
144 struct libbenchmark_datastructure_btree_au_pthread_rwlock_element
149 LFDS710_PAL_ASSERT( baus != NULL );
150 LFDS710_PAL_ASSERT( baue != NULL );
151 // TRD : existing_baue can be NULL
153 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_GET_WRITE( baus->lock );
155 baue->up = baue->left = baue->right = NULL;
157 baue_temp = baus->root;
159 while( baue_temp != NULL )
161 compare_result = baus->key_compare_function( baue->key, baue_temp->key );
163 if( compare_result == 0 )
165 if( existing_baue != NULL )
166 *existing_baue = baue_temp;
168 switch( baus->existing_key )
170 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_EXISTING_KEY_OVERWRITE:
171 LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_SET_VALUE_IN_ELEMENT( *baus, *baue_temp, baue->value );
172 return LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_INSERT_RESULT_SUCCESS_OVERWRITE;
175 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_EXISTING_KEY_FAIL:
176 return LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_INSERT_RESULT_FAILURE_EXISTING_KEY;
181 if( compare_result < 0 )
182 baue_next = baue_temp->left;
184 if( compare_result > 0 )
185 baue_next = baue_temp->right;
187 baue_parent = baue_temp;
188 baue_temp = baue_next;
191 if( baue_parent == NULL )
193 baue->up = baus->root;
196 if( baue_parent != NULL )
198 if( compare_result <= 0 )
200 baue->up = baue_parent;
201 baue_parent->left = baue;
204 if( compare_result > 0 )
206 baue->up = baue_parent;
207 baue_parent->right = baue;
211 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_RELEASE( baus->lock );
213 // TRD : if we get to here, we added (not failed or overwrite on exist) a new element
214 if( existing_baue != NULL )
215 *existing_baue = NULL;
217 return LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_INSERT_RESULT_SUCCESS;
224 /****************************************************************************/
225 int libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_key_for_read( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus,
226 int (*key_compare_function)(void const *new_key, void const *existing_key),
228 struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue )
234 LFDS710_PAL_ASSERT( baus != NULL );
235 // TRD : key_compare_function can be NULL
236 // TRD : key can be NULL
237 LFDS710_PAL_ASSERT( baue != NULL );
239 if( key_compare_function == NULL )
240 key_compare_function = baus->key_compare_function;
242 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_GET_READ( baus->lock );
246 while( *baue != NULL and compare_result != 0 )
248 compare_result = key_compare_function( key, (*baue)->key );
250 if( compare_result < 0 )
251 *baue = (*baue)->left;
253 if( compare_result > 0 )
254 *baue = (*baue)->right;
257 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_RELEASE( baus->lock );
269 /****************************************************************************/
270 int libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_key_for_write( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus,
271 int (*key_compare_function)(void const *new_key, void const *existing_key),
273 struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue )
279 LFDS710_PAL_ASSERT( baus != NULL );
280 // TRD : key_compare_function can be NULL
281 // TRD : key can be NULL
282 LFDS710_PAL_ASSERT( baue != NULL );
284 if( key_compare_function == NULL )
285 key_compare_function = baus->key_compare_function;
287 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_GET_WRITE( baus->lock );
291 while( *baue != NULL and compare_result != 0 )
293 compare_result = key_compare_function( key, (*baue)->key );
295 if( compare_result < 0 )
296 *baue = (*baue)->left;
298 if( compare_result > 0 )
299 *baue = (*baue)->right;
302 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_RELEASE( baus->lock );
314 /****************************************************************************/
315 int libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_absolute_position_for_read( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus, struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue, enum libbenchmark_datastructure_btree_au_pthread_rwlock_absolute_position absolute_position )
320 LFDS710_PAL_ASSERT( baus != NULL );
321 LFDS710_PAL_ASSERT( baue != NULL );
322 // TRD : absolute_position can be any value in its range
324 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_GET_READ( baus->lock );
328 switch( absolute_position )
330 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_ABSOLUTE_POSITION_ROOT:
333 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_ABSOLUTE_POSITION_LARGEST_IN_TREE:
335 while( (*baue)->right != NULL )
336 *baue = (*baue)->right;
339 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_ABSOLUTE_POSITION_SMALLEST_IN_TREE:
341 while( (*baue)->left != NULL )
342 *baue = (*baue)->left;
346 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_RELEASE( baus->lock );
358 /****************************************************************************/
359 int libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_relative_position_for_read( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus, struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue, enum libbenchmark_datastructure_btree_au_pthread_rwlock_relative_position relative_position )
364 LFDS710_PAL_ASSERT( baus != NULL );
365 LFDS710_PAL_ASSERT( baue != NULL );
366 // TRD : relative_position can baue any value in its range
371 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_GET_READ( baus->lock );
373 switch( relative_position )
375 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_UP:
379 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_LEFT:
380 *baue = (*baue)->left;
383 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_RIGHT:
384 *baue = (*baue)->right;
387 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_SMALLEST_ELEMENT_BELOW_CURRENT_ELEMENT:
388 *baue = (*baue)->left;
390 while( (*baue)->right != NULL )
391 *baue = (*baue)->right;
394 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_LARGEST_ELEMENT_BELOW_CURRENT_ELEMENT:
395 *baue = (*baue)->right;
397 while( (*baue)->left != NULL )
398 *baue = (*baue)->left;
401 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE:
402 libbenchmark_datastructure_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( baus, baue );
405 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_PTHREAD_RWLOCK_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE:
406 libbenchmark_datastructure_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( baus, baue );
410 LIBBENCHMARK_PAL_LOCK_PTHREAD_RWLOCK_RELEASE( baus->lock );
422 /****************************************************************************/
423 #pragma warning( disable : 4100 )
425 static void libbenchmark_datastructure_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus, struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue )
427 enum libbenchmark_datastructure_btree_au_move
428 action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_INVALID;
431 finished_flag = LOWERED;
433 struct libbenchmark_datastructure_btree_au_pthread_rwlock_element
439 LFDS710_PAL_ASSERT( baus != NULL );
440 LFDS710_PAL_ASSERT( baue != NULL );
442 /* TRD : from any given element, the next smallest element is;
443 1. if we have a left, it's the largest element on the right branch of our left child
444 2. if we don't have a left, and we're on the right of our parent, then it's our parent
445 3. if we don't have a left, and we're on the left of our parent or we have no parent,
446 iterative up the tree until we find the first child who is on the right of its parent; then it's the parent
449 left = (*baue)->left;
453 up_left = (*baue)->up->left;
454 up_right = (*baue)->up->right;
458 action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD;
460 if( left == NULL and up != NULL and up_right == *baue )
461 action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_GET_PARENT;
463 if( (left == NULL and up == NULL) or (up != NULL and up_left == *baue and left == NULL) )
464 action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_MOVE_UP_TREE;
468 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_INVALID:
469 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD:
470 // TRD : eliminates a compiler warning
473 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD:
476 while( (*baue)->right != NULL )
477 *baue = (*baue)->right;
480 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_GET_PARENT:
484 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_MOVE_UP_TREE:
485 while( finished_flag == LOWERED )
489 up_left = (*baue)->up->left;
491 if( *baue != NULL and up != NULL and *baue == up_left )
494 finished_flag = RAISED;
504 #pragma warning( default : 4100 )
510 /****************************************************************************/
511 #pragma warning( disable : 4100 )
513 static void libbenchmark_datastructure_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus, struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue )
515 enum libbenchmark_datastructure_btree_au_move
516 action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_INVALID;
519 finished_flag = LOWERED;
521 struct libbenchmark_datastructure_btree_au_pthread_rwlock_element
527 LFDS710_PAL_ASSERT( baus != NULL );
528 LFDS710_PAL_ASSERT( baue != NULL );
530 right = (*baue)->right;
534 up_left = (*baue)->up->left;
535 up_right = (*baue)->up->right;
539 action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD;
541 if( right == NULL and up != NULL and up_left == *baue )
542 action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_GET_PARENT;
544 if( (right == NULL and up == NULL) or (up != NULL and up_right == *baue and right == NULL) )
545 action = LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_MOVE_UP_TREE;
549 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_INVALID:
550 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD:
551 // TRD : remove compiler warning
554 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD:
557 while( (*baue)->left != NULL )
558 *baue = (*baue)->left;
561 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_GET_PARENT:
565 case LIBBENCHMARK_DATASTRUCTURE_BTREE_AU_MOVE_MOVE_UP_TREE:
566 while( finished_flag == LOWERED )
570 up_right = (*baue)->up->right;
572 if( *baue != NULL and up != NULL and *baue == up_right )
575 finished_flag = RAISED;
585 #pragma warning( default : 4100 )
591 /****************************************************************************/
592 int libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_absolute_position_and_then_by_relative_position( struct libbenchmark_datastructure_btree_au_pthread_rwlock_state *baus, struct libbenchmark_datastructure_btree_au_pthread_rwlock_element **baue, enum libbenchmark_datastructure_btree_au_pthread_rwlock_absolute_position absolute_position, enum libbenchmark_datastructure_btree_au_pthread_rwlock_relative_position relative_position )
597 LFDS710_PAL_ASSERT( baus != NULL );
598 LFDS710_PAL_ASSERT( baue != NULL );
599 // TRD: absolute_position can be any value in its range
600 // TRD: relative_position can be any value in its range
603 rv = libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_absolute_position_for_read( baus, baue, absolute_position );
605 rv = libbenchmark_datastructure_btree_au_pthread_rwlock_get_by_relative_position_for_read( baus, baue, relative_position );