summaryrefslogtreecommitdiffstats
path: root/jv_aux.c
diff options
context:
space:
mode:
authorStephen Dolan <mu@netsoc.tcd.ie>2012-12-29 16:13:06 +0000
committerStephen Dolan <mu@netsoc.tcd.ie>2012-12-29 16:13:06 +0000
commit465a4ec565a106e0e4cc1d64214fb2d6d791c8dc (patch)
treeee18274667b431f725954e8be9b3cdf97e1a6a87 /jv_aux.c
parent3a5377e183976cc6dafa16a17f608e091dfa96b9 (diff)
Improvements to del(foo).
del(foo,bar) is now very different from del(foo),del(bar). See #37.
Diffstat (limited to 'jv_aux.c')
-rw-r--r--jv_aux.c158
1 files changed, 121 insertions, 37 deletions
diff --git a/jv_aux.c b/jv_aux.c
index 83695f96..f0e15b50 100644
--- a/jv_aux.c
+++ b/jv_aux.c
@@ -60,31 +60,63 @@ jv jv_set(jv t, jv k, jv v) {
return t;
}
-jv jv_del(jv t, jv k) {
- if (jv_get_kind(t) == JV_KIND_NULL) {
- jv_free(k);
- } else if (jv_get_kind(t) == JV_KIND_ARRAY &&
- jv_get_kind(k) == JV_KIND_NUMBER) {
- int idx = (int)jv_number_value(k);
- jv_free(k);
- int len = jv_array_length(jv_copy(t));
- if (idx >= 0 && idx < len) {
- for (int i = idx+1; i < len; i++) {
- t = jv_array_set(t, i-1, jv_array_get(jv_copy(t), i));
+// assumes keys is a sorted array
+jv jv_dels(jv t, jv keys) {
+ assert(jv_get_kind(keys) == JV_KIND_ARRAY);
+ assert(jv_is_valid(t));
+
+ if (jv_get_kind(t) == JV_KIND_NULL || jv_array_length(jv_copy(keys)) == 0) {
+ // no change
+ } else if (jv_get_kind(t) == JV_KIND_ARRAY) {
+ jv new_array = jv_array();
+ int kidx = 0;
+ for (int i=0; i<jv_array_length(jv_copy(t)); i++) {
+ int del = 0;
+ while (kidx < jv_array_length(jv_copy(keys))) {
+ jv nextdel = jv_array_get(jv_copy(keys), kidx);
+ if (jv_get_kind(nextdel) != JV_KIND_NUMBER) {
+ jv err = jv_invalid_with_msg(jv_string_fmt("Cannot delete %s element of array",
+ jv_kind_name(jv_get_kind(nextdel))));
+ jv_free(nextdel);
+ jv_free(new_array);
+ new_array = err;
+ goto arr_out; // break twice
+ }
+ int delidx = (int)jv_number_value(nextdel);
+ jv_free(nextdel);
+ if (i == delidx) {
+ del = 1;
+ }
+ if (i < delidx) {
+ break;
+ }
+ kidx++;
+ }
+ if (!del)
+ new_array = jv_array_append(new_array, jv_array_get(jv_copy(t), i));
+ }
+ arr_out:
+ jv_free(t);
+ t = new_array;
+ } else if (jv_get_kind(t) == JV_KIND_OBJECT) {
+ for (int i=0; i<jv_array_length(jv_copy(keys)); i++) {
+ jv k = jv_array_get(jv_copy(keys), i);
+ if (jv_get_kind(k) != JV_KIND_STRING) {
+ jv_free(t);
+ t = jv_invalid_with_msg(jv_string_fmt("Cannot delete %s field of object",
+ jv_kind_name(jv_get_kind(k))));
+ jv_free(k);
+ break;
}
- t = jv_array_slice(t, 0, len-1);
+ t = jv_object_delete(t, k);
}
- } else if (jv_get_kind(t) == JV_KIND_OBJECT &&
- jv_get_kind(k) == JV_KIND_STRING) {
- t = jv_object_delete(t, k);
} else {
- jv err = jv_invalid_with_msg(jv_string_fmt("Cannot delete field at %s index of %s",
- jv_kind_name(jv_get_kind(k)),
+ jv err = jv_invalid_with_msg(jv_string_fmt("Cannot delete fields from %s",
jv_kind_name(jv_get_kind(t))));
jv_free(t);
- jv_free(k);
t = err;
}
+ jv_free(keys);
return t;
}
@@ -130,31 +162,83 @@ jv jv_getpath(jv root, jv path) {
return jv_getpath(jv_get(root, pathcurr), pathrest);
}
-jv jv_delpath(jv root, jv path) {
- if (jv_get_kind(path) != JV_KIND_ARRAY) {
- jv_free(root);
- jv_free(path);
- return jv_invalid_with_msg(jv_string("Path must be specified as an array"));
+// assumes paths is a sorted array of arrays
+static jv delpaths_sorted(jv object, jv paths, int start) {
+ jv delkeys = jv_array();
+ for (int i=0; i<jv_array_length(jv_copy(paths));) {
+ int j = i;
+ assert(jv_array_length(jv_array_get(jv_copy(paths), i)) > start);
+ int delkey = jv_array_length(jv_array_get(jv_copy(paths), i)) == start + 1;
+ jv key = jv_array_get(jv_array_get(jv_copy(paths), i), start);
+ while (j < jv_array_length(jv_copy(paths)) &&
+ jv_equal(jv_copy(key), jv_array_get(jv_array_get(jv_copy(paths), j), start)))
+ j++;
+ // if i <= entry < j, then entry starts with key
+ if (delkey) {
+ // deleting this entire key, we don't care about any more specific deletions
+ delkeys = jv_array_append(delkeys, key);
+ } else {
+ // deleting certain sub-parts of this key
+ jv subobject = jv_get(jv_copy(object), jv_copy(key));
+ if (!jv_is_valid(subobject)) {
+ jv_free(key);
+ jv_free(object);
+ object = subobject;
+ break;
+ } else if (jv_get_kind(subobject) == JV_KIND_NULL) {
+ jv_free(key);
+ jv_free(subobject);
+ } else {
+ jv newsubobject = delpaths_sorted(subobject, jv_array_slice(jv_copy(paths), i, j), start+1);
+ if (!jv_is_valid(newsubobject)) {
+ jv_free(key);
+ jv_free(object);
+ object = newsubobject;
+ break;
+ }
+ object = jv_set(object, key, newsubobject);
+ }
+ if (!jv_is_valid(object)) break;
+ }
+ i = j;
}
- if (!jv_is_valid(root)) {
- jv_free(path);
- return root;
+ jv_free(paths);
+ if (jv_is_valid(object))
+ object = jv_dels(object, delkeys);
+ else
+ jv_free(delkeys);
+ return object;
+}
+
+jv jv_delpaths(jv object, jv paths) {
+ paths = jv_sort(paths, jv_copy(paths));
+ for (int i=0; i<jv_array_length(jv_copy(paths)); i++) {
+ jv elem = jv_array_get(jv_copy(paths), i);
+ if (jv_get_kind(elem) != JV_KIND_ARRAY) {
+ jv_free(object);
+ jv_free(paths);
+ jv err = jv_invalid_with_msg(jv_string_fmt("Path must be specified as array, not %s",
+ jv_kind_name(jv_get_kind(elem))));
+ jv_free(elem);
+ return err;
+ }
+ jv_free(elem);
}
- if (jv_array_length(jv_copy(path)) == 1) {
- return jv_del(root, jv_array_get(path, 0));
+ if (jv_array_length(jv_copy(paths)) == 0) {
+ // nothing is being deleted
+ jv_free(paths);
+ return object;
}
- jv pathcurr = jv_array_get(jv_copy(path), 0);
- jv pathrest = jv_array_slice(path, 1, jv_array_length(jv_copy(path)));
- jv new_obj = jv_delpath(jv_get(jv_copy(root), jv_copy(pathcurr)), pathrest);
- if (jv_get_kind(new_obj) == JV_KIND_NULL) {
- jv_free(pathcurr);
- jv_free(new_obj);
- return root;
- } else {
- return jv_set(root, pathcurr, new_obj);
+ if (jv_array_length(jv_array_get(jv_copy(paths), 0)) == 0) {
+ // everything is being deleted
+ jv_free(paths);
+ jv_free(object);
+ return jv_null();
}
+ return delpaths_sorted(object, paths, 0);
}
+
static int string_cmp(const void* pa, const void* pb){
const jv* a = pa;
const jv* b = pb;