d3_rails 2.8.0 → 2.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/README.md +27 -5
- data/lib/d3_rails/version.rb +1 -1
- data/vendor/.DS_Store +0 -0
- data/vendor/assets/.DS_Store +0 -0
- data/vendor/assets/javascripts/.DS_Store +0 -0
- data/vendor/assets/javascripts/d3.v2.js +99 -80
- data/vendor/assets/javascripts/morris.js +1 -0
- data/vendor/assets/javascripts/morris/.DS_Store +0 -0
- data/vendor/assets/javascripts/morris/Makefile +10 -0
- data/vendor/assets/javascripts/morris/README.md +87 -0
- data/vendor/assets/javascripts/morris/examples/_template.html +18 -0
- data/vendor/assets/javascripts/morris/examples/days.html +36 -0
- data/vendor/assets/javascripts/morris/examples/decimal.html +31 -0
- data/vendor/assets/javascripts/morris/examples/lib/example.css +13 -0
- data/vendor/assets/javascripts/morris/examples/lib/example.js +4 -0
- data/vendor/assets/javascripts/morris/examples/lib/prettify.css +1 -0
- data/vendor/assets/javascripts/morris/examples/lib/prettify.js +28 -0
- data/vendor/assets/javascripts/morris/examples/months-no-smooth.html +37 -0
- data/vendor/assets/javascripts/morris/examples/negative.html +35 -0
- data/vendor/assets/javascripts/morris/examples/non-date.html +36 -0
- data/vendor/assets/javascripts/morris/examples/quarters.html +53 -0
- data/vendor/assets/javascripts/morris/examples/timestamps.html +37 -0
- data/vendor/assets/javascripts/morris/examples/weeks.html +52 -0
- data/vendor/assets/javascripts/morris/morris.coffee +444 -0
- data/vendor/assets/javascripts/morris/morris.js +493 -0
- data/vendor/assets/javascripts/morris/morris.min.js +1 -0
- data/vendor/assets/javascripts/tesseract.js +1 -0
- data/vendor/assets/javascripts/tesseract/.gitignore +2 -0
- data/vendor/assets/javascripts/tesseract/LICENSE +12 -0
- data/vendor/assets/javascripts/tesseract/Makefile +48 -0
- data/vendor/assets/javascripts/tesseract/README.md +11 -0
- data/vendor/assets/javascripts/tesseract/index.js +1 -0
- data/vendor/assets/javascripts/tesseract/lib/dart/AUTHORS +9 -0
- data/vendor/assets/javascripts/tesseract/lib/dart/LICENSE +25 -0
- data/vendor/assets/javascripts/tesseract/lib/dart/dual_pivot_quicksort.dart +342 -0
- data/vendor/assets/javascripts/tesseract/package.json +11 -0
- data/vendor/assets/javascripts/tesseract/src/array.js +32 -0
- data/vendor/assets/javascripts/tesseract/src/bisect.js +44 -0
- data/vendor/assets/javascripts/tesseract/src/filter.js +19 -0
- data/vendor/assets/javascripts/tesseract/src/heap.js +44 -0
- data/vendor/assets/javascripts/tesseract/src/heapselect.js +36 -0
- data/vendor/assets/javascripts/tesseract/src/identity.js +3 -0
- data/vendor/assets/javascripts/tesseract/src/insertionsort.js +18 -0
- data/vendor/assets/javascripts/tesseract/src/null.js +3 -0
- data/vendor/assets/javascripts/tesseract/src/package.js +14 -0
- data/vendor/assets/javascripts/tesseract/src/permute.js +8 -0
- data/vendor/assets/javascripts/tesseract/src/quicksort.js +282 -0
- data/vendor/assets/javascripts/tesseract/src/reduce.js +19 -0
- data/vendor/assets/javascripts/tesseract/src/tesseract.js +663 -0
- data/vendor/assets/javascripts/tesseract/src/version.js +1 -0
- data/vendor/assets/javascripts/tesseract/src/zero.js +3 -0
- data/vendor/assets/javascripts/tesseract/tesseract.js +1177 -0
- data/vendor/assets/javascripts/tesseract/tesseract.min.js +1 -0
- data/vendor/assets/javascripts/tesseract/test/benchmark.js +177 -0
- data/vendor/assets/javascripts/tesseract/test/bisect-test.js +206 -0
- data/vendor/assets/javascripts/tesseract/test/heap-test.js +44 -0
- data/vendor/assets/javascripts/tesseract/test/permute-test.js +51 -0
- data/vendor/assets/javascripts/tesseract/test/select-test.js +63 -0
- data/vendor/assets/javascripts/tesseract/test/sort-test.js +83 -0
- data/vendor/assets/javascripts/tesseract/test/tesseract-test.js +655 -0
- data/vendor/assets/javascripts/tesseract/test/version-test.js +16 -0
- metadata +63 -8
@@ -0,0 +1,32 @@
|
|
1
|
+
var tesseract_array8 = tesseract_arrayUntyped,
|
2
|
+
tesseract_array16 = tesseract_arrayUntyped,
|
3
|
+
tesseract_array32 = tesseract_arrayUntyped,
|
4
|
+
tesseract_arrayLengthen = tesseract_identity,
|
5
|
+
tesseract_arrayWiden = tesseract_identity;
|
6
|
+
|
7
|
+
if (typeof Uint8Array !== "undefined") {
|
8
|
+
tesseract_array8 = function(n) { return new Uint8Array(n); };
|
9
|
+
tesseract_array16 = function(n) { return new Uint16Array(n); };
|
10
|
+
tesseract_array32 = function(n) { return new Uint32Array(n); };
|
11
|
+
|
12
|
+
tesseract_arrayLengthen = function(array, length) {
|
13
|
+
var copy = new array.constructor(length);
|
14
|
+
copy.set(array);
|
15
|
+
return copy;
|
16
|
+
};
|
17
|
+
|
18
|
+
tesseract_arrayWiden = function(array, width) {
|
19
|
+
var copy;
|
20
|
+
switch (width) {
|
21
|
+
case 16: copy = tesseract_array16(array.length); break;
|
22
|
+
case 32: copy = tesseract_array32(array.length); break;
|
23
|
+
default: throw new Error("invalid array width!");
|
24
|
+
}
|
25
|
+
copy.set(array);
|
26
|
+
return copy;
|
27
|
+
};
|
28
|
+
}
|
29
|
+
|
30
|
+
function tesseract_arrayUntyped(n) {
|
31
|
+
return new Array(n);
|
32
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
var bisect = tesseract.bisect = bisect_by(tesseract_identity);
|
2
|
+
|
3
|
+
bisect.by = bisect_by;
|
4
|
+
|
5
|
+
function bisect_by(f) {
|
6
|
+
|
7
|
+
// Locate the insertion point for x in a to maintain sorted order. The
|
8
|
+
// arguments lo and hi may be used to specify a subset of the array which
|
9
|
+
// should be considered; by default the entire array is used. If x is already
|
10
|
+
// present in a, the insertion point will be before (to the left of) any
|
11
|
+
// existing entries. The return value is suitable for use as the first
|
12
|
+
// argument to `array.splice` assuming that a is already sorted.
|
13
|
+
//
|
14
|
+
// The returned insertion point i partitions the array a into two halves so
|
15
|
+
// that all v < x for v in a[lo:i] for the left side and all v >= x for v in
|
16
|
+
// a[i:hi] for the right side.
|
17
|
+
function bisectLeft(a, x, lo, hi) {
|
18
|
+
while (lo < hi) {
|
19
|
+
var mid = lo + hi >> 1;
|
20
|
+
if (f(a[mid]) < x) lo = mid + 1;
|
21
|
+
else hi = mid;
|
22
|
+
}
|
23
|
+
return lo;
|
24
|
+
}
|
25
|
+
|
26
|
+
// Similar to bisectLeft, but returns an insertion point which comes after (to
|
27
|
+
// the right of) any existing entries of x in a.
|
28
|
+
//
|
29
|
+
// The returned insertion point i partitions the array into two halves so that
|
30
|
+
// all v <= x for v in a[lo:i] for the left side and all v > x for v in
|
31
|
+
// a[i:hi] for the right side.
|
32
|
+
function bisectRight(a, x, lo, hi) {
|
33
|
+
while (lo < hi) {
|
34
|
+
var mid = lo + hi >> 1;
|
35
|
+
if (x < f(a[mid])) hi = mid;
|
36
|
+
else lo = mid + 1;
|
37
|
+
}
|
38
|
+
return lo;
|
39
|
+
}
|
40
|
+
|
41
|
+
bisectRight.right = bisectRight;
|
42
|
+
bisectRight.left = bisectLeft;
|
43
|
+
return bisectRight;
|
44
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
function tesseract_filterExact(bisect, value) {
|
2
|
+
return function(values) {
|
3
|
+
var n = values.length;
|
4
|
+
return [bisect.left(values, value, 0, n), bisect.right(values, value, 0, n)];
|
5
|
+
};
|
6
|
+
}
|
7
|
+
|
8
|
+
function tesseract_filterRange(bisect, range) {
|
9
|
+
var min = range[0],
|
10
|
+
max = range[1];
|
11
|
+
return function(values) {
|
12
|
+
var n = values.length;
|
13
|
+
return [bisect.left(values, min, 0, n), bisect.left(values, max, 0, n)];
|
14
|
+
};
|
15
|
+
}
|
16
|
+
|
17
|
+
function tesseract_filterAll(values) {
|
18
|
+
return [0, values.length];
|
19
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
var heap = tesseract.heap = heap_by(tesseract_identity);
|
2
|
+
|
3
|
+
heap.by = heap_by;
|
4
|
+
|
5
|
+
function heap_by(f) {
|
6
|
+
|
7
|
+
// Builds a binary heap within the specified array a[lo:hi]. The heap has the
|
8
|
+
// property such that the parent a[lo+i] is always less than or equal to its
|
9
|
+
// two children: a[lo+2*i+1] and a[lo+2*i+2].
|
10
|
+
function heap(a, lo, hi) {
|
11
|
+
var n = hi - lo,
|
12
|
+
i = (n >>> 1) + 1;
|
13
|
+
while (--i > 0) sift(a, i, n, lo);
|
14
|
+
return a;
|
15
|
+
}
|
16
|
+
|
17
|
+
// Sorts the specified array a[lo:hi] in descending order, assuming it is
|
18
|
+
// already a heap.
|
19
|
+
function sort(a, lo, hi) {
|
20
|
+
var n = hi - lo,
|
21
|
+
t;
|
22
|
+
while (--n > 0) t = a[lo], a[lo] = a[lo + n], a[lo + n] = t, sift(a, 1, n, lo);
|
23
|
+
return a;
|
24
|
+
}
|
25
|
+
|
26
|
+
// Sifts the element a[lo+i-1] down the heap, where the heap is the contiguous
|
27
|
+
// slice of array a[lo:lo+n]. This method can also be used to update the heap
|
28
|
+
// incrementally, without incurring the full cost of reconstructing the heap.
|
29
|
+
function sift(a, i, n, lo) {
|
30
|
+
var d = a[--lo + i],
|
31
|
+
x = f(d),
|
32
|
+
child;
|
33
|
+
while ((child = i << 1) <= n) {
|
34
|
+
if (child < n && f(a[lo + child]) > f(a[lo + child + 1])) child++;
|
35
|
+
if (x <= f(a[lo + child])) break;
|
36
|
+
a[lo + i] = a[lo + child];
|
37
|
+
i = child;
|
38
|
+
}
|
39
|
+
a[lo + i] = d;
|
40
|
+
}
|
41
|
+
|
42
|
+
heap.sort = sort;
|
43
|
+
return heap;
|
44
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
var heapselect = tesseract.heapselect = heapselect_by(tesseract_identity);
|
2
|
+
|
3
|
+
heapselect.by = heapselect_by;
|
4
|
+
|
5
|
+
function heapselect_by(f) {
|
6
|
+
var heap = heap_by(f);
|
7
|
+
|
8
|
+
// Returns a new array containing the top k elements in the array a[lo:hi].
|
9
|
+
// The returned array is not sorted, but maintains the heap property. If k is
|
10
|
+
// greater than hi - lo, then fewer than k elements will be returned. The
|
11
|
+
// order of elements in a is unchanged by this operation.
|
12
|
+
function heapselect(a, lo, hi, k) {
|
13
|
+
var queue = new Array(k = Math.min(hi - lo, k)),
|
14
|
+
min,
|
15
|
+
i,
|
16
|
+
x,
|
17
|
+
d;
|
18
|
+
|
19
|
+
for (i = 0; i < k; ++i) queue[i] = a[lo++];
|
20
|
+
heap(queue, 0, k);
|
21
|
+
|
22
|
+
if (lo < hi) {
|
23
|
+
min = f(queue[0]);
|
24
|
+
do {
|
25
|
+
if (x = f(d = a[lo]) > min) {
|
26
|
+
queue[0] = d;
|
27
|
+
min = f(heap(queue, 0, k)[0]);
|
28
|
+
}
|
29
|
+
} while (++lo < hi);
|
30
|
+
}
|
31
|
+
|
32
|
+
return queue;
|
33
|
+
}
|
34
|
+
|
35
|
+
return heapselect;
|
36
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
var insertionsort = tesseract.insertionsort = insertionsort_by(tesseract_identity);
|
2
|
+
|
3
|
+
insertionsort.by = insertionsort_by;
|
4
|
+
|
5
|
+
function insertionsort_by(f) {
|
6
|
+
|
7
|
+
function insertionsort(a, lo, hi) {
|
8
|
+
for (var i = lo + 1; i < hi; ++i) {
|
9
|
+
for (var j = i, t = a[i], x = f(t); j > lo && f(a[j - 1]) > x; --j) {
|
10
|
+
a[j] = a[j - 1];
|
11
|
+
}
|
12
|
+
a[j] = t;
|
13
|
+
}
|
14
|
+
return a;
|
15
|
+
}
|
16
|
+
|
17
|
+
return insertionsort;
|
18
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
var util = require("util"),
|
2
|
+
tesseract = require("../tesseract").tesseract;
|
3
|
+
|
4
|
+
util.puts(JSON.stringify({
|
5
|
+
"name": "tesseract",
|
6
|
+
"version": tesseract.version,
|
7
|
+
"private": true,
|
8
|
+
"main": "./index.js",
|
9
|
+
"devDependencies": {
|
10
|
+
"d3": "2.8.0",
|
11
|
+
"vows": "0.6.1",
|
12
|
+
"uglify-js": "1.2.5"
|
13
|
+
}
|
14
|
+
}, null, 2));
|
@@ -0,0 +1,282 @@
|
|
1
|
+
// Algorithm designed by Vladimir Yaroslavskiy.
|
2
|
+
// Implementation based on the Dart project; see lib/dart/LICENSE for details.
|
3
|
+
|
4
|
+
var quicksort = tesseract.quicksort = quicksort_by(tesseract_identity);
|
5
|
+
|
6
|
+
quicksort.by = quicksort_by;
|
7
|
+
|
8
|
+
function quicksort_by(f) {
|
9
|
+
var insertionsort = insertionsort_by(f);
|
10
|
+
|
11
|
+
function sort(a, lo, hi) {
|
12
|
+
return (hi - lo < quicksort_sizeThreshold
|
13
|
+
? insertionsort
|
14
|
+
: quicksort)(a, lo, hi);
|
15
|
+
}
|
16
|
+
|
17
|
+
function quicksort(a, lo, hi) {
|
18
|
+
|
19
|
+
// Compute the two pivots by looking at 5 elements.
|
20
|
+
var sixth = (hi - lo) / 6 | 0,
|
21
|
+
i1 = lo + sixth,
|
22
|
+
i5 = hi - 1 - sixth,
|
23
|
+
i3 = lo + hi - 1 >> 1, // The midpoint.
|
24
|
+
i2 = i3 - sixth,
|
25
|
+
i4 = i3 + sixth;
|
26
|
+
|
27
|
+
var e1 = a[i1], x1 = f(e1),
|
28
|
+
e2 = a[i2], x2 = f(e2),
|
29
|
+
e3 = a[i3], x3 = f(e3),
|
30
|
+
e4 = a[i4], x4 = f(e4),
|
31
|
+
e5 = a[i5], x5 = f(e5);
|
32
|
+
|
33
|
+
// Sort the selected 5 elements using a sorting network.
|
34
|
+
if (x1 > x2) t = e1, e1 = e2, e2 = t, t = x1, x1 = x2, x2 = t;
|
35
|
+
if (x4 > x5) t = e4, e4 = e5, e5 = t, t = x4, x4 = x5, x5 = t;
|
36
|
+
if (x1 > x3) t = e1, e1 = e3, e3 = t, t = x1, x1 = x3, x3 = t;
|
37
|
+
if (x2 > x3) t = e2, e2 = e3, e3 = t, t = x2, x2 = x3, x3 = t;
|
38
|
+
if (x1 > x4) t = e1, e1 = e4, e4 = t, t = x1, x1 = x4, x4 = t;
|
39
|
+
if (x3 > x4) t = e3, e3 = e4, e4 = t, t = x3, x3 = x4, x4 = t;
|
40
|
+
if (x2 > x5) t = e2, e2 = e5, e5 = t, t = x2, x2 = x5, x5 = t;
|
41
|
+
if (x2 > x3) t = e2, e2 = e3, e3 = t, t = x2, x2 = x3, x3 = t;
|
42
|
+
if (x4 > x5) t = e4, e4 = e5, e5 = t, t = x4, x4 = x5, x5 = t;
|
43
|
+
|
44
|
+
var pivot1 = e2, pivotValue1 = x2,
|
45
|
+
pivot2 = e4, pivotValue2 = x4;
|
46
|
+
|
47
|
+
// e2 and e4 have been saved in the pivot variables. They will be written
|
48
|
+
// back, once the partitioning is finished.
|
49
|
+
a[i1] = e1;
|
50
|
+
a[i2] = a[lo];
|
51
|
+
a[i3] = e3;
|
52
|
+
a[i4] = a[hi - 1];
|
53
|
+
a[i5] = e5;
|
54
|
+
|
55
|
+
var less = lo + 1, // First element in the middle partition.
|
56
|
+
great = hi - 2; // Last element in the middle partition.
|
57
|
+
|
58
|
+
// Note that for value comparison, <, <=, >= and > coerce to a primitive via
|
59
|
+
// Object.prototype.valueOf; == and === do not, so in order to be consistent
|
60
|
+
// with natural order (such as for Date objects), we must do two compares.
|
61
|
+
var pivotsEqual = pivotValue1 <= pivotValue2 && pivotValue1 >= pivotValue2;
|
62
|
+
if (pivotsEqual) {
|
63
|
+
|
64
|
+
// Degenerated case where the partitioning becomes a dutch national flag
|
65
|
+
// problem.
|
66
|
+
//
|
67
|
+
// [ | < pivot | == pivot | unpartitioned | > pivot | ]
|
68
|
+
// ^ ^ ^ ^ ^
|
69
|
+
// left less k great right
|
70
|
+
//
|
71
|
+
// a[left] and a[right] are undefined and are filled after the
|
72
|
+
// partitioning.
|
73
|
+
//
|
74
|
+
// Invariants:
|
75
|
+
// 1) for x in ]left, less[ : x < pivot.
|
76
|
+
// 2) for x in [less, k[ : x == pivot.
|
77
|
+
// 3) for x in ]great, right[ : x > pivot.
|
78
|
+
for (var k = less; k <= great; ++k) {
|
79
|
+
var ek = a[k], xk = f(ek);
|
80
|
+
if (xk < pivotValue1) {
|
81
|
+
if (k !== less) {
|
82
|
+
a[k] = a[less];
|
83
|
+
a[less] = ek;
|
84
|
+
}
|
85
|
+
++less;
|
86
|
+
} else if (xk > pivotValue1) {
|
87
|
+
|
88
|
+
// Find the first element <= pivot in the range [k - 1, great] and
|
89
|
+
// put [:ek:] there. We know that such an element must exist:
|
90
|
+
// When k == less, then el3 (which is equal to pivot) lies in the
|
91
|
+
// interval. Otherwise a[k - 1] == pivot and the search stops at k-1.
|
92
|
+
// Note that in the latter case invariant 2 will be violated for a
|
93
|
+
// short amount of time. The invariant will be restored when the
|
94
|
+
// pivots are put into their final positions.
|
95
|
+
while (true) {
|
96
|
+
var greatValue = f(a[great]);
|
97
|
+
if (greatValue > pivotValue1) {
|
98
|
+
great--;
|
99
|
+
// This is the only location in the while-loop where a new
|
100
|
+
// iteration is started.
|
101
|
+
continue;
|
102
|
+
} else if (greatValue < pivotValue1) {
|
103
|
+
// Triple exchange.
|
104
|
+
a[k] = a[less];
|
105
|
+
a[less++] = a[great];
|
106
|
+
a[great--] = ek;
|
107
|
+
break;
|
108
|
+
} else {
|
109
|
+
a[k] = a[great];
|
110
|
+
a[great--] = ek;
|
111
|
+
// Note: if great < k then we will exit the outer loop and fix
|
112
|
+
// invariant 2 (which we just violated).
|
113
|
+
break;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
} else {
|
119
|
+
|
120
|
+
// We partition the list into three parts:
|
121
|
+
// 1. < pivot1
|
122
|
+
// 2. >= pivot1 && <= pivot2
|
123
|
+
// 3. > pivot2
|
124
|
+
//
|
125
|
+
// During the loop we have:
|
126
|
+
// [ | < pivot1 | >= pivot1 && <= pivot2 | unpartitioned | > pivot2 | ]
|
127
|
+
// ^ ^ ^ ^ ^
|
128
|
+
// left less k great right
|
129
|
+
//
|
130
|
+
// a[left] and a[right] are undefined and are filled after the
|
131
|
+
// partitioning.
|
132
|
+
//
|
133
|
+
// Invariants:
|
134
|
+
// 1. for x in ]left, less[ : x < pivot1
|
135
|
+
// 2. for x in [less, k[ : pivot1 <= x && x <= pivot2
|
136
|
+
// 3. for x in ]great, right[ : x > pivot2
|
137
|
+
for (var k = less; k <= great; k++) {
|
138
|
+
var ek = a[k], xk = f(ek);
|
139
|
+
if (xk < pivotValue1) {
|
140
|
+
if (k !== less) {
|
141
|
+
a[k] = a[less];
|
142
|
+
a[less] = ek;
|
143
|
+
}
|
144
|
+
++less;
|
145
|
+
} else {
|
146
|
+
if (xk > pivotValue2) {
|
147
|
+
while (true) {
|
148
|
+
var greatValue = f(a[great]);
|
149
|
+
if (greatValue > pivotValue2) {
|
150
|
+
great--;
|
151
|
+
if (great < k) break;
|
152
|
+
// This is the only location inside the loop where a new
|
153
|
+
// iteration is started.
|
154
|
+
continue;
|
155
|
+
} else {
|
156
|
+
// a[great] <= pivot2.
|
157
|
+
if (greatValue < pivotValue1) {
|
158
|
+
// Triple exchange.
|
159
|
+
a[k] = a[less];
|
160
|
+
a[less++] = a[great];
|
161
|
+
a[great--] = ek;
|
162
|
+
} else {
|
163
|
+
// a[great] >= pivot1.
|
164
|
+
a[k] = a[great];
|
165
|
+
a[great--] = ek;
|
166
|
+
}
|
167
|
+
break;
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
// Move pivots into their final positions.
|
176
|
+
// We shrunk the list from both sides (a[left] and a[right] have
|
177
|
+
// meaningless values in them) and now we move elements from the first
|
178
|
+
// and third partition into these locations so that we can store the
|
179
|
+
// pivots.
|
180
|
+
a[lo] = a[less - 1];
|
181
|
+
a[less - 1] = pivot1;
|
182
|
+
a[hi - 1] = a[great + 1];
|
183
|
+
a[great + 1] = pivot2;
|
184
|
+
|
185
|
+
// The list is now partitioned into three partitions:
|
186
|
+
// [ < pivot1 | >= pivot1 && <= pivot2 | > pivot2 ]
|
187
|
+
// ^ ^ ^ ^
|
188
|
+
// left less great right
|
189
|
+
|
190
|
+
// Recursive descent. (Don't include the pivot values.)
|
191
|
+
sort(a, lo, less - 1);
|
192
|
+
sort(a, great + 2, hi);
|
193
|
+
|
194
|
+
if (pivotsEqual) {
|
195
|
+
// All elements in the second partition are equal to the pivot. No
|
196
|
+
// need to sort them.
|
197
|
+
return a;
|
198
|
+
}
|
199
|
+
|
200
|
+
// In theory it should be enough to call _doSort recursively on the second
|
201
|
+
// partition.
|
202
|
+
// The Android source however removes the pivot elements from the recursive
|
203
|
+
// call if the second partition is too large (more than 2/3 of the list).
|
204
|
+
if (less < i1 && great > i5) {
|
205
|
+
var lessValue, greatValue;
|
206
|
+
while ((lessValue = f(a[less])) <= pivotValue1 && lessValue >= pivotValue1) ++less;
|
207
|
+
while ((greatValue = f(a[great])) <= pivotValue2 && greatValue >= pivotValue2) --great;
|
208
|
+
|
209
|
+
// Copy paste of the previous 3-way partitioning with adaptions.
|
210
|
+
//
|
211
|
+
// We partition the list into three parts:
|
212
|
+
// 1. == pivot1
|
213
|
+
// 2. > pivot1 && < pivot2
|
214
|
+
// 3. == pivot2
|
215
|
+
//
|
216
|
+
// During the loop we have:
|
217
|
+
// [ == pivot1 | > pivot1 && < pivot2 | unpartitioned | == pivot2 ]
|
218
|
+
// ^ ^ ^
|
219
|
+
// less k great
|
220
|
+
//
|
221
|
+
// Invariants:
|
222
|
+
// 1. for x in [ *, less[ : x == pivot1
|
223
|
+
// 2. for x in [less, k[ : pivot1 < x && x < pivot2
|
224
|
+
// 3. for x in ]great, * ] : x == pivot2
|
225
|
+
for (var k = less; k <= great; k++) {
|
226
|
+
var ek = a[k], xk = f(ek);
|
227
|
+
if (xk <= pivotValue1 && xk >= pivotValue1) {
|
228
|
+
if (k !== less) {
|
229
|
+
a[k] = a[less];
|
230
|
+
a[less] = ek;
|
231
|
+
}
|
232
|
+
less++;
|
233
|
+
} else {
|
234
|
+
if (xk <= pivotValue2 && xk >= pivotValue2) {
|
235
|
+
while (true) {
|
236
|
+
var greatValue = f(a[great]);
|
237
|
+
if (greatValue <= pivotValue2 && greatValue >= pivotValue2) {
|
238
|
+
great--;
|
239
|
+
if (great < k) break;
|
240
|
+
// This is the only location inside the loop where a new
|
241
|
+
// iteration is started.
|
242
|
+
continue;
|
243
|
+
} else {
|
244
|
+
// a[great] < pivot2.
|
245
|
+
if (greatValue < pivotValue1) {
|
246
|
+
// Triple exchange.
|
247
|
+
a[k] = a[less];
|
248
|
+
a[less++] = a[great];
|
249
|
+
a[great--] = ek;
|
250
|
+
} else {
|
251
|
+
// a[great] == pivot1.
|
252
|
+
a[k] = a[great];
|
253
|
+
a[great--] = ek;
|
254
|
+
}
|
255
|
+
break;
|
256
|
+
}
|
257
|
+
}
|
258
|
+
}
|
259
|
+
}
|
260
|
+
}
|
261
|
+
}
|
262
|
+
|
263
|
+
// The second partition has now been cleared of pivot elements and looks
|
264
|
+
// as follows:
|
265
|
+
// [ * | > pivot1 && < pivot2 | * ]
|
266
|
+
// ^ ^
|
267
|
+
// less great
|
268
|
+
// Sort the second partition using recursive descent.
|
269
|
+
|
270
|
+
// The second partition looks as follows:
|
271
|
+
// [ * | >= pivot1 && <= pivot2 | * ]
|
272
|
+
// ^ ^
|
273
|
+
// less great
|
274
|
+
// Simply sort it by recursive descent.
|
275
|
+
|
276
|
+
return sort(a, less, great + 1);
|
277
|
+
}
|
278
|
+
|
279
|
+
return sort;
|
280
|
+
}
|
281
|
+
|
282
|
+
var quicksort_sizeThreshold = 32;
|