Skip to content

Commit 01c5d10

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 3c69dfa commit 01c5d10

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
@@ -1687,6 +1687,248 @@ ecma_builtin_typedarray_prototype_find_index (ecma_value_t this_arg, /**< this a
16871687
return ecma_builtin_typedarray_prototype_find_helper (this_arg, predicate, predicate_this_arg, false);
16881688
} /* ecma_builtin_typedarray_prototype_find_index */
16891689

1690+
/**
1691+
* Helper function to normalizing an array index
1692+
*
1693+
* The function clamps the given argument to the [0, length] range.
1694+
*
1695+
* See also:
1696+
* - ECMA-262 v6, 22.1.3.3 steps 7,10,13
1697+
* - ECMA-262 v6, 22.2.3.23 steps 7,10
1698+
* Used by:
1699+
* - The %TypedArray%.prototype.copyWithin routine.
1700+
* - The %TypedArray%.prototype.slice routine.
1701+
*
1702+
* @return ecma value
1703+
* Returned value must be freed with ecma_free_value.
1704+
*/
1705+
static uint32_t
1706+
ecma_builtin_typedarray_prototype_index_helper (uint32_t length, /**< length of the typedarray */
1707+
ecma_number_t index, /**< index */
1708+
bool is_end_index) /**< true - normalize the end index */
1709+
{
1710+
uint32_t ret_value;
1711+
1712+
if (!ecma_number_is_nan (index))
1713+
{
1714+
if (ecma_number_is_zero (index))
1715+
{
1716+
ret_value = 0;
1717+
}
1718+
else if (ecma_number_is_infinity (index))
1719+
{
1720+
ret_value = ecma_number_is_negative (index) ? 0 : length;
1721+
}
1722+
else if (ecma_number_is_negative (index))
1723+
{
1724+
int32_t norm_index = (int32_t) length + ecma_number_to_int32 (index);
1725+
ret_value = (uint32_t) JERRY_MAX (norm_index, 0);
1726+
}
1727+
else
1728+
{
1729+
ret_value = JERRY_MIN (ecma_number_to_uint32 (index), length);
1730+
}
1731+
}
1732+
else
1733+
{
1734+
ret_value = is_end_index ? length : 0;
1735+
}
1736+
1737+
return ret_value;
1738+
} /* ecma_builtin_typedarray_prototype_index_helper */
1739+
1740+
/**
1741+
* Helper function to get the uint32_t value from an argument.
1742+
*
1743+
* @return ecma value
1744+
* Returned value must be freed with ecma_free_value.
1745+
*/
1746+
static uint32_t
1747+
ecma_builtin_get_uint32_value_from_argument (ecma_value_t arg_value, /**< this argument */
1748+
ecma_value_t ret_value, /**< base function's ret_value */
1749+
uint32_t length, /**< length of the TypedArray */
1750+
bool is_end_index) /**< true - normalize the end index */
1751+
{
1752+
ecma_number_t num_var;
1753+
uint32_t index;
1754+
1755+
ret_value = ecma_get_number (arg_value, &num_var);
1756+
1757+
if (ECMA_IS_VALUE_ERROR (ret_value))
1758+
{
1759+
return ret_value;
1760+
}
1761+
1762+
index = ecma_builtin_typedarray_prototype_index_helper (length, num_var, is_end_index);
1763+
1764+
return index;
1765+
} /* ecma_builtin_get_uint32_value_from_argument */
1766+
1767+
/**
1768+
* The %TypedArray%.prototype object's 'copyWithin' routine
1769+
*
1770+
* See also:
1771+
* ECMA-262 v6, 22.2.3.5
1772+
*
1773+
* @return ecma value
1774+
* Returned value must be freed with ecma_free_value.
1775+
*/
1776+
static ecma_value_t
1777+
ecma_builtin_typedarray_prototype_copy_within (ecma_value_t this_arg, /**< this argument */
1778+
const ecma_value_t args[], /**< arguments list */
1779+
ecma_length_t args_number) /**< number of arguments */
1780+
{
1781+
if (!ecma_is_typedarray (this_arg))
1782+
{
1783+
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
1784+
}
1785+
1786+
ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
1787+
uint32_t length = ecma_typedarray_get_length (typedarray_p);
1788+
lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
1789+
lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p);
1790+
uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
1791+
uint8_t element_size = (uint8_t) (1 << shift);
1792+
uint32_t limit = length * element_size;
1793+
uint32_t target = 0;
1794+
uint32_t start = 0;
1795+
uint32_t end = limit;
1796+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1797+
1798+
if (args_number > 0)
1799+
{
1800+
target = ecma_builtin_get_uint32_value_from_argument (args[0], ret_value, length, false) * element_size;
1801+
if (args_number > 1)
1802+
{
1803+
start = ecma_builtin_get_uint32_value_from_argument (args[1], ret_value, length, false) * element_size;
1804+
if (args_number > 2)
1805+
{
1806+
end = ecma_builtin_get_uint32_value_from_argument (args[2], ret_value, length, true) * element_size;
1807+
}
1808+
}
1809+
}
1810+
1811+
int32_t distance = (int32_t) (end - start);
1812+
int32_t offset = (int32_t) (limit - target);
1813+
int32_t count = JERRY_MIN (distance, offset);
1814+
count /= element_size;
1815+
int32_t direction = 1;
1816+
uint32_t counter = (uint32_t) ((count - 1) * element_size);
1817+
1818+
if (start < target && target < start + (uint32_t) (count * element_size))
1819+
{
1820+
direction *= -1;
1821+
start += counter;
1822+
target += counter;
1823+
}
1824+
1825+
while (count > 0)
1826+
{
1827+
ecma_number_t target_element = ecma_get_typedarray_element (typedarray_buffer_p + start,
1828+
class_id);
1829+
1830+
ecma_set_typedarray_element (typedarray_buffer_p + target, target_element, class_id);
1831+
1832+
if (direction < 0)
1833+
{
1834+
start -= element_size;
1835+
target -= element_size;
1836+
}
1837+
else
1838+
{
1839+
start += element_size;
1840+
target += element_size;
1841+
}
1842+
1843+
count--;
1844+
}
1845+
1846+
if (ecma_is_value_empty (ret_value))
1847+
{
1848+
ret_value = ecma_copy_value (this_arg);
1849+
}
1850+
1851+
return ret_value;
1852+
} /* ecma_builtin_typedarray_prototype_copy_within */
1853+
1854+
/**
1855+
* The %TypedArray%.prototype object's 'slice' routine
1856+
*
1857+
* See also:
1858+
* ECMA-262 v6, 22.2.3.23
1859+
*
1860+
* @return ecma value
1861+
* Returned value must be freed with ecma_free_value.
1862+
*/
1863+
static ecma_value_t
1864+
ecma_builtin_typedarray_prototype_slice (ecma_value_t this_arg, /**< this argument */
1865+
const ecma_value_t args[], /**< arguments list */
1866+
ecma_length_t args_number) /**< number of arguments */
1867+
{
1868+
if (!ecma_is_typedarray (this_arg))
1869+
{
1870+
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
1871+
}
1872+
1873+
ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg);
1874+
uint32_t length = ecma_typedarray_get_length (typedarray_p);
1875+
lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
1876+
lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p);
1877+
uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
1878+
uint8_t element_size = (uint8_t) (1 << shift);
1879+
uint32_t start = 0;
1880+
uint32_t end = length;
1881+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1882+
1883+
if (args_number > 0)
1884+
{
1885+
start = ecma_builtin_get_uint32_value_from_argument (args[0], ret_value, length, false);
1886+
if (args_number > 1)
1887+
{
1888+
end = ecma_builtin_get_uint32_value_from_argument (args[1], ret_value, length, true);
1889+
}
1890+
}
1891+
1892+
int32_t distance = (int32_t) (end - start);
1893+
uint32_t count = distance > 0 ? (uint32_t) distance : 0;
1894+
1895+
ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (typedarray_p, count);
1896+
1897+
if (ECMA_IS_VALUE_ERROR (new_typedarray))
1898+
{
1899+
return new_typedarray;
1900+
}
1901+
1902+
ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray);
1903+
lit_magic_string_id_t new_class_id = ecma_object_get_class_name (new_typedarray_p);
1904+
lit_utf8_byte_t *new_typedarray_buffer_p = ecma_typedarray_get_buffer (new_typedarray_p);
1905+
1906+
if (count > 0)
1907+
{
1908+
ecma_length_t src_byte_offset = ecma_typedarray_get_offset (typedarray_p);
1909+
uint32_t target_byte_index = 0;
1910+
uint32_t src_byte_index = (start * element_size) + src_byte_offset;
1911+
1912+
while (target_byte_index < count * element_size)
1913+
{
1914+
ecma_number_t value = ecma_get_typedarray_element (typedarray_buffer_p + src_byte_index,
1915+
class_id);
1916+
1917+
ecma_set_typedarray_element (new_typedarray_buffer_p + target_byte_index, value, new_class_id);
1918+
1919+
src_byte_index += element_size;
1920+
target_byte_index += element_size;
1921+
}
1922+
}
1923+
1924+
if (ecma_is_value_empty (ret_value))
1925+
{
1926+
ret_value = new_typedarray;
1927+
}
1928+
1929+
return ret_value;
1930+
} /* ecma_builtin_typedarray_prototype_slice */
1931+
16901932
/**
16911933
* @}
16921934
* @}

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
#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR)
7577

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BYTE_OFFSET_UL, "byteOffset")
547547
#if ENABLED (JERRY_BUILTIN_STRING)
548548
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CHAR_CODE_AT_UL, "charCodeAt")
549549
#endif
550+
#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
551+
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COPY_WITHIN, "copyWithin")
552+
#endif
550553
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENUMERABLE, "enumerable")
551554
#if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW)
552555
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_FLOAT_32_UL, "getFloat32")
@@ -796,6 +799,8 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_TYPED_ARRAY_UL)
796799
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_BYTE_LENGTH_UL)
797800
#elif ENABLED (JERRY_BUILTIN_STRING)
798801
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_CHAR_CODE_AT_UL)
802+
#elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
803+
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_COPY_WITHIN)
799804
#else
800805
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_ENUMERABLE)
801806
#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)