Skip to content

Commit d232756

Browse files
committed
Add copyWithin and slice function to TypedArray
The algorithm's are based on ECMA-262 v6, 22.2.3.5 and 22.2.3.23 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 d232756

File tree

6 files changed

+385
-0
lines changed

6 files changed

+385
-0
lines changed

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

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,248 @@ 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+
* Helper function to normalizing an array index
1606+
*
1607+
* The function clamps the given argument to the [0, length] range.
1608+
*
1609+
* See also:
1610+
* - ECMA-262 v6, 22.1.3.3 steps 7,10,13
1611+
* - ECMA-262 v6, 22.2.3.23 steps 7,10
1612+
* Used by:
1613+
* - The %TypedArray%.prototype.copyWithin routine.
1614+
* - The %TypedArray%.prototype.slice routine.
1615+
*
1616+
* @return ecma value
1617+
* Returned value must be freed with ecma_free_value.
1618+
*/
1619+
static uint32_t
1620+
ecma_builtin_typedarray_prototype_index_helper (uint32_t length, /**< length of the typedarray */
1621+
ecma_number_t index, /**< index */
1622+
bool is_end_index) /**< true - normalize the end index */
1623+
{
1624+
uint32_t ret_value;
1625+
1626+
if (!ecma_number_is_nan (index))
1627+
{
1628+
if (ecma_number_is_zero (index))
1629+
{
1630+
ret_value = 0;
1631+
}
1632+
else if (ecma_number_is_infinity (index))
1633+
{
1634+
ret_value = ecma_number_is_negative (index) ? 0 : length;
1635+
}
1636+
else if (ecma_number_is_negative (index))
1637+
{
1638+
int32_t norm_index = (int32_t) length + ecma_number_to_int32 (index);
1639+
ret_value = (uint32_t) JERRY_MAX (norm_index, 0);
1640+
}
1641+
else
1642+
{
1643+
ret_value = JERRY_MIN (ecma_number_to_uint32 (index), length);
1644+
}
1645+
}
1646+
else
1647+
{
1648+
ret_value = is_end_index ? length : 0;
1649+
}
1650+
1651+
return ret_value;
1652+
} /* ecma_builtin_typedarray_prototype_index_helper */
1653+
1654+
/**
1655+
* Helper function to get the uint32_t value from an argument.
1656+
*
1657+
* @return ecma value
1658+
* Returned value must be freed with ecma_free_value.
1659+
*/
1660+
static uint32_t
1661+
ecma_builtin_get_uint32_value_from_argument (ecma_value_t arg_value, /**< this argument */
1662+
ecma_value_t ret_value, /**< base function's ret_value */
1663+
uint32_t length, /**< length of the TypedArray */
1664+
bool is_end_index) /**< true - normalize the end index */
1665+
{
1666+
ecma_number_t num_var;
1667+
uint32_t index;
1668+
1669+
ret_value = ecma_get_number (arg_value, &num_var);
1670+
1671+
if (ECMA_IS_VALUE_ERROR (ret_value))
1672+
{
1673+
return ret_value;
1674+
}
1675+
1676+
index = ecma_builtin_typedarray_prototype_index_helper (length, num_var, is_end_index);
1677+
1678+
return index;
1679+
} /* ecma_builtin_get_uint32_value_from_argument */
1680+
1681+
/**
1682+
* The %TypedArray%.prototype object's 'copyWithin' routine
1683+
*
1684+
* See also:
1685+
* ECMA-262 v6, 22.2.3.5
1686+
*
1687+
* @return ecma value
1688+
* Returned value must be freed with ecma_free_value.
1689+
*/
1690+
static ecma_value_t
1691+
ecma_builtin_typedarray_prototype_copy_within (ecma_value_t this_arg, /**< this argument */
1692+
const ecma_value_t args[], /**< arguments list */
1693+
ecma_length_t args_number) /**< number of arguments */
1694+
{
1695+
if (!ecma_is_typedarray (this_arg))
1696+
{
1697+
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
1698+
}
1699+
1700+
ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
1701+
uint32_t length = ecma_typedarray_get_length (typedarray_p);
1702+
lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
1703+
lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p);
1704+
uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
1705+
uint8_t element_size = (uint8_t) (1 << shift);
1706+
uint32_t limit = length * element_size;
1707+
uint32_t target = 0;
1708+
uint32_t start = 0;
1709+
uint32_t end = limit;
1710+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1711+
1712+
if (args_number > 0)
1713+
{
1714+
target = ecma_builtin_get_uint32_value_from_argument (args[0], ret_value, length, false) * element_size;
1715+
if (args_number > 1)
1716+
{
1717+
start = ecma_builtin_get_uint32_value_from_argument (args[1], ret_value, length, false) * element_size;
1718+
if (args_number > 2)
1719+
{
1720+
end = ecma_builtin_get_uint32_value_from_argument (args[2], ret_value, length, true) * element_size;
1721+
}
1722+
}
1723+
}
1724+
1725+
int32_t distance = (int32_t) (end - start);
1726+
int32_t offset = (int32_t) (limit - target);
1727+
int32_t count = JERRY_MIN (distance, offset);
1728+
count /= element_size;
1729+
int32_t direction = 1;
1730+
uint32_t counter = (uint32_t) ((count - 1) * element_size);
1731+
1732+
if (start < target && target < start + (uint32_t) (count * element_size))
1733+
{
1734+
direction *= -1;
1735+
start += counter;
1736+
target += counter;
1737+
}
1738+
1739+
while (count > 0)
1740+
{
1741+
ecma_number_t target_element = ecma_get_typedarray_element (typedarray_buffer_p + start,
1742+
class_id);
1743+
1744+
ecma_set_typedarray_element (typedarray_buffer_p + target, target_element, class_id);
1745+
1746+
if (direction < 0)
1747+
{
1748+
start -= element_size;
1749+
target -= element_size;
1750+
}
1751+
else
1752+
{
1753+
start += element_size;
1754+
target += element_size;
1755+
}
1756+
1757+
count--;
1758+
}
1759+
1760+
if (ecma_is_value_empty (ret_value))
1761+
{
1762+
ret_value = ecma_copy_value (this_arg);
1763+
}
1764+
1765+
return ret_value;
1766+
} /* ecma_builtin_typedarray_prototype_copy_within */
1767+
1768+
/**
1769+
* The %TypedArray%.prototype object's 'slice' routine
1770+
*
1771+
* See also:
1772+
* ECMA-262 v6, 22.2.3.23
1773+
*
1774+
* @return ecma value
1775+
* Returned value must be freed with ecma_free_value.
1776+
*/
1777+
static ecma_value_t
1778+
ecma_builtin_typedarray_prototype_slice (ecma_value_t this_arg, /**< this argument */
1779+
const ecma_value_t args[], /**< arguments list */
1780+
ecma_length_t args_number) /**< number of arguments */
1781+
{
1782+
if (!ecma_is_typedarray (this_arg))
1783+
{
1784+
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
1785+
}
1786+
1787+
ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
1788+
uint32_t length = ecma_typedarray_get_length (typedarray_p);
1789+
lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
1790+
lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p);
1791+
uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
1792+
uint8_t element_size = (uint8_t) (1 << shift);
1793+
uint32_t start = 0;
1794+
uint32_t end = length;
1795+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1796+
1797+
if (args_number > 0)
1798+
{
1799+
start = ecma_builtin_get_uint32_value_from_argument (args[0], ret_value, length, false);
1800+
if (args_number > 1)
1801+
{
1802+
end = ecma_builtin_get_uint32_value_from_argument (args[1], ret_value, length, true);
1803+
}
1804+
}
1805+
1806+
int32_t distance = (int32_t) (end - start);
1807+
uint32_t count = distance > 0 ? (uint32_t) distance : 0;
1808+
1809+
ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (typedarray_p, count);
1810+
1811+
if (ECMA_IS_VALUE_ERROR (new_typedarray))
1812+
{
1813+
return new_typedarray;
1814+
}
1815+
1816+
ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray);
1817+
lit_magic_string_id_t new_class_id = ecma_object_get_class_name (new_typedarray_p);
1818+
lit_utf8_byte_t *new_typedarray_buffer_p = ecma_typedarray_get_buffer (new_typedarray_p);
1819+
1820+
if (count > 0)
1821+
{
1822+
ecma_length_t src_byte_offset = ecma_typedarray_get_offset (typedarray_p);
1823+
uint32_t target_byte_index = 0;
1824+
uint32_t src_byte_index = (start * element_size) + src_byte_offset;
1825+
1826+
while (target_byte_index < count * element_size)
1827+
{
1828+
ecma_number_t value = ecma_get_typedarray_element (typedarray_buffer_p + src_byte_index,
1829+
class_id);
1830+
1831+
ecma_set_typedarray_element (new_typedarray_buffer_p + target_byte_index, value, new_class_id);
1832+
1833+
src_byte_index += element_size;
1834+
target_byte_index += element_size;
1835+
}
1836+
}
1837+
1838+
if (ecma_is_value_empty (ret_value))
1839+
{
1840+
ret_value = new_typedarray;
1841+
}
1842+
1843+
return ret_value;
1844+
} /* ecma_builtin_typedarray_prototype_slice */
1845+
16041846
/**
16051847
* @}
16061848
* @}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ 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)
74+
ROUTINE (LIT_MAGIC_STRING_SLICE, ecma_builtin_typedarray_prototype_slice, NON_FIXED, 2)
7375

7476
#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
7577

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)