Skip to content

Commit 50ed1d2

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 50ed1d2

File tree

5 files changed

+225
-0
lines changed

5 files changed

+225
-0
lines changed

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

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,159 @@ 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+
lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p);
1670+
lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p);
1671+
uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
1672+
uint8_t element_size = (uint8_t) (1 << shift);
1673+
uint32_t limit = length * element_size;
1674+
uint32_t target = 0;
1675+
uint32_t start = 0;
1676+
uint32_t end = limit;
1677+
ecma_number_t num_var;
1678+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1679+
1680+
if (args_number > 0)
1681+
{
1682+
ret_value = ecma_get_number (args[0], &num_var);
1683+
1684+
if (ECMA_IS_VALUE_ERROR (ret_value))
1685+
{
1686+
return ret_value;
1687+
}
1688+
1689+
target = ecma_builtin_typedarray_prototype_copy_within_helper (length, num_var, false) * element_size;
1690+
if (args_number > 1)
1691+
{
1692+
ret_value = ecma_get_number (args[1], &num_var);
1693+
1694+
if (ECMA_IS_VALUE_ERROR (ret_value))
1695+
{
1696+
return ret_value;
1697+
}
1698+
1699+
start = ecma_builtin_typedarray_prototype_copy_within_helper (length, num_var, false) * element_size;
1700+
if (args_number > 2)
1701+
{
1702+
ret_value = ecma_get_number (args[2], &num_var);
1703+
1704+
if (ECMA_IS_VALUE_ERROR (ret_value))
1705+
{
1706+
return ret_value;
1707+
}
1708+
1709+
end = ecma_builtin_typedarray_prototype_copy_within_helper (length, num_var, true) * element_size;
1710+
}
1711+
}
1712+
}
1713+
1714+
int32_t distance = (int32_t) (end - start);
1715+
int32_t offset = (int32_t) (limit - target);
1716+
int32_t count = distance > offset ? offset : distance;
1717+
count /= element_size;
1718+
int32_t direction = element_size;
1719+
uint32_t counter = (uint32_t) ((count - 1) * element_size);
1720+
1721+
if (start < target && target < start + (uint32_t) (count * element_size))
1722+
{
1723+
direction *= -1;
1724+
start += counter;
1725+
target += counter;
1726+
}
1727+
1728+
while (count > 0)
1729+
{
1730+
ecma_number_t target_element = ecma_get_typedarray_element (typedarray_buffer_p + start,
1731+
class_id);
1732+
1733+
ecma_set_typedarray_element (typedarray_buffer_p + target, target_element, class_id);
1734+
1735+
if (direction < 0)
1736+
{
1737+
start -= element_size;
1738+
target -= element_size;
1739+
}
1740+
else
1741+
{
1742+
start += element_size;
1743+
target += element_size;
1744+
}
1745+
1746+
count --;
1747+
}
1748+
1749+
if (ecma_is_value_empty (ret_value))
1750+
{
1751+
ret_value = ecma_copy_value (this_arg);
1752+
}
1753+
1754+
return ret_value;
1755+
} /* ecma_builtin_typedarray_prototype_copy_within */
1756+
16041757
/**
16051758
* @}
16061759
* @}

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)