123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- //! stable.js 0.1.8, https://github.com/Two-Screen/stable
- //! © 2018 Angry Bytes and contributors. MIT licensed.
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global.stable = factory());
- }(this, (function () { 'use strict';
- // A stable array sort, because `Array#sort()` is not guaranteed stable.
- // This is an implementation of merge sort, without recursion.
- var stable = function (arr, comp) {
- return exec(arr.slice(), comp)
- };
- stable.inplace = function (arr, comp) {
- var result = exec(arr, comp);
- // This simply copies back if the result isn't in the original array,
- // which happens on an odd number of passes.
- if (result !== arr) {
- pass(result, null, arr.length, arr);
- }
- return arr
- };
- // Execute the sort using the input array and a second buffer as work space.
- // Returns one of those two, containing the final result.
- function exec(arr, comp) {
- if (typeof(comp) !== 'function') {
- comp = function (a, b) {
- return String(a).localeCompare(b)
- };
- }
- // Short-circuit when there's nothing to sort.
- var len = arr.length;
- if (len <= 1) {
- return arr
- }
- // 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) {
- pass(arr, comp, chk, buffer);
- var tmp = arr;
- arr = buffer;
- buffer = tmp;
- }
- return arr
- }
- // Run a single pass with the given chunk size.
- var pass = function (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++];
- }
- }
- // Nothing to compare, just flush what's left.
- else if (li < r) {
- result[i++] = arr[li++];
- }
- else if (ri < e) {
- result[i++] = arr[ri++];
- }
- // Both iterators are at the chunk ends.
- else {
- break
- }
- }
- }
- };
- return stable;
- })));
|