[njs] Refactored njs_object_traverse().
Dmitry Volyntsev
xeioex at nginx.com
Thu Aug 19 16:18:54 UTC 2021
details: https://hg.nginx.org/njs/rev/b0177571ce1d
branches:
changeset: 1689:b0177571ce1d
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Thu Aug 19 16:17:19 2021 +0000
description:
Refactored njs_object_traverse().
The previous approach was inconsistent in treating shared properties
with other places (JSON.stringify()) where object is iterated.
diffstat:
src/njs_builtin.c | 1 +
src/njs_object.c | 109 +++++++++++++++++++++++++++-------------------
src/njs_object.h | 6 +-
src/test/njs_unit_test.c | 3 +-
test/njs_expect_test.exp | 6 +-
5 files changed, 72 insertions(+), 53 deletions(-)
diffs (212 lines):
diff -r 0fb3ced41fdc -r b0177571ce1d src/njs_builtin.c
--- a/src/njs_builtin.c Fri Aug 13 12:20:46 2021 +0000
+++ b/src/njs_builtin.c Thu Aug 19 16:17:19 2021 +0000
@@ -470,6 +470,7 @@ njs_builtin_traverse(njs_vm_t *vm, njs_t
}
}
+ njs_assert(njs_is_string(&key));
njs_string_get(&key, &name);
if (njs_slow_path((p + name.length + 3) > end)) {
diff -r 0fb3ced41fdc -r b0177571ce1d src/njs_object.c
--- a/src/njs_object.c Fri Aug 13 12:20:46 2021 +0000
+++ b/src/njs_object.c Thu Aug 19 16:17:19 2021 +0000
@@ -1128,87 +1128,104 @@ njs_int_t
njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx,
njs_object_traverse_cb_t cb)
{
- njs_int_t depth, ret;
- njs_str_t name;
- njs_arr_t visited;
- njs_object_t **start;
- njs_value_t value, obj;
- njs_object_prop_t *prop;
- njs_traverse_t state[NJS_TRAVERSE_MAX_DEPTH];
-
- depth = 0;
-
- state[depth].prop = NULL;
- state[depth].parent = NULL;
- state[depth].object = object;
- state[depth].hash = &object->shared_hash;
- njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto);
+ njs_int_t ret;
+ njs_arr_t visited;
+ njs_object_t **start;
+ njs_value_t value, *key;
+ njs_traverse_t *s;
+ njs_object_prop_t *prop;
+ njs_property_query_t pq;
+ njs_traverse_t state[NJS_TRAVERSE_MAX_DEPTH];
+
+ s = &state[0];
+ s->prop = NULL;
+ s->parent = NULL;
+ s->index = 0;
+ njs_set_object(&s->value, object);
+ s->keys = njs_value_own_enumerate(vm, &s->value, NJS_ENUM_KEYS,
+ NJS_ENUM_STRING | NJS_ENUM_SYMBOL, 1);
+ if (njs_slow_path(s->keys == NULL)) {
+ return NJS_ERROR;
+ }
start = njs_arr_init(vm->mem_pool, &visited, NULL, 8, sizeof(void *));
if (njs_slow_path(start == NULL)) {
return NJS_ERROR;
}
- njs_set_object(&value, object);
- (void) njs_traverse_visit(&visited, &value);
+ (void) njs_traverse_visit(&visited, &s->value);
for ( ;; ) {
- prop = njs_lvlhsh_each(state[depth].hash, &state[depth].lhe);
-
- if (prop == NULL) {
- if (state[depth].hash == &state[depth].object->shared_hash) {
- state[depth].hash = &state[depth].object->hash;
- njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto);
+
+ if (s->index >= s->keys->length) {
+ njs_array_destroy(vm, s->keys);
+ s->keys = NULL;
+
+ if (s == &state[0]) {
+ goto done;
+ }
+
+ s--;
+ continue;
+ }
+
+ njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);
+ key = &s->keys->start[s->index++];
+
+ ret = njs_property_query(vm, &pq, &s->value, key);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret == NJS_DECLINED) {
continue;
}
- if (depth == 0) {
- goto done;
- }
-
- depth--;
- continue;
+ return NJS_ERROR;
}
- state[depth].prop = prop;
-
- ret = cb(vm, &state[depth], ctx);
+ prop = pq.lhq.value;
+ s->prop = prop;
+
+ ret = cb(vm, s, ctx);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- value = prop->value;
+ njs_value_assign(&value, &prop->value);
if (prop->type == NJS_PROPERTY_HANDLER) {
- njs_set_object(&obj, state[depth].object);
- ret = prop->value.data.u.prop_handler(vm, prop, &obj, NULL, &value);
+ ret = prop->value.data.u.prop_handler(vm, prop, &s->value, NULL,
+ &value);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
}
- njs_string_get(&prop->name, &name);
-
- if (njs_is_object(&value) && !njs_traverse_visited(&visited, &value)) {
+ if (njs_is_object(&value)
+ && !njs_is_array(&value)
+ && !njs_traverse_visited(&visited, &value))
+ {
ret = njs_traverse_visit(&visited, &value);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
- if (++depth > (NJS_TRAVERSE_MAX_DEPTH - 1)) {
+ if (s == &state[NJS_TRAVERSE_MAX_DEPTH - 1]) {
njs_type_error(vm, "njs_object_traverse() recursion limit:%d",
- depth);
+ NJS_TRAVERSE_MAX_DEPTH);
return NJS_ERROR;
}
- state[depth].prop = NULL;
- state[depth].parent = &state[depth - 1];
- state[depth].object = njs_object(&value);
- state[depth].hash = &njs_object(&value)->shared_hash;
- njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto);
+ s++;
+ s->prop = NULL;
+ s->parent = &s[-1];
+ s->index = 0;
+ njs_value_assign(&s->value, &value);
+ s->keys = njs_value_own_enumerate(vm, &s->value, NJS_ENUM_KEYS,
+ NJS_ENUM_STRING | NJS_ENUM_SYMBOL, 1);
+ if (njs_slow_path(s->keys == NULL)) {
+ return NJS_ERROR;
+ }
}
-
}
done:
diff -r 0fb3ced41fdc -r b0177571ce1d src/njs_object.h
--- a/src/njs_object.h Fri Aug 13 12:20:46 2021 +0000
+++ b/src/njs_object.h Thu Aug 19 16:17:19 2021 +0000
@@ -27,9 +27,9 @@ struct njs_traverse_s {
struct njs_traverse_s *parent;
njs_object_prop_t *prop;
- njs_object_t *object;
- njs_lvlhsh_t *hash;
- njs_lvlhsh_each_t lhe;
+ njs_value_t value;
+ njs_array_t *keys;
+ int64_t index;
#define NJS_TRAVERSE_MAX_DEPTH 32
};
diff -r 0fb3ced41fdc -r b0177571ce1d src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Fri Aug 13 12:20:46 2021 +0000
+++ b/src/test/njs_unit_test.c Thu Aug 19 16:17:19 2021 +0000
@@ -21265,8 +21265,9 @@ static njs_unit_test_t njs_shell_test[]
" at main (:1)\n") },
{ njs_str("$shared.method({}.a.a)" ENTER),
+ /* FIXME: at $shared.method (native) */
njs_str("TypeError: cannot get property \"a\" of undefined\n"
- " at $shared.method (native)\n"
+ " at $r.method (native)\n"
" at main (:1)\n") },
{ njs_str("new Function(\n\n@)" ENTER),
diff -r 0fb3ced41fdc -r b0177571ce1d test/njs_expect_test.exp
--- a/test/njs_expect_test.exp Fri Aug 13 12:20:46 2021 +0000
+++ b/test/njs_expect_test.exp Thu Aug 19 16:17:19 2021 +0000
@@ -121,10 +121,10 @@ njs_test {
}
njs_test {
- {"Ma\t"
- "Ma\a*th"}
+ {"JS\t"
+ "JS\a*ON"}
{"\t\t"
- "Math.abs*Math.atan2"}
+ "JSON.parse*JSON.stringify"}
}
# Global completions, no matches
More information about the nginx-devel
mailing list