|
| 1 | +'use strict'; |
| 2 | +var aFunction = require('../internals/a-function'); |
| 3 | +var toObject = require('../internals/to-object'); |
| 4 | +var toLength = require('../internals/to-length'); |
| 5 | +var fails = require('../internals/fails'); |
| 6 | +var arrayMethodIsStrict = require('../internals/array-method-is-strict'); |
| 7 | + |
| 8 | +var test = []; |
| 9 | +var nativeSort = test.sort; |
| 10 | +var floor = Math.floor; |
| 11 | + |
| 12 | +// IE8- |
| 13 | +var FAILS_ON_UNDEFINED = fails(function () { |
| 14 | + test.sort(undefined); |
| 15 | +}); |
| 16 | +// V8 bug |
| 17 | +var FAILS_ON_NULL = fails(function () { |
| 18 | + test.sort(null); |
| 19 | +}); |
| 20 | +// Old WebKit |
| 21 | +var STRICT_METHOD = arrayMethodIsStrict('sort'); |
| 22 | + |
| 23 | +var STABLE_SORT = !fails(function () { |
| 24 | + var result = ''; |
| 25 | + var code, chr, value, index; |
| 26 | + |
| 27 | + // generate an array with more 512 elements (Chakra and old V8 fails only in this case) |
| 28 | + for (code = 65; code < 76; code++) { |
| 29 | + chr = String.fromCharCode(code); |
| 30 | + switch (code) { |
| 31 | + case 66: case 69: case 70: case 72: value = 3; break; |
| 32 | + case 68: case 71: value = 4; break; |
| 33 | + default: value = 2; |
| 34 | + } |
| 35 | + |
| 36 | + for (index = 0; index < 47; index++) { |
| 37 | + test.push({ k: chr + index, v: value }); |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | + test.sort(function (a, b) { return b.v - a.v; }); |
| 42 | + |
| 43 | + for (index = 0; index < test.length; index++) { |
| 44 | + chr = test[index].k.charAt(0); |
| 45 | + if (result.charAt(result.length - 1) !== chr) result += chr; |
| 46 | + } |
| 47 | + |
| 48 | + return result !== 'DGBEFHACIJK'; |
| 49 | +}); |
| 50 | + |
| 51 | +var FORCED = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD || !STABLE_SORT; |
| 52 | + |
| 53 | +var mergeSort = function (array, comparefn) { |
| 54 | + var length = array.length; |
| 55 | + var middle = floor(length / 2); |
| 56 | + if (length < 2) return array; |
| 57 | + return merge( |
| 58 | + mergeSort(array.slice(0, middle), comparefn), |
| 59 | + mergeSort(array.slice(middle), comparefn), |
| 60 | + comparefn |
| 61 | + ); |
| 62 | +}; |
| 63 | + |
| 64 | +var merge = function (left, right, comparefn) { |
| 65 | + var llength = left.length; |
| 66 | + var rlength = right.length; |
| 67 | + var lindex = 0; |
| 68 | + var rindex = 0; |
| 69 | + var result = []; |
| 70 | + |
| 71 | + while (lindex < llength || rindex < rlength) { |
| 72 | + if (lindex < llength && rindex < rlength) { |
| 73 | + result.push(sortCompare(left[lindex], right[rindex], comparefn) <= 0 ? left[lindex++] : right[rindex++]); |
| 74 | + } else { |
| 75 | + result.push(lindex < llength ? left[lindex++] : right[rindex++]); |
| 76 | + } |
| 77 | + } return result; |
| 78 | +}; |
| 79 | + |
| 80 | +var sortCompare = function (x, y, comparefn) { |
| 81 | + if (x === undefined && y === undefined) return 0; |
| 82 | + if (x === undefined) return 1; |
| 83 | + if (y === undefined) return -1; |
| 84 | + if (comparefn !== undefined) { |
| 85 | + return +comparefn(x, y) || 0; |
| 86 | + } return String(x) > String(y) ? 1 : -1; |
| 87 | +}; |
| 88 | + |
| 89 | +// `Array.prototype.sort` method |
| 90 | +// https://tc39.es/ecma262/#sec-array.prototype.sort |
| 91 | +module.exports = FORCED ? function sort(comparefn) { |
| 92 | + if (comparefn !== undefined) aFunction(comparefn); |
| 93 | + |
| 94 | + var array = toObject(this); |
| 95 | + |
| 96 | + if (STABLE_SORT) return comparefn === undefined ? nativeSort.call(array) : nativeSort.call(array, comparefn); |
| 97 | + |
| 98 | + var items = []; |
| 99 | + var arrayLength = toLength(array.length); |
| 100 | + var itemsLength, index; |
| 101 | + |
| 102 | + for (index = 0; index < arrayLength; index++) { |
| 103 | + if (index in array) items.push(array[index]); |
| 104 | + } |
| 105 | + |
| 106 | + items = mergeSort(items, comparefn); |
| 107 | + itemsLength = items.length; |
| 108 | + index = 0; |
| 109 | + |
| 110 | + while (index < itemsLength) array[index] = items[index++]; |
| 111 | + while (index < arrayLength) delete array[index++]; |
| 112 | + |
| 113 | + return array; |
| 114 | +} : nativeSort; |
0 commit comments