Initial commit
[yaffs-website] / node_modules / source-map / lib / quick-sort.js
1 /* -*- Mode: js; js-indent-level: 2; -*- */
2 /*
3  * Copyright 2011 Mozilla Foundation and contributors
4  * Licensed under the New BSD license. See LICENSE or:
5  * http://opensource.org/licenses/BSD-3-Clause
6  */
7
8 // It turns out that some (most?) JavaScript engines don't self-host
9 // `Array.prototype.sort`. This makes sense because C++ will likely remain
10 // faster than JS when doing raw CPU-intensive sorting. However, when using a
11 // custom comparator function, calling back and forth between the VM's C++ and
12 // JIT'd JS is rather slow *and* loses JIT type information, resulting in
13 // worse generated code for the comparator function than would be optimal. In
14 // fact, when sorting with a comparator, these costs outweigh the benefits of
15 // sorting in C++. By using our own JS-implemented Quick Sort (below), we get
16 // a ~3500ms mean speed-up in `bench/bench.html`.
17
18 /**
19  * Swap the elements indexed by `x` and `y` in the array `ary`.
20  *
21  * @param {Array} ary
22  *        The array.
23  * @param {Number} x
24  *        The index of the first item.
25  * @param {Number} y
26  *        The index of the second item.
27  */
28 function swap(ary, x, y) {
29   var temp = ary[x];
30   ary[x] = ary[y];
31   ary[y] = temp;
32 }
33
34 /**
35  * Returns a random integer within the range `low .. high` inclusive.
36  *
37  * @param {Number} low
38  *        The lower bound on the range.
39  * @param {Number} high
40  *        The upper bound on the range.
41  */
42 function randomIntInRange(low, high) {
43   return Math.round(low + (Math.random() * (high - low)));
44 }
45
46 /**
47  * The Quick Sort algorithm.
48  *
49  * @param {Array} ary
50  *        An array to sort.
51  * @param {function} comparator
52  *        Function to use to compare two items.
53  * @param {Number} p
54  *        Start index of the array
55  * @param {Number} r
56  *        End index of the array
57  */
58 function doQuickSort(ary, comparator, p, r) {
59   // If our lower bound is less than our upper bound, we (1) partition the
60   // array into two pieces and (2) recurse on each half. If it is not, this is
61   // the empty array and our base case.
62
63   if (p < r) {
64     // (1) Partitioning.
65     //
66     // The partitioning chooses a pivot between `p` and `r` and moves all
67     // elements that are less than or equal to the pivot to the before it, and
68     // all the elements that are greater than it after it. The effect is that
69     // once partition is done, the pivot is in the exact place it will be when
70     // the array is put in sorted order, and it will not need to be moved
71     // again. This runs in O(n) time.
72
73     // Always choose a random pivot so that an input array which is reverse
74     // sorted does not cause O(n^2) running time.
75     var pivotIndex = randomIntInRange(p, r);
76     var i = p - 1;
77
78     swap(ary, pivotIndex, r);
79     var pivot = ary[r];
80
81     // Immediately after `j` is incremented in this loop, the following hold
82     // true:
83     //
84     //   * Every element in `ary[p .. i]` is less than or equal to the pivot.
85     //
86     //   * Every element in `ary[i+1 .. j-1]` is greater than the pivot.
87     for (var j = p; j < r; j++) {
88       if (comparator(ary[j], pivot) <= 0) {
89         i += 1;
90         swap(ary, i, j);
91       }
92     }
93
94     swap(ary, i + 1, j);
95     var q = i + 1;
96
97     // (2) Recurse on each half.
98
99     doQuickSort(ary, comparator, p, q - 1);
100     doQuickSort(ary, comparator, q + 1, r);
101   }
102 }
103
104 /**
105  * Sort the given array in-place with the given comparator function.
106  *
107  * @param {Array} ary
108  *        An array to sort.
109  * @param {function} comparator
110  *        Function to use to compare two items.
111  */
112 exports.quickSort = function (ary, comparator) {
113   doQuickSort(ary, comparator, 0, ary.length - 1);
114 };