| /* |
| * |
| * Copyright (c) 1994, 2009 |
| * Hewlett-Packard Company |
| * |
| * Permission to use, copy, modify, distribute and sell this software |
| * and its documentation for any purpose is hereby granted without fee, |
| * provided that the above copyright notice appear in all copies and |
| * that both that copyright notice and this permission notice appear |
| * in supporting documentation. Hewlett-Packard Company makes no |
| * representations about the suitability of this software for any |
| * purpose. It is provided "as is" without express or implied warranty. |
| * |
| * Copyright (c) 1997 |
| * Silicon Graphics Computer Systems, Inc. |
| * |
| * Permission to use, copy, modify, distribute and sell this software |
| * and its documentation for any purpose is hereby granted without fee, |
| * provided that the above copyright notice appear in all copies and |
| * that both that copyright notice and this permission notice appear |
| * in supporting documentation. Silicon Graphics makes no |
| * representations about the suitability of this software for any |
| * purpose. It is provided "as is" without express or implied warranty. |
| * |
| * Contributions: |
| * IBM - Ported the code to Java |
| */ |
| |
| package org.eclipse.ui.internal.views.markers; |
| |
| import java.util.Arrays; |
| import java.util.Comparator; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| |
| /** |
| * @since 3.5 |
| * |
| * @author Hitesh |
| */ |
| public class MarkerSortUtil { |
| |
| /* |
| * Note: partial quicksort or introsort would not be of much use here as the |
| * sorting direction can be reversed easily from the UI. These would perform |
| * at quadratic complexities in these conditions. The code below is based on |
| * a variant of Modified HeapSort.Runs in O(NlogN) in worst case. |
| */ |
| |
| /* |
| * Increasing BATCH_SIZE increases memory consumption but increases speed, |
| * and vice-versa.This indirectly controls the number of active caches in |
| * MarkerEntry[] array passed for sorting. |
| */ |
| private static int BATCH_SIZE = 10000; |
| |
| /* |
| * For n/k ratios less than this , we will use Arrays.Sort(). The heapsort |
| * performs nearly as good as mergesort for small data.We can still benefit |
| * from the mergesort - Arrays.Sort(). When the number of elements to be sorted, |
| * are almost as much as the elements we have. |
| */ |
| private static float MERGE_OR_HEAP_SWITCH=1.5f; |
| |
| /** |
| * Sorts [first,middle] in the array of [first,last] using a variant of |
| * modified heapsort, such that |
| * array[first]<array[first+1]<...<array[middle] and |
| * array[middle]<arra[middle+1||middle+2|| ....last] |
| * |
| * @param array |
| * @param first |
| * @param middle |
| * @param last |
| * @param comparator |
| */ |
| private static void partiallySort(MarkerEntry[] array, int first, |
| int middle, int last, Comparator comparator) { |
| heapify(array, first, middle, comparator); |
| |
| adjustMaxElement(array, first, middle, last, comparator); |
| |
| heapToSortedArray(array, first, middle, comparator); |
| } |
| |
| /** |
| * Swap the max heap element with any greater elements in rest of the array |
| * |
| * @param heapArray |
| * @param first |
| * @param heapSize |
| * @param last |
| * @param comparator |
| */ |
| private static void adjustMaxElement(MarkerEntry[] heapArray, int first, |
| int heapSize, int last, Comparator comparator) { |
| /* |
| * we do not clear caches for heap elements when re-adjusting and |
| * sorting this will ensure sorting remains fast |
| */ |
| int current = heapSize; |
| while (current <= last) { |
| if (comparator.compare(heapArray[current], heapArray[first]) < 0) { |
| MarkerEntry tmp = heapArray[current]; |
| heapArray[current] = heapArray[first]; |
| heapArray[first] = tmp; |
| adjustHeap(heapArray, first, first, heapSize, comparator); |
| } |
| // clear cache of the one not in heap |
| heapArray[current].clearCache(); |
| |
| ++current; |
| } |
| } |
| |
| /** |
| * Re-adjust the elements in the heap to maintain heap-property |
| * |
| * Note: caches are not cleared in this method, as it would offset |
| * to a certain extent the benefit of caching in sorting. |
| * |
| * @param array |
| * @param first |
| * @param position |
| * @param last |
| * @param comparator |
| */ |
| private static void adjustHeap(MarkerEntry[] array, int first, |
| int position, int last, Comparator comparator) { |
| MarkerEntry hole = array[position]; |
| int holeIndex = position; |
| holeIndex = leafSearch(array, first, holeIndex, last, comparator); |
| holeIndex = bottomUpSearch(array, first, holeIndex,position,hole,last, comparator); |
| array[holeIndex] = hole; |
| } |
| |
| /** |
| * Percolate down the Heap: adjust left ,right, self nodes for heap starting |
| * from hole all the way down the heap |
| * |
| * @param array |
| * @param first |
| * @param position |
| * @param last |
| * @param comparator |
| * @return new holeIndex |
| */ |
| private static int leafSearch(MarkerEntry[] array, int first, int position, |
| int last, Comparator comparator) { |
| int holeOffset = position - first; |
| int len = last - first; |
| int childOffset = 2 * holeOffset + 2; |
| // |
| while (childOffset < len) { |
| if (comparator.compare(array[first + childOffset], array[first |
| + (childOffset - 1)]) < 0) |
| --childOffset; |
| array[first + holeOffset] = array[first + childOffset]; |
| holeOffset = childOffset++; |
| childOffset *= 2; |
| } |
| if (childOffset-- == len) { |
| array[first + holeOffset] = array[first + childOffset]; |
| holeOffset = childOffset; |
| } |
| return holeOffset + first; |
| } |
| |
| /** |
| * percolate up the Heap: add the hole element back to heap at the right |
| * position, all the way up the heap between fromIndex and toIndex |
| * |
| * @param array |
| * @param first |
| * @param fromIndex |
| * @param toIndex |
| * @param hole |
| * @param last |
| * @param comparator |
| * @return new holeIndex |
| */ |
| private static int bottomUpSearch(MarkerEntry[] array, int first, int fromIndex, |
| int toIndex, MarkerEntry hole, int last, Comparator comparator) { |
| int holeOffset = fromIndex - first; |
| int parent = (holeOffset - 1) / 2; |
| int top = toIndex - first; |
| |
| while (holeOffset != top |
| && (comparator.compare(array[first + parent], hole) < 0)) { |
| array[first + holeOffset] = array[first + parent]; |
| holeOffset = parent; |
| parent = (holeOffset - 1) / 2; |
| } |
| |
| /* |
| * Using Binary search to locate the parent to replace. |
| * This is worse compared to linear search as most of the |
| * holes would replace only a few parents above them. |
| * This code has been left commented for future examination. |
| * */ |
| /* |
| int top = position - first; |
| int lowParent = 1; |
| int highParent = 0; |
| int from = holeOffset; |
| while (from > top) { |
| from = (from - 1) / 2; |
| highParent++; |
| } |
| if (from != top) |
| highParent--;// Between, exculding top//n++; |
| |
| int parentReplaceCount = -1; |
| // start at lower ranges because of heap property |
| int midParent = lowParent + (highParent - lowParent) / 4; |
| while (lowParent <= highParent) { |
| // mth parent |
| int currenParentIndex = holeOffset; |
| int mth = midParent; |
| while (mth > 0) { |
| currenParentIndex = (currenParentIndex - 1) / 2; |
| mth--; |
| } |
| int value = comparator.compare(array[first + currenParentIndex], hole); |
| if (value < 0) { |
| parentReplaceCount = midParent; |
| lowParent = midParent + 1; |
| } else if (value > 0) { |
| highParent = midParent - 1; |
| } else { |
| // we are looking for just lower |
| // not exact match |
| highParent = midParent - 1; |
| } |
| midParent = (highParent + lowParent) / 2; |
| } |
| int parent = (holeOffset - 1) / 2; |
| for (int i = 1; i <= parentReplaceCount; i++) { |
| array[first + holeOffset] = array[first + parent]; |
| holeOffset = parent; |
| parent = (holeOffset - 1) / 2; |
| } |
| */ |
| return first + holeOffset; |
| } |
| |
| |
| |
| /** |
| * Makes a heap in the array |
| * @param array |
| * @param first |
| * @param last |
| * @param comparator |
| */ |
| private static void heapify(MarkerEntry[] array, int first, int last, |
| Comparator comparator) { |
| if (last - first < 2) |
| return; |
| int parent = (last - first - 2) / 2; |
| do |
| adjustHeap(array, first, first + parent, last, comparator); |
| while (parent-- != 0); |
| } |
| |
| /** |
| * Converts a heap array to sorted array |
| * |
| * @param array |
| * @param first |
| * @param last |
| * @param comparator |
| * |
| */ |
| private static void heapToSortedArray(MarkerEntry[] array, int first, |
| int last, Comparator comparator) { |
| //TODO:Use mergesort to convert the heap to sorted array? |
| |
| while (last - first > 1) { |
| // clear cache sorted and present at the end |
| array[last].clearCache(); |
| // leave out the max elements at the end |
| MarkerEntry tmp = array[--last]; |
| array[last] = array[first]; |
| array[first] = tmp; |
| // readjust for next max |
| adjustHeap(array, first, first, last, comparator); |
| } |
| array[first+1].clearCache(); |
| array[first].clearCache(); |
| } |
| |
| /** |
| * Sorts [from,first+k-1] in the array of [from,to] using a variant of |
| * modified heapsort, such that |
| * array[from]<array[from+1]<...<array[from+k-1] and |
| * array[from+k-1]<arra[from+k||from+k+1||from+k+2|| ....to] |
| * |
| * Note: if k is greater than a number,the sorting happens in batches of |
| * that number, this for performance reasons. |
| * |
| * @param entries |
| * @param comparator |
| * @param from |
| * @param to |
| * @param k |
| * @param monitor |
| */ |
| public static void sortStartingKElement(MarkerEntry[] entries, |
| Comparator comparator, int from, int to, int k,IProgressMonitor monitor) { |
| // check range valid |
| int last = from + k-1; |
| if (entries.length == 0 || from < 0 || from >= to || last < from |
| || last > to || to > entries.length - 1 || to < 0) |
| return; |
| int n=to-from+1; |
| if (n <= BATCH_SIZE && (((float) n / k) <= MERGE_OR_HEAP_SWITCH) |
| /*|| ((float) n / k) <= MERGE_OR_HEAP_SWITCH*/) { |
| // use arrays sort |
| Arrays.sort(entries, from, to + 1, comparator); |
| // clear cache for first to middle since we are done with sort |
| for (int i = from; i <= to; i++) { |
| entries[i].clearCache(); |
| } |
| return; |
| } |
| |
| // do it in blocks of BATCH_SIZE so we get a chance |
| // of clearing caches to keep memory usage to a minimum |
| |
| //we choose k-1 so that last batch includes last element |
| //in case k is a multiple of BATCH_SIZE |
| int totalBatches = (k-1) / BATCH_SIZE; |
| int batchCount = 0; |
| while (totalBatches > 0) { |
| if(monitor.isCanceled()){ |
| return; |
| } |
| int fromTemp = from + batchCount * BATCH_SIZE; |
| int toTemp = from + (batchCount + 1) * BATCH_SIZE; |
| partiallySort(entries, fromTemp, toTemp, to, comparator); |
| batchCount++; |
| totalBatches--; |
| } |
| if(monitor.isCanceled()){ |
| return; |
| } |
| if (last >= from + batchCount * BATCH_SIZE) { |
| // the last remaining enteries |
| if (last == to) { |
| partiallySort(entries, from + batchCount * BATCH_SIZE, last, |
| to, comparator); |
| } else { |
| partiallySort(entries, from + batchCount * BATCH_SIZE, last+1, |
| to, comparator); |
| } |
| } |
| } |
| |
| /** |
| * @param fArray1 |
| * @param comparator |
| * @param from |
| * @param k |
| * @param limit |
| */ |
| public static void sortStartingKElement(MockMarkerEntry[] fArray1, |
| Comparator comparator, int from, int k, int limit) { |
| sortStartingKElement(fArray1, comparator, from, k, limit,new NullProgressMonitor()); |
| } |
| /** |
| * Sorts [0,k-1] in the array of [0,entries.length-1] using a variant of |
| * modified heapsort, such that |
| * array[0]<array[1]<...<array[k-1] and |
| * array[k-1]<arra[k||k+1||k+2|| ....entries.length-1] |
| * |
| * Note: if k is greater than a number,the sorting happens in batches of |
| * that number, this for performance reasons. |
| * |
| * @param entries |
| * @param comparator |
| * @param k |
| * @param monitor |
| */ |
| public static void sortStartingKElement(MarkerEntry[] entries, |
| Comparator comparator, int k,IProgressMonitor monitor) { |
| sortStartingKElement(entries, comparator, 0, entries.length - 1, k,monitor); |
| } |
| |
| /** |
| * |
| * Sorts [from,first+k-1] in the array of [from,entries.length-1] using a variant of |
| * modified heapsort, such that |
| * array[from]<array[from+1]<...<array[from+k-1] and |
| * array[from+k-1]<arra[from+k||from+k+1||from+k+2|| ....entries.length-1] |
| * |
| * Note: if k is greater than a number,the sorting happens in batches of |
| * that number, this for performance reasons. |
| * |
| * @param entries |
| * @param comparator |
| * @param from |
| * @param k |
| * @param monitor |
| */ |
| public static void sortStartingKElement(MarkerEntry[] entries, |
| Comparator comparator, int from, int k, IProgressMonitor monitor) { |
| sortStartingKElement(entries, comparator, from, entries.length - 1, k,monitor); |
| } |
| |
| } |