Skip to content

Commit c76d123

Browse files
committed
Add copyWithin function to TypedArray
The algorithm is based on ECMA-262 v6, 22.2.3.5 Co-authored-by: Tibor Dusnoki tdusnoki@inf.u-szeged.hu JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu
1 parent 3c2088c commit c76d123

File tree

5 files changed

+257
-0
lines changed

5 files changed

+257
-0
lines changed

jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,191 @@ ecma_builtin_typedarray_prototype_find_index (ecma_value_t this_arg, /**< this a
16011601
return ecma_builtin_typedarray_prototype_find_helper (this_arg, predicate, predicate_this_arg, false);
16021602
} /* ecma_builtin_typedarray_prototype_find_index */
16031603

1604+
/**
1605+
* The %TypedArray%.prototype object's 'copyWithin' routine helper
1606+
*
1607+
* @return ecma value
1608+
* Returned value must be freed with ecma_free_value.
1609+
*/
1610+
static uint32_t
1611+
ecma_builtin_typedarray_prototype_copy_within_helper (uint32_t length, /**< length of the typedarray */
1612+
ecma_number_t index, /**< copyWithin target/start/end property */
1613+
bool is_end_index) /**< true - normalize the end index */
1614+
{
1615+
uint32_t ret_value;
1616+
1617+
if (!ecma_number_is_nan (index))
1618+
{
1619+
if (ecma_number_is_zero (index))
1620+
{
1621+
ret_value = 0;
1622+
}
1623+
else if (ecma_number_is_infinity (index))
1624+
{
1625+
ret_value = ecma_number_is_negative (index) ? 0 : length;
1626+
}
1627+
else
1628+
{
1629+
if (ecma_number_is_negative (index))
1630+
{
1631+
ecma_number_t index_neg = -index;
1632+
int32_t norm_index = (int32_t) ((int32_t) length - (int32_t) ecma_number_to_int32 (index_neg));
1633+
ret_value = norm_index > 0 ? (uint32_t) norm_index : 0;
1634+
}
1635+
else
1636+
{
1637+
ret_value = ecma_number_to_uint32 (index) > length ? length : ecma_number_to_uint32 (index);
1638+
}
1639+
}
1640+
}
1641+
else
1642+
{
1643+
ret_value = is_end_index ? length : 0;
1644+
}
1645+
1646+
return ret_value;
1647+
} /* ecma_builtin_typedarray_prototype_copy_within_helper */
1648+
1649+
/**
1650+
* The %TypedArray%.prototype object's 'copyWithin' routine
1651+
*
1652+
* See also:
1653+
* ECMA-262 v6, 22.2.3.5
1654+
*
1655+
* @return ecma value
1656+
* Returned value must be freed with ecma_free_value.
1657+
*/
1658+
static ecma_value_t
1659+
ecma_builtin_typedarray_prototype_copy_within (ecma_value_t this_arg, /**< this argument */
1660+
const ecma_value_t args[], /**< arguments list */
1661+
ecma_length_t args_number) /**< number of arguments */
1662+
{
1663+
if (!ecma_is_typedarray (this_arg))
1664+
{
1665+
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
1666+
}
1667+
ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
1668+
uint32_t length = ecma_typedarray_get_length (typedarray_p);
1669+
uint32_t target = 0;
1670+
uint32_t start = 0;
1671+
uint32_t end = length;
1672+
ecma_number_t num_var;
1673+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1674+
1675+
if (args_number > 0)
1676+
{
1677+
ret_value = ecma_get_number (args[0], &num_var);
1678+
1679+
if (ECMA_IS_VALUE_ERROR (ret_value))
1680+
{
1681+
return ret_value;
1682+
}
1683+
1684+
target = ecma_builtin_typedarray_prototype_copy_within_helper (length, num_var, false);
1685+
if (args_number > 1)
1686+
{
1687+
ret_value = ecma_get_number (args[1], &num_var);
1688+
1689+
if (ECMA_IS_VALUE_ERROR (ret_value))
1690+
{
1691+
return ret_value;
1692+
}
1693+
1694+
start = ecma_builtin_typedarray_prototype_copy_within_helper (length, num_var, false);
1695+
if (args_number > 2)
1696+
{
1697+
ret_value = ecma_get_number (args[2], &num_var);
1698+
1699+
if (ECMA_IS_VALUE_ERROR (ret_value))
1700+
{
1701+
return ret_value;
1702+
}
1703+
1704+
end = ecma_builtin_typedarray_prototype_copy_within_helper (length, num_var, true);
1705+
}
1706+
}
1707+
}
1708+
1709+
int32_t distance = (int32_t) (end - start);
1710+
int32_t offset = (int32_t) (length - target);
1711+
int32_t count = distance > offset ? offset : distance;
1712+
int32_t direction;
1713+
1714+
if (start < target && target < start + (uint32_t) count)
1715+
{
1716+
direction = -1;
1717+
start += (uint32_t) count -1;
1718+
target += (uint32_t) count -1;
1719+
}
1720+
else
1721+
{
1722+
direction = 1;
1723+
}
1724+
1725+
while (count > 0)
1726+
{
1727+
ecma_value_t start_value = ecma_make_uint32_value (start);
1728+
ecma_value_t from_key = ecma_op_to_string (start_value);
1729+
if (ECMA_IS_VALUE_ERROR (from_key))
1730+
{
1731+
return from_key;
1732+
}
1733+
ecma_string_t *from_key_p = ecma_get_string_from_value (from_key);
1734+
1735+
ecma_value_t target_value = ecma_make_uint32_value (target);
1736+
ecma_value_t to_key = ecma_op_to_string (target_value);
1737+
if (ECMA_IS_VALUE_ERROR (to_key))
1738+
{
1739+
return to_key;
1740+
}
1741+
ecma_string_t *to_key_p = ecma_get_string_from_value (to_key);
1742+
1743+
ecma_value_t from_present = ecma_op_object_find (typedarray_p, from_key_p);
1744+
1745+
if (from_present != ECMA_VALUE_NOT_FOUND)
1746+
{
1747+
ecma_value_t from_val = ecma_op_object_get (typedarray_p, from_key_p);
1748+
ecma_value_t set_status = ecma_op_object_put (typedarray_p, to_key_p, from_val, true);
1749+
1750+
if (ECMA_IS_VALUE_ERROR (set_status))
1751+
{
1752+
return set_status;
1753+
}
1754+
1755+
ecma_free_value (from_val);
1756+
ecma_free_value (set_status);
1757+
}
1758+
else
1759+
{
1760+
ecma_value_t delete_status = ecma_op_object_delete (typedarray_p, to_key_p, true);
1761+
1762+
if (ECMA_IS_VALUE_ERROR (delete_status))
1763+
{
1764+
return delete_status;
1765+
}
1766+
1767+
ecma_free_value (delete_status);
1768+
}
1769+
1770+
ecma_deref_ecma_string (from_key_p);
1771+
ecma_deref_ecma_string (to_key_p);
1772+
ecma_free_value (from_present);
1773+
ecma_free_value (start_value);
1774+
ecma_free_value (target_value);
1775+
1776+
start += (uint32_t) direction;
1777+
target += (uint32_t) direction;
1778+
count--;
1779+
}
1780+
1781+
if (ecma_is_value_empty (ret_value))
1782+
{
1783+
ret_value = ecma_copy_value (this_arg);
1784+
}
1785+
1786+
return ret_value;
1787+
} /* ecma_builtin_typedarray_prototype_copy_within */
1788+
16041789
/**
16051790
* @}
16061791
* @}

jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ ROUTINE (LIT_MAGIC_STRING_FILL, ecma_builtin_typedarray_prototype_fill, 3, 1)
7070
ROUTINE (LIT_MAGIC_STRING_SORT, ecma_builtin_typedarray_prototype_sort, 1, 1)
7171
ROUTINE (LIT_MAGIC_STRING_FIND, ecma_builtin_typedarray_prototype_find, 2, 1)
7272
ROUTINE (LIT_MAGIC_STRING_FIND_INDEX, ecma_builtin_typedarray_prototype_find_index, 2, 1)
73+
ROUTINE (LIT_MAGIC_STRING_COPY_WITHIN, ecma_builtin_typedarray_prototype_copy_within, NON_FIXED, 2)
7374

7475
#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
7576

jerry-core/lit/lit-magic-strings.inc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BYTE_OFFSET_UL, "byteOffset")
545545
#if ENABLED (JERRY_BUILTIN_STRING)
546546
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CHAR_CODE_AT_UL, "charCodeAt")
547547
#endif
548+
#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
549+
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COPY_WITHIN, "copyWithin")
550+
#endif
548551
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENUMERABLE, "enumerable")
549552
#if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW)
550553
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_FLOAT_32_UL, "getFloat32")
@@ -794,6 +797,8 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_TYPED_ARRAY_UL)
794797
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_BYTE_LENGTH_UL)
795798
#elif ENABLED (JERRY_BUILTIN_STRING)
796799
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_CHAR_CODE_AT_UL)
800+
#elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
801+
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_COPY_WITHIN)
797802
#else
798803
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_ENUMERABLE)
799804
#endif

jerry-core/lit/lit-magic-strings.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ LIT_MAGIC_STRING_UINT8_ARRAY_UL = "Uint8Array"
236236
LIT_MAGIC_STRING_BYTE_LENGTH_UL = "byteLength"
237237
LIT_MAGIC_STRING_BYTE_OFFSET_UL = "byteOffset"
238238
LIT_MAGIC_STRING_CHAR_CODE_AT_UL = "charCodeAt"
239+
LIT_MAGIC_STRING_COPY_WITHIN = "copyWithin"
239240
LIT_MAGIC_STRING_ENUMERABLE = "enumerable"
240241
LIT_MAGIC_STRING_GET_FLOAT_32_UL = "getFloat32"
241242
LIT_MAGIC_STRING_GET_FLOAT_64_UL = "getFloat64"
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* Copyright JS Foundation and other contributors, http://js.foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
var normal_typedarras = [
17+
new Uint8Array([0, 1, 2, 3, 4, 5]),
18+
new Uint16Array([0, 1, 2, 3, 4, 5]),
19+
new Uint32Array([0, 1, 2, 3, 4, 5]),
20+
new Float32Array([0, 1, 2, 3, 4, 5]),
21+
new Float64Array([0, 1, 2, 3, 4, 5]),
22+
new Int8Array([0, 1, 2, 3, 4, 5]),
23+
new Int16Array([0, 1, 2, 3, 4, 5]),
24+
new Int32Array([0, 1, 2, 3, 4, 5])
25+
];
26+
27+
normal_typedarras.forEach(function(e){
28+
try {
29+
e.prototype.copyWithin.call (undefined);
30+
assert (false);
31+
} catch (e) {
32+
assert (e instanceof TypeError);
33+
}
34+
35+
// Test with normal inputs
36+
assert(JSON.stringify(e.copyWithin(2, 1 ,4)) === '{"0":0,"1":1,"2":1,"3":2,"4":3,"5":5}');
37+
assert(JSON.stringify(e.copyWithin(3, 4, 6)) === '{"0":0,"1":1,"2":1,"3":3,"4":5,"5":5}');
38+
assert(JSON.stringify(e.copyWithin(5, 1, 3)) === '{"0":0,"1":1,"2":1,"3":3,"4":5,"5":1}');
39+
40+
// Test with negative inputs
41+
assert(JSON.stringify(e.copyWithin(2, -10, 3)) === '{"0":0,"1":1,"2":0,"3":1,"4":1,"5":1}');
42+
assert(JSON.stringify(e.copyWithin(-3, 1, 6)) === '{"0":0,"1":1,"2":0,"3":1,"4":0,"5":1}');
43+
assert(JSON.stringify(e.copyWithin(2, 0, -3)) === '{"0":0,"1":1,"2":0,"3":1,"4":0,"5":1}');
44+
45+
// Test with default inputs
46+
assert(JSON.stringify(e.copyWithin()) === '{"0":0,"1":1,"2":0,"3":1,"4":0,"5":1}');
47+
assert(JSON.stringify(e.copyWithin(3)) === '{"0":0,"1":1,"2":0,"3":0,"4":1,"5":0}');
48+
assert(JSON.stringify(e.copyWithin(1, 5)) === '{"0":0,"1":0,"2":0,"3":0,"4":1,"5":0}');
49+
50+
// Test with too big inputs
51+
assert(JSON.stringify(e.copyWithin(2, 12, 21)) === '{"0":0,"1":0,"2":0,"3":0,"4":1,"5":0}');
52+
assert(JSON.stringify(e.copyWithin(13, 2, 43)) === '{"0":0,"1":0,"2":0,"3":0,"4":1,"5":0}');
53+
54+
// Test with undefined inputs
55+
assert(JSON.stringify(e.copyWithin(undefined, 2, 4)) === '{"0":0,"1":0,"2":0,"3":0,"4":1,"5":0}');
56+
assert(JSON.stringify(e.copyWithin(undefined, undefined, 4)) === '{"0":0,"1":0,"2":0,"3":0,"4":1,"5":0}');
57+
assert(JSON.stringify(e.copyWithin(3, undefined, 5)) === '{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0}');
58+
59+
e.set([0, 2, 4, 2, 1, 5]);
60+
61+
// Test with NaN/+-Infinity
62+
assert(JSON.stringify(e.copyWithin(NaN, 1, 5)) === '{"0":2,"1":4,"2":2,"3":1,"4":1,"5":5}');
63+
assert(JSON.stringify(e.copyWithin(3, Infinity, 5)) === '{"0":2,"1":4,"2":2,"3":1,"4":1,"5":5}');
64+
assert(JSON.stringify(e.copyWithin(5, 2, -Infinity)) === '{"0":2,"1":4,"2":2,"3":1,"4":1,"5":5}');
65+
});

0 commit comments

Comments
 (0)