module std::sort; <* Perform a binary search over the sorted array and return the index in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true for j in [i, array.len). @require @is_sortable(list) "The list must be sortable" @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values" @require @is_valid_context(cmp, context) "Expected a valid context" *> macro usz binarysearch(list, x, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { usz i; usz len = len_from_list(list); var $no_cmp = @is_empty_macro_slot(cmp); var $has_context = @is_valid_macro_slot(context); for (usz j = len; i < j;) { usz half = i + (j - i) / 2; $if $no_cmp: switch { case greater(list[half], x): j = half; case less(list[half], x): i = half + 1; default: return half; } $else $switch $case $defined(cmp(list[0], list[0], context)): int res = cmp(list[half], x, context); $case $defined(cmp(list[0], list[0])): assert(!$has_context); int res = cmp(list[half], x); $case $defined(cmp(&list[0], &list[0], context)): int res = cmp(&list[half], &x, context); $case $defined(cmp(&list[0], &list[0])): assert(!$has_context); int res = cmp(&list[half], &x); $default: assert(false, "Invalid comparison function"); $endswitch switch { case res > 0: j = half; case res < 0: i = half + 1; default: return half; } $endif } return i; }