#include "jv_aux.h" #include #include #include "jv_alloc.h" jv jv_get(jv t, jv k) { jv v; if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { v = jv_object_get(t, k); if (!jv_is_valid(v)) { jv_free(v); v = jv_null(); } } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { // FIXME: don't do lookup for noninteger index v = jv_array_get(t, (int)jv_number_value(k)); if (!jv_is_valid(v)) { jv_free(v); v = jv_null(); } } else if (jv_get_kind(t) == JV_KIND_NULL && (jv_get_kind(k) == JV_KIND_STRING || jv_get_kind(k) == JV_KIND_NUMBER)) { jv_free(t); jv_free(k); v = jv_null(); } else { v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with %s", jv_kind_name(jv_get_kind(t)), jv_kind_name(jv_get_kind(k)))); jv_free(t); jv_free(k); } return v; } jv jv_set(jv t, jv k, jv v) { if (!jv_is_valid(v)) { jv_free(t); jv_free(k); return v; } int isnull = jv_get_kind(t) == JV_KIND_NULL; if (jv_get_kind(k) == JV_KIND_STRING && (jv_get_kind(t) == JV_KIND_OBJECT || isnull)) { if (isnull) t = jv_object(); t = jv_object_set(t, k, v); } else if (jv_get_kind(k) == JV_KIND_NUMBER && (jv_get_kind(t) == JV_KIND_ARRAY || isnull)) { if (isnull) t = jv_array(); t = jv_array_set(t, (int)jv_number_value(k), v); } else { jv err = jv_invalid_with_msg(jv_string_fmt("Cannot update field at %s index of %s", jv_kind_name(jv_get_kind(t)), jv_kind_name(jv_get_kind(v)))); jv_free(t); jv_free(k); jv_free(v); t = err; } return t; } // 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 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; } 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(a)); int b_done = i >= jv_array_length(jv_copy(b)); if (a_done || b_done) { r = b_done - a_done; //suddenly, logic break; } jv xa = jv_array_get(jv_copy(a), i); jv xb = jv_array_get(jv_copy(b), i); r = jv_cmp(xa, xb); i++; } break; } case JV_KIND_OBJECT: { jv keys_a = jv_keys(jv_copy(a)); jv keys_b = jv_keys(jv_copy(b)); r = jv_cmp(jv_copy(keys_a), keys_b); if (r == 0) { for (int i=0; ikey), jv_copy(b->key)); // comparing by address if r == 0 makes the sort stable return r ? r : (int)(a - b); } static struct sort_entry* sort_items(jv objects, jv keys) { assert(jv_get_kind(objects) == JV_KIND_ARRAY); assert(jv_get_kind(keys) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(objects)) == jv_array_length(jv_copy(keys))); int n = jv_array_length(jv_copy(objects)); struct sort_entry* entries = jv_mem_alloc(sizeof(struct sort_entry) * n); for (int i=0; i