diff --git a/src/builtin.c b/src/builtin.c index a7366a68fa..dd4f5d0e34 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -46,7 +46,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); \ @@ -780,6 +779,61 @@ 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); + 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: diff --git a/tests/jq.test b/tests/jq.test index b94f29d245..b954ad18b6 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -1553,6 +1553,10 @@ bsearch(0,2,4) 1 -4 +bsearch({x:1} +[{ "x": 0 },{ "x": 1 },{ "x": 2 }] +1 + # strptime tests are in optional.test strftime("%Y-%m-%dT%H:%M:%SZ")