From a56b28979eab72e0bfd90c8f85b2cf5f2806f25f Mon Sep 17 00:00:00 2001 From: Denis Pushkarev Date: Fri, 4 Jun 2021 10:33:11 +0700 Subject: [PATCH] improve polyfill of stable sort --- packages/core-js/internals/array-sort.js | 32 ++++++++++++++++--- .../core-js/internals/engine-ff-version.js | 5 +++ .../core-js/internals/engine-is-ie-or-edge.js | 3 ++ .../internals/engine-webkit-version.js | 5 +++ .../object-prototype-accessors-forced.js | 5 ++- .../core-js/modules/es.typed-array.sort.js | 10 ++++++ 6 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 packages/core-js/internals/engine-ff-version.js create mode 100644 packages/core-js/internals/engine-is-ie-or-edge.js create mode 100644 packages/core-js/internals/engine-webkit-version.js diff --git a/packages/core-js/internals/array-sort.js b/packages/core-js/internals/array-sort.js index 7e4af389b92e..dd9f9057ba40 100644 --- a/packages/core-js/internals/array-sort.js +++ b/packages/core-js/internals/array-sort.js @@ -4,6 +4,10 @@ var toObject = require('../internals/to-object'); var toLength = require('../internals/to-length'); var fails = require('../internals/fails'); var arrayMethodIsStrict = require('../internals/array-method-is-strict'); +var FF = require('../internals/engine-ff-version'); +var IE_OR_EDGE = require('../internals/engine-is-ie-or-edge'); +var V8 = require('../internals/engine-v8-version'); +var WEBKIT = require('../internals/engine-webkit-version'); var test = []; var nativeSort = test.sort; @@ -21,6 +25,12 @@ var FAILS_ON_NULL = fails(function () { var STRICT_METHOD = arrayMethodIsStrict('sort'); var STABLE_SORT = !fails(function () { + // feature detection can be too slow, so check engines versions + if (V8) return V8 < 70; + if (FF && FF > 3) return; + if (IE_OR_EDGE) return true; + if (WEBKIT) return WEBKIT < 603; + var result = ''; var code, chr, value, index; @@ -53,14 +63,28 @@ var FORCED = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD || !STABLE_S var mergeSort = function (array, comparefn) { var length = array.length; var middle = floor(length / 2); - if (length < 2) return array; - return merge( + return length < 8 ? insertionSort(array, comparefn) : merge( mergeSort(array.slice(0, middle), comparefn), mergeSort(array.slice(middle), comparefn), comparefn ); }; +var insertionSort = function (array, comparefn) { + var length = array.length; + var i = 1; + var element, j; + + while (i < length) { + j = i; + element = array[i]; + while (j && sortCompare(array[j - 1], element, comparefn) > 0) { + array[j] = array[--j]; + } + if (j !== i++) array[j] = element; + } return array; +}; + var merge = function (left, right, comparefn) { var llength = left.length; var rlength = right.length; @@ -78,9 +102,8 @@ var merge = function (left, right, comparefn) { }; var sortCompare = function (x, y, comparefn) { - if (x === undefined && y === undefined) return 0; - if (x === undefined) return 1; if (y === undefined) return -1; + if (x === undefined) return 1; if (comparefn !== undefined) { return +comparefn(x, y) || 0; } return String(x) > String(y) ? 1 : -1; @@ -103,6 +126,7 @@ module.exports = FORCED ? function sort(comparefn) { if (index in array) items.push(array[index]); } + // TODO: use something more complex like timsort? items = mergeSort(items, comparefn); itemsLength = items.length; index = 0; diff --git a/packages/core-js/internals/engine-ff-version.js b/packages/core-js/internals/engine-ff-version.js new file mode 100644 index 000000000000..83ba0ffb9e45 --- /dev/null +++ b/packages/core-js/internals/engine-ff-version.js @@ -0,0 +1,5 @@ +var userAgent = require('../internals/engine-user-agent'); + +var firefox = userAgent.match(/firefox\/(\d+)/i); + +module.exports = !!firefox && +firefox[1]; diff --git a/packages/core-js/internals/engine-is-ie-or-edge.js b/packages/core-js/internals/engine-is-ie-or-edge.js new file mode 100644 index 000000000000..813c745eda81 --- /dev/null +++ b/packages/core-js/internals/engine-is-ie-or-edge.js @@ -0,0 +1,3 @@ +var UA = require('../internals/engine-user-agent'); + +module.exports = /MSIE|Trident/.test(UA); diff --git a/packages/core-js/internals/engine-webkit-version.js b/packages/core-js/internals/engine-webkit-version.js new file mode 100644 index 000000000000..55f7d47807bd --- /dev/null +++ b/packages/core-js/internals/engine-webkit-version.js @@ -0,0 +1,5 @@ +var userAgent = require('../internals/engine-user-agent'); + +var webkit = userAgent.match(/AppleWebKit\/(\d+)\./); + +module.exports = !!webkit && +webkit[1]; diff --git a/packages/core-js/internals/object-prototype-accessors-forced.js b/packages/core-js/internals/object-prototype-accessors-forced.js index fb45bd2f212c..2d65faa9aa05 100644 --- a/packages/core-js/internals/object-prototype-accessors-forced.js +++ b/packages/core-js/internals/object-prototype-accessors-forced.js @@ -2,14 +2,13 @@ var IS_PURE = require('../internals/is-pure'); var global = require('../internals/global'); var fails = require('../internals/fails'); -var userAgent = require('../internals/engine-user-agent'); +var WEBKIT = require('../internals/engine-webkit-version'); // Forced replacement object prototype accessors methods module.exports = IS_PURE || !fails(function () { // This feature detection crashes old WebKit // https://github.com/zloirock/core-js/issues/232 - var webkit = userAgent.match(/AppleWebKit\/(\d+)\./); - if (webkit && +webkit[1] < 535) return; + if (WEBKIT && WEBKIT < 535) return; var key = Math.random(); // In FF throws only define methods // eslint-disable-next-line no-undef, no-useless-call -- required for testing diff --git a/packages/core-js/modules/es.typed-array.sort.js b/packages/core-js/modules/es.typed-array.sort.js index a22e95b09b59..f234c12adf0f 100644 --- a/packages/core-js/modules/es.typed-array.sort.js +++ b/packages/core-js/modules/es.typed-array.sort.js @@ -2,11 +2,21 @@ var ArrayBufferViewCore = require('../internals/array-buffer-view-core'); var fails = require('../internals/fails'); var $sort = require('../internals/array-sort'); +var FF = require('../internals/engine-ff-version'); +var IE_OR_EDGE = require('../internals/engine-is-ie-or-edge'); +var V8 = require('../internals/engine-v8-version'); +var WEBKIT = require('../internals/engine-webkit-version'); var aTypedArray = ArrayBufferViewCore.aTypedArray; var exportTypedArrayMethod = ArrayBufferViewCore.exportTypedArrayMethod; var STABLE_SORT = !fails(function () { + // feature detection can be too slow, so check engines versions + if (V8) return V8 < 73; + if (FF) return FF < 67; + if (IE_OR_EDGE) return true; + if (WEBKIT) return WEBKIT < 602; + // eslint-disable-next-line es/no-typed-arrays -- required for testing var array = new Uint16Array(516); var expected = Array(516);