diff --git a/src/builtin.c b/src/builtin.c index cf4792c446..04dae75acc 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -7,6 +7,7 @@ #endif #include #include +#include #include #ifdef HAVE_ALLOCA_H # include @@ -46,7 +47,6 @@ void *alloca (size_t); #include "jv_private.h" #include "util.h" - #define BINOP(name) \ static jv f_ ## name(jq_state *jq, jv input, jv a, jv b) { \ jv_free(input); \ @@ -807,6 +807,62 @@ static jv f_sort_by_impl(jq_state *jq, jv input, jv keys) { } } +/* Assuming the input array is sorted, bsearch/1 returns */ +/* the index of the target if the target is in the input array; and otherwise */ +/* (-1 - ix), where ix is the insertion point that would leave the array sorted. */ +/* If the input is not sorted, bsearch will terminate but with irrelevant results. */ +static jv f_bsearch(jq_state *jq, jv input, jv target) { + assert(jv_get_kind(input) == JV_KIND_ARRAY); + assert(jv_get_kind(target) == JV_KIND_NUMBER); + int len = jv_array_length(jv_copy(input)); + if (len == 0) { + jv_free(input); + jv_free(target); + return jv_number(-1); + } else if (len == 1) { + int result = jv_cmp(target, jv_array_get(input, 0)); + if (result == 0 ) { + return jv_number(0); + } else if (result > 0) { + return jv_number(-2); + } else { + return jv_number(-1); + } + } + + int start = 0; + int end = len - 1; + jv answer = jv_null(); + while (start .[1] ; - if .[2] != null then (.[1] = -1) # i.e. break - else - ( ( (.[1] + .[0]) / 2 ) | floor ) as $mid - | $in[$mid] as $monkey - | if $monkey == $target then (.[2] = $mid) # success - elif .[0] == .[1] then (.[1] = -1) # failure - elif $monkey < $target then (.[0] = ($mid + 1)) - else (.[1] = ($mid - 1)) - end - end ) - | if .[2] == null then # compute the insertion point - if $in[ .[0] ] < $target then (-2 -.[0]) - else (-1 -.[0]) - end - else .[2] - end - end; - # Apply f to composite entities recursively, and to atoms def walk(f): def w: