summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@gmail.com>2015-09-21 11:15:25 -0700
committerDavid Tolnay <dtolnay@gmail.com>2015-09-21 20:33:06 -0700
commit58f082d74fa29ead024ff2d695eae874b9b67538 (patch)
tree5234c99f98af885d6ee2944662c423530944ea0e
parent154d0ee4a824c666c056d7fd4e6028e3f3247c22 (diff)
Delete negative indices in array (fix #954)
-rw-r--r--src/jv_aux.c37
-rw-r--r--tests/jq.test4
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
#