extern signed_32 NumValues( select_list *list, signed_32 hi ) { /********************************************************************/ signed_32 cases; cases = 0; while( list != NULL ) { if( SelCompare( list->high, hi ) > 0 ) break; cases += list->high - list->low + 1; list = list->next; } return( cases ); }
signed_32 NumValues( select_list *list, signed_32 hi ) /**********************************************************/ { signed_32 cases; cases = 0; for( ; list != NULL; list = list->next ) { if( SelCompare( list->high, hi ) > 0 ) { break; } cases += list->high - list->low + 1; } return( cases ); }
static void DoBinarySearch( an node, select_list *list, type_def *tipe, int lo, int hi, label_handle other, signed_32 lobound, signed_32 hibound, bool have_lobound, bool have_hibound ) /*************************************************************************/ { int num; int mid; select_list *mid_list; an cmp; label_handle lt; mid = lo + ( hi - lo ) / 2; mid_list = list; for( num = mid; num > 0; --num ) { mid_list = mid_list->next; } if( lo == hi ) { if( have_lobound && lobound == mid_list->low && have_hibound && hibound == mid_list->high ) { BGControl( O_GOTO, NULL, mid_list->label ); return; } else if( mid_list->low == mid_list->high ) { cmp = BGCompare( O_EQ, BGDuplicate( node ), BGInteger( mid_list->low, tipe ), NULL, tipe ); BGControl( O_IF_TRUE, cmp, mid_list->label ); BGControl( O_GOTO, NULL, other ); return; } } if( hi == mid + 1 && mid_list->next->low == mid_list->next->high ) { /* a linear sequence for three different non-sequential cases where c1<c2<c3, looks like: if( a == c3 ) goto l3; if( a == c2 ) goto l2; if( a != c1 ) goto default; l1: ... a binary sequence for these three cases looks like: if( a < c2 goto lt; \ if( a <= c2 ) goto l2; /only one cmp ins on x86 if( a == c3 ) goto l3; goto default; lt: if ( a != c1 ) goto default; l1: ... Advantage of the linear search: * 3 goto's instead of 5, resulting in smaller code. Advantage of the binary search: * Execution time for all the cases is more balanced. which one is really faster depends a lot on the CPU's branch prediction and other things that are very hard to measure here. Using a linear search here for <= 3 cases to save on code size with negligible performance loss or gain. */ mid_list = mid_list->next; cmp = BGCompare( O_EQ, BGDuplicate( node ), BGInteger( mid_list->low, tipe ), NULL, tipe ); BGControl( O_IF_TRUE, cmp, mid_list->label ); /* Because we only compared for equality, it is only possible to decrease the upper bound if it was already set and equal to the value we are comparing to. Otherwise the incoming value may still be higher, where the inner call may produce an unconditional O_GOTO to a specific case label! */ if( have_hibound && hibound == mid_list->low ) hibound--; DoBinarySearch( node, list, tipe, lo, mid, other, lobound, hibound, have_lobound, have_hibound ); return; } lt = AskForNewLabel(); if( !have_lobound || SelCompare( lobound, mid_list->low ) < 0 ) { if( have_hibound && SelCompare( hibound, mid_list->low ) < 0 ) { BGControl( O_GOTO, NULL, lt ); } else { cmp = BGCompare( O_LT, BGDuplicate( node ), BGInteger( mid_list->low, tipe ), NULL, tipe ); BGControl( O_IF_TRUE, cmp, lt ); } } if( !have_lobound || SelCompare( lobound, mid_list->high ) <= 0 ) { if( have_hibound && SelCompare( hibound, mid_list->high ) <= 0 ) { BGControl( O_GOTO, NULL, mid_list->label ); } else { cmp = BGCompare( O_LE, BGDuplicate( node ), BGInteger( mid_list->high, tipe ), NULL, tipe ); BGControl( O_IF_TRUE, cmp, mid_list->label ); } } if( mid < hi ) { DoBinarySearch( node, list, tipe, mid+1, hi, other, mid_list->high+1, hibound, true, have_hibound ); } else if( other != NULL ) { BGControl( O_GOTO, NULL, other ); } BGControl( O_LABEL, NULL, lt ); if( lo < mid ) { DoBinarySearch( node, list, tipe, lo, mid-1, other, lobound, mid_list->low-1, have_lobound, true ); } else if( other != NULL ) { BGControl( O_GOTO, NULL, other ); } }
static bool NodeLess( void *s1, void *s2 ) /****************************************************/ { return( SelCompare( ((select_list *)s1)->low, ((select_list *)s2)->low ) < 0 ); }