|
129 | 129 | };
|
130 | 130 | }
|
131 | 131 |
|
| 132 | + function compareStringsByCodePoints(a, b) { |
| 133 | + var ia = 0; |
| 134 | + var ib = 0; |
| 135 | + while (true) { |
| 136 | + // Offset each code point by 1, leaving 0 for end of string. |
| 137 | + var aCodePoint = (a.codePointAt(ia) + 1) || 0; |
| 138 | + var bCodePoint = (b.codePointAt(ib) + 1) || 0; |
| 139 | + var result = aCodePoint - bCodePoint; |
| 140 | + if (result) { |
| 141 | + return result; |
| 142 | + } else if (!aCodePoint) { |
| 143 | + // Having reached the end of both strings, they must be equal. |
| 144 | + return 0; |
| 145 | + } |
| 146 | + // Increment each index by the right amount. |
| 147 | + ia += aCodePoint <= 0xFFFF ? 1 : 2; |
| 148 | + ib += bCodePoint <= 0xFFFF ? 1 : 2; |
| 149 | + } |
| 150 | + } |
| 151 | + |
132 | 152 | // Type constants used to define functions.
|
133 | 153 | var TYPE_NUMBER = 0;
|
134 | 154 | var TYPE_ANY = 1;
|
|
1334 | 1354 | _functionReverse: function(resolvedArgs) {
|
1335 | 1355 | var typeName = this._getTypeName(resolvedArgs[0]);
|
1336 | 1356 | if (typeName === TYPE_STRING) {
|
1337 |
| - var originalStr = resolvedArgs[0]; |
1338 |
| - var reversedStr = ""; |
1339 |
| - for (var i = originalStr.length - 1; i >= 0; i--) { |
1340 |
| - reversedStr += originalStr[i]; |
1341 |
| - } |
1342 |
| - return reversedStr; |
| 1357 | + return Array.from(resolvedArgs[0]).reverse().join(""); |
1343 | 1358 | } else {
|
1344 | 1359 | var reversedArray = resolvedArgs[0].slice(0);
|
1345 | 1360 | reversedArray.reverse();
|
|
1374 | 1389 |
|
1375 | 1390 | _functionLength: function(resolvedArgs) {
|
1376 | 1391 | if (!isObject(resolvedArgs[0])) {
|
1377 |
| - return resolvedArgs[0].length; |
| 1392 | + return Array.from(resolvedArgs[0]).length; |
1378 | 1393 | } else {
|
1379 | 1394 | // As far as I can tell, there's no way to get the length
|
1380 | 1395 | // of an object without O(n) iteration through the object.
|
|
1533 | 1548 |
|
1534 | 1549 | _functionSort: function(resolvedArgs) {
|
1535 | 1550 | var sortedArray = resolvedArgs[0].slice(0);
|
1536 |
| - sortedArray.sort(); |
| 1551 | + if (sortedArray.length === 0) { |
| 1552 | + return sortedArray; |
| 1553 | + } |
| 1554 | + if (this._getTypeName(sortedArray[0]) === TYPE_STRING) { |
| 1555 | + sortedArray.sort(compareStringsByCodePoints); |
| 1556 | + } else { |
| 1557 | + sortedArray.sort(); |
| 1558 | + } |
1537 | 1559 | return sortedArray;
|
1538 | 1560 | },
|
1539 | 1561 |
|
|
1573 | 1595 | "TypeError: expected " + requiredType + ", received " +
|
1574 | 1596 | that._getTypeName(exprB));
|
1575 | 1597 | }
|
1576 |
| - if (exprA > exprB) { |
| 1598 | + if (requiredType === TYPE_STRING) { |
| 1599 | + return compareStringsByCodePoints(exprA, exprB) || a[0] - b[0]; |
| 1600 | + } else if (exprA > exprB) { |
1577 | 1601 | return 1;
|
1578 | 1602 | } else if (exprA < exprB) {
|
1579 | 1603 | return -1;
|
|
0 commit comments