Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Unified Diff: src/array.js

Issue 1513020: Early specialize sorting functions depending if there is a custom comparator or not. (Closed)
Patch Set: Addressing Ivan's comments Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/array.js
diff --git a/src/array.js b/src/array.js
index c367d7ea28e0b9d09401799ff9a386c09795fdd1..4a2be989a36ff401cd5fda8efc934e2f62204eb5 100644
--- a/src/array.js
+++ b/src/array.js
@@ -644,16 +644,77 @@ function ArraySort(comparefn) {
// In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.
- var custom_compare = IS_FUNCTION(comparefn);
+ function InsertionSortWithFunc(a, from, to) {
+ for (var i = from + 1; i < to; i++) {
+ var element = a[i];
Lasse Reichstein 2010/04/07 17:43:27 Come to think of it, using binary search seems ove
antonm 2010/04/07 17:47:27 Agree. That's the thing I implemented in C++, but
+ // place element in a[from..i[
+ // binary search
+ var min = from;
+ var max = i;
+ // The search interval is a[min..max[
+ while (min < max) {
+ var mid = min + ((max - min) >> 1);
+ var order = (a[mid] === element) ?
+ 0 : comparefn.call(null, a[mid], element);
Lasse Reichstein 2010/04/07 17:43:27 Reading a[mid] twice. Maybe assign to temporary va
antonm 2010/04/07 17:47:27 Thanks, will give it a try.
+ if (order == 0) {
+ min = max = mid;
Lasse Reichstein 2010/04/07 17:43:27 No need to assign to max.
antonm 2010/04/07 17:47:27 Will give it a try as well.
+ break;
+ }
+ if (order < 0) {
+ min = mid + 1;
+ } else {
+ max = mid;
+ }
+ }
+ // place element at position min==max.
+ for (var j = i; j > min; j--) {
+ a[j] = a[j - 1];
+ }
+ a[min] = element;
+ }
+ }
+
+ function QuickSortWithFunc(a, from, to) {
+ // Insertion sort is faster for short arrays.
+ if (to - from <= 22) {
+ InsertionSortWithFunc(a, from, to);
+ return;
+ }
+ var pivot_index = $floor($random() * (to - from)) + from;
+ var pivot = a[pivot_index];
+ // Issue 95: Keep the pivot element out of the comparisons to avoid
+ // infinite recursion if comparefn(pivot, pivot) != 0.
+ a[pivot_index] = a[from];
+ a[from] = pivot;
+ var low_end = from; // Upper bound of the elements lower than pivot.
+ var high_start = to; // Lower bound of the elements greater than pivot.
+ // From low_end to i are elements equal to pivot.
+ // From i to high_start are elements that haven't been compared yet.
+ for (var i = from + 1; i < high_start; ) {
+ var element = a[i];
+ var order = (element === pivot) ?
+ 0 : comparefn.call(null, element, pivot);
+ if (order < 0) {
+ a[i] = a[low_end];
+ a[low_end] = element;
+ i++;
+ low_end++;
+ } else if (order > 0) {
+ high_start--;
+ a[i] = a[high_start];
+ a[high_start] = element;
+ } else { // order == 0
+ i++;
+ }
+ }
+ QuickSortWithFunc(a, from, low_end);
+ QuickSortWithFunc(a, high_start, to);
+ }
function Compare(x,y) {
// Assume the comparefn, if any, is a consistent comparison function.
// If it isn't, we are allowed arbitrary behavior by ECMA 15.4.4.11.
Lasse Reichstein 2010/04/07 17:43:27 Comment doesn't make sense any more (not here, at
antonm 2010/04/07 17:47:27 Agree. Will remove.
if (x === y) return 0;
- if (custom_compare) {
- // Don't call directly to avoid exposing the builtin's global object.
- return comparefn.call(null, x, y);
- }
if (%_IsSmi(x) && %_IsSmi(y)) {
return %SmiLexicographicCompare(x, y);
}
@@ -668,8 +729,7 @@ function ArraySort(comparefn) {
var element = a[i];
// Pre-convert the element to a string for comparison if we know
// it will happen on each compare anyway.
- var key =
- (custom_compare || %_IsSmi(element)) ? element : ToString(element);
+ var key = %_IsSmi(element) ? element : ToString(element);
// place element in a[from..i[
// binary search
var min = from;
@@ -706,8 +766,7 @@ function ArraySort(comparefn) {
var pivot = a[pivot_index];
// Pre-convert the element to a string for comparison if we know
// it will happen on each compare anyway.
- var pivot_key =
- (custom_compare || %_IsSmi(pivot)) ? pivot : ToString(pivot);
+ var pivot_key = %_IsSmi(pivot) ? pivot : ToString(pivot);
// Issue 95: Keep the pivot element out of the comparisons to avoid
// infinite recursion if comparefn(pivot, pivot) != 0.
a[pivot_index] = a[from];
@@ -736,8 +795,6 @@ function ArraySort(comparefn) {
QuickSort(a, high_start, to);
}
- var length;
-
// Copies elements in the range 0..length from obj's prototype chain
// to obj itself, if obj has holes. Returns one more than the maximal index
// of a prototype property.
@@ -855,7 +912,7 @@ function ArraySort(comparefn) {
return first_undefined;
}
- length = TO_UINT32(this.length);
+ var length = TO_UINT32(this.length);
if (length < 2) return this;
var is_array = IS_ARRAY(this);
@@ -880,7 +937,11 @@ function ArraySort(comparefn) {
num_non_undefined = SafeRemoveArrayHoles(this);
}
- QuickSort(this, 0, num_non_undefined);
+ if(IS_FUNCTION(comparefn)) {
+ QuickSortWithFunc(this, 0, num_non_undefined);
+ } else {
+ QuickSort(this, 0, num_non_undefined);
+ }
if (!is_array && (num_non_undefined + 1 < max_prototype_element)) {
// For compatibility with JSC, we shadow any elements in the prototype
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698