Skip to content

Commit 215fa1f

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 215fa1f

File tree

5 files changed

+237
-0
lines changed

5 files changed

+237
-0
lines changed

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

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,163 @@ 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+
* The function clamps the given argument to the [0, length] range, based on ECMA-262 v6, 22.1.3.3 7,10,13
1608+
*
1609+
* @return ecma value
1610+
* Returned value must be freed with ecma_free_value.
1611+
*/
1612+
static uint32_t
1613+
ecma_builtin_typedarray_prototype_copy_within_helper (uint32_t length, /**< length of the typedarray */
1614+
ecma_number_t index, /**< copyWithin target/start/end property */
1615+
bool is_end_index) /**< true - normalize the end index */
1616+
{
1617+
uint32_t ret_value;
1618+
1619+
if (!ecma_number_is_nan (index))
1620+
{
1621+
if (ecma_number_is_zero (index))
1622+
{
1623+
ret_value = 0;
1624+
}
1625+
else if (ecma_number_is_infinity (index))
1626+
{
1627+
ret_value = ecma_number_is_negative (index) ? 0 : length;
1628+
}
1629+
else if (ecma_number_is_negative (index))
1630+
{
1631+
int32_t norm_index = (int32_t) length + ecma_number_to_int32 (index);
1632+
ret_value = (uint32_t) JERRY_MAX (norm_index, 0);
1633+
}
1634+
else
1635+
{
1636+
ret_value = JERRY_MIN (ecma_number_to_uint32 (index), length);
1637+
}
1638+
}
1639+
else
1640+
{
1641+
ret_value = is_end_index ? length : 0;
1642+
}
1643+
1644+
return ret_value;
1645+
} /* ecma_builtin_typedarray_prototype_copy_within_helper */
1646+
1647+
/**
1648+
* Helper function to get the uint32_t value from an argument for the 'copyWithin' method.
1649+
*
1650+
* @return ecma value
1651+
* Returned value must be freed with ecma_free_value.
1652+
*/
1653+
static uint32_t
1654+
ecma_builtin_get_uint32_value_from_argument (ecma_value_t arg_value, /**< this argument */
1655+
ecma_value_t ret_value, /**< base function's ret_value */
1656+
uint32_t length, /**< length of the TypedArray */
1657+
bool is_end_index) /**< true - normalize the end index */
1658+
{
1659+
ecma_number_t num_var;
1660+
uint32_t index;
1661+
1662+
ret_value = ecma_get_number (arg_value, &num_var);
1663+
1664+
if (ECMA_IS_VALUE_ERROR (ret_value))
1665+
{
1666+
return ret_value;
1667+
}
1668+
1669+
index = ecma_builtin_typedarray_prototype_copy_within_helper (length, num_var, is_end_index);
1670+
1671+
return index;
1672+
} /* ecma_builtin_get_uint32_value_from_argument */
1673+
1674+
/**
1675+
* The %TypedArray%.prototype object's 'copyWithin' routine
1676+
*
1677+
* See also:
1678+
* ECMA-262 v6, 22.2.3.5
1679+
*
1680+
* @return ecma value
1681+
* Returned value must be freed with ecma_free_value.
1682+
*/
1683+
static ecma_value_t
1684+
ecma_builtin_typedarray_prototype_copy_within (ecma_value_t this_arg, /**< this argument */
1685+
const ecma_value_t args[], /**< arguments list */
1686+
ecma_length_t args_number) /**< number of arguments */
1687+
{
1688+
if (!ecma_is_typedarray (this_arg))
1689+
{
1690+
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
1691+
}
1692+
1693+
ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
1694+
uint32_t length = ecma_typedarray_get_length (typedarray_p);
1695+
lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
1696+
lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p);
1697+
uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
1698+
uint8_t element_size = (uint8_t) (1 << shift);
1699+
uint32_t limit = length * element_size;
1700+
uint32_t target = 0;
1701+
uint32_t start = 0;
1702+
uint32_t end = limit;
1703+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1704+
1705+
if (args_number > 0)
1706+
{
1707+
target = ecma_builtin_get_uint32_value_from_argument (args[0], ret_value, length, false) * element_size;
1708+
if (args_number > 1)
1709+
{
1710+
start = ecma_builtin_get_uint32_value_from_argument (args[1], ret_value, length, false) * element_size;
1711+
if (args_number > 2)
1712+
{
1713+
end = ecma_builtin_get_uint32_value_from_argument (args[2], ret_value, length, true) * element_size;
1714+
}
1715+
}
1716+
}
1717+
1718+
int32_t distance = (int32_t) (end - start);
1719+
int32_t offset = (int32_t) (limit - target);
1720+
int32_t count = JERRY_MIN (distance, offset);
1721+
count /= element_size;
1722+
int32_t direction = 1;
1723+
uint32_t counter = (uint32_t) ((count - 1) * element_size);
1724+
1725+
if (start < target && target < start + (uint32_t) (count * element_size))
1726+
{
1727+
direction *= -1;
1728+
start += counter;
1729+
target += counter;
1730+
}
1731+
1732+
while (count > 0)
1733+
{
1734+
ecma_number_t target_element = ecma_get_typedarray_element (typedarray_buffer_p + start,
1735+
class_id);
1736+
1737+
ecma_set_typedarray_element (typedarray_buffer_p + target, target_element, class_id);
1738+
1739+
if (direction < 0)
1740+
{
1741+
start -= element_size;
1742+
target -= element_size;
1743+
}
1744+
else
1745+
{
1746+
start += element_size;
1747+
target += element_size;
1748+
}
1749+
1750+
count --;
1751+
}
1752+
1753+
if (ecma_is_value_empty (ret_value))
1754+
{
1755+
ret_value = ecma_copy_value (this_arg);
1756+
}
1757+
1758+
return ret_value;
1759+
} /* ecma_builtin_typedarray_prototype_copy_within */
1760+
16041761
/**
16051762
* @}
16061763
* @}

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: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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(e.copyWithin(2, 1 ,4).toString() === '0,1,1,2,3,5');
37+
assert(e.copyWithin(3, 4, 6).toString() === '0,1,1,3,5,5');
38+
assert(e.copyWithin(4, 1, 3).toString() === '0,1,1,3,1,1');
39+
40+
e.set([5, 2, 1, 3, 4, 4]);
41+
42+
// Test with negative inputs
43+
assert(e.copyWithin(2, -10, 3).toString() === '5,2,5,2,1,4');
44+
assert(e.copyWithin(-3, 1, 6).toString() === '5,2,5,2,5,2');
45+
assert(e.copyWithin(2, 0, -3).toString() === '5,2,5,2,5,2');
46+
47+
e.set([9, 3, 4, 5, 1, 7]);
48+
49+
// Test with default inputs
50+
assert(e.copyWithin().toString() === '9,3,4,5,1,7');
51+
assert(e.copyWithin(3).toString() === '9,3,4,9,3,4');
52+
assert(e.copyWithin(1, 5).toString() === '9,4,4,9,3,4');
53+
54+
e.set([12, 3, 1, 43, 2, 9]);
55+
56+
// Test with too big inputs
57+
assert(e.copyWithin(2, 12, 21).toString() === '12,3,1,43,2,9');
58+
assert(e.copyWithin(4, 5, 13).toString() === '12,3,1,43,9,9');
59+
60+
e.set([1, 2, 3, 1, 2, 1]);
61+
62+
// Test with undefined inputs
63+
assert(e.copyWithin(undefined, 2, 4).toString() === '3,1,3,1,2,1');
64+
assert(e.copyWithin(undefined, undefined, 2).toString() === '3,1,3,1,2,1');
65+
assert(e.copyWithin(3, undefined, 5).toString() === '3,1,3,3,1,3');
66+
67+
e.set([0, 2, 4, 2, 1, 5]);
68+
69+
// Test with NaN/+-Infinity
70+
assert(e.copyWithin(NaN, 3, 5).toString() === '2,1,4,2,1,5');
71+
assert(e.copyWithin(3, Infinity, 5).toString() === '2,1,4,2,1,5');
72+
assert(e.copyWithin(1, 3, -Infinity).toString() === '2,1,4,2,1,5');
73+
});

0 commit comments

Comments
 (0)