Skip to content

Commit b2cf7eb

Browse files
AnthonyCalandraLaszloLango
authored andcommitted
Add %TypedArray%.prototype.sort([ compareFunction ]) support. (#2437)
JerryScript-DCO-1.0-Signed-off-by: Anthony Calandra anthony@anthony-calandra.com
1 parent 6e94414 commit b2cf7eb

File tree

7 files changed

+453
-166
lines changed

7 files changed

+453
-166
lines changed

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

Lines changed: 27 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -890,9 +890,9 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t this_arg, /**< 'this' ar
890890
* Returned value must be freed with ecma_free_value.
891891
*/
892892
static ecma_value_t
893-
ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< left value */
894-
ecma_value_t k, /**< right value */
895-
ecma_value_t comparefn) /**< compare function */
893+
ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t lhs, /**< left value */
894+
ecma_value_t rhs, /**< right value */
895+
ecma_value_t compare_func) /**< compare function */
896896
{
897897
/*
898898
* 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
903903
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
904904
ecma_number_t result = ECMA_NUMBER_ZERO;
905905

906-
bool j_is_undef = ecma_is_value_undefined (j);
907-
bool k_is_undef = ecma_is_value_undefined (k);
906+
bool lhs_is_undef = ecma_is_value_undefined (lhs);
907+
bool rhs_is_undef = ecma_is_value_undefined (rhs);
908908

909-
if (j_is_undef)
909+
if (lhs_is_undef)
910910
{
911-
if (k_is_undef)
911+
if (rhs_is_undef)
912912
{
913913
result = ECMA_NUMBER_ZERO;
914914
}
@@ -919,25 +919,25 @@ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< le
919919
}
920920
else
921921
{
922-
if (k_is_undef)
922+
if (rhs_is_undef)
923923
{
924924
result = ECMA_NUMBER_MINUS_ONE;
925925
}
926926
else
927927
{
928-
if (ecma_is_value_undefined (comparefn))
928+
if (ecma_is_value_undefined (compare_func))
929929
{
930-
/* Default comparison when no comparefn is passed. */
931-
ECMA_TRY_CATCH (j_value, ecma_op_to_string (j), ret_value);
932-
ECMA_TRY_CATCH (k_value, ecma_op_to_string (k), ret_value);
933-
ecma_string_t *j_str_p = ecma_get_string_from_value (j_value);
934-
ecma_string_t *k_str_p = ecma_get_string_from_value (k_value);
930+
/* Default comparison when no compare_func is passed. */
931+
ECMA_TRY_CATCH (lhs_value, ecma_op_to_string (lhs), ret_value);
932+
ECMA_TRY_CATCH (rhs_value, ecma_op_to_string (rhs), ret_value);
933+
ecma_string_t *lhs_str_p = ecma_get_string_from_value (lhs_value);
934+
ecma_string_t *rhs_str_p = ecma_get_string_from_value (rhs_value);
935935

936-
if (ecma_compare_ecma_strings_relational (j_str_p, k_str_p))
936+
if (ecma_compare_ecma_strings_relational (lhs_str_p, rhs_str_p))
937937
{
938938
result = ECMA_NUMBER_MINUS_ONE;
939939
}
940-
else if (!ecma_compare_ecma_strings (j_str_p, k_str_p))
940+
else if (!ecma_compare_ecma_strings (lhs_str_p, rhs_str_p))
941941
{
942942
result = ECMA_NUMBER_ONE;
943943
}
@@ -946,19 +946,19 @@ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< le
946946
result = ECMA_NUMBER_ZERO;
947947
}
948948

949-
ECMA_FINALIZE (k_value);
950-
ECMA_FINALIZE (j_value);
949+
ECMA_FINALIZE (rhs_value);
950+
ECMA_FINALIZE (lhs_value);
951951
}
952952
else
953953
{
954954
/*
955-
* comparefn, if not undefined, will always contain a callable function object.
955+
* compare_func, if not undefined, will always contain a callable function object.
956956
* We checked this previously, before this function was called.
957957
*/
958-
JERRY_ASSERT (ecma_op_is_callable (comparefn));
959-
ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (comparefn);
958+
JERRY_ASSERT (ecma_op_is_callable (compare_func));
959+
ecma_object_t *comparefn_obj_p = ecma_get_object_from_value (compare_func);
960960

961-
ecma_value_t compare_args[] = {j, k};
961+
ecma_value_t compare_args[] = { lhs, rhs };
962962

963963
ECMA_TRY_CATCH (call_value,
964964
ecma_op_function_call (comparefn_obj_p,
@@ -991,145 +991,6 @@ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t j, /**< le
991991
return ret_value;
992992
} /* ecma_builtin_array_prototype_object_sort_compare_helper */
993993

994-
/**
995-
* Function used to reconstruct the ordered binary tree.
996-
* Shifts 'index' down in the tree until it is in the correct position.
997-
*
998-
* @return ecma value
999-
* Returned value must be freed with ecma_free_value.
1000-
*/
1001-
static ecma_value_t
1002-
ecma_builtin_array_prototype_object_array_to_heap_helper (ecma_value_t array[], /**< heap data array */
1003-
int index, /**< current item index */
1004-
int right, /**< right index is a maximum index */
1005-
ecma_value_t comparefn) /**< compare function */
1006-
{
1007-
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1008-
1009-
/* Left child of the current index. */
1010-
int child = index * 2 + 1;
1011-
ecma_value_t swap = array[index];
1012-
bool should_break = false;
1013-
1014-
while (child <= right && ecma_is_value_empty (ret_value) && !should_break)
1015-
{
1016-
if (child < right)
1017-
{
1018-
/* Compare the two child nodes. */
1019-
ECMA_TRY_CATCH (child_compare_value,
1020-
ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
1021-
array[child + 1],
1022-
comparefn),
1023-
ret_value);
1024-
1025-
JERRY_ASSERT (ecma_is_value_number (child_compare_value));
1026-
1027-
/* Use the child that is greater. */
1028-
if (ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO)
1029-
{
1030-
child++;
1031-
}
1032-
1033-
ECMA_FINALIZE (child_compare_value);
1034-
}
1035-
1036-
if (ecma_is_value_empty (ret_value))
1037-
{
1038-
JERRY_ASSERT (child <= right);
1039-
1040-
/* Compare current child node with the swap (tree top). */
1041-
ECMA_TRY_CATCH (swap_compare_value,
1042-
ecma_builtin_array_prototype_object_sort_compare_helper (array[child],
1043-
swap,
1044-
comparefn),
1045-
ret_value);
1046-
JERRY_ASSERT (ecma_is_value_number (swap_compare_value));
1047-
1048-
if (ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO)
1049-
{
1050-
/* Break from loop if current child is less than swap (tree top) */
1051-
should_break = true;
1052-
}
1053-
else
1054-
{
1055-
/* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */
1056-
int parent = (child - 1) / 2;
1057-
JERRY_ASSERT (parent >= 0 && parent <= right);
1058-
array[parent] = array[child];
1059-
1060-
/* Update child to be the left child of the current node. */
1061-
child = child * 2 + 1;
1062-
}
1063-
1064-
ECMA_FINALIZE (swap_compare_value);
1065-
}
1066-
}
1067-
1068-
/*
1069-
* Loop ended, either current child does not exist, or is less than swap.
1070-
* This means that 'swap' should be placed in the parent node.
1071-
*/
1072-
int parent = (child - 1) / 2;
1073-
JERRY_ASSERT (parent >= 0 && parent <= right);
1074-
array[parent] = swap;
1075-
1076-
if (ecma_is_value_empty (ret_value))
1077-
{
1078-
ret_value = ECMA_VALUE_UNDEFINED;
1079-
}
1080-
1081-
return ret_value;
1082-
} /* ecma_builtin_array_prototype_object_array_to_heap_helper */
1083-
1084-
/**
1085-
* Heapsort function
1086-
*
1087-
* @return ecma value
1088-
* Returned value must be freed with ecma_free_value.
1089-
*/
1090-
static ecma_value_t
1091-
ecma_builtin_array_prototype_object_array_heap_sort_helper (ecma_value_t array[], /**< array to sort */
1092-
int right, /**< right index */
1093-
ecma_value_t comparefn) /**< compare function */
1094-
{
1095-
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1096-
1097-
/* First, construct the ordered binary tree from the array. */
1098-
for (int i = right / 2; i >= 0 && ecma_is_value_empty (ret_value); i--)
1099-
{
1100-
ECMA_TRY_CATCH (value,
1101-
ecma_builtin_array_prototype_object_array_to_heap_helper (array,
1102-
i,
1103-
right,
1104-
comparefn),
1105-
ret_value);
1106-
ECMA_FINALIZE (value);
1107-
}
1108-
1109-
/* Sorting elements. */
1110-
for (int i = right; i > 0 && ecma_is_value_empty (ret_value); i--)
1111-
{
1112-
/*
1113-
* The top element will always contain the largest value.
1114-
* Move top to the end, and remove it from the tree.
1115-
*/
1116-
ecma_value_t swap = array[0];
1117-
array[0] = array[i];
1118-
array[i] = swap;
1119-
1120-
/* Rebuild binary tree from the remaining elements. */
1121-
ECMA_TRY_CATCH (value,
1122-
ecma_builtin_array_prototype_object_array_to_heap_helper (array,
1123-
0,
1124-
i - 1,
1125-
comparefn),
1126-
ret_value);
1127-
ECMA_FINALIZE (value);
1128-
}
1129-
1130-
return ret_value;
1131-
} /* ecma_builtin_array_prototype_object_array_heap_sort_helper */
1132-
1133994
/**
1134995
* The Array.prototype object's 'sort' routine
1135996
*
@@ -1218,10 +1079,12 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum
12181079
/* Sorting. */
12191080
if (copied_num > 1 && ecma_is_value_empty (ret_value))
12201081
{
1082+
const ecma_builtin_helper_sort_compare_fn_t sort_cb = &ecma_builtin_array_prototype_object_sort_compare_helper;
12211083
ECMA_TRY_CATCH (sort_value,
1222-
ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer,
1223-
(int)(copied_num - 1),
1224-
arg1),
1084+
ecma_builtin_helper_array_heap_sort_helper (values_buffer,
1085+
(uint32_t) (copied_num - 1),
1086+
arg1,
1087+
sort_cb),
12251088
ret_value);
12261089
ECMA_FINALIZE (sort_value);
12271090
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
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+
#include "ecma-builtin-helpers.h"
17+
#include "ecma-globals.h"
18+
#include "ecma-try-catch-macro.h"
19+
20+
/**
21+
* Function used to reconstruct the ordered binary tree.
22+
* Shifts 'index' down in the tree until it is in the correct position.
23+
*
24+
* @return ecma value
25+
* Returned value must be freed with ecma_free_value.
26+
*/
27+
static ecma_value_t
28+
ecma_builtin_helper_array_to_heap (ecma_value_t *array_p, /**< heap data array */
29+
uint32_t index, /**< current item index */
30+
uint32_t right, /**< right index is a maximum index */
31+
ecma_value_t compare_func, /**< compare function */
32+
const ecma_builtin_helper_sort_compare_fn_t sort_cb) /**< sorting cb */
33+
{
34+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
35+
36+
/* Left child of the current index. */
37+
uint32_t child = index * 2 + 1;
38+
ecma_value_t swap = array_p[index];
39+
bool should_break = false;
40+
41+
while (child <= right && ecma_is_value_empty (ret_value) && !should_break)
42+
{
43+
if (child < right)
44+
{
45+
/* Compare the two child nodes. */
46+
ECMA_TRY_CATCH (child_compare_value, sort_cb (array_p[child], array_p[child + 1], compare_func),
47+
ret_value);
48+
49+
JERRY_ASSERT (ecma_is_value_number (child_compare_value));
50+
51+
/* Use the child that is greater. */
52+
if (ecma_get_number_from_value (child_compare_value) < ECMA_NUMBER_ZERO)
53+
{
54+
child++;
55+
}
56+
57+
ECMA_FINALIZE (child_compare_value);
58+
}
59+
60+
if (ecma_is_value_empty (ret_value))
61+
{
62+
JERRY_ASSERT (child <= right);
63+
64+
/* Compare current child node with the swap (tree top). */
65+
ECMA_TRY_CATCH (swap_compare_value, sort_cb (array_p[child], swap, compare_func), ret_value);
66+
JERRY_ASSERT (ecma_is_value_number (swap_compare_value));
67+
68+
if (ecma_get_number_from_value (swap_compare_value) <= ECMA_NUMBER_ZERO)
69+
{
70+
/* Break from loop if current child is less than swap (tree top) */
71+
should_break = true;
72+
}
73+
else
74+
{
75+
/* We have to move 'swap' lower in the tree, so shift current child up in the hierarchy. */
76+
uint32_t parent = (child - 1) / 2;
77+
JERRY_ASSERT (parent <= right);
78+
array_p[parent] = array_p[child];
79+
80+
/* Update child to be the left child of the current node. */
81+
child = child * 2 + 1;
82+
}
83+
84+
ECMA_FINALIZE (swap_compare_value);
85+
}
86+
}
87+
88+
/*
89+
* Loop ended, either current child does not exist, or is less than swap.
90+
* This means that 'swap' should be placed in the parent node.
91+
*/
92+
uint32_t parent = (child - 1) / 2;
93+
JERRY_ASSERT (parent <= right);
94+
array_p[parent] = swap;
95+
96+
if (ecma_is_value_empty (ret_value))
97+
{
98+
ret_value = ECMA_VALUE_UNDEFINED;
99+
}
100+
101+
return ret_value;
102+
} /* ecma_builtin_helper_array_to_heap */
103+
104+
/**
105+
* Heapsort function
106+
*
107+
* @return ecma value
108+
* Returned value must be freed with ecma_free_value.
109+
*/
110+
ecma_value_t
111+
ecma_builtin_helper_array_heap_sort_helper (ecma_value_t *array_p, /**< array to sort */
112+
uint32_t right, /**< right index */
113+
ecma_value_t compare_func, /**< compare function */
114+
const ecma_builtin_helper_sort_compare_fn_t sort_cb) /**< sorting cb */
115+
{
116+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
117+
118+
/* First, construct the ordered binary tree from the array. */
119+
for (uint32_t i = (right / 2) + 1; i > 0 && ecma_is_value_empty (ret_value); i--)
120+
{
121+
ECMA_TRY_CATCH (value,
122+
ecma_builtin_helper_array_to_heap (array_p, i - 1, right, compare_func, sort_cb),
123+
ret_value);
124+
ECMA_FINALIZE (value);
125+
}
126+
127+
/* Sorting elements. */
128+
for (uint32_t i = right; i > 0 && ecma_is_value_empty (ret_value); i--)
129+
{
130+
/*
131+
* The top element will always contain the largest value.
132+
* Move top to the end, and remove it from the tree.
133+
*/
134+
ecma_value_t swap = array_p[0];
135+
array_p[0] = array_p[i];
136+
array_p[i] = swap;
137+
138+
/* Rebuild binary tree from the remaining elements. */
139+
ECMA_TRY_CATCH (value,
140+
ecma_builtin_helper_array_to_heap (array_p, 0, i - 1, compare_func, sort_cb),
141+
ret_value);
142+
ECMA_FINALIZE (value);
143+
}
144+
145+
return ret_value;
146+
} /* ecma_builtin_helper_array_heap_sort_helper */

0 commit comments

Comments
 (0)