diff options
author | David Tolnay <dtolnay@gmail.com> | 2015-09-21 11:15:25 -0700 |
---|---|---|
committer | David Tolnay <dtolnay@gmail.com> | 2015-09-21 20:33:06 -0700 |
commit | 58f082d74fa29ead024ff2d695eae874b9b67538 (patch) | |
tree | 5234c99f98af885d6ee2944662c423530944ea0e | |
parent | 154d0ee4a824c666c056d7fd4e6028e3f3247c22 (diff) |
Delete negative indices in array (fix #954)
-rw-r--r-- | src/jv_aux.c | 37 | ||||
-rw-r--r-- | tests/jq.test | 4 |
2 files changed, 31 insertions, 10 deletions
diff --git a/src/jv_aux.c b/src/jv_aux.c index 4d48f577..17500139 100644 --- a/src/jv_aux.c +++ b/src/jv_aux.c @@ -214,7 +214,7 @@ jv jv_has(jv t, jv k) { } // assumes keys is a sorted array -jv jv_dels(jv t, jv keys) { +static jv jv_dels(jv t, jv keys) { assert(jv_get_kind(keys) == JV_KIND_ARRAY); assert(jv_is_valid(t)); @@ -222,13 +222,17 @@ jv jv_dels(jv t, jv keys) { // no change } else if (jv_get_kind(t) == JV_KIND_ARRAY) { // extract slices, they must be handled differently - jv orig_keys = keys; - keys = jv_array(); + jv neg_keys = jv_array(); + jv nonneg_keys = jv_array(); jv new_array = jv_array(); jv starts = jv_array(), ends = jv_array(); - jv_array_foreach(orig_keys, i, key) { + jv_array_foreach(keys, i, key) { if (jv_get_kind(key) == JV_KIND_NUMBER) { - keys = jv_array_append(keys, key); + if (jv_number_value(key) < 0) { + neg_keys = jv_array_append(neg_keys, key); + } else { + nonneg_keys = jv_array_append(nonneg_keys, key); + } } else if (jv_get_kind(key) == JV_KIND_OBJECT) { int start, end; if (parse_slice(jv_copy(t), key, &start, &end)) { @@ -248,18 +252,30 @@ jv jv_dels(jv t, jv keys) { } } - int kidx = 0; + int neg_idx = 0; + int nonneg_idx = 0; + int len = jv_array_length(jv_copy(t)); jv_array_foreach(t, i, elem) { int del = 0; - while (kidx < jv_array_length(jv_copy(keys))) { - int delidx = (int)jv_number_value(jv_array_get(jv_copy(keys), kidx)); + while (neg_idx < jv_array_length(jv_copy(neg_keys))) { + int delidx = len + (int)jv_number_value(jv_array_get(jv_copy(neg_keys), neg_idx)); + if (i == delidx) { + del = 1; + } + if (i < delidx) { + break; + } + neg_idx++; + } + while (nonneg_idx < jv_array_length(jv_copy(nonneg_keys))) { + int delidx = (int)jv_number_value(jv_array_get(jv_copy(nonneg_keys), nonneg_idx)); if (i == delidx) { del = 1; } if (i < delidx) { break; } - kidx++; + nonneg_idx++; } for (int sidx=0; !del && sidx<jv_array_length(jv_copy(starts)); sidx++) { if ((int)jv_number_value(jv_array_get(jv_copy(starts), sidx)) <= i && @@ -273,9 +289,10 @@ jv jv_dels(jv t, jv keys) { jv_free(elem); } arr_out: + jv_free(neg_keys); + jv_free(nonneg_keys); jv_free(starts); jv_free(ends); - jv_free(orig_keys); jv_free(t); t = new_array; } else if (jv_get_kind(t) == JV_KIND_OBJECT) { diff --git a/tests/jq.test b/tests/jq.test index 830d157b..6c75192e 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -784,6 +784,10 @@ null {"foo": [1,4], "bar": [1]} {"bar": [1]} +del(.[1], .[-6], .[2], .[-3:9]) +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +[0, 3, 5, 6, 9] + # # Assignment # |