{"ScriptPreparationCode":"const fastSortTS = () =\u003E {\r\n // \u003E\u003E\u003E INTERFACES \u003C\u003C\u003C\r\n // \u003E\u003E\u003E HELPERS \u003C\u003C\u003C\r\n const castComparer = (comparer) =\u003E (a, b, order) =\u003E comparer(a, b, order) * order;\r\n const throwInvalidConfigErrorIfTrue = function(condition, context) {\r\n if (condition)\r\n throw Error(\u0060Invalid sort config: ${context}\u0060);\r\n };\r\n const unpackObjectSorter = function(sortByObj) {\r\n const {\r\n asc,\r\n desc\r\n } = sortByObj || {};\r\n const order = asc ? 1 : -1;\r\n const sortBy = (asc || desc);\r\n // Validate object config\r\n throwInvalidConfigErrorIfTrue(!sortBy, \u0027Expected \u0060asc\u0060 or \u0060desc\u0060 property\u0027);\r\n throwInvalidConfigErrorIfTrue(asc \u0026\u0026 desc, \u0027Ambiguous object with \u0060asc\u0060 and \u0060desc\u0060 config properties\u0027);\r\n const comparer = sortByObj.comparer \u0026\u0026 castComparer(sortByObj.comparer);\r\n return {\r\n order,\r\n sortBy,\r\n comparer\r\n };\r\n };\r\n // \u003E\u003E\u003E SORTERS \u003C\u003C\u003C\r\n const multiPropertySorterProvider = function(defaultComparer) {\r\n return function multiPropertySorter(sortBy, sortByArr, depth, order, comparer, a, b) {\r\n let valA;\r\n let valB;\r\n if (typeof sortBy === \u0027string\u0027) {\r\n valA = a[sortBy];\r\n valB = b[sortBy];\r\n } else if (typeof sortBy === \u0027function\u0027) {\r\n valA = sortBy(a);\r\n valB = sortBy(b);\r\n } else {\r\n const objectSorterConfig = unpackObjectSorter(sortBy);\r\n return multiPropertySorter(objectSorterConfig.sortBy, sortByArr, depth, objectSorterConfig.order, objectSorterConfig.comparer || defaultComparer, a, b);\r\n }\r\n const equality = comparer(valA, valB, order);\r\n if ((equality === 0 || (valA == null \u0026\u0026 valB == null)) \u0026\u0026\r\n sortByArr.length \u003E depth) {\r\n return multiPropertySorter(sortByArr[depth], sortByArr, depth \u002B 1, order, comparer, a, b);\r\n }\r\n return equality;\r\n };\r\n };\r\n\r\n function getSortStrategy(sortBy, comparer, order) {\r\n // Flat array sorter\r\n if (sortBy === undefined || sortBy === true) {\r\n return (a, b) =\u003E comparer(a, b, order);\r\n }\r\n // Sort list of objects by single object key\r\n if (typeof sortBy === \u0027string\u0027) {\r\n throwInvalidConfigErrorIfTrue(sortBy.includes(\u0027.\u0027), \u0027String syntax not allowed for nested properties.\u0027);\r\n return (a, b) =\u003E comparer(a[sortBy], b[sortBy], order);\r\n }\r\n // Sort list of objects by single function sorter\r\n if (typeof sortBy === \u0027function\u0027) {\r\n return (a, b) =\u003E comparer(sortBy(a), sortBy(b), order);\r\n }\r\n // Sort by multiple properties\r\n if (Array.isArray(sortBy)) {\r\n const multiPropSorter = multiPropertySorterProvider(comparer);\r\n return (a, b) =\u003E multiPropSorter(sortBy[0], sortBy, 1, order, comparer, a, b);\r\n }\r\n // Unpack object config to get actual sorter strategy\r\n const objectSorterConfig = unpackObjectSorter(sortBy);\r\n return getSortStrategy(objectSorterConfig.sortBy, objectSorterConfig.comparer || comparer, objectSorterConfig.order);\r\n }\r\n const sortArray = function(order, ctx, sortBy, comparer) {\r\n if (!Array.isArray(ctx)) {\r\n return ctx;\r\n }\r\n // Unwrap sortBy if array with only 1 value to get faster sort strategy\r\n if (Array.isArray(sortBy) \u0026\u0026 sortBy.length \u003C 2) {\r\n [sortBy] = sortBy;\r\n }\r\n return ctx.sort(getSortStrategy(sortBy, comparer, order));\r\n };\r\n\r\n function createNewSortInstance(opts) {\r\n const comparer = castComparer(opts.comparer);\r\n return function(arrayToSort) {\r\n const ctx = Array.isArray(arrayToSort) \u0026\u0026 !opts.inPlaceSorting ?\r\n arrayToSort.slice() :\r\n arrayToSort;\r\n return {\r\n asc(sortBy) {\r\n return sortArray(1, ctx, sortBy, comparer);\r\n },\r\n desc(sortBy) {\r\n return sortArray(-1, ctx, sortBy, comparer);\r\n },\r\n by(sortBy) {\r\n return sortArray(1, ctx, sortBy, comparer);\r\n },\r\n };\r\n };\r\n }\r\n const defaultComparer = (a, b, order) =\u003E {\r\n if (a == null)\r\n return order;\r\n if (b == null)\r\n return -order;\r\n if (typeof a !== typeof b) {\r\n return typeof a \u003C typeof b ? -1 : 1;\r\n }\r\n if (a \u003C b)\r\n return -1;\r\n if (a \u003E b)\r\n return 1;\r\n return 0;\r\n };\r\n return createNewSortInstance({\r\n comparer: defaultComparer,\r\n });\r\n\r\n}\r\n\r\n\r\n\r\n\r\nconst {\r\n isArray\r\n} = Array\r\n\r\nconst castComparer = (comparer) =\u003E (a, b, order) =\u003E comparer(a, b, order) * order\r\n\r\nconst throwInvalidConfigErrorIfTrue = (condition, context) =\u003E {\r\n if (condition) throw Error(\u0060Invalid sort config: ${context}\u0060)\r\n}\r\n\r\nconst unpackObjectSorter = (sortByObj) =\u003E {\r\n const {\r\n asc,\r\n desc\r\n } = sortByObj || {}\r\n\r\n const sortBy = (asc || desc)\r\n // Validate object config\r\n throwInvalidConfigErrorIfTrue(!sortBy, \u0027Expected \u0060asc\u0060 or \u0060desc\u0060 property\u0027)\r\n throwInvalidConfigErrorIfTrue(asc \u0026\u0026 desc, \u0027Ambiguous object with \u0060asc\u0060 and \u0060desc\u0060 config properties\u0027)\r\n\r\n return {\r\n order: asc ? 1 : -1,\r\n sortBy,\r\n comparer: sortByObj.comparer \u0026\u0026 castComparer(sortByObj.comparer)\r\n }\r\n}\r\n\r\n// \u003E\u003E\u003E SORTERS \u003C\u003C\u003C\r\nconst multiPropertySorterProvider = (defaultComparer) =\u003E {\r\n const multiPropertySorter = (sortBy, sortByArr, depth, order, comparer, a, b) =\u003E {\r\n const type = typeof sortBy\r\n let valA;\r\n let valB;\r\n if (type === \u0027string\u0027) {\r\n valA = a[sortBy];\r\n valB = b[sortBy];\r\n } else if (type === \u0027function\u0027) {\r\n valA = sortBy(a);\r\n valB = sortBy(b);\r\n } else {\r\n const objectSorterConfig = unpackObjectSorter(sortBy);\r\n return multiPropertySorter(objectSorterConfig.sortBy, sortByArr, depth, objectSorterConfig.order, objectSorterConfig.comparer || defaultComparer, a, b);\r\n }\r\n const equality = comparer(valA, valB, order);\r\n if ((equality === 0 || (valA == null \u0026\u0026 valB == null)) \u0026\u0026\r\n sortByArr.length \u003E depth) {\r\n return multiPropertySorter(sortByArr[depth], sortByArr, depth \u002B 1, order, comparer, a, b);\r\n }\r\n return equality\r\n }\r\n return multiPropertySorter\r\n}\r\n\r\nconst getSortStrategy = (sortBy, comparer, order) =\u003E {\r\n const type = typeof sortBy\r\n // Flat array sorter\r\n if (sortBy === undefined || sortBy === true) return (a, b) =\u003E comparer(a, b, order);\r\n\r\n // Sort list of objects by single object key\r\n if (type === \u0027string\u0027) {\r\n throwInvalidConfigErrorIfTrue(sortBy.includes(\u0027.\u0027), \u0027String syntax not allowed for nested properties.\u0027)\r\n return (a, b) =\u003E comparer(a[sortBy], b[sortBy], order)\r\n }\r\n // Sort list of objects by single function sorter\r\n if (type === \u0027function\u0027) return (a, b) =\u003E comparer(sortBy(a), sortBy(b), order)\r\n\r\n // Sort by multiple properties\r\n if (isArray(sortBy)) {\r\n const multiPropSorter = multiPropertySorterProvider(comparer)\r\n return (a, b) =\u003E multiPropSorter(sortBy[0], sortBy, 1, order, comparer, a, b);\r\n }\r\n // Unpack object config to get actual sorter strategy\r\n const objectSorterConfig = unpackObjectSorter(sortBy)\r\n return getSortStrategy(objectSorterConfig.sortBy, objectSorterConfig.comparer || comparer, objectSorterConfig.order)\r\n}\r\n\r\nconst sortArray = (order, ctx, sortBy, comparer) =\u003E {\r\n if (!isArray(ctx)) return ctx\r\n if (isArray(sortBy) \u0026\u0026 sortBy.length \u003C 2)[sortBy] = sortBy\r\n\r\n return ctx.sort(getSortStrategy(sortBy, comparer, order))\r\n}\r\n\r\nconst createNewSortInstance = (opts) =\u003E {\r\n const comparer = castComparer(opts.comparer)\r\n return (arrayToSort) =\u003E {\r\n const ctx = isArray(arrayToSort) \u0026\u0026 !opts.inPlaceSorting ? arrayToSort.slice() : arrayToSort;\r\n return {\r\n asc: (sortBy) =\u003E sortArray(1, ctx, sortBy, comparer),\r\n desc: (sortBy) =\u003E sortArray(-1, ctx, sortBy, comparer),\r\n by: sortBy =\u003E sortArray(1, ctx, sortBy, comparer),\r\n }\r\n }\r\n}\r\n\r\nconst defaultComparer = (a, b, order) =\u003E {\r\n if (a == null) return order\r\n if (b == null) return -order\r\n if (typeof a !== typeof b) return typeof a \u003C typeof b ? -1 : 1\r\n\r\n if (a \u003C b) return -1\r\n if (a \u003E b) return 1\r\n return 0\r\n}\r\n\r\nvar sort = createNewSortInstance({\r\n comparer: defaultComparer,\r\n})\r\nvar sortTS = fastSortTS()\r\n\r\n\r\nfunction runTests(sort) {\r\n sort([1, 4, 2]).asc()\r\n sort([1, 4, 2]).by({\r\n asc: true\r\n })\r\n sort([1, 4, 2]).desc()\r\n sort([1, 4, 2]).by({\r\n desc: true\r\n })\r\n}","TestCases":[{"Name":"JS fast-sort","Code":"for(let i = 0; i \u003C 10000; i\u002B\u002B){\r\n runTests(sort)\r\n}","IsDeferred":false},{"Name":"TS fast-sort","Code":"for(let i = 0; i \u003C 10000; i\u002B\u002B){\r\n runTests(sortTS)\r\n}","IsDeferred":false}]}