using System;
using System.Collections.Generic;
using System.Linq;
namespace Amphora.UnitTests
{
public class RadixKeySorterTests : UnitTestSharp.TestFixture
{
///
/// Makes keys in no order that all fit in the bits of .
///
public static int[] Scrambled(int count, int mask)
{
var returnMe = new int[count];
uint state = 12345;
for (int i = 0; i < count; ++i)
{
state = unchecked(state * 1664525u + 1013904223u);
returnMe[i] = (int)(state >> 1 ^ state << 7) & mask;
}
return returnMe;
}
public static uint[] Unsigned(int[] keys)
{
return keys.Select(key => (uint)key).ToArray();
}
public class SortTests : UnitTestSharp.TestFixture
{
///
/// Sorts the first keys and checks they come out in order and the rest stay put.
///
[UnitTestSharp.IgnoreTest]
public void CheckSorts(RadixKeySorter sorter, int[] keys, int count)
{
var expected = (int[])keys.Clone();
Array.Sort(expected, 0, count);
sorter.Sort(keys, count);
CheckEqual(expected, keys);
}
[UnitTestSharp.IgnoreTest]
public void CheckSorts(int[] keys)
{
CheckSorts(new RadixKeySorter(), keys, keys.Length);
}
[UnitTestSharp.IgnoreTest]
public void CheckSortsUnsigned(RadixKeySorter sorter, uint[] keys, int count)
{
var expected = (uint[])keys.Clone();
Array.Sort(expected, 0, count);
sorter.Sort(keys, count);
CheckEqual(expected, keys);
}
[UnitTestSharp.IgnoreTest]
public void CheckSortsUnsigned(uint[] keys)
{
CheckSortsUnsigned(new RadixKeySorter(), keys, keys.Length);
}
public void NoKeys_ChangesNothing()
{
CheckSorts(new RadixKeySorter(), new[] { 3, 1, 2 }, 0);
}
public void OneKey_ChangesNothing()
{
CheckSorts(new RadixKeySorter(), new[] { 3, 1, 2 }, 1);
}
public void AFewKeys_AreSorted()
{
CheckSorts(Scrambled(10, 0xFFFF));
}
public void TwoKeysOutOfOrder_AreSorted()
{
CheckSorts(new[] { 2, 1 });
}
public void AFewKeysWithNegatives_AreSorted()
{
CheckSorts(new[] { 5, -3, 0, -100, 2, -1 });
}
public void ManyKeys_AreSorted()
{
CheckSorts(Scrambled(20000, 0x7FFFFFFF));
}
public void AlreadyAscending_AreUnchanged()
{
CheckSorts(Enumerable.Range(0, 3000).ToArray());
}
public void ManyDescending_BecomeAscending()
{
CheckSorts(Enumerable.Range(0, 3000).Reverse().ToArray());
}
public void AllEqual_AreUnchanged()
{
CheckSorts(Enumerable.Repeat(7, 3000).ToArray());
}
public void ManyDuplicates_AreSorted()
{
CheckSorts(Scrambled(3000, 0x7));
}
public void NegativeAndPositiveKeys_PutNegativesFirst()
{
int[] keys = Scrambled(3000, 0x7FFFFFFF);
for (int i = 0; i < keys.Length; i += 3)
{
keys[i] = -keys[i];
}
CheckSorts(keys);
}
public void OnlyNegativeKeys_AreSorted()
{
CheckSorts(Scrambled(3000, 0x7FFFFFFF).Select(key => -key - 1).ToArray());
}
public void TheExtremeKeys_AreSorted()
{
var keys = new int[3000];
for (int i = 0; i < keys.Length; ++i)
{
keys[i] = new[] { int.MaxValue, int.MinValue, 0, -1, 1 }[i % 5];
}
CheckSorts(keys);
}
public void KeysDifferingOnlyInTheSignBit_AreSorted()
{
CheckSorts(Scrambled(3000, int.MinValue));
}
public void KeysDifferingOnlyInTheLowBits_AreSorted()
{
CheckSorts(Scrambled(3000, 0xFF));
}
public void KeysDifferingInTwoDigits_AreSorted()
{
CheckSorts(Scrambled(3000, 0xFFFF));
}
public void KeysDifferingOnlyInHighBits_AreSorted()
{
CheckSorts(Scrambled(3000, 0x00F00000));
}
public void KeysWhoseMiddleDigitNeverDiffers_AreSorted()
{
CheckSorts(Scrambled(3000, unchecked((int)0xF000000F)));
}
public void OnlyTheFirstCount_AreSorted()
{
CheckSorts(new RadixKeySorter(), Scrambled(4000, 0x7FFFFFFF), 3000);
}
public void OnlyTheFirstCountOfAFew_AreSorted()
{
CheckSorts(new RadixKeySorter(), new[] { 5, 4, 3, 2, 1, 0 }, 4);
}
public void AfterABiggerBatch_ASmallerOneIsSorted()
{
var sorter = new RadixKeySorter();
CheckSorts(sorter, Scrambled(20000, 0x7FFFFFFF), 20000);
CheckSorts(sorter, Scrambled(2000, 0x7FFFFFFF), 2000);
}
public void AfterASmallerBatch_ABiggerOneIsSorted()
{
var sorter = new RadixKeySorter();
CheckSorts(sorter, Scrambled(2000, 0x7FFFFFFF), 2000);
CheckSorts(sorter, Scrambled(20000, 0x7FFFFFFF), 20000);
}
public void ArraysLongerThanTheCount_ReuseTheSpareSpace()
{
var sorter = new RadixKeySorter();
CheckSorts(sorter, Scrambled(5000, 0x7FFFFFFF), 4000);
CheckSorts(sorter, Scrambled(5000, 0x7FFFFFFF), 3000);
}
public void UnsignedKeysPastTheIntRange_AreSortedAsUnsigned()
{
CheckSortsUnsigned(Unsigned(Scrambled(3000, -1)).Select(key => key | 0x80000000).ToArray());
}
public void UnsignedKeysAcrossTheWholeRange_AreSorted()
{
CheckSortsUnsigned(Unsigned(Scrambled(20000, -1)));
}
public void UnsignedTheLargestKeys_AreSorted()
{
var keys = new uint[3000];
for (int i = 0; i < keys.Length; ++i)
{
keys[i] = new uint[] { uint.MaxValue, 0u, int.MaxValue, 1u << 31 }[i % 4];
}
CheckSortsUnsigned(keys);
}
public void UnsignedAlreadyAscending_AreUnchanged()
{
CheckSortsUnsigned(Enumerable.Range(0, 3000).Select(i => (uint)i * 1000).ToArray());
}
public void UnsignedAFewKeys_AreSorted()
{
CheckSortsUnsigned(Unsigned(Scrambled(10, -1)));
}
public void UnsignedOnlyTheFirstCount_AreSorted()
{
CheckSortsUnsigned(new RadixKeySorter(), Unsigned(Scrambled(4000, -1)), 3000);
}
///
/// Sorts keys with the bits they differ in found by .
///
[UnitTestSharp.IgnoreTest]
public void CheckSortsGivenBits(RadixKeySorter sorter, int[] keys, int count)
{
var expected = (int[])keys.Clone();
Array.Sort(expected, 0, count);
int low;
int high;
bool anyNegative;
RadixKeySorter.FindDifferingBits(keys, count, out low, out high, out anyNegative);
sorter.Sort(keys, count, low, high, anyNegative);
CheckEqual(expected, keys);
}
[UnitTestSharp.IgnoreTest]
public void CheckSortsUnsignedGivenBits(RadixKeySorter sorter, uint[] keys, int count)
{
var expected = (uint[])keys.Clone();
Array.Sort(expected, 0, count);
int low;
int high;
bool anyNegative;
RadixKeySorter.FindDifferingBits((int[])(object)keys, count, out low, out high, out anyNegative);
sorter.Sort(keys, count, low, high);
CheckEqual(expected, keys);
}
public void GivenTheirBits_ManyKeysAreSorted()
{
CheckSortsGivenBits(new RadixKeySorter(), Scrambled(3000, 0x7FFFFFFF), 3000);
}
public void GivenTheirBits_AFewKeysAreSorted()
{
CheckSortsGivenBits(new RadixKeySorter(), Scrambled(10, 0xFFFF), 10);
}
public void GivenTheirBits_KeysInTheMiddleBitsAreSorted()
{
CheckSortsGivenBits(new RadixKeySorter(), Scrambled(3000, 0x00FF0000), 3000);
}
public void GivenTheirBits_NegativeKeysComeFirst()
{
int[] keys = Scrambled(3000, 0x7FFFFFFF);
for (int i = 0; i < keys.Length; i += 2)
{
keys[i] = -keys[i];
}
CheckSortsGivenBits(new RadixKeySorter(), keys, 3000);
}
public void GivenTheirBits_OnlyTheFirstCountAreSorted()
{
CheckSortsGivenBits(new RadixKeySorter(), Scrambled(4000, 0x7FFFFFFF), 3000);
}
public void GivenMoreBitsThanTheyDifferIn_KeysAreStillSorted()
{
int[] keys = Scrambled(3000, 0xFF);
var expected = (int[])keys.Clone();
Array.Sort(expected);
new RadixKeySorter().Sort(keys, keys.Length, 0, 32, true);
CheckEqual(expected, keys);
}
public void GivenNoBitsAndNoKeys_ChangesNothing()
{
var keys = new[] { 3, 1, 2 };
new RadixKeySorter().Sort(keys, 0, 0, 0, false);
CheckEqual(new[] { 3, 1, 2 }, keys);
}
public void GivenTheirBits_UnsignedKeysAreSorted()
{
CheckSortsUnsignedGivenBits(new RadixKeySorter(), Unsigned(Scrambled(3000, -1)), 3000);
}
public void GivenTheirBits_UnsignedKeysInTheMiddleBitsAreSorted()
{
CheckSortsUnsignedGivenBits(new RadixKeySorter(), Unsigned(Scrambled(3000, 0x00FF0000)), 3000);
}
public void GivenTheirBits_UnsignedOnlyTheFirstCountAreSorted()
{
CheckSortsUnsignedGivenBits(new RadixKeySorter(), Unsigned(Scrambled(4000, -1)), 3000);
}
public void GivenBits_NullKeysThrow()
{
CheckThrow(typeof(ArgumentNullException));
new RadixKeySorter().Sort((int[])null, 0, 0, 0, false);
}
public void GivenBits_UnsignedNullKeysThrow()
{
CheckThrow(typeof(ArgumentNullException));
new RadixKeySorter().Sort((uint[])null, 0, 0, 0);
}
public void GivenBits_CountBeyondTheKeysThrows()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().Sort(new int[3], 4, 0, 32, false);
}
public void GivenBits_UnsignedCountBeyondTheKeysThrows()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().Sort(new uint[3], 4, 0, 32);
}
public void GivenBits_AnEndBeforeTheStartThrows()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().Sort(new int[3], 3, 5, 4, false);
}
public void GivenBits_UnsignedAnEndBeyondAKeyThrows()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().Sort(new uint[3], 3, 0, 33);
}
public void NullKeys_Throws()
{
CheckThrow(typeof(ArgumentNullException));
new RadixKeySorter().Sort((int[])null, 0);
}
public void UnsignedNullKeys_Throws()
{
CheckThrow(typeof(ArgumentNullException));
new RadixKeySorter().Sort((uint[])null, 0);
}
public void NegativeCount_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().Sort(new int[3], -1);
}
public void CountBeyondTheKeys_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().Sort(new int[3], 4);
}
public void UnsignedCountBeyondTheKeys_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().Sort(new uint[3], 4);
}
public static readonly int[] AllocationSource = Scrambled(5000, 0x7FFFFFFF);
public static readonly int[] AllocationKeys = new int[5000];
public static readonly RadixKeySorter AllocationSorter = Grown();
public static RadixKeySorter Grown()
{
var returnMe = new RadixKeySorter();
Array.Copy(AllocationSource, AllocationKeys, 5000);
returnMe.Sort(AllocationKeys, 5000);
return returnMe;
}
[UnitTestSharp.AllocationTest]
public void OnceTheScratchSpaceHasGrown_AllocatesNothing()
{
Array.Copy(AllocationSource, AllocationKeys, 5000);
AllocationSorter.Sort(AllocationKeys, 5000);
CheckNoAllocations();
CheckTrue(AllocationKeys[0] <= AllocationKeys[4999]);
}
}
public class SortedCopyTests : UnitTestSharp.TestFixture
{
[UnitTestSharp.IgnoreTest]
public void CheckCopies(int[] keys)
{
var original = (int[])keys.Clone();
var expected = (int[])keys.Clone();
Array.Sort(expected);
int[] sorted = new RadixKeySorter().SortedCopy(keys);
CheckEqual(expected, sorted);
CheckEqual(original, keys);
CheckFalse(ReferenceEquals(keys, sorted));
}
[UnitTestSharp.IgnoreTest]
public void CheckCopiesUnsigned(uint[] keys)
{
var original = (uint[])keys.Clone();
var expected = (uint[])keys.Clone();
Array.Sort(expected);
uint[] sorted = new RadixKeySorter().SortedCopy(keys);
CheckEqual(expected, sorted);
CheckEqual(original, keys);
CheckFalse(ReferenceEquals(keys, sorted));
}
public void NoKeys_ReturnsAnEmptyArray()
{
CheckCopies(new int[0]);
}
public void AFewKeys_AreSortedAndTheOriginalIsUntouched()
{
CheckCopies(Scrambled(10, 0xFFFF));
}
public void ManyKeys_AreSortedAndTheOriginalIsUntouched()
{
CheckCopies(Scrambled(20000, 0x7FFFFFFF));
}
public void ManyKeysThatTakeOnePass_AreSorted()
{
CheckCopies(Scrambled(3000, 0xFF));
}
public void ManyKeysThatTakeTwoPasses_AreSorted()
{
CheckCopies(Scrambled(3000, 0xFFFF));
}
public void ManyKeysThatTakeThreePasses_AreSorted()
{
CheckCopies(Scrambled(3000, 0x7FFFFFFF));
}
public void OneKey_ReturnsACopy()
{
CheckCopies(new[] { 4 });
}
public void ManyAlreadyAscending_ReturnACopy()
{
CheckCopies(Enumerable.Range(0, 3000).ToArray());
}
public void ManyEqualKeys_ReturnACopy()
{
CheckCopies(Enumerable.Repeat(7, 3000).ToArray());
}
public void ManyWithNegatives_PutNegativesFirst()
{
int[] keys = Scrambled(3000, 0x7FFFFFFF);
for (int i = 0; i < keys.Length; i += 2)
{
keys[i] = -keys[i];
}
CheckCopies(keys);
}
public void UnsignedKeysPastTheIntRange_AreSortedAsUnsigned()
{
CheckCopiesUnsigned(Unsigned(Scrambled(3000, -1)));
}
public void UnsignedAFewKeys_AreSorted()
{
CheckCopiesUnsigned(Unsigned(Scrambled(10, -1)));
}
public void UnsignedAlreadyAscending_ReturnACopy()
{
CheckCopiesUnsigned(Enumerable.Range(0, 3000).Select(i => (uint)i).ToArray());
}
public void UnsignedManyEqualKeys_ReturnACopy()
{
CheckCopiesUnsigned(Enumerable.Repeat(7u, 3000).ToArray());
}
public void UnsignedKeysThatTakeOnePass_AreSorted()
{
CheckCopiesUnsigned(Unsigned(Scrambled(3000, 0xFF)));
}
[UnitTestSharp.IgnoreTest]
public void CheckCopiesGivenBits(int[] keys)
{
var original = (int[])keys.Clone();
var expected = (int[])keys.Clone();
Array.Sort(expected);
int low = 0;
int high = 0;
bool anyNegative = false;
if (keys.Length > 1)
{
RadixKeySorter.FindDifferingBits(keys, keys.Length, out low, out high, out anyNegative);
}
int[] sorted = new RadixKeySorter().SortedCopy(keys, low, high, anyNegative);
CheckEqual(expected, sorted);
CheckEqual(original, keys);
CheckFalse(ReferenceEquals(keys, sorted));
}
[UnitTestSharp.IgnoreTest]
public void CheckCopiesUnsignedGivenBits(uint[] keys)
{
var original = (uint[])keys.Clone();
var expected = (uint[])keys.Clone();
Array.Sort(expected);
int low = 0;
int high = 0;
if (keys.Length > 1)
{
bool anyNegative;
RadixKeySorter.FindDifferingBits((int[])(object)keys, keys.Length, out low, out high,
out anyNegative);
}
uint[] sorted = new RadixKeySorter().SortedCopy(keys, low, high);
CheckEqual(expected, sorted);
CheckEqual(original, keys);
CheckFalse(ReferenceEquals(keys, sorted));
}
public void GivenTheirBits_ManyKeysAreSortedAndTheOriginalIsUntouched()
{
CheckCopiesGivenBits(Scrambled(3000, 0x7FFFFFFF));
}
public void GivenTheirBits_NegativesComeFirst()
{
int[] keys = Scrambled(3000, 0x7FFFFFFF);
for (int i = 0; i < keys.Length; i += 2)
{
keys[i] = -keys[i];
}
CheckCopiesGivenBits(keys);
}
public void GivenTheirBits_EqualKeysReturnACopy()
{
CheckCopiesGivenBits(Enumerable.Repeat(7, 3000).ToArray());
}
public void GivenTheirBits_NoKeysReturnsAnEmptyArray()
{
CheckCopiesGivenBits(new int[0]);
}
public void GivenTheirBits_OneKeyReturnsACopy()
{
CheckCopiesGivenBits(new[] { 4 });
}
public void GivenTheirBits_UnsignedKeysAreSortedAndTheOriginalIsUntouched()
{
CheckCopiesUnsignedGivenBits(Unsigned(Scrambled(3000, -1)));
}
public void GivenTheirBits_UnsignedEqualKeysReturnACopy()
{
CheckCopiesUnsignedGivenBits(Enumerable.Repeat(7u, 3000).ToArray());
}
public void GivenTheirBits_UnsignedOneKeyReturnsACopy()
{
CheckCopiesUnsignedGivenBits(new uint[] { 4 });
}
public void GivenBits_NullKeysThrow()
{
CheckThrow(typeof(ArgumentNullException));
new RadixKeySorter().SortedCopy((int[])null, 0, 0, false);
}
public void GivenBits_UnsignedNullKeysThrow()
{
CheckThrow(typeof(ArgumentNullException));
new RadixKeySorter().SortedCopy((uint[])null, 0, 0);
}
public void GivenBits_AStartBelowZeroThrows()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().SortedCopy(new int[3], -1, 4, false);
}
public void GivenBits_UnsignedAnEndBeforeTheStartThrows()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
new RadixKeySorter().SortedCopy(new uint[3], 5, 4);
}
public void NullKeys_Throws()
{
CheckThrow(typeof(ArgumentNullException));
new RadixKeySorter().SortedCopy((int[])null);
}
public void UnsignedNullKeys_Throws()
{
CheckThrow(typeof(ArgumentNullException));
new RadixKeySorter().SortedCopy((uint[])null);
}
}
public class CheckBitsTests : UnitTestSharp.TestFixture
{
public void EveryRangeWithinAKey_IsAccepted()
{
for (int low = 0; low <= 32; ++low)
{
for (int high = low; high <= 32; ++high)
{
RadixKeySorter.CheckBits(low, high);
}
}
}
public void ALowBelowZero_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
RadixKeySorter.CheckBits(-1, 5);
}
public void ALowBeyondAKey_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
RadixKeySorter.CheckBits(33, 33);
}
public void AHighBeforeTheLow_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
RadixKeySorter.CheckBits(5, 4);
}
public void AHighBeyondAKey_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
RadixKeySorter.CheckBits(0, 33);
}
}
public class FindDifferingBitsTests : UnitTestSharp.TestFixture
{
[UnitTestSharp.IgnoreTest]
public void CheckFinds(int[] keys, int count, int expectedLow, int expectedHigh, bool expectedNegative)
{
int low;
int high;
bool anyNegative;
RadixKeySorter.FindDifferingBits(keys, count, out low, out high, out anyNegative);
CheckEqual(expectedLow, low);
CheckEqual(expectedHigh, high);
CheckEqual(expectedNegative, anyNegative);
}
public void EqualKeys_DifferInNoBits()
{
CheckFinds(new[] { 5, 5, 5 }, 3, 0, 0, false);
}
public void KeysDifferingInTheLowBits_GiveThatRange()
{
CheckFinds(new[] { 4, 5, 6 }, 3, 0, 2, false);
}
public void KeysDifferingOnlyInTheMiddle_GiveThatRange()
{
CheckFinds(new[] { 0x100, 0x300, 0x200 }, 3, 8, 10, false);
}
public void KeysDifferingInTheTopBit_ReachBitThirtyOne()
{
CheckFinds(new[] { 0, 1 << 30 }, 2, 30, 31, false);
}
public void ANegativeFirstKey_IsNegative()
{
CheckFinds(new[] { -1, -1 }, 2, 0, 0, true);
}
public void ANegativeLaterKey_IsNegative()
{
CheckFinds(new[] { 1, 2, -3 }, 3, 0, 32, true);
}
public void OnlyTheFirstCountKeysAreLookedAt()
{
CheckFinds(new[] { 1, 3, -1 }, 2, 1, 2, false);
}
public void AWholeArray_IsLookedAtToItsEnd()
{
CheckFinds(new[] { 1, 3, 0x10 }, 3, 0, 5, false);
}
}
public class ChoosePassesTests : UnitTestSharp.TestFixture
{
public void OneBit_TakesOnePass()
{
CheckEqual(1, RadixKeySorter.ChoosePasses(span: 1, count: 100000));
}
public void ADigitsWorthOfBits_TakesOnePass()
{
CheckEqual(1, RadixKeySorter.ChoosePasses(span: 8, count: 100000));
}
public void MoreBitsThanADigit_TakeMorePasses()
{
CheckTrue(RadixKeySorter.ChoosePasses(span: 31, count: 100000) >= 3);
}
public void NeverMoreBitsThanADigitCanHold_InAPass()
{
for (int span = 1; span <= 32; ++span)
{
int passes = RadixKeySorter.ChoosePasses(span, count: 5000);
CheckTrue((span + passes - 1) / passes <= RadixKeySorter.MaxDigitBits);
}
}
public void FewKeys_PreferNarrowerDigitsToClearingBigBuckets()
{
int fewKeys = RadixKeySorter.ChoosePasses(span: 16, count: 50);
int manyKeys = RadixKeySorter.ChoosePasses(span: 16, count: 5000000);
CheckTrue(fewKeys > manyKeys);
}
}
public class FlipSignsTests : UnitTestSharp.TestFixture
{
public void SwapsWhichKeysSortFirst()
{
var keys = new[] { -1, 1 };
RadixKeySorter.FlipSigns(keys, 2);
CheckEqual(new[] { int.MaxValue, int.MinValue + 1 }, keys);
}
public void TwiceRestoresTheKeys()
{
int[] keys = Scrambled(100, -1);
int[] original = (int[])keys.Clone();
RadixKeySorter.FlipSigns(keys, 100);
RadixKeySorter.FlipSigns(keys, 100);
CheckEqual(original, keys);
}
public void OnlyTheFirstCountKeysChange()
{
var keys = new[] { 0, 0, 0 };
RadixKeySorter.FlipSigns(keys, 2);
CheckEqual(new[] { int.MinValue, int.MinValue, 0 }, keys);
}
}
public class ClearCountsTests : UnitTestSharp.TestFixture
{
public void SetsEveryCountToZero()
{
var counts = new[] { 3, 1, 4, 1, 5 };
RadixKeySorter.ClearCounts(counts);
CheckEqual(new[] { 0, 0, 0, 0, 0 }, counts);
}
}
public class BucketsForTests : UnitTestSharp.TestFixture
{
public void HasOneBucketForEachValueOfTheDigit()
{
var cache = new int[RadixKeySorter.MaxDigitBits + 1][];
CheckEqual(64, RadixKeySorter.BucketsFor(cache, 6).Length);
CheckEqual(2048, RadixKeySorter.BucketsFor(cache, 11).Length);
}
public void AskedAgain_ReturnsTheSameCounts()
{
var cache = new int[RadixKeySorter.MaxDigitBits + 1][];
int[] first = RadixKeySorter.BucketsFor(cache, 5);
CheckTrue(ReferenceEquals(first, RadixKeySorter.BucketsFor(cache, 5)));
}
public void ForDifferentDigitSizes_ReturnsDifferentCounts()
{
var cache = new int[RadixKeySorter.MaxDigitBits + 1][];
CheckFalse(ReferenceEquals(RadixKeySorter.BucketsFor(cache, 5), RadixKeySorter.BucketsFor(cache, 6)));
}
}
public class StartOffsetsTests : UnitTestSharp.TestFixture
{
public void TurnsCountsIntoWhereEachBucketStarts()
{
var counts = new[] { 2, 0, 3, 1 };
RadixKeySorter.StartOffsets(counts);
CheckEqual(new[] { 0, 2, 2, 5 }, counts);
}
}
public class CountDigitsTests : UnitTestSharp.TestFixture
{
public void CountsTheKeysInEachBucketOfTheDigit()
{
var counts = new int[4];
RadixKeySorter.CountDigits(new[] { 0, 1, 1, 2, 3, 3, 3 }, 7, counts, shift: 0, shiftedMask: 3);
CheckEqual(new[] { 1, 2, 1, 3 }, counts);
}
public void LooksAtTheDigitAtTheShift()
{
var counts = new int[4];
RadixKeySorter.CountDigits(new[] { 0x4, 0x8, 0xC, 0x0 }, 4, counts, shift: 2, shiftedMask: 3 << 2);
CheckEqual(new[] { 1, 1, 1, 1 }, counts);
}
public void OnlyTheFirstCountKeysAreCounted()
{
var counts = new int[4];
RadixKeySorter.CountDigits(new[] { 0, 1, 2, 3 }, 2, counts, shift: 0, shiftedMask: 3);
CheckEqual(new[] { 1, 1, 0, 0 }, counts);
}
public void OfAll_CountsEveryKey()
{
var counts = new int[4];
RadixKeySorter.CountDigitsOfAll(new[] { 0, 1, 1, 2, 3, 3, 3 }, counts, shift: 0, shiftedMask: 3);
CheckEqual(new[] { 1, 2, 1, 3 }, counts);
}
}
public class ScatterTests : UnitTestSharp.TestFixture
{
public void PutsEachKeyWhereItsBucketStartsAndKeepsTheOrderInABucket()
{
var target = new int[5];
var starts = new[] { 0, 1, 3, 4 };
RadixKeySorter.Scatter(new[] { 1, 0, 1, 3, 2 }, target, 5, starts, shift: 0, shiftedMask: 3);
CheckEqual(new[] { 0, 1, 1, 2, 3 }, target);
}
public void OnlyTheFirstCountKeysMove()
{
var target = new int[3];
var starts = new[] { 0, 1, 2, 2 };
RadixKeySorter.Scatter(new[] { 1, 0, 2, 3 }, target, 3, starts, shift: 0, shiftedMask: 3);
CheckEqual(new[] { 0, 1, 2 }, target);
}
public void OfAll_MovesEveryKey()
{
var target = new int[5];
var starts = new[] { 0, 1, 3, 4 };
RadixKeySorter.ScatterAll(new[] { 1, 0, 1, 3, 2 }, target, starts, shift: 0, shiftedMask: 3);
CheckEqual(new[] { 0, 1, 1, 2, 3 }, target);
}
}
}
}