mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Implement Array.prototype's copyWithin method (#3269)
The algorithm is based on ECMA-262 v6, 22.1.3.3 JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu
This commit is contained in:
parent
dc458111ba
commit
798655a871
@ -77,6 +77,7 @@ enum
|
||||
ECMA_ARRAY_PROTOTYPE_KEYS,
|
||||
ECMA_ARRAY_PROTOTYPE_SYMBOL_ITERATOR,
|
||||
ECMA_ARRAY_PROTOTYPE_FILL,
|
||||
ECMA_ARRAY_PROTOTYPE_COPY_WITHIN,
|
||||
};
|
||||
|
||||
#define BUILTIN_INC_HEADER_NAME "ecma-builtin-array-prototype.inc.h"
|
||||
@ -2268,6 +2269,131 @@ ecma_builtin_array_prototype_object_find (ecma_value_t predicate, /**< callback
|
||||
/* 9. */
|
||||
return is_find ? ECMA_VALUE_UNDEFINED : ecma_make_integer_value (-1);
|
||||
} /* ecma_builtin_array_prototype_object_find */
|
||||
|
||||
/**
|
||||
* The Array.prototype object's 'copyWithin' routine
|
||||
*
|
||||
* See also:
|
||||
* ECMA-262 v6, 22.1.3.3
|
||||
*
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
static ecma_value_t
|
||||
ecma_builtin_array_prototype_object_copy_within (const ecma_value_t args[], /**< arguments list */
|
||||
ecma_length_t args_number, /**< number of arguments */
|
||||
ecma_object_t *obj_p, /**< array object */
|
||||
uint32_t len) /**< array object's length */
|
||||
{
|
||||
if (args_number == 0)
|
||||
{
|
||||
return ecma_copy_value (ecma_make_object_value (obj_p));
|
||||
}
|
||||
|
||||
ecma_number_t target_num;
|
||||
ecma_value_t error = ecma_op_to_integer (args[0], &target_num);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (error))
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
uint32_t target = (uint32_t) (ecma_number_is_negative (target_num) ? JERRY_MAX (len + target_num, 0) :
|
||||
JERRY_MIN (target_num, len));
|
||||
|
||||
uint32_t start = 0;
|
||||
uint32_t end = len;
|
||||
|
||||
if (args_number > 1)
|
||||
{
|
||||
ecma_number_t start_num;
|
||||
error = ecma_op_to_integer (args[1], &start_num);
|
||||
if (ECMA_IS_VALUE_ERROR (error))
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
start = (uint32_t) (ecma_number_is_negative (start_num) ? JERRY_MAX (len + start_num, 0) :
|
||||
JERRY_MIN (start_num, len));
|
||||
|
||||
if (args_number > 2)
|
||||
{
|
||||
if (ecma_is_value_undefined (args[2]))
|
||||
{
|
||||
end = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_number_t end_num;
|
||||
error = ecma_op_to_integer (args[2], &end_num);
|
||||
if (ECMA_IS_VALUE_ERROR (error))
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
end = (uint32_t) (ecma_number_is_negative (end_num) ? JERRY_MAX (len + end_num, 0) :
|
||||
JERRY_MIN (end_num, len));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ecma_free_value (error);
|
||||
|
||||
uint32_t count = JERRY_MIN (end - start, len - target);
|
||||
bool forward = true;
|
||||
|
||||
if (start < target && target < start + count)
|
||||
{
|
||||
start = start + count - 1;
|
||||
target = target + count - 1;
|
||||
forward = false;
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
ecma_value_t get_value = ecma_op_object_find_by_uint32_index (obj_p, start);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (get_value))
|
||||
{
|
||||
return get_value;
|
||||
}
|
||||
|
||||
ecma_value_t op_value;
|
||||
|
||||
if (ecma_is_value_found (get_value))
|
||||
{
|
||||
op_value = ecma_op_object_put_by_uint32_index (obj_p, target, get_value, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
op_value = ecma_op_object_delete_by_uint32_index (obj_p, target, true);
|
||||
}
|
||||
|
||||
ecma_free_value (get_value);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (op_value))
|
||||
{
|
||||
return op_value;
|
||||
}
|
||||
|
||||
ecma_free_value (op_value);
|
||||
|
||||
if (forward)
|
||||
{
|
||||
start++;
|
||||
target++;
|
||||
}
|
||||
else
|
||||
{
|
||||
start--;
|
||||
target--;
|
||||
}
|
||||
|
||||
count--;
|
||||
}
|
||||
|
||||
return ecma_copy_value (ecma_make_object_value (obj_p));
|
||||
} /* ecma_builtin_array_prototype_object_copy_within */
|
||||
#endif /* ENABLED (JERRY_ES2015_BUILTIN) */
|
||||
|
||||
#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR)
|
||||
@ -2498,6 +2624,14 @@ ecma_builtin_array_prototype_dispatch_routine (uint16_t builtin_routine_id, /**<
|
||||
break;
|
||||
}
|
||||
#if ENABLED (JERRY_ES2015_BUILTIN)
|
||||
case ECMA_ARRAY_PROTOTYPE_COPY_WITHIN:
|
||||
{
|
||||
ret_value = ecma_builtin_array_prototype_object_copy_within (arguments_list_p,
|
||||
arguments_number,
|
||||
obj_p,
|
||||
length);
|
||||
break;
|
||||
}
|
||||
case ECMA_ARRAY_PROTOTYPE_FIND:
|
||||
case ECMA_ARRAY_PROTOTYPE_FIND_INDEX:
|
||||
{
|
||||
|
||||
@ -66,6 +66,7 @@ ROUTINE (LIT_MAGIC_STRING_REDUCE_RIGHT_UL, ECMA_ARRAY_PROTOTYPE_REDUCE_RIGHT, NO
|
||||
ROUTINE (LIT_MAGIC_STRING_FIND, ECMA_ARRAY_PROTOTYPE_FIND, 2, 1)
|
||||
ROUTINE (LIT_MAGIC_STRING_FIND_INDEX, ECMA_ARRAY_PROTOTYPE_FIND_INDEX, 2, 1)
|
||||
ROUTINE (LIT_MAGIC_STRING_FILL, ECMA_ARRAY_PROTOTYPE_FILL, 3, 1)
|
||||
ROUTINE (LIT_MAGIC_STRING_COPY_WITHIN, ECMA_ARRAY_PROTOTYPE_COPY_WITHIN, NON_FIXED, 2)
|
||||
#endif /* ENABLED (JERRY_ES2015_BUILTIN) */
|
||||
#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR)
|
||||
ROUTINE (LIT_MAGIC_STRING_ENTRIES, ECMA_ARRAY_PROTOTYPE_ENTRIES, 0, 0)
|
||||
|
||||
@ -564,7 +564,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BYTE_OFFSET_UL, "byteOffset")
|
||||
#if ENABLED (JERRY_BUILTIN_STRING)
|
||||
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CHAR_CODE_AT_UL, "charCodeAt")
|
||||
#endif
|
||||
#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
|
||||
#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015_BUILTIN) \
|
||||
|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
|
||||
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COPY_WITHIN, "copyWithin")
|
||||
#endif
|
||||
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENUMERABLE, "enumerable")
|
||||
@ -832,7 +833,8 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_TYPED_ARRAY_UL)
|
||||
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_BYTE_LENGTH_UL)
|
||||
#elif ENABLED (JERRY_BUILTIN_STRING)
|
||||
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_CHAR_CODE_AT_UL)
|
||||
#elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
|
||||
#elif ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015_BUILTIN) \
|
||||
|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
|
||||
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_COPY_WITHIN)
|
||||
#else
|
||||
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_ENUMERABLE)
|
||||
|
||||
81
tests/jerry/es2015/array-prototype-copywithin.js
Normal file
81
tests/jerry/es2015/array-prototype-copywithin.js
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright JS Foundation and other contributors, http://js.foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
var obj = {};
|
||||
|
||||
// Checking behavior with normal inputs
|
||||
var array = ["foo", 1, "bar", obj, 2, "baz"];
|
||||
assert(array.copyWithin(2,0,6).toString() === "foo,1,foo,1,bar,[object Object]");
|
||||
assert(array.copyWithin(0,1,3).toString() === "1,foo,foo,1,bar,[object Object]");
|
||||
assert(array.copyWithin(3,0,4).toString() === "1,foo,foo,1,foo,foo");
|
||||
|
||||
// Checking behavior with default inputs
|
||||
var array = ["foo", 1, "bar", obj, 2, "baz"];
|
||||
assert(array.copyWithin().toString() === "foo,1,bar,[object Object],2,baz");
|
||||
assert(array.copyWithin(2).toString() === "foo,1,foo,1,bar,[object Object]");
|
||||
assert(array.copyWithin(1,4).toString() === "foo,bar,[object Object],1,bar,[object Object]");
|
||||
|
||||
// Checking behavior when argument is negative or bigger then length
|
||||
var array = ["foo", 1, "bar", obj, 2, "baz"];
|
||||
assert(array.copyWithin(12,3,-3).toString() === "foo,1,bar,[object Object],2,baz");
|
||||
assert(array.copyWithin(-2,-4,3).toString() === "foo,1,bar,[object Object],bar,baz");
|
||||
assert(array.copyWithin(1,-5,30).toString() === "foo,1,bar,[object Object],bar,baz");
|
||||
|
||||
// Checking behavior with undefined, NaN, +/- Infinity
|
||||
var array = ["foo", 1, "bar", obj, 2, "baz"];
|
||||
assert(array.copyWithin(undefined).toString() === "foo,1,bar,[object Object],2,baz");
|
||||
assert(array.copyWithin(2, NaN).toString()=== "foo,1,foo,1,bar,[object Object]");
|
||||
assert(array.copyWithin(2,undefined,5).toString() === "foo,1,foo,1,foo,1");
|
||||
|
||||
var array = ["foo", 1, "bar", obj, 2, "baz"];
|
||||
assert(array.copyWithin(Infinity,2,NaN).toString() === "foo,1,bar,[object Object],2,baz");
|
||||
assert(array.copyWithin(Infinity,-Infinity,4).toString()=== "foo,1,bar,[object Object],2,baz");
|
||||
assert(array.copyWithin(NaN,0,3).toString() === "foo,1,bar,[object Object],2,baz");
|
||||
|
||||
// Checking behavior when no length property defined
|
||||
var obj = { copyWithin : Array.prototype.copyWithin };
|
||||
|
||||
obj.copyWithin();
|
||||
assert(obj.length === undefined);
|
||||
|
||||
// Checking behavior when unable to get length
|
||||
var obj = { copyWithin : Array.prototype.copyWithin };
|
||||
Object.defineProperty(obj, 'length', { 'get' : function () {throw new ReferenceError ("foo"); } });
|
||||
|
||||
try {
|
||||
obj.copyWithin(1);
|
||||
assert(false)
|
||||
} catch (e) {
|
||||
assert(e.message === "foo");
|
||||
assert(e instanceof ReferenceError);
|
||||
}
|
||||
|
||||
// Checking behavior when unable to get element
|
||||
var obj = { copyWithin : Array.prototype.copyWithin, length : 5 };
|
||||
Object.defineProperty(obj, '2', { 'get' : function () {throw new ReferenceError ("foo"); } });
|
||||
|
||||
try {
|
||||
obj.copyWithin(2);
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
assert(e.message === "foo");
|
||||
assert(e instanceof ReferenceError);
|
||||
}
|
||||
|
||||
// Checking behavior when a property is not defined
|
||||
var obj = { '0' : 2, '2' : "foo", length : 3, copyWithin : Array.prototype.copyWithin };
|
||||
|
||||
obj.copyWithin(1);
|
||||
assert(obj[0] === 2);
|
||||
assert(obj[1] === 2);
|
||||
Loading…
x
Reference in New Issue
Block a user