1 using System.Collections;
2 using System.Collections.Generic;
8 // Private value type used by the Sort methods.
9 private struct SorterObjectArray
11 private Object[] keys;
12 private Object[] items;
13 private IComparer comparer;
15 internal SorterObjectArray(Object[] keys, Object[] items, IComparer comparer)
17 if (comparer == null) comparer = Comparer.Default;
20 this.comparer = comparer;
23 internal void SwapIfGreaterWithItems(int a, int b)
27 if (comparer.Compare(keys[a], keys[b]) > 0)
29 Object temp = keys[a];
34 Object item = items[a];
42 private void Swap(int i, int j)
50 Object item = items[i];
56 internal void Sort(int left, int length)
58 IntrospectiveSort(left, length);
61 private void IntrospectiveSort(int left, int length)
68 IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2(keys.Length));
70 catch (IndexOutOfRangeException)
72 IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
76 throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
80 private void IntroSort(int lo, int hi, int depthLimit)
84 int partitionSize = hi - lo + 1;
85 if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
87 if (partitionSize == 1)
91 if (partitionSize == 2)
93 SwapIfGreaterWithItems(lo, hi);
96 if (partitionSize == 3)
98 SwapIfGreaterWithItems(lo, hi - 1);
99 SwapIfGreaterWithItems(lo, hi);
100 SwapIfGreaterWithItems(hi - 1, hi);
104 InsertionSort(lo, hi);
115 int p = PickPivotAndPartition(lo, hi);
116 IntroSort(p + 1, hi, depthLimit);
121 private int PickPivotAndPartition(int lo, int hi)
123 // Compute median-of-three. But also partition them, since we've done the comparison.
124 int mid = lo + (hi - lo) / 2;
125 // Sort lo, mid and hi appropriately, then pick mid as the pivot.
126 SwapIfGreaterWithItems(lo, mid);
127 SwapIfGreaterWithItems(lo, hi);
128 SwapIfGreaterWithItems(mid, hi);
130 Object pivot = keys[mid];
132 int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
136 while (comparer.Compare(keys[++left], pivot) < 0) ;
137 while (comparer.Compare(pivot, keys[--right]) < 0) ;
145 // Put pivot in the right location.
146 Swap(left, (hi - 1));
150 private void Heapsort(int lo, int hi)
153 for (int i = n / 2; i >= 1; i = i - 1)
157 for (int i = n; i > 1; i = i - 1)
159 Swap(lo, lo + i - 1);
161 DownHeap(1, i - 1, lo);
165 private void DownHeap(int i, int n, int lo)
167 Object d = keys[lo + i - 1];
168 Object dt = (items != null) ? items[lo + i - 1] : null;
173 if (child < n && comparer.Compare(keys[lo + child - 1], keys[lo + child]) < 0)
177 if (!(comparer.Compare(d, keys[lo + child - 1]) < 0))
179 keys[lo + i - 1] = keys[lo + child - 1];
181 items[lo + i - 1] = items[lo + child - 1];
184 keys[lo + i - 1] = d;
186 items[lo + i - 1] = dt;
189 private void InsertionSort(int lo, int hi)
193 for (i = lo; i < hi; i++)
197 ti = (items != null) ? items[i + 1] : null;
198 while (j >= lo && comparer.Compare(t, keys[j]) < 0)
200 keys[j + 1] = keys[j];
202 items[j + 1] = items[j];
212 // Private value used by the Sort methods for instances of Array.
213 // This is slower than the one for Object[], since we can't use the JIT helpers
214 // to access the elements. We must use GetValue & SetValue.
215 private struct SorterGenericArray
219 private IComparer comparer;
221 internal SorterGenericArray(Array keys, Array items, IComparer comparer)
223 if (comparer == null) comparer = Comparer.Default;
226 this.comparer = comparer;
229 internal void SwapIfGreaterWithItems(int a, int b)
233 if (comparer.Compare(keys.GetValue(a), keys.GetValue(b)) > 0)
235 Object key = keys.GetValue(a);
236 keys.SetValue(keys.GetValue(b), a);
237 keys.SetValue(key, b);
240 Object item = items.GetValue(a);
241 items.SetValue(items.GetValue(b), a);
242 items.SetValue(item, b);
248 private void Swap(int i, int j)
250 Object t1 = keys.GetValue(i);
251 keys.SetValue(keys.GetValue(j), i);
252 keys.SetValue(t1, j);
256 Object t2 = items.GetValue(i);
257 items.SetValue(items.GetValue(j), i);
258 items.SetValue(t2, j);
262 internal void Sort(int left, int length)
264 IntrospectiveSort(left, length);
267 private void IntrospectiveSort(int left, int length)
274 IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2(keys.Length));
276 catch (IndexOutOfRangeException)
278 IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
282 throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
286 private void IntroSort(int lo, int hi, int depthLimit)
290 int partitionSize = hi - lo + 1;
291 if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
293 if (partitionSize == 1)
297 if (partitionSize == 2)
299 SwapIfGreaterWithItems(lo, hi);
302 if (partitionSize == 3)
304 SwapIfGreaterWithItems(lo, hi - 1);
305 SwapIfGreaterWithItems(lo, hi);
306 SwapIfGreaterWithItems(hi - 1, hi);
310 InsertionSort(lo, hi);
321 int p = PickPivotAndPartition(lo, hi);
322 IntroSort(p + 1, hi, depthLimit);
327 private int PickPivotAndPartition(int lo, int hi)
329 // Compute median-of-three. But also partition them, since we've done the comparison.
330 int mid = lo + (hi - lo) / 2;
332 SwapIfGreaterWithItems(lo, mid);
333 SwapIfGreaterWithItems(lo, hi);
334 SwapIfGreaterWithItems(mid, hi);
336 Object pivot = keys.GetValue(mid);
338 int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
342 while (comparer.Compare(keys.GetValue(++left), pivot) < 0) ;
343 while (comparer.Compare(pivot, keys.GetValue(--right)) < 0) ;
351 // Put pivot in the right location.
352 Swap(left, (hi - 1));
356 private void Heapsort(int lo, int hi)
359 for (int i = n / 2; i >= 1; i = i - 1)
363 for (int i = n; i > 1; i = i - 1)
365 Swap(lo, lo + i - 1);
367 DownHeap(1, i - 1, lo);
371 private void DownHeap(int i, int n, int lo)
373 Object d = keys.GetValue(lo + i - 1);
374 Object dt = (items != null) ? items.GetValue(lo + i - 1) : null;
379 if (child < n && comparer.Compare(keys.GetValue(lo + child - 1), keys.GetValue(lo + child)) < 0)
384 if (!(comparer.Compare(d, keys.GetValue(lo + child - 1)) < 0))
387 keys.SetValue(keys.GetValue(lo + child - 1), lo + i - 1);
389 items.SetValue(items.GetValue(lo + child - 1), lo + i - 1);
392 keys.SetValue(d, lo + i - 1);
394 items.SetValue(dt, lo + i - 1);
397 private void InsertionSort(int lo, int hi)
401 for (i = lo; i < hi; i++)
404 t = keys.GetValue(i + 1);
405 dt = (items != null) ? items.GetValue(i + 1) : null;
407 while (j >= lo && comparer.Compare(t, keys.GetValue(j)) < 0)
409 keys.SetValue(keys.GetValue(j), j + 1);
411 items.SetValue(items.GetValue(j), j + 1);
415 keys.SetValue(t, j + 1);
417 items.SetValue(dt, j + 1);