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 |