Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/ArrayHelper.java @ 657:6334b0267103
ParentChildMap can supply RevisionMap. Refactor ArrayHelper to keep most of sorted/reverse index magic inside
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 04 Jul 2013 20:27:45 +0200 |
| parents | b9592e21176a |
| children | d10399f80f4e |
comparison
equal
deleted
inserted
replaced
| 656:a937e63b6e02 | 657:6334b0267103 |
|---|---|
| 14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
| 15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
| 16 */ | 16 */ |
| 17 package org.tmatesoft.hg.internal; | 17 package org.tmatesoft.hg.internal; |
| 18 | 18 |
| 19 import java.util.Arrays; | |
| 20 | |
| 19 /** | 21 /** |
| 20 * Internal alternative to Arrays.sort to build reversed index along with sorting | 22 * Internal alternative to Arrays.sort to build reversed index along with sorting |
| 23 * and to perform lookup (binary search) without sorted array, using reversed index. | |
| 21 * | 24 * |
| 22 * @author Artem Tikhomirov | 25 * @author Artem Tikhomirov |
| 23 * @author TMate Software Ltd. | 26 * @author TMate Software Ltd. |
| 24 */ | 27 */ |
| 25 public class ArrayHelper { | 28 public final class ArrayHelper<T extends Comparable<T>> { |
| 26 private int[] reverse; | 29 private int[] reverse; // aka sorted2natural |
| 27 | 30 private final T[] data; |
| 28 @SuppressWarnings("unchecked") | 31 private T[] sorted; |
| 29 public void sort(Comparable<?>[] a) { | 32 |
| 30 // Object[] aux = (Object[]) a.clone(); | 33 public ArrayHelper(T[] _data) { |
| 31 reverse = new int[a.length]; | 34 assert _data != null; |
| 32 sort1((Comparable<Object>[])a, 0, a.length); | 35 data = _data; |
| 36 } | |
| 37 | |
| 38 /** | |
| 39 * Sort data this helper wraps, possibly using supplied array (optional) | |
| 40 * to keep sorted elements | |
| 41 * @param sortDest array to keep sorted values at, or <code>null</code> | |
| 42 * @param sortDestIsEmpty <code>false</code> when sortDest already contains copy of data to be sorted | |
| 43 * @param keepSorted <code>true</code> to save sorted array for future use (e.g. in | |
| 44 */ | |
| 45 public void sort(T[] sortDest, boolean sortDestIsEmpty, boolean keepSorted) { | |
| 46 if (sortDest != null) { | |
| 47 assert sortDest.length >= data.length; | |
| 48 if (sortDestIsEmpty) { | |
| 49 System.arraycopy(data, 0, sortDest, 0, data.length); | |
| 50 } | |
| 51 sorted = sortDest; | |
| 52 } else { | |
| 53 sorted = data.clone(); | |
| 54 } | |
| 55 reverse = new int[data.length]; | |
| 33 for (int i = 0; i < reverse.length; i++) { | 56 for (int i = 0; i < reverse.length; i++) { |
| 34 // element that was not moved don't have an index in reverse. | 57 // initial reverse indexes, so that elements that do |
| 35 // perhaps, can do it inside sort alg? | 58 // not move during sort got correct indexes |
| 36 // Alternatively, may start with filling reverse[] array with initial indexes and | 59 reverse[i] = i; |
| 37 // avoid != 0 comparisons in #swap altogether? | 60 } |
| 38 if (reverse[i] == 0) { | 61 sort1(0, data.length); |
| 39 reverse[i] = i+1; | 62 if (!keepSorted) { |
| 40 } | 63 sorted = null; |
| 41 } | 64 } |
| 65 } | |
| 66 | |
| 67 /** | |
| 68 * @return all reverse indexes | |
| 69 */ | |
| 70 public int[] getReverseIndexes() { | |
| 71 return reverse; | |
| 72 } | |
| 73 | |
| 74 public int getReverseIndex(int sortedIndex) { | |
| 75 return reverse[sortedIndex]; | |
| 76 } | |
| 77 | |
| 78 public T get(int index) { | |
| 79 return data[index]; | |
| 80 } | |
| 81 | |
| 82 public T[] getData() { | |
| 83 return data; | |
| 84 } | |
| 85 | |
| 86 /** | |
| 87 * Look up sorted index of the value, using sort information | |
| 88 * @return same value as {@link Arrays#binarySearch(Object[], Object)} does | |
| 89 */ | |
| 90 public int binarySearchSorted(T value) { | |
| 91 if (sorted != null) { | |
| 92 return Arrays.binarySearch(sorted, 0, data.length, value); | |
| 93 } | |
| 94 return binarySearchWithReverse(0, data.length, value); | |
| 95 } | |
| 96 | |
| 97 /** | |
| 98 * Look up index of the value in the original array. | |
| 99 * @return index in original data, or <code>defaultValue</code> if value not found | |
| 100 */ | |
| 101 public int binarySearch(T value, int defaultValue) { | |
| 102 int x = binarySearchSorted(value); | |
| 103 if (x < 0) { | |
| 104 return defaultValue; | |
| 105 } | |
| 106 return reverse[x]; | |
| 42 } | 107 } |
| 43 | 108 |
| 44 /** | 109 /** |
| 45 * Slightly modified version of Arrays.sort1(int[], int, int) quicksort alg (just to deal with Object[]) | 110 * Slightly modified version of Arrays.sort1(int[], int, int) quicksort alg (just to deal with Object[]) |
| 46 */ | 111 */ |
| 47 private void sort1(Comparable<Object> x[], int off, int len) { | 112 private void sort1(int off, int len) { |
| 113 @SuppressWarnings("unchecked") | |
| 114 Comparable<Object>[] x = (Comparable<Object>[]) sorted; | |
| 48 // Insertion sort on smallest arrays | 115 // Insertion sort on smallest arrays |
| 49 if (len < 7) { | 116 if (len < 7) { |
| 50 for (int i=off; i<len+off; i++) | 117 for (int i=off; i<len+off; i++) |
| 51 for (int j=i; j>off && x[j-1].compareTo(x[j]) > 0; j--) | 118 for (int j=i; j>off && x[j-1].compareTo(x[j]) > 0; j--) |
| 52 swap(x, j, j-1); | 119 swap(j, j-1); |
| 53 return; | 120 return; |
| 54 } | 121 } |
| 55 | 122 |
| 56 // Choose a partition element, v | 123 // Choose a partition element, v |
| 57 int m = off + (len >> 1); // Small arrays, middle element | 124 int m = off + (len >> 1); // Small arrays, middle element |
| 58 if (len > 7) { | 125 if (len > 7) { |
| 59 int l = off; | 126 int l = off; |
| 60 int n = off + len - 1; | 127 int n = off + len - 1; |
| 61 if (len > 40) { // Big arrays, pseudomedian of 9 | 128 if (len > 40) { // Big arrays, pseudomedian of 9 |
| 62 int s = len/8; | 129 int s = len/8; |
| 63 l = med3(x, l, l+s, l+2*s); | 130 l = med3(l, l+s, l+2*s); |
| 64 m = med3(x, m-s, m, m+s); | 131 m = med3(m-s, m, m+s); |
| 65 n = med3(x, n-2*s, n-s, n); | 132 n = med3(n-2*s, n-s, n); |
| 66 } | 133 } |
| 67 m = med3(x, l, m, n); // Mid-size, med of 3 | 134 m = med3(l, m, n); // Mid-size, med of 3 |
| 68 } | 135 } |
| 69 Comparable<Object> v = x[m]; | 136 Comparable<Object> v = x[m]; |
| 70 | 137 |
| 71 // Establish Invariant: v* (<v)* (>v)* v* | 138 // Establish Invariant: v* (<v)* (>v)* v* |
| 72 int a = off, b = a, c = off + len - 1, d = c; | 139 int a = off, b = a, c = off + len - 1, d = c; |
| 73 while(true) { | 140 while(true) { |
| 74 while (b <= c && x[b].compareTo(v) <= 0) { | 141 while (b <= c && x[b].compareTo(v) <= 0) { |
| 75 if (x[b] == v) | 142 if (x[b] == v) |
| 76 swap(x, a++, b); | 143 swap(a++, b); |
| 77 b++; | 144 b++; |
| 78 } | 145 } |
| 79 while (c >= b && x[c].compareTo(v) >= 0) { | 146 while (c >= b && x[c].compareTo(v) >= 0) { |
| 80 if (x[c] == v) | 147 if (x[c] == v) |
| 81 swap(x, c, d--); | 148 swap(c, d--); |
| 82 c--; | 149 c--; |
| 83 } | 150 } |
| 84 if (b > c) | 151 if (b > c) |
| 85 break; | 152 break; |
| 86 swap(x, b++, c--); | 153 swap(b++, c--); |
| 87 } | 154 } |
| 88 | 155 |
| 89 // Swap partition elements back to middle | 156 // Swap partition elements back to middle |
| 90 int s, n = off + len; | 157 int s, n = off + len; |
| 91 s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); | 158 s = Math.min(a-off, b-a ); vecswap(off, b-s, s); |
| 92 s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); | 159 s = Math.min(d-c, n-d-1); vecswap(b, n-s, s); |
| 93 | 160 |
| 94 // Recursively sort non-partition-elements | 161 // Recursively sort non-partition-elements |
| 95 if ((s = b-a) > 1) | 162 if ((s = b-a) > 1) |
| 96 sort1(x, off, s); | 163 sort1(off, s); |
| 97 if ((s = d-c) > 1) | 164 if ((s = d-c) > 1) |
| 98 sort1(x, n-s, s); | 165 sort1(n-s, s); |
| 99 } | 166 } |
| 100 | 167 |
| 101 /** | 168 /** |
| 102 * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. | 169 * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. |
| 103 */ | 170 */ |
| 104 private void vecswap(Object[] x, int a, int b, int n) { | 171 private void vecswap(int a, int b, int n) { |
| 105 for (int i=0; i<n; i++, a++, b++) { | 172 for (int i=0; i<n; i++, a++, b++) { |
| 106 swap(x, a, b); | 173 swap(a, b); |
| 107 } | 174 } |
| 108 } | 175 } |
| 109 | 176 |
| 110 /** | 177 /** |
| 111 * Returns the index of the median of the three indexed integers. | 178 * Returns the index of the median of the three indexed integers. |
| 112 */ | 179 */ |
| 113 private static int med3(Comparable<Object>[] x, int a, int b, int c) { | 180 private int med3(int a, int b, int c) { |
| 114 return (x[a].compareTo(x[b]) < 0 ? | 181 @SuppressWarnings("unchecked") |
| 115 (x[b].compareTo(x[c]) < 0 ? b : x[a].compareTo(x[c]) < 0 ? c : a) : | 182 Comparable<Object>[] x = (Comparable<Object>[]) sorted; |
| 116 (x[b].compareTo(x[c]) > 0 ? b : x[a].compareTo(x[c]) > 0 ? c : a)); | 183 return (x[a].compareTo(x[b]) < 0 ? |
| 184 (x[b].compareTo(x[c]) < 0 ? b : x[a].compareTo(x[c]) < 0 ? c : a) : | |
| 185 (x[b].compareTo(x[c]) > 0 ? b : x[a].compareTo(x[c]) > 0 ? c : a)); | |
| 117 } | 186 } |
| 118 | 187 |
| 119 | 188 /** |
| 120 /** | |
| 121 * @return the reverse | |
| 122 */ | |
| 123 public int[] getReverse() { | |
| 124 return reverse; | |
| 125 } | |
| 126 | |
| 127 /** | |
| 128 * Swaps x[a] with x[b]. | 189 * Swaps x[a] with x[b]. |
| 129 */ | 190 */ |
| 130 private void swap(Object[] x, int a, int b) { | 191 private void swap(int a, int b) { |
| 192 Object[] x = sorted; | |
| 131 Object t = x[a]; | 193 Object t = x[a]; |
| 132 x[a] = x[b]; | 194 x[a] = x[b]; |
| 133 x[b] = t; | 195 x[b] = t; |
| 134 int z1 = reverse[a] != 0 ? reverse[a] : a+1; | 196 int z1 = reverse[a]; |
| 135 int z2 = reverse[b] != 0 ? reverse[b] : b+1; | 197 int z2 = reverse[b]; |
| 136 reverse[b] = z1; | 198 reverse[b] = z1; |
| 137 reverse[a] = z2; | 199 reverse[a] = z2; |
| 138 } | 200 } |
| 201 | |
| 202 // copied from Arrays.binarySearch0, update to be instance method and to use reverse indexes | |
| 203 private int binarySearchWithReverse(int fromIndex, int toIndex, T key) { | |
| 204 int low = fromIndex; | |
| 205 int high = toIndex - 1; | |
| 206 | |
| 207 while (low <= high) { | |
| 208 int mid = (low + high) >>> 1; | |
| 209 // data[reverse[x]] gives sorted value at index x | |
| 210 T midVal = data[reverse[mid]]; | |
| 211 int cmp = midVal.compareTo(key); | |
| 212 | |
| 213 if (cmp < 0) | |
| 214 low = mid + 1; | |
| 215 else if (cmp > 0) | |
| 216 high = mid - 1; | |
| 217 else | |
| 218 return mid; // key found | |
| 219 } | |
| 220 return -(low + 1); // key not found. | |
| 221 } | |
| 222 | |
| 139 } | 223 } |
