< Summary

Information
Class: SwiftCollections.SwiftArraySortHelper
Assembly: SwiftCollections
File(s): /home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Utility/SwiftArraySortHelper.cs
Line coverage
70%
Covered lines: 99
Uncovered lines: 41
Coverable lines: 140
Total lines: 325
Line coverage: 70.7%
Branch coverage
63%
Covered branches: 53
Total branches: 84
Branch coverage: 63%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Sort(...)83.33%6685.71%
Sort(...)50%2275%
IntroSort(...)87.5%8887.5%
PickPivotAndPartition(...)100%66100%
HeapSort(...)0%2040%
DownHeap(...)0%7280%
InsertionSort(...)100%66100%
SwapIfGreater(...)75%44100%
IntroSort(...)87.5%8887.5%
PickPivotAndPartition(...)100%66100%
HeapSort(...)0%2040%
DownHeap(...)0%7280%
InsertionSort(...)100%66100%
SwapIfGreater(...)75%44100%
Swap(...)50%2283.33%
FloorLog2(...)100%22100%

File(s)

/home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Utility/SwiftArraySortHelper.cs

#LineLine coverage
 1//=======================================================================
 2// SwiftArraySortHelper.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Collections.Generic;
 10using System.Runtime.CompilerServices;
 11
 12namespace SwiftCollections;
 13
 14internal static class SwiftArraySortHelper
 15{
 16    private const int InsertionSortThreshold = 16;
 17
 18    public static void Sort<T>(T[] array, int index, int length, IComparer<T>? comparer)
 19    {
 5620        if (length <= 1)
 021            return;
 22
 5623        if (comparer == null || ReferenceEquals(comparer, Comparer<T>.Default))
 24        {
 4125            Array.Sort(array, index, length);
 4126            return;
 27        }
 28
 1529        IntroSort(array, index, index + length - 1, FloorLog2(length) * 2, comparer);
 1530    }
 31
 32    public static void Sort<T, TComparer>(T[] array, int index, int length, TComparer comparer)
 33        where TComparer : struct, IComparer<T>
 34    {
 935        if (length <= 1)
 036            return;
 37
 38        // Keep the struct-comparer path generic: it avoids boxing and lets the JIT devirtualize hot comparer calls.
 939        IntroSort(array, index, index + length - 1, FloorLog2(length) * 2, comparer);
 940    }
 41
 42    private static void IntroSort<T>(T[] array, int lo, int hi, int depthLimit, IComparer<T> comparer)
 43    {
 145544        while (hi > lo)
 45        {
 111346            int partitionSize = hi - lo + 1;
 111347            if (partitionSize <= InsertionSortThreshold)
 48            {
 39349                InsertionSort(array, lo, hi, comparer);
 39350                return;
 51            }
 52
 72053            if (depthLimit == 0)
 54            {
 055                HeapSort(array, lo, hi, comparer);
 056                return;
 57            }
 58
 72059            depthLimit--;
 72060            int partition = PickPivotAndPartition(array, lo, hi, comparer);
 61
 72062            if (partition - lo < hi - partition)
 63            {
 49264                IntroSort(array, lo, partition - 1, depthLimit, comparer);
 49265                lo = partition + 1;
 66            }
 67            else
 68            {
 22869                IntroSort(array, partition + 1, hi, depthLimit, comparer);
 22870                hi = partition - 1;
 71            }
 72        }
 34273    }
 74
 75    private static int PickPivotAndPartition<T>(T[] array, int lo, int hi, IComparer<T> comparer)
 76    {
 72077        int middle = lo + ((hi - lo) >> 1);
 78
 72079        SwapIfGreater(array, comparer, lo, middle);
 72080        SwapIfGreater(array, comparer, lo, hi);
 72081        SwapIfGreater(array, comparer, middle, hi);
 82
 72083        T pivot = array[middle];
 72084        Swap(array, middle, hi - 1);
 85
 72086        int left = lo;
 72087        int right = hi - 1;
 88
 340289        while (true)
 90        {
 1776691            while (comparer.Compare(array[++left], pivot) < 0)
 92            {
 93            }
 94
 4082495            while (comparer.Compare(pivot, array[--right]) < 0)
 96            {
 97            }
 98
 412299            if (left >= right)
 100                break;
 101
 3402102            Swap(array, left, right);
 103        }
 104
 720105        Swap(array, left, hi - 1);
 720106        return left;
 107    }
 108
 109    private static void HeapSort<T>(T[] array, int lo, int hi, IComparer<T> comparer)
 110    {
 0111        int count = hi - lo + 1;
 0112        for (int i = count >> 1; i >= 1; i--)
 0113            DownHeap(array, i, count, lo, comparer);
 114
 0115        for (int i = count; i > 1; i--)
 116        {
 0117            Swap(array, lo, lo + i - 1);
 0118            DownHeap(array, 1, i - 1, lo, comparer);
 119        }
 0120    }
 121
 122    private static void DownHeap<T>(T[] array, int index, int count, int lo, IComparer<T> comparer)
 123    {
 0124        T value = array[lo + index - 1];
 125
 0126        while (index <= (count >> 1))
 127        {
 0128            int child = index << 1;
 0129            if (child < count && comparer.Compare(array[lo + child - 1], array[lo + child]) < 0)
 0130                child++;
 131
 0132            if (comparer.Compare(value, array[lo + child - 1]) >= 0)
 133                break;
 134
 0135            array[lo + index - 1] = array[lo + child - 1];
 0136            index = child;
 137        }
 138
 0139        array[lo + index - 1] = value;
 0140    }
 141
 142    private static void InsertionSort<T>(T[] array, int lo, int hi, IComparer<T> comparer)
 143    {
 10246144        for (int i = lo + 1; i <= hi; i++)
 145        {
 4730146            T value = array[i];
 4730147            int j = i - 1;
 9472148            while (j >= lo && comparer.Compare(value, array[j]) < 0)
 149            {
 4742150                array[j + 1] = array[j];
 4742151                j--;
 152            }
 153
 4730154            array[j + 1] = value;
 155        }
 393156    }
 157
 158    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 159    private static void SwapIfGreater<T>(T[] array, IComparer<T> comparer, int left, int right)
 160    {
 2160161        if (left != right && comparer.Compare(array[left], array[right]) > 0)
 1038162            Swap(array, left, right);
 2160163    }
 164
 165    private static void IntroSort<T, TComparer>(T[] array, int lo, int hi, int depthLimit, TComparer comparer)
 166        where TComparer : struct, IComparer<T>
 167    {
 489168        while (hi > lo)
 169        {
 375170            int partitionSize = hi - lo + 1;
 375171            if (partitionSize <= InsertionSortThreshold)
 172            {
 135173                InsertionSort(array, lo, hi, comparer);
 135174                return;
 175            }
 176
 240177            if (depthLimit == 0)
 178            {
 0179                HeapSort(array, lo, hi, comparer);
 0180                return;
 181            }
 182
 240183            depthLimit--;
 240184            int partition = PickPivotAndPartition(array, lo, hi, comparer);
 185
 240186            if (partition - lo < hi - partition)
 187            {
 164188                IntroSort(array, lo, partition - 1, depthLimit, comparer);
 164189                lo = partition + 1;
 190            }
 191            else
 192            {
 76193                IntroSort(array, partition + 1, hi, depthLimit, comparer);
 76194                hi = partition - 1;
 195            }
 196        }
 114197    }
 198
 199    private static int PickPivotAndPartition<T, TComparer>(T[] array, int lo, int hi, TComparer comparer)
 200        where TComparer : struct, IComparer<T>
 201    {
 240202        int middle = lo + ((hi - lo) >> 1);
 203
 240204        SwapIfGreater(array, comparer, lo, middle);
 240205        SwapIfGreater(array, comparer, lo, hi);
 240206        SwapIfGreater(array, comparer, middle, hi);
 207
 240208        T pivot = array[middle];
 240209        Swap(array, middle, hi - 1);
 210
 240211        int left = lo;
 240212        int right = hi - 1;
 213
 1134214        while (true)
 215        {
 5922216            while (comparer.Compare(array[++left], pivot) < 0)
 217            {
 218            }
 219
 13608220            while (comparer.Compare(pivot, array[--right]) < 0)
 221            {
 222            }
 223
 1374224            if (left >= right)
 225                break;
 226
 1134227            Swap(array, left, right);
 228        }
 229
 240230        Swap(array, left, hi - 1);
 240231        return left;
 232    }
 233
 234    private static void HeapSort<T, TComparer>(T[] array, int lo, int hi, TComparer comparer)
 235        where TComparer : struct, IComparer<T>
 236    {
 0237        int count = hi - lo + 1;
 0238        for (int i = count >> 1; i >= 1; i--)
 0239            DownHeap(array, i, count, lo, comparer);
 240
 0241        for (int i = count; i > 1; i--)
 242        {
 0243            Swap(array, lo, lo + i - 1);
 0244            DownHeap(array, 1, i - 1, lo, comparer);
 245        }
 0246    }
 247
 248    private static void DownHeap<T, TComparer>(T[] array, int index, int count, int lo, TComparer comparer)
 249        where TComparer : struct, IComparer<T>
 250    {
 0251        T value = array[lo + index - 1];
 252
 0253        while (index <= (count >> 1))
 254        {
 0255            int child = index << 1;
 0256            if (child < count && comparer.Compare(array[lo + child - 1], array[lo + child]) < 0)
 0257                child++;
 258
 0259            if (comparer.Compare(value, array[lo + child - 1]) >= 0)
 260                break;
 261
 0262            array[lo + index - 1] = array[lo + child - 1];
 0263            index = child;
 264        }
 265
 0266        array[lo + index - 1] = value;
 0267    }
 268
 269    private static void InsertionSort<T, TComparer>(T[] array, int lo, int hi, TComparer comparer)
 270        where TComparer : struct, IComparer<T>
 271    {
 3440272        for (int i = lo + 1; i <= hi; i++)
 273        {
 1585274            T value = array[i];
 1585275            int j = i - 1;
 3178276            while (j >= lo && comparer.Compare(value, array[j]) < 0)
 277            {
 1593278                array[j + 1] = array[j];
 1593279                j--;
 280            }
 281
 1585282            array[j + 1] = value;
 283        }
 135284    }
 285
 286    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 287    private static void SwapIfGreater<T, TComparer>(T[] array, TComparer comparer, int left, int right)
 288        where TComparer : struct, IComparer<T>
 289    {
 720290        if (left != right && comparer.Compare(array[left], array[right]) > 0)
 346291            Swap(array, left, right);
 720292    }
 293
 294    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 295    private static void Swap<T>(T[] array, int left, int right)
 296    {
 7840297        if (left == right)
 0298            return;
 299
 7840300        T value = array[left];
 7840301        array[left] = array[right];
 7840302        array[right] = value;
 7840303    }
 304
 305    private static int FloorLog2(int value)
 306    {
 24307        int result = 0;
 130308        while (value >= 2)
 309        {
 106310            result++;
 106311            value >>= 1;
 312        }
 313
 24314        return result;
 315    }
 316}
 317
 318internal readonly struct SwiftIntAscendingComparer : IComparer<int>
 319{
 320    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 321    public int Compare(int x, int y)
 322    {
 323        return x.CompareTo(y);
 324    }
 325}