mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Add %TypedArray%.prototype.sort([ compareFunction ]) support. (#2437)
JerryScript-DCO-1.0-Signed-off-by: Anthony Calandra anthony@anthony-calandra.com
This commit is contained in:
parent
6e94414f9c
commit
b2cf7eb659
@ -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);
|
||||
}
|
||||
|
||||
146
jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c
Normal file
146
jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c
Normal file
@ -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 */
|
||||
@ -172,6 +172,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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@ -1280,6 +1280,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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@ -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 */
|
||||
|
||||
|
||||
@ -125,8 +125,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)
|
||||
|
||||
74
tests/jerry/es2015/typedArray-sort.js
Normal file
74
tests/jerry/es2015/typedArray-sort.js
Normal file
@ -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');
|
||||
Loading…
x
Reference in New Issue
Block a user