Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 637 | 637 |
| 638 // Return the deleted elements. | 638 // Return the deleted elements. |
| 639 return deleted_elements; | 639 return deleted_elements; |
| 640 } | 640 } |
| 641 | 641 |
| 642 | 642 |
| 643 function ArraySort(comparefn) { | 643 function ArraySort(comparefn) { |
| 644 // In-place QuickSort algorithm. | 644 // In-place QuickSort algorithm. |
| 645 // For short (length <= 22) arrays, insertion sort is used for efficiency. | 645 // For short (length <= 22) arrays, insertion sort is used for efficiency. |
| 646 | 646 |
| 647 var custom_compare = IS_FUNCTION(comparefn); | 647 function InsertionSortWithFunc(a, from, to) { |
| 648 for (var i = from + 1; i < to; i++) { | |
| 649 var element = a[i]; | |
|
Lasse Reichstein
2010/04/07 17:43:27
Come to think of it, using binary search seems ove
antonm
2010/04/07 17:47:27
Agree. That's the thing I implemented in C++, but
| |
| 650 // place element in a[from..i[ | |
| 651 // binary search | |
| 652 var min = from; | |
| 653 var max = i; | |
| 654 // The search interval is a[min..max[ | |
| 655 while (min < max) { | |
| 656 var mid = min + ((max - min) >> 1); | |
| 657 var order = (a[mid] === element) ? | |
| 658 0 : comparefn.call(null, a[mid], element); | |
|
Lasse Reichstein
2010/04/07 17:43:27
Reading a[mid] twice. Maybe assign to temporary va
antonm
2010/04/07 17:47:27
Thanks, will give it a try.
| |
| 659 if (order == 0) { | |
| 660 min = max = mid; | |
|
Lasse Reichstein
2010/04/07 17:43:27
No need to assign to max.
antonm
2010/04/07 17:47:27
Will give it a try as well.
| |
| 661 break; | |
| 662 } | |
| 663 if (order < 0) { | |
| 664 min = mid + 1; | |
| 665 } else { | |
| 666 max = mid; | |
| 667 } | |
| 668 } | |
| 669 // place element at position min==max. | |
| 670 for (var j = i; j > min; j--) { | |
| 671 a[j] = a[j - 1]; | |
| 672 } | |
| 673 a[min] = element; | |
| 674 } | |
| 675 } | |
| 676 | |
| 677 function QuickSortWithFunc(a, from, to) { | |
| 678 // Insertion sort is faster for short arrays. | |
| 679 if (to - from <= 22) { | |
| 680 InsertionSortWithFunc(a, from, to); | |
| 681 return; | |
| 682 } | |
| 683 var pivot_index = $floor($random() * (to - from)) + from; | |
| 684 var pivot = a[pivot_index]; | |
| 685 // Issue 95: Keep the pivot element out of the comparisons to avoid | |
| 686 // infinite recursion if comparefn(pivot, pivot) != 0. | |
| 687 a[pivot_index] = a[from]; | |
| 688 a[from] = pivot; | |
| 689 var low_end = from; // Upper bound of the elements lower than pivot. | |
| 690 var high_start = to; // Lower bound of the elements greater than pivot. | |
| 691 // From low_end to i are elements equal to pivot. | |
| 692 // From i to high_start are elements that haven't been compared yet. | |
| 693 for (var i = from + 1; i < high_start; ) { | |
| 694 var element = a[i]; | |
| 695 var order = (element === pivot) ? | |
| 696 0 : comparefn.call(null, element, pivot); | |
| 697 if (order < 0) { | |
| 698 a[i] = a[low_end]; | |
| 699 a[low_end] = element; | |
| 700 i++; | |
| 701 low_end++; | |
| 702 } else if (order > 0) { | |
| 703 high_start--; | |
| 704 a[i] = a[high_start]; | |
| 705 a[high_start] = element; | |
| 706 } else { // order == 0 | |
| 707 i++; | |
| 708 } | |
| 709 } | |
| 710 QuickSortWithFunc(a, from, low_end); | |
| 711 QuickSortWithFunc(a, high_start, to); | |
| 712 } | |
| 648 | 713 |
| 649 function Compare(x,y) { | 714 function Compare(x,y) { |
| 650 // Assume the comparefn, if any, is a consistent comparison function. | 715 // Assume the comparefn, if any, is a consistent comparison function. |
| 651 // If it isn't, we are allowed arbitrary behavior by ECMA 15.4.4.11. | 716 // If it isn't, we are allowed arbitrary behavior by ECMA 15.4.4.11. |
|
Lasse Reichstein
2010/04/07 17:43:27
Comment doesn't make sense any more (not here, at
antonm
2010/04/07 17:47:27
Agree. Will remove.
| |
| 652 if (x === y) return 0; | 717 if (x === y) return 0; |
| 653 if (custom_compare) { | |
| 654 // Don't call directly to avoid exposing the builtin's global object. | |
| 655 return comparefn.call(null, x, y); | |
| 656 } | |
| 657 if (%_IsSmi(x) && %_IsSmi(y)) { | 718 if (%_IsSmi(x) && %_IsSmi(y)) { |
| 658 return %SmiLexicographicCompare(x, y); | 719 return %SmiLexicographicCompare(x, y); |
| 659 } | 720 } |
| 660 x = ToString(x); | 721 x = ToString(x); |
| 661 y = ToString(y); | 722 y = ToString(y); |
| 662 if (x == y) return 0; | 723 if (x == y) return 0; |
| 663 else return x < y ? -1 : 1; | 724 else return x < y ? -1 : 1; |
| 664 }; | 725 }; |
| 665 | 726 |
| 666 function InsertionSort(a, from, to) { | 727 function InsertionSort(a, from, to) { |
| 667 for (var i = from + 1; i < to; i++) { | 728 for (var i = from + 1; i < to; i++) { |
| 668 var element = a[i]; | 729 var element = a[i]; |
| 669 // Pre-convert the element to a string for comparison if we know | 730 // Pre-convert the element to a string for comparison if we know |
| 670 // it will happen on each compare anyway. | 731 // it will happen on each compare anyway. |
| 671 var key = | 732 var key = %_IsSmi(element) ? element : ToString(element); |
| 672 (custom_compare || %_IsSmi(element)) ? element : ToString(element); | |
| 673 // place element in a[from..i[ | 733 // place element in a[from..i[ |
| 674 // binary search | 734 // binary search |
| 675 var min = from; | 735 var min = from; |
| 676 var max = i; | 736 var max = i; |
| 677 // The search interval is a[min..max[ | 737 // The search interval is a[min..max[ |
| 678 while (min < max) { | 738 while (min < max) { |
| 679 var mid = min + ((max - min) >> 1); | 739 var mid = min + ((max - min) >> 1); |
| 680 var order = Compare(a[mid], key); | 740 var order = Compare(a[mid], key); |
| 681 if (order == 0) { | 741 if (order == 0) { |
| 682 min = max = mid; | 742 min = max = mid; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 699 function QuickSort(a, from, to) { | 759 function QuickSort(a, from, to) { |
| 700 // Insertion sort is faster for short arrays. | 760 // Insertion sort is faster for short arrays. |
| 701 if (to - from <= 22) { | 761 if (to - from <= 22) { |
| 702 InsertionSort(a, from, to); | 762 InsertionSort(a, from, to); |
| 703 return; | 763 return; |
| 704 } | 764 } |
| 705 var pivot_index = $floor($random() * (to - from)) + from; | 765 var pivot_index = $floor($random() * (to - from)) + from; |
| 706 var pivot = a[pivot_index]; | 766 var pivot = a[pivot_index]; |
| 707 // Pre-convert the element to a string for comparison if we know | 767 // Pre-convert the element to a string for comparison if we know |
| 708 // it will happen on each compare anyway. | 768 // it will happen on each compare anyway. |
| 709 var pivot_key = | 769 var pivot_key = %_IsSmi(pivot) ? pivot : ToString(pivot); |
| 710 (custom_compare || %_IsSmi(pivot)) ? pivot : ToString(pivot); | |
| 711 // Issue 95: Keep the pivot element out of the comparisons to avoid | 770 // Issue 95: Keep the pivot element out of the comparisons to avoid |
| 712 // infinite recursion if comparefn(pivot, pivot) != 0. | 771 // infinite recursion if comparefn(pivot, pivot) != 0. |
| 713 a[pivot_index] = a[from]; | 772 a[pivot_index] = a[from]; |
| 714 a[from] = pivot; | 773 a[from] = pivot; |
| 715 var low_end = from; // Upper bound of the elements lower than pivot. | 774 var low_end = from; // Upper bound of the elements lower than pivot. |
| 716 var high_start = to; // Lower bound of the elements greater than pivot. | 775 var high_start = to; // Lower bound of the elements greater than pivot. |
| 717 // From low_end to i are elements equal to pivot. | 776 // From low_end to i are elements equal to pivot. |
| 718 // From i to high_start are elements that haven't been compared yet. | 777 // From i to high_start are elements that haven't been compared yet. |
| 719 for (var i = from + 1; i < high_start; ) { | 778 for (var i = from + 1; i < high_start; ) { |
| 720 var element = a[i]; | 779 var element = a[i]; |
| 721 var order = Compare(element, pivot_key); | 780 var order = Compare(element, pivot_key); |
| 722 if (order < 0) { | 781 if (order < 0) { |
| 723 a[i] = a[low_end]; | 782 a[i] = a[low_end]; |
| 724 a[low_end] = element; | 783 a[low_end] = element; |
| 725 i++; | 784 i++; |
| 726 low_end++; | 785 low_end++; |
| 727 } else if (order > 0) { | 786 } else if (order > 0) { |
| 728 high_start--; | 787 high_start--; |
| 729 a[i] = a[high_start]; | 788 a[i] = a[high_start]; |
| 730 a[high_start] = element; | 789 a[high_start] = element; |
| 731 } else { // order == 0 | 790 } else { // order == 0 |
| 732 i++; | 791 i++; |
| 733 } | 792 } |
| 734 } | 793 } |
| 735 QuickSort(a, from, low_end); | 794 QuickSort(a, from, low_end); |
| 736 QuickSort(a, high_start, to); | 795 QuickSort(a, high_start, to); |
| 737 } | 796 } |
| 738 | 797 |
| 739 var length; | |
| 740 | |
| 741 // Copies elements in the range 0..length from obj's prototype chain | 798 // Copies elements in the range 0..length from obj's prototype chain |
| 742 // to obj itself, if obj has holes. Returns one more than the maximal index | 799 // to obj itself, if obj has holes. Returns one more than the maximal index |
| 743 // of a prototype property. | 800 // of a prototype property. |
| 744 function CopyFromPrototype(obj, length) { | 801 function CopyFromPrototype(obj, length) { |
| 745 var max = 0; | 802 var max = 0; |
| 746 for (var proto = obj.__proto__; proto; proto = proto.__proto__) { | 803 for (var proto = obj.__proto__; proto; proto = proto.__proto__) { |
| 747 var indices = %GetArrayKeys(proto, length); | 804 var indices = %GetArrayKeys(proto, length); |
| 748 if (indices.length > 0) { | 805 if (indices.length > 0) { |
| 749 if (indices[0] == -1) { | 806 if (indices[0] == -1) { |
| 750 // It's an interval. | 807 // It's an interval. |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 848 obj[i] = void 0; | 905 obj[i] = void 0; |
| 849 } else { | 906 } else { |
| 850 delete obj[i]; | 907 delete obj[i]; |
| 851 } | 908 } |
| 852 } | 909 } |
| 853 | 910 |
| 854 // Return the number of defined elements. | 911 // Return the number of defined elements. |
| 855 return first_undefined; | 912 return first_undefined; |
| 856 } | 913 } |
| 857 | 914 |
| 858 length = TO_UINT32(this.length); | 915 var length = TO_UINT32(this.length); |
| 859 if (length < 2) return this; | 916 if (length < 2) return this; |
| 860 | 917 |
| 861 var is_array = IS_ARRAY(this); | 918 var is_array = IS_ARRAY(this); |
| 862 var max_prototype_element; | 919 var max_prototype_element; |
| 863 if (!is_array) { | 920 if (!is_array) { |
| 864 // For compatibility with JSC, we also sort elements inherited from | 921 // For compatibility with JSC, we also sort elements inherited from |
| 865 // the prototype chain on non-Array objects. | 922 // the prototype chain on non-Array objects. |
| 866 // We do this by copying them to this object and sorting only | 923 // We do this by copying them to this object and sorting only |
| 867 // local elements. This is not very efficient, but sorting with | 924 // local elements. This is not very efficient, but sorting with |
| 868 // inherited elements happens very, very rarely, if at all. | 925 // inherited elements happens very, very rarely, if at all. |
| 869 // The specification allows "implementation dependent" behavior | 926 // The specification allows "implementation dependent" behavior |
| 870 // if an element on the prototype chain has an element that | 927 // if an element on the prototype chain has an element that |
| 871 // might interact with sorting. | 928 // might interact with sorting. |
| 872 max_prototype_element = CopyFromPrototype(this, length); | 929 max_prototype_element = CopyFromPrototype(this, length); |
| 873 } | 930 } |
| 874 | 931 |
| 875 var num_non_undefined = %RemoveArrayHoles(this, length); | 932 var num_non_undefined = %RemoveArrayHoles(this, length); |
| 876 if (num_non_undefined == -1) { | 933 if (num_non_undefined == -1) { |
| 877 // There were indexed accessors in the array. Move array holes and | 934 // There were indexed accessors in the array. Move array holes and |
| 878 // undefineds to the end using a Javascript function that is safe | 935 // undefineds to the end using a Javascript function that is safe |
| 879 // in the presence of accessors. | 936 // in the presence of accessors. |
| 880 num_non_undefined = SafeRemoveArrayHoles(this); | 937 num_non_undefined = SafeRemoveArrayHoles(this); |
| 881 } | 938 } |
| 882 | 939 |
| 883 QuickSort(this, 0, num_non_undefined); | 940 if(IS_FUNCTION(comparefn)) { |
| 941 QuickSortWithFunc(this, 0, num_non_undefined); | |
| 942 } else { | |
| 943 QuickSort(this, 0, num_non_undefined); | |
| 944 } | |
| 884 | 945 |
| 885 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) { | 946 if (!is_array && (num_non_undefined + 1 < max_prototype_element)) { |
| 886 // For compatibility with JSC, we shadow any elements in the prototype | 947 // For compatibility with JSC, we shadow any elements in the prototype |
| 887 // chain that has become exposed by sort moving a hole to its position. | 948 // chain that has become exposed by sort moving a hole to its position. |
| 888 ShadowPrototypeElements(this, num_non_undefined, max_prototype_element); | 949 ShadowPrototypeElements(this, num_non_undefined, max_prototype_element); |
| 889 } | 950 } |
| 890 | 951 |
| 891 return this; | 952 return this; |
| 892 } | 953 } |
| 893 | 954 |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1149 "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1), | 1210 "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1), |
| 1150 "reduce", getFunction("reduce", ArrayReduce, 1), | 1211 "reduce", getFunction("reduce", ArrayReduce, 1), |
| 1151 "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1) | 1212 "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1) |
| 1152 )); | 1213 )); |
| 1153 | 1214 |
| 1154 %FinishArrayPrototypeSetup($Array.prototype); | 1215 %FinishArrayPrototypeSetup($Array.prototype); |
| 1155 } | 1216 } |
| 1156 | 1217 |
| 1157 | 1218 |
| 1158 SetupArray(); | 1219 SetupArray(); |
| OLD | NEW |