public static int[] Sort <TElement, TKey>(TElement[] data, Func <TElement, TKey> keySelector, IComparer <TKey> comparer, bool descending, OrderBy <TElement> parent, IndexSorter <TElement> tail) { // Comparer<string>.Default creates a string comparer that will always get the threads current culture, // but as we're going to do a sort where we are not changing the culture until the operation is over // we can lock in the StringComparer.CurrentCulture up front. comparer = typeof(TKey) == typeof(string) && comparer == Comparer <string> .Default ? (IComparer <TKey>)StringComparer.CurrentCulture : comparer; if (descending && FastTypeInfo <TKey> .IsValueType() && comparer == Comparer <TKey> .Default) { DescendingWrapperForValueTypeWithDefaultComparer <TKey> keySelectorWrapper(TElement element) => new DescendingWrapperForValueTypeWithDefaultComparer <TKey>(keySelector(element)); var sorter = new IndexSorterKeyed <TElement, DescendingWrapperForValueTypeWithDefaultComparer <TKey> >(keySelectorWrapper, Comparer <DescendingWrapperForValueTypeWithDefaultComparer <TKey> > .Default, tail); return(parent != null?parent.Sort(data, sorter) : sorter.StableSortedIndexes(data)); } else { comparer = descending ? new DescendingComparer <TKey>(comparer) : comparer; var sorter = new IndexSorterKeyed <TElement, TKey>(keySelector, comparer, tail); return(parent != null?parent.Sort(data, sorter) : sorter.StableSortedIndexes(data)); } }
public int[] StableSortedIndexes(TElement[] data) { var size = data.Length; Initialize(size); var indexes = new int[size]; for (var idx = 0; idx < indexes.Length; ++idx) { indexes[idx] = idx; } // There is some point at which LateredSort is just better, but depends on what is // being sorted on. 1000 didn't seem unreasonable, but not particularly scientific, // although there were a few benchmarks. if (size >= 1000 || FastTypeInfo <TKey> .IsValueType()) { return(LayeredSort(data, indexes)); } return(CombinedComparerSort(data, indexes)); }