From: Alexander Borisov Date: Tue, 5 Nov 2019 17:24:48 +0000 (+0300) Subject: Added implementation of Array.prototype.copyWithin(). X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=34231a98adb16c1c2d64fed947a71a136085fbfe;p=njs.git Added implementation of Array.prototype.copyWithin(). --- diff --git a/src/njs_array.c b/src/njs_array.c index c7f9cbd6..1b27903d 100644 --- a/src/njs_array.c +++ b/src/njs_array.c @@ -2770,6 +2770,120 @@ start: } +static njs_int_t +njs_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused) +{ + int8_t direction; + int64_t count, to, from, end; + uint32_t length; + njs_int_t ret; + njs_array_t *array; + njs_value_t *this, *value, from_key, to_key, prop; + + this = njs_arg(args, nargs, 0); + + ret = njs_value_to_object(vm, this); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + ret = njs_value_length(vm, this, &length); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &to); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + to = (to < 0) ? njs_max(length + to, 0) : njs_min(to, length); + + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &from); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + from = (from < 0) ? njs_max(length + from, 0) : njs_min(from, length); + + value = njs_arg(args, nargs, 3); + + if (njs_is_undefined(value)) { + end = length; + + } else { + ret = njs_value_to_integer(vm, value, &end); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + } + + end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length); + + count = njs_min(end - from, length - to); + + if (from < to && from + count) { + direction = -1; + from = from + count - 1; + to = to + count - 1; + + } else { + direction = 1; + } + + njs_vm_retval_set(vm, this); + + if (njs_is_array(this)) { + if (njs_slow_path(!njs_object_hash_is_empty(this))) { + goto process_object; + } + + array = njs_array(this); + + while (count-- > 0) { + array->start[to] = array->start[from]; + + from = from + direction; + to = to + direction; + } + + return NJS_OK; + } + +process_object: + + while (count-- > 0) { + /* FIXME: largest index is 2**53-1. */ + + njs_uint32_to_string(&from_key, (uint32_t) from); + njs_uint32_to_string(&to_key, (uint32_t) to); + + ret = njs_value_property(vm, this, &from_key, &prop); + + if (ret == NJS_OK) { + ret = njs_value_property_set(vm, this, &to_key, &prop); + + } else { + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + ret = njs_value_property_delete(vm, this, &to_key, NULL); + } + + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + from = from + direction; + to = to + direction; + } + + return NJS_OK; +} + + static const njs_object_prop_t njs_array_prototype_properties[] = { { @@ -2982,6 +3096,14 @@ static const njs_object_prop_t njs_array_prototype_properties[] = .writable = 1, .configurable = 1, }, + + { + .type = NJS_PROPERTY, + .name = njs_string("copyWithin"), + .value = njs_native_function(njs_array_prototype_copy_within, 2), + .writable = 1, + .configurable = 1, + }, }; diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 8780e343..97daf93b 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -4019,6 +4019,40 @@ static njs_unit_test_t njs_test[] = "Object.defineProperty(a, 'length', {writable:true})"), njs_str("TypeError: Cannot redefine property: \"length\"") }, + { njs_str("[1, 2, 3, 4, 5].copyWithin(0, 3)"), + njs_str("4,5,3,4,5") }, + + { njs_str("[1, 2, 3, 4, 5].copyWithin(0, 3, 4)"), + njs_str("4,2,3,4,5") }, + + { njs_str("[1, 2, 3, 4, 5].copyWithin(0, -2, -1)"), + njs_str("4,2,3,4,5") }, + + { njs_str("[1, 2, 3, 4, 5].copyWithin(100, 200, 500)"), + njs_str("1,2,3,4,5") }, + + { njs_str("[0, 1, , , 1].copyWithin(0, 1, 4)"), + njs_str("1,,,,1") }, + + { njs_str("var o = [0, 1, , , 1].copyWithin(0, 1, 4); typeof o"), + njs_str("object") }, + + { njs_str("[].copyWithin.call({length: 5, 3: 1}, 0, 3)"), + njs_str("[object Object]") }, + + { njs_str("var o = [1, 2, 3, 4]; Object.defineProperties(o, { 5: {value: 'abc'}});" + "[].copyWithin.call(o, 0, 3, 4);"), + njs_str("4,2,3,4,,abc") }, + + { njs_str("var obj = {length: 5, 3: 1}; [].copyWithin.call(obj, 0, 3);" + "Object.keys(obj)"), + njs_str("length,3,0") }, + + { njs_str("var obj = {length: 5, 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'};" + "[].copyWithin.call(obj, 0, -2, -1);" + "Object.keys(obj) + '|' + Object.values(obj)"), + njs_str("length,1,2,3,4,5,0|5,a,b,c,d,e,c") }, + { njs_str("Array.prototype.slice(1)"), njs_str("") },