forked from phaserjs/phaser
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStableSort.js
More file actions
183 lines (157 loc) · 4.2 KB
/
Copy pathStableSort.js
File metadata and controls
183 lines (157 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/**
* @author Richard Davey <rich@phaser.io>
* @author Angry Bytes (and contributors)
* @copyright 2013-2026 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Device = require('../../device');
/**
* The comparator function.
*
* @ignore
*
* @param {*} a - The first item to test.
* @param {*} b - The second item to test.
*
* @return {boolean} The numeric result of the locale comparison between the two string values.
*/
function Compare (a, b)
{
return String(a).localeCompare(b);
}
/**
* Process the array contents.
*
* @ignore
*
* @param {array} array - The array to process.
* @param {function} compare - The comparison function.
*
* @return {array} - The processed array.
*/
function Process (array, compare)
{
// Short-circuit when there's nothing to sort.
var len = array.length;
if (len <= 1)
{
return array;
}
// Rather than dividing input, simply iterate chunks of 1, 2, 4, 8, etc.
// Chunks are the size of the left or right hand in merge sort.
// Stop when the left-hand covers all of the array.
var buffer = new Array(len);
for (var chk = 1; chk < len; chk *= 2)
{
RunPass(array, compare, chk, buffer);
var tmp = array;
array = buffer;
buffer = tmp;
}
return array;
}
/**
* Run a single pass with the given chunk size.
*
* @ignore
*
* @param {array} arr - The array to run the pass on.
* @param {function} comp - The comparison function.
* @param {number} chk - The chunk size for this pass, i.e. the size of each partition being merged.
* @param {array} result - The array to store the result in.
*/
function RunPass (arr, comp, chk, result)
{
var len = arr.length;
var i = 0;
// Step size / double chunk size.
var dbl = chk * 2;
// Bounds of the left and right chunks.
var l, r, e;
// Iterators over the left and right chunk.
var li, ri;
// Iterate over pairs of chunks.
for (l = 0; l < len; l += dbl)
{
r = l + chk;
e = r + chk;
if (r > len)
{
r = len;
}
if (e > len)
{
e = len;
}
// Iterate both chunks in parallel.
li = l;
ri = r;
while (true)
{
// Compare the chunks.
if (li < r && ri < e)
{
// This works for a regular `sort()` compatible comparator,
// but also for a simple comparator like: `a > b`
if (comp(arr[li], arr[ri]) <= 0)
{
result[i++] = arr[li++];
}
else
{
result[i++] = arr[ri++];
}
}
else if (li < r)
{
// Nothing to compare, just flush what's left.
result[i++] = arr[li++];
}
else if (ri < e)
{
result[i++] = arr[ri++];
}
else
{
// Both iterators are at the chunk ends.
break;
}
}
}
}
/**
* An in-place stable array sort, because `Array#sort()` is not guaranteed stable.
*
* This is an implementation of merge sort, without recursion.
*
* Function based on the Two-Screen/stable sort 0.1.8 from https://github.com/Two-Screen/stable
*
* @function Phaser.Utils.Array.StableSort
* @since 3.0.0
*
* @param {array} array - The input array to be sorted.
* @param {function} [compare] - The comparison function.
*
* @return {array} The sorted result.
*/
var StableSort = function (array, compare)
{
if (compare === undefined) { compare = Compare; }
// Short-circuit when there's nothing to sort.
if (!array || array.length < 2)
{
return array;
}
if (Device.features.stableSort)
{
return array.sort(compare);
}
var result = Process(array, compare);
// This simply copies back if the result isn't in the original array, which happens on an odd number of passes.
if (result !== array)
{
RunPass(result, null, array.length, array);
}
return array;
};
module.exports = StableSort;