diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index d84ca2dcc4..0a1cf8c670 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -890,9 +890,9 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t this_arg, /**< 'this' ar * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< left value */ - ecma_value_t k, /**< right value */ - ecma_value_t comparefn) /**< compare function */ +ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t lhs, /**< left value */ + ecma_value_t rhs, /**< right value */ + ecma_value_t compare_func) /**< compare function */ { /* * ECMA-262 v5, 15.4.4.11 NOTE1: Because non-existent property values always @@ -903,12 +903,12 @@ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< le ecma_value_t ret_value = ECMA_VALUE_EMPTY; ecma_number_t result = ECMA_NUMBER_ZERO; - bool j_is_undef = ecma_is_value_undefined (j); - bool k_is_undef = ecma_is_value_undefined (k); + bool lhs_is_undef = ecma_is_value_undefined (lhs); + bool rhs_is_undef = ecma_is_value_undefined (rhs); - if (j_is_undef) + if (lhs_is_undef) { - if (k_is_undef) + if (rhs_is_undef) { result = ECMA_NUMBER_ZERO; } @@ -919,25 +919,25 @@ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< le } else { - if (k_is_undef) + if (rhs_is_undef) { result = ECMA_NUMBER_MINUS_ONE; } else { - if (ecma_is_value_undefined (comparefn)) + if (ecma_is_value_undefined (compare_func)) { - /* Default comparison when no comparefn is passed. */ - ECMA_TRY_CATCH (j_value, ecma_op_to_string (j), ret_value); - ECMA_TRY_CATCH (k_value, ecma_op_to_string (k), ret_value); - ecma_string_t *j_str_p = ecma_get_string_from_value (j_value); - ecma_string_t *k_str_p = ecma_get_string_from_value (k_value); + /* Default comparison when no compare_func is passed. */ + ECMA_TRY_CATCH (lhs_value, ecma_op_to_string (lhs), ret_value); + ECMA_TRY_CATCH (rhs_value, ecma_op_to_string (rhs), ret_value); + ecma_string_t *lhs_str_p = ecma_get_string_from_value (lhs_value); + ecma_string_t *rhs_str_p = ecma_get_string_from_value (rhs_value); - if (ecma_compare_ecma_strings_relational (j_str_p, k_str_p)) + if (ecma_compare_ecma_strings_relational (lhs_str_p, rhs_str_p)) { result = ECMA_NUMBER_MINUS_ONE; } - else if (!ecma_compare_ecma_strings (j_str_p, k_str_p)) + else if (!ecma_compare_ecma_strings (lhs_str_p, rhs_str_p)) { result = ECMA_NUMBER_ONE; } @@ -946,19 +946,19 @@ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< le result = ECMA_NUMBER_ZERO; } - ECMA_FINALIZE (k_value); - ECMA_FINALIZE (j_value); + ECMA_FINALIZE (rhs_value); + ECMA_FINALIZE (lhs_value); } else { /* - * comparefn, if not undefined, will always contain a callable function object. + * compare_func, if not undefined, will always contain a callable function object. * We checked this previously, before this function was called. */ - JERRY_ASSERT (ecma_op_is_callable (comparefn)); - ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (comparefn); + JERRY_ASSERT (ecma_op_is_callable (compare_func)); + ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (compare_func); - ecma_value_t compare_args[] = {j, k}; + ecma_value_t compare_args[] = { lhs, rhs }; ECMA_TRY_CATCH (call_value, ecma_op_function_call (comparefn_obj_p, @@ -991,145 +991,6 @@ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< le return ret_value; } /* ecma_builtin_array_prototype_object_sort_compare_helper */ -/** - * Function used to reconstruct the ordered binary tree. - * Shifts 'index' down in the tree until it is in the correct position. - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_array_prototype_object_array_to_heap_helper (ecma_value_t array[], /**< heap data array */ - int index, /**< current item index */ - int right, /**< right index is a maximum index */ - ecma_value_t comparefn) /**< compare function */ -{ - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - /* Left child of the current index. */ - int child = index * 2 + 1; - ecma_value_t swap = array[index]; - bool should_break = false; - - while (child <= right && ecma_is_value_empty (ret_value) && !should_break) - { - if (child < right) - { - /* Compare the two child nodes. */ - ECMA_TRY_CATCH (child_compare_value, - ecma_builtin_array_prototype_object_sort_compare_helper (array[child], - array[child + 1], - comparefn), - ret_value); - - JERRY_ASSERT (ecma_is_value_number (child_compare_value)); - - /* Use the child that is greater. */ - if (ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO) - { - child++; - } - - ECMA_FINALIZE (child_compare_value); - } - - if (ecma_is_value_empty (ret_value)) - { - JERRY_ASSERT (child <= right); - - /* Compare current child node with the swap (tree top). */ - ECMA_TRY_CATCH (swap_compare_value, - ecma_builtin_array_prototype_object_sort_compare_helper (array[child], - swap, - comparefn), - ret_value); - JERRY_ASSERT (ecma_is_value_number (swap_compare_value)); - - if (ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO) - { - /* Break from loop if current child is less than swap (tree top) */ - should_break = true; - } - else - { - /* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */ - int parent = (child - 1) / 2; - JERRY_ASSERT (parent >= 0 && parent <= right); - array[parent] = array[child]; - - /* Update child to be the left child of the current node. */ - child = child * 2 + 1; - } - - ECMA_FINALIZE (swap_compare_value); - } - } - - /* - * Loop ended, either current child does not exist, or is less than swap. - * This means that 'swap' should be placed in the parent node. - */ - int parent = (child - 1) / 2; - JERRY_ASSERT (parent >= 0 && parent <= right); - array[parent] = swap; - - if (ecma_is_value_empty (ret_value)) - { - ret_value = ECMA_VALUE_UNDEFINED; - } - - return ret_value; -} /* ecma_builtin_array_prototype_object_array_to_heap_helper */ - -/** - * Heapsort function - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_array_prototype_object_array_heap_sort_helper (ecma_value_t array[], /**< array to sort */ - int right, /**< right index */ - ecma_value_t comparefn) /**< compare function */ -{ - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - /* First, construct the ordered binary tree from the array. */ - for (int i = right / 2; i >= 0 && ecma_is_value_empty (ret_value); i--) - { - ECMA_TRY_CATCH (value, - ecma_builtin_array_prototype_object_array_to_heap_helper (array, - i, - right, - comparefn), - ret_value); - ECMA_FINALIZE (value); - } - - /* Sorting elements. */ - for (int i = right; i > 0 && ecma_is_value_empty (ret_value); i--) - { - /* - * The top element will always contain the largest value. - * Move top to the end, and remove it from the tree. - */ - ecma_value_t swap = array[0]; - array[0] = array[i]; - array[i] = swap; - - /* Rebuild binary tree from the remaining elements. */ - ECMA_TRY_CATCH (value, - ecma_builtin_array_prototype_object_array_to_heap_helper (array, - 0, - i - 1, - comparefn), - ret_value); - ECMA_FINALIZE (value); - } - - return ret_value; -} /* ecma_builtin_array_prototype_object_array_heap_sort_helper */ - /** * The Array.prototype object's 'sort' routine * @@ -1218,10 +1079,12 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum /* Sorting. */ if (copied_num > 1 && ecma_is_value_empty (ret_value)) { + const ecma_builtin_helper_sort_compare_fn_t sort_cb = &ecma_builtin_array_prototype_object_sort_compare_helper; ECMA_TRY_CATCH (sort_value, - ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer, - (int)(copied_num - 1), - arg1), + ecma_builtin_helper_array_heap_sort_helper (values_buffer, + (uint32_t) (copied_num - 1), + arg1, + sort_cb), ret_value); ECMA_FINALIZE (sort_value); } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c new file mode 100644 index 0000000000..241cec3dc1 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c @@ -0,0 +1,146 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtin-helpers.h" +#include "ecma-globals.h" +#include "ecma-try-catch-macro.h" + +/** + * Function used to reconstruct the ordered binary tree. + * Shifts 'index' down in the tree until it is in the correct position. + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_helper_array_to_heap (ecma_value_t *array_p, /**< heap data array */ + uint32_t index, /**< current item index */ + uint32_t right, /**< right index is a maximum index */ + ecma_value_t compare_func, /**< compare function */ + const ecma_builtin_helper_sort_compare_fn_t sort_cb) /**< sorting cb */ +{ + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + /* Left child of the current index. */ + uint32_t child = index * 2 + 1; + ecma_value_t swap = array_p[index]; + bool should_break = false; + + while (child <= right && ecma_is_value_empty (ret_value) && !should_break) + { + if (child < right) + { + /* Compare the two child nodes. */ + ECMA_TRY_CATCH (child_compare_value, sort_cb (array_p[child], array_p[child + 1], compare_func), + ret_value); + + JERRY_ASSERT (ecma_is_value_number (child_compare_value)); + + /* Use the child that is greater. */ + if (ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO) + { + child++; + } + + ECMA_FINALIZE (child_compare_value); + } + + if (ecma_is_value_empty (ret_value)) + { + JERRY_ASSERT (child <= right); + + /* Compare current child node with the swap (tree top). */ + ECMA_TRY_CATCH (swap_compare_value, sort_cb (array_p[child], swap, compare_func), ret_value); + JERRY_ASSERT (ecma_is_value_number (swap_compare_value)); + + if (ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO) + { + /* Break from loop if current child is less than swap (tree top) */ + should_break = true; + } + else + { + /* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */ + uint32_t parent = (child - 1) / 2; + JERRY_ASSERT (parent <= right); + array_p[parent] = array_p[child]; + + /* Update child to be the left child of the current node. */ + child = child * 2 + 1; + } + + ECMA_FINALIZE (swap_compare_value); + } + } + + /* + * Loop ended, either current child does not exist, or is less than swap. + * This means that 'swap' should be placed in the parent node. + */ + uint32_t parent = (child - 1) / 2; + JERRY_ASSERT (parent <= right); + array_p[parent] = swap; + + if (ecma_is_value_empty (ret_value)) + { + ret_value = ECMA_VALUE_UNDEFINED; + } + + return ret_value; +} /* ecma_builtin_helper_array_to_heap */ + +/** + * Heapsort function + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_helper_array_heap_sort_helper (ecma_value_t *array_p, /**< array to sort */ + uint32_t right, /**< right index */ + ecma_value_t compare_func, /**< compare function */ + const ecma_builtin_helper_sort_compare_fn_t sort_cb) /**< sorting cb */ +{ + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + /* First, construct the ordered binary tree from the array. */ + for (uint32_t i = (right / 2) + 1; i > 0 && ecma_is_value_empty (ret_value); i--) + { + ECMA_TRY_CATCH (value, + ecma_builtin_helper_array_to_heap (array_p, i - 1, right, compare_func, sort_cb), + ret_value); + ECMA_FINALIZE (value); + } + + /* Sorting elements. */ + for (uint32_t i = right; i > 0 && ecma_is_value_empty (ret_value); i--) + { + /* + * The top element will always contain the largest value. + * Move top to the end, and remove it from the tree. + */ + ecma_value_t swap = array_p[0]; + array_p[0] = array_p[i]; + array_p[i] = swap; + + /* Rebuild binary tree from the remaining elements. */ + ECMA_TRY_CATCH (value, + ecma_builtin_helper_array_to_heap (array_p, 0, i - 1, compare_func, sort_cb), + ret_value); + ECMA_FINALIZE (value); + } + + return ret_value; +} /* ecma_builtin_helper_array_heap_sort_helper */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h index 1e14a86abb..601ec615c7 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h @@ -174,6 +174,20 @@ ecma_value_t ecma_builtin_helper_error_dispatch_call (ecma_standard_error_t error_type, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); +/* ecma-builtin-helpers-sort.c */ + +/** + * Comparison callback function header for sorting helper routines. + */ +typedef ecma_value_t (*ecma_builtin_helper_sort_compare_fn_t)(ecma_value_t lhs, /**< left value */ + ecma_value_t rhs, /**< right value */ + ecma_value_t compare_func); /**< compare function */ + +ecma_value_t ecma_builtin_helper_array_heap_sort_helper (ecma_value_t *array_p, + uint32_t right, + ecma_value_t compare_func, + const ecma_builtin_helper_sort_compare_fn_t sort_cb); + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c index de59a65e01..b2b367c18a 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c @@ -1276,6 +1276,197 @@ ecma_builtin_typedarray_prototype_fill (ecma_value_t this_arg, /**< this argumen return ecma_copy_value (this_arg); } /* ecma_builtin_typedarray_prototype_fill */ +/** + * SortCompare abstract method + * + * See also: + * ECMA-262 v5, 15.4.4.11 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_typedarray_prototype_sort_compare_helper (ecma_value_t lhs, /**< left value */ + ecma_value_t rhs, /**< right value */ + ecma_value_t compare_func) /**< compare function */ +{ + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + ecma_number_t result = ECMA_NUMBER_ZERO; + + if (ecma_is_value_undefined (compare_func)) + { + /* Default comparison when no comparefn is passed. */ + double lhs_value = (double) ecma_get_number_from_value (lhs); + double rhs_value = (double) ecma_get_number_from_value (rhs); + + if (ecma_number_is_nan (lhs_value)) + { + // Keep NaNs at the end of the array. + result = ECMA_NUMBER_ONE; + } + else if (ecma_number_is_nan (rhs_value)) + { + // Keep NaNs at the end of the array. + result = ECMA_NUMBER_MINUS_ONE; + } + else if (lhs_value < rhs_value) + { + result = ECMA_NUMBER_MINUS_ONE; + } + else if (lhs_value > rhs_value) + { + result = ECMA_NUMBER_ONE; + } + else + { + result = ECMA_NUMBER_ZERO; + } + + return ecma_make_number_value (result); + } + + /* + * compare_func, if not undefined, will always contain a callable function object. + * We checked this previously, before this function was called. + */ + JERRY_ASSERT (ecma_op_is_callable (compare_func)); + ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (compare_func); + + ecma_value_t compare_args[] = { lhs, rhs }; + + ECMA_TRY_CATCH (call_value, + ecma_op_function_call (comparefn_obj_p, + ECMA_VALUE_UNDEFINED, + compare_args, + 2), + ret_value); + + if (!ecma_is_value_number (call_value)) + { + ECMA_OP_TO_NUMBER_TRY_CATCH (ret_num, call_value, ret_value); + result = ret_num; + ECMA_OP_TO_NUMBER_FINALIZE (ret_num); + + // If the coerced value can't be represented as a Number, compare them as equals. + if (ecma_number_is_nan (result)) + { + result = ECMA_NUMBER_ZERO; + } + } + else + { + result = ecma_get_number_from_value (call_value); + } + + ECMA_FINALIZE (call_value); + + if (ecma_is_value_empty (ret_value)) + { + ret_value = ecma_make_number_value (result); + } + + return ret_value; +} /* ecma_builtin_typedarray_prototype_sort_compare_helper */ + +/** + * The %TypedArray%.prototype object's 'sort' routine. + * + * See also: + * ES2015, 22.2.3.25, 22.1.3.24 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_typedarray_prototype_sort (ecma_value_t this_arg, /**< this argument */ + ecma_value_t compare_func) /**< comparator fn */ +{ + if (!ecma_is_typedarray (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray.")); + } + + if (!ecma_is_value_undefined (compare_func) && !ecma_op_is_callable (compare_func)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Compare function is not callable.")); + } + + ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_length_t typedarray_length = ecma_typedarray_get_length (typedarray_p); + + if (!typedarray_length) + { + return ecma_copy_value (this_arg); + } + + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + JMEM_DEFINE_LOCAL_ARRAY (values_buffer, typedarray_length, ecma_value_t); + + lit_magic_string_id_t class_id = ecma_object_get_class_name (typedarray_p); + lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p); + uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p); + uint8_t element_size = (uint8_t) (1 << shift); + + uint32_t byte_index = 0, buffer_index = 0; + uint32_t limit = typedarray_length * element_size; + + /* Copy unsorted array into a native c array. */ + while (byte_index < limit) + { + JERRY_ASSERT (buffer_index < typedarray_length); + ecma_number_t element_num = ecma_get_typedarray_element (typedarray_buffer_p + byte_index, + class_id); + ecma_value_t element_value = ecma_make_number_value (element_num); + values_buffer[buffer_index++] = element_value; + byte_index += element_size; + } + + JERRY_ASSERT (buffer_index == typedarray_length); + + const ecma_builtin_helper_sort_compare_fn_t sort_cb = &ecma_builtin_typedarray_prototype_sort_compare_helper; + ECMA_TRY_CATCH (sort_value, + ecma_builtin_helper_array_heap_sort_helper (values_buffer, + (uint32_t) (typedarray_length - 1), + compare_func, + sort_cb), + ret_value); + ECMA_FINALIZE (sort_value); + + if (ecma_is_value_empty (ret_value)) + { + byte_index = 0; + buffer_index = 0; + limit = typedarray_length * element_size; + /* Put sorted values from the native array back into the typedarray buffer. */ + while (byte_index < limit) + { + JERRY_ASSERT (buffer_index < typedarray_length); + ecma_value_t element_value = values_buffer[buffer_index++]; + ecma_number_t element_num = ecma_get_number_from_value (element_value); + ecma_set_typedarray_element (typedarray_buffer_p + byte_index, element_num, class_id); + byte_index += element_size; + } + + JERRY_ASSERT (buffer_index == typedarray_length); + } + + /* Free values that were copied to the local array. */ + for (uint32_t index = 0; index < typedarray_length; index++) + { + ecma_free_value (values_buffer[index]); + } + + JMEM_FINALIZE_LOCAL_ARRAY (values_buffer); + + if (ecma_is_value_empty (ret_value)) + { + ret_value = ecma_copy_value (this_arg); + } + + return ret_value; +} /* ecma_builtin_typedarray_prototype_sort */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h index 0fbd5213d0..b15b384601 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h @@ -60,6 +60,7 @@ ROUTINE (LIT_MAGIC_STRING_REVERSE, ecma_builtin_typedarray_prototype_reverse, 0, ROUTINE (LIT_MAGIC_STRING_SET, ecma_builtin_typedarray_prototype_set, 2, 1) ROUTINE (LIT_MAGIC_STRING_SUBARRAY, ecma_builtin_typedarray_prototype_subarray, 2, 2) ROUTINE (LIT_MAGIC_STRING_FILL, ecma_builtin_typedarray_prototype_fill, 3, 1) +ROUTINE (LIT_MAGIC_STRING_SORT, ecma_builtin_typedarray_prototype_sort, 1, 1) #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 950725b717..042aed6539 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -128,8 +128,6 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEAL, "seal") #if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \ || !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SOME, "some") -#endif -#if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SORT, "sort") #endif #if !defined (CONFIG_DISABLE_MATH_BUILTIN) diff --git a/tests/jerry/es2015/typedArray-sort.js b/tests/jerry/es2015/typedArray-sort.js new file mode 100644 index 0000000000..82ccac15c8 --- /dev/null +++ b/tests/jerry/es2015/typedArray-sort.js @@ -0,0 +1,74 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Default sorting behavior. +var a = Uint8Array.from([4, 1, 3, 5, 4, 2]); +assert(a.sort().toString() === '1,2,3,4,4,5'); +assert(a.toString() === '1,2,3,4,4,5'); + +// Views into typedarrays should be properly sorted. +var b = Uint8Array.from([2, 1, 4, 3, 0]); +assert(b.subarray(2, 4).sort().toString() === '3,4'); +assert(b.toString() === '2,1,3,4,0'); + +// Empty typedarrays should be able to be "sorted". +var c = Uint8Array.from([]); +assert(c.sort().toString() === ''); + +// Infinity should be supported. +var d = Float32Array.from([Infinity, 3, 2, 1, -Infinity]); +assert(d.sort().toString() === '-Infinity,1,2,3,Infinity'); + +// +0 and -0 should be properly sorted. +var e = Float32Array.from([1, 0, -0, -1]); +assert(e.sort().toString() === '-1,0,0,1'); + +// NaN should be supported and always at the end. +var f = Float32Array.from([NaN, 0, 1, -1, -Infinity, Infinity, NaN]); +assert(f.sort().toString() === '-Infinity,-1,0,1,Infinity,NaN,NaN'); + +// The element size of the view should be sorted properly. +var ab = new ArrayBuffer(4); +var g = new Uint32Array(ab); +var h = new Uint8Array(ab); +h.set([0xFF, 0, 0xFF, 0]); +assert(h.toString() === '255,0,255,0'); +assert(g.toString() === '16711935'); +assert(h.subarray(0, 2).sort().toString() === '0,255'); +assert(h.subarray(2, 4).sort().toString() === '0,255'); +assert(g.toString() === '4278255360'); +assert(g.sort().toString() === '4278255360'); +assert(h.toString() === '0,255,0,255'); + +// Comparator argument should be callable. +var i = Uint8Array.from([1, 2, 3]); +try { + i.sort({}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// Comparator function returns a Number. +i.sort(function (lhs, rhs) { + return rhs - lhs; +}); +assert(i.toString() === '3,2,1'); + +// Comparator function returns a non-Number type that coerces to a Number. +i.sort(function (lhs, rhs) { + return { valueOf: function() { return rhs - lhs; } }; +}); +assert(i.toString() === '3,2,1');