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 }