diff options
Diffstat (limited to 'test/source/TestSort.cpp')
-rw-r--r-- | test/source/TestSort.cpp | 961 |
1 files changed, 0 insertions, 961 deletions
diff --git a/test/source/TestSort.cpp b/test/source/TestSort.cpp deleted file mode 100644 index 114a73b..0000000 --- a/test/source/TestSort.cpp +++ /dev/null @@ -1,961 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -///////////////////////////////////////////////////////////////////////////// - - -#include <EABase/eabase.h> - -// Some versions of GCC generate an array bounds warning in opt builds which -// doesn't say what line below it comes from and doesn't appear to be a valid -// warning. In researching this on the Internet it appears that this is a -// known problem with GCC. -#if defined(EA_DISABLE_GCC_WARNING) - EA_DISABLE_GCC_WARNING(-Warray-bounds) -#endif - -#include "EASTLTest.h" -#include <EASTL/sort.h> -#include <EASTL/bonus/sort_extra.h> -#include <EASTL/vector.h> -#include <EASTL/list.h> -#include <EASTL/deque.h> -#include <EASTL/algorithm.h> -#include <EASTL/allocator.h> -#include <EASTL/numeric.h> -#include <EASTL/random.h> -#include <EABase/eahave.h> -#include <cmath> - - -namespace eastl -{ - namespace Internal - { - typedef eastl::vector<int> IntArray; - typedef eastl::vector<IntArray> IntArrayArray; - - - // IntArrayCompare - // Used to compare IntArray objects. - struct IntArrayCompare - { - bool operator()(const IntArray& a, const IntArray& b) - { return a.front() < b.front(); } - }; - - - // SafeFloatCompare - // - // Float comparison has a problem for the case that either of the floats are a NaN. - // If you use a NaN in a sort function that uses default floating point comparison then - // you will get undefined behavior, as all NaNs compare false. This compare function - // class sorts floats such that all negative NaNs sort lower than all integers, and all - // positive NaNs sort higher than all integers. - // - // Example usage: - // eastl::sort(floatArray.begin(), floatArray.end(), SafeFloatCompare()); - // - struct SafeFloatCompare - { - union FloatInt32{ float f; int32_t i; }; - - bool operator()(float a, float b) const - { - #if defined(EA_HAVE_ISNAN) - bool aNan = (EA_HAVE_ISNAN(a) != 0); - bool bNan = (EA_HAVE_ISNAN(b) != 0); - #else - bool aNan = (a != a); // This works as long as the compiler doesn't do any tricks to optimize it away. - bool bNan = (b != b); - #endif - - if(!aNan && !bNan) - return (a < b); - - FloatInt32 fia = { a }; - FloatInt32 fib = { b }; - - if(aNan) - { - if(bNan) - return (fia.i < fib.i); // Both are NaNs, so do a binary compare. - else - return (fia.i < 0); // All negative NaNs are assumed to be less than all non-NaNs. - } - else - return (0 < fib.i); // All negative NaNs are assumed to be less than all non-NaNs. - } - }; - - - - // StatefulCompare - // Used to verify that sort<int, StatefulCompare&>() respects the - // fact that StatefulCompare is passed by reference instead of by value. - // All existing commercial STL implementations fail to do what the user - // wants and instead pass around the compare object by value, even if - // the user specifically asks to use it by reference. EASTL doesn't - // have this problem. - struct StatefulCompare - { - static int nCtorCount; - static int nDtorCount; - static int nCopyCount; - - StatefulCompare() - { nCtorCount++; } - - StatefulCompare(StatefulCompare&) - { nCopyCount++; } - - ~StatefulCompare() - { nDtorCount++; } - - StatefulCompare& operator=(const StatefulCompare&) - { nCopyCount++; return *this; } - - bool operator()(int a, int b) - { return a < b; } - - static void Reset() - { nCtorCount = 0; nDtorCount = 0; nCopyCount = 0; } - }; - - int StatefulCompare::nCtorCount = 0; - int StatefulCompare::nDtorCount = 0; - int StatefulCompare::nCopyCount = 0; - - - // TestObjectPtrCompare - // Used to compare sorted objects by pointer instead of value. - struct TestObjectPtrCompare - { - bool operator()(TestObject* a, TestObject* b) - { return a->mX < b->mX; } - }; - - - // TestObjectIndexCompare - // Used to compare sorted objects by array index instead of value. - struct TestObjectIndexCompare - { - vector<TestObject>* mpArray; - - TestObjectIndexCompare(vector<TestObject>* pArray) : mpArray(pArray) { } - TestObjectIndexCompare(const TestObjectIndexCompare& x) : mpArray(x.mpArray){ } - TestObjectIndexCompare& operator=(const TestObjectIndexCompare& x) { mpArray = x.mpArray; return *this; } - - bool operator()(eastl_size_t a, eastl_size_t b) - { return (*mpArray)[a] < (*mpArray)[b]; } - }; - - // Radix sort elements - template <typename Key> - struct RadixSortElement - { - typedef Key radix_type; - Key mKey; - uint16_t mData; - - bool operator<(const RadixSortElement<Key> &other) const - { - return mKey < other.mKey; - } - }; - - typedef RadixSortElement<uint8_t> RadixSortElement8; - typedef RadixSortElement<uint16_t> RadixSortElement16; - typedef RadixSortElement<uint32_t> RadixSortElement32; - - template <typename integer_type> - struct identity_extract_radix_key - { - typedef integer_type radix_type; - - const radix_type operator()(const integer_type& x) const - { - return x; - } - }; - - struct TestNoLessOperator - { - int i {}; - }; - } // namespace Internal - - template <> - struct less<Internal::TestNoLessOperator> - { - bool operator()(const Internal::TestNoLessOperator& lhs, const Internal::TestNoLessOperator& rhs) const noexcept - { - return lhs.i < rhs.i; - } - }; - -} // namespace eastl - -int TestSort() -{ - using namespace eastl; - using namespace Internal; - - int nErrorCount = 0; - - EASTLTest_Rand rng(EA::UnitTest::GetRandSeed()); - - { - // is_sorted - int array[] = { 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 2, 2, 1, 0 }; - - EATEST_VERIFY( is_sorted(array + 0, array + 0)); - EATEST_VERIFY( is_sorted(array + 2, array + 4)); - EATEST_VERIFY( is_sorted(array + 0, array + 10)); - EATEST_VERIFY(!is_sorted(array + 0, array + 14)); - EATEST_VERIFY( is_sorted(array + 11, array + 23, eastl::greater<int>())); - } - - { - // is_sorted_until - int sorted[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - int notsorted[] = { 0, 1, 2, 3, 4, 42, 6, 7, 8, 9 }; - - EATEST_VERIFY( is_sorted_until(sorted + EAArrayCount(sorted), sorted + EAArrayCount(sorted)) == sorted + EAArrayCount(sorted) ); - EATEST_VERIFY( is_sorted_until(sorted , sorted + EAArrayCount(sorted)) == sorted + EAArrayCount(sorted) ); - - EATEST_VERIFY( is_sorted_until(sorted + 0, sorted + 0) == sorted ); - EATEST_VERIFY( is_sorted_until(sorted + 2, sorted + 8) == sorted + 8 ); - - EATEST_VERIFY( is_sorted_until(notsorted + 2, notsorted + 8) == notsorted + 6 ); - - // is_sorted_until (with compare function) - EATEST_VERIFY( is_sorted_until(sorted + EAArrayCount(sorted), sorted + EAArrayCount(sorted), eastl::less<int>()) == sorted + EAArrayCount(sorted) ); - EATEST_VERIFY( is_sorted_until(notsorted + 2, notsorted + 8, eastl::less<int>()) == notsorted + 6 ); - } - - // Sort arrays of size 0 - N. Sort M random permutations of each. - { - vector<int64_t> intArray, intArraySaved; - - for(int i = 0; i < (150 + (gEASTL_TestLevel * 200)); i += (i < 5) ? 1 : 37) // array sizes of 0 to 300 - 2100, depending on test level. - { - // intArraySaved.clear(); // Do we want to do this? - - for(int n = 0; n < i; n++) - { - intArraySaved.push_back(n); - - if(rng.RandLimit(10) == 0) - { - intArraySaved.push_back(n); - - if(rng.RandLimit(5) == 0) - intArraySaved.push_back(n); - } - } - const int64_t expectedSum = eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)); - - for(int j = 0; j < 300 + (gEASTL_TestLevel * 50); j++) - { - eastl::random_shuffle(intArraySaved.begin(), intArraySaved.end(), rng); - - intArray = intArraySaved; - bubble_sort(intArray.begin(), intArray.end()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - shaker_sort(intArray.begin(), intArray.end()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - insertion_sort(intArray.begin(), intArray.end()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - selection_sort(intArray.begin(), intArray.end()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - shell_sort(intArray.begin(), intArray.end()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - comb_sort(intArray.begin(), intArray.end()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - heap_sort(intArray.begin(), intArray.end()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - merge_sort(intArray.begin(), intArray.end(), *get_default_allocator((EASTLAllocatorType*)NULL)); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - vector<int64_t> buffer(intArray.size()); - merge_sort_buffer(intArray.begin(), intArray.end(), buffer.data()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - quick_sort(intArray.begin(), intArray.end()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - - intArray = intArraySaved; - buffer.resize(intArray.size()/2); - tim_sort_buffer(intArray.begin(), intArray.end(), buffer.data()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum); - } - } - } - - // Test tim sort with a specific array size and seed that caused a crash - { - vector<int64_t> intArray; - int i = 1000000; - { - EASTLTest_Rand testRng(232526); - - for (int n = 0; n < i; n++) - { - intArray.push_back(testRng.Rand()); - } - vector<int64_t> buffer(intArray.size() / 2); - tim_sort_buffer(intArray.begin(), intArray.end(), buffer.data()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - } - } - - // Test insertion_sort() does not invalidate a BidirectionalIterator by doing --BidirectionalIterator.begin() - { - // Test Passes if the Test doesn't crash - eastl::deque<int> deque; - deque.push_back(1); - - insertion_sort(deque.begin(), deque.end()); - - insertion_sort(deque.begin(), deque.end(), eastl::less<int>{}); - } - - - // TestObject sorting - TestObject::Reset(); - { - vector<TestObject> toArray, toArraySaved; - - for(int i = 0; i < (150 + (gEASTL_TestLevel * 200)); i += (i < 5) ? 1 : 37) // array sizes of 0 to 300 - 2100, depending on test level. - { - for(int n = 0; n < i; n++) - { - toArraySaved.push_back(TestObject(n)); - - if(rng.RandLimit(10) == 0) - { - toArraySaved.push_back(TestObject(n)); - - if(rng.RandLimit(5) == 0) - toArraySaved.push_back(TestObject(n)); - } - } - - for(int j = 0; j < 300 + (gEASTL_TestLevel * 50); j++) - { - eastl::random_shuffle(toArraySaved.begin(), toArraySaved.end(), rng); - - toArray = toArraySaved; - bubble_sort(toArray.begin(), toArray.end()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - toArray = toArraySaved; - shaker_sort(toArray.begin(), toArray.end()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - toArray = toArraySaved; - insertion_sort(toArray.begin(), toArray.end()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - toArray = toArraySaved; - selection_sort(toArray.begin(), toArray.end()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - toArray = toArraySaved; - shell_sort(toArray.begin(), toArray.end()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - toArray = toArraySaved; - comb_sort(toArray.begin(), toArray.end()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - toArray = toArraySaved; - heap_sort(toArray.begin(), toArray.end()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - // Not ready yet: - toArray = toArraySaved; - merge_sort(toArray.begin(), toArray.end(), *get_default_allocator((EASTLAllocatorType*)NULL)); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - toArray = toArraySaved; - quick_sort(toArray.begin(), toArray.end()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - - toArray = toArraySaved; - vector<TestObject> buffer(toArray.size()/2); - tim_sort_buffer(toArray.begin(), toArray.end(), buffer.data()); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end())); - } - } - } - - // Test that stable sorting algorithms are actually stable - { - struct StableSortTestObj - { - StableSortTestObj() - { - } - - StableSortTestObj(int value) - :value(value) - ,initialPositionIndex(0) - { - } - - int value; - size_t initialPositionIndex; - }; - - // During the test this comparison is used to sort elements based on value. - struct StableSortCompare - { - bool operator()(const StableSortTestObj& a, const StableSortTestObj& b) - { - return a.value < b.value; - } - }; - - // During the test this comparison is used to verify the sort was a stable sort. i.e. if values are the same then - // their relative position should be maintained. - struct StableSortCompareForStability - { - bool operator()(const StableSortTestObj& a, const StableSortTestObj& b) - { - if (a.value != b.value) - { - return a.value < b.value; - } - else - { - return a.initialPositionIndex < b.initialPositionIndex; - } - } - }; - - vector<StableSortTestObj> toArray, toArraySaved; - StableSortCompare compare; - StableSortCompareForStability compareForStability; - - for (int i = 0; i < (150 + (gEASTL_TestLevel * 200)); i += (i < 5) ? 1 : 37) // array sizes of 0 to 300 - 2100, depending on test level. - { - for (int n = 0; n < i; n++) - { - toArraySaved.push_back(StableSortTestObj(n)); - - if (rng.RandLimit(10) == 0) - { - toArraySaved.push_back(StableSortTestObj(n)); - - if (rng.RandLimit(5) == 0) - toArraySaved.push_back(StableSortTestObj(n)); - } - } - vector<StableSortTestObj> tempBuffer; - tempBuffer.resize(toArraySaved.size()); - - for (int j = 0; j < 300 + (gEASTL_TestLevel * 50); j++) - { - eastl::random_shuffle(toArraySaved.begin(), toArraySaved.end(), rng); - // Store the intial position of each element in the array before sorting. This position can then be used to verify that the sorting operation is stable. - for (vector<StableSortTestObj>::size_type k = 0; k < toArraySaved.size(); k++) - { - toArraySaved[k].initialPositionIndex = k; - } - - toArray = toArraySaved; - bubble_sort(toArray.begin(), toArray.end(), compare); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability)); - - toArray = toArraySaved; - shaker_sort(toArray.begin(), toArray.end(), compare); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability)); - - toArray = toArraySaved; - insertion_sort(toArray.begin(), toArray.end(), compare); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability)); - - toArray = toArraySaved; - tim_sort_buffer(toArray.begin(), toArray.end(), tempBuffer.data(), compare); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability)); - - toArray = toArraySaved; - merge_sort(toArray.begin(), toArray.end(), *get_default_allocator((EASTLAllocatorType*)NULL), compare); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability)); - - toArray = toArraySaved; - merge_sort_buffer(toArray.begin(), toArray.end(), tempBuffer.data(), compare); - EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability)); - } - } - } - - { - // OutputIterator merge(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) - // This is tested by merge_sort. - } - - - { - // void partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) - // This is tested by quick_sort. - } - - - { - // void nth_element(RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last) - // void nth_element(RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last, Compare compare) - const int intArrayInit[16] = { 4, 2, 8, 6, 9, 1, 1, 4, 0, 5, 5, 7, 8, 9, 3, 3 }; - int intArraySorted[16]; // Same as intArrayInit but sorted - int intArray[16]; - size_t i, j; - - // We test many combinations of nth_element on the int array. - for(i = 1; i < 16; i++) - { - for(j = 0; j < i; j++) - { - eastl::copy(intArrayInit, intArrayInit + i, intArraySorted); - eastl::sort(intArraySorted, intArraySorted + i); - - eastl::copy(intArrayInit, intArrayInit + i, intArray); - nth_element(intArray, intArray + j, intArray + i); - EATEST_VERIFY(intArray[j] == intArraySorted[j]); - } - } - - for(i = 1; i < 16; i++) - { - for(j = 0; j < i; j++) - { - eastl::copy(intArrayInit, intArrayInit + i, intArraySorted); - eastl::sort(intArraySorted, intArraySorted + i); - - eastl::copy(intArrayInit, intArrayInit + 16, intArray); - nth_element(intArray, intArray + j, intArray + i, eastl::less<int>()); - EATEST_VERIFY(intArray[j] == intArraySorted[j]); - } - } - } - - - { - // void radix_sort(RandomAccessIterator first, RandomAccessIterator last, RandomAccessIterator buffer); - const uint32_t kCount = 100; - - { - RadixSortElement32* pRadixSortElementArray32 = new RadixSortElement32[kCount]; - RadixSortElement32* pRadixSortElementArrayTemp32 = new RadixSortElement32[kCount]; - for(uint32_t i = 0; i < kCount; i++) - { - pRadixSortElementArray32[i].mKey = (uint16_t)(kCount - i); - pRadixSortElementArray32[i].mData = (uint16_t)i; - } - radix_sort<RadixSortElement32*, extract_radix_key<RadixSortElement32> >(pRadixSortElementArray32, pRadixSortElementArray32 + kCount, pRadixSortElementArrayTemp32); - EATEST_VERIFY(is_sorted(pRadixSortElementArray32, pRadixSortElementArray32 + kCount)); - delete[] pRadixSortElementArray32; - delete[] pRadixSortElementArrayTemp32; - } - - { - RadixSortElement16* pRadixSortElementArray16 = new RadixSortElement16[kCount]; - RadixSortElement16* pRadixSortElementArrayTemp16 = new RadixSortElement16[kCount]; - for(uint32_t i = 0; i < kCount; i++) - { - pRadixSortElementArray16[i].mKey = (uint16_t)(kCount - i); - pRadixSortElementArray16[i].mData = (uint16_t)i; - } - radix_sort<RadixSortElement16*, extract_radix_key<RadixSortElement16> >(pRadixSortElementArray16, pRadixSortElementArray16 + kCount, pRadixSortElementArrayTemp16); - EATEST_VERIFY(is_sorted(pRadixSortElementArray16, pRadixSortElementArray16 + kCount)); - delete[] pRadixSortElementArray16; - delete[] pRadixSortElementArrayTemp16; - } - - { - RadixSortElement8* pRadixSortElementArray8 = new RadixSortElement8[kCount]; - RadixSortElement8* pRadixSortElementArrayTemp8 = new RadixSortElement8[kCount]; - for(uint32_t i = 0; i < kCount; i++) - { - pRadixSortElementArray8[i].mKey = (uint8_t)(kCount - i); - pRadixSortElementArray8[i].mData = (uint8_t)i; - } - radix_sort<RadixSortElement8*, extract_radix_key<RadixSortElement8> >(pRadixSortElementArray8, pRadixSortElementArray8 + kCount, pRadixSortElementArrayTemp8); - EATEST_VERIFY(is_sorted(pRadixSortElementArray8, pRadixSortElementArray8 + kCount)); - delete[] pRadixSortElementArray8; - delete[] pRadixSortElementArrayTemp8; - } - } - - { - // Do some white-box testing of radix sort to verify internal optimizations work properly for some edge cases. - - { - uint32_t input[] = { 123, 15, 76, 2, 74, 12, 62, 91 }; - uint32_t buffer[EAArrayCount(input)]; - radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - { - // Test values where some digit positions have identical values - uint32_t input[] = { 0x75000017, 0x74000003, 0x73000045, 0x76000024, 0x78000033, 0x76000099, 0x78000043, 0x75000010 }; - uint32_t buffer[EAArrayCount(input)]; - radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - { - // Test values where some digit positions have identical values - uint32_t input[] = { 0x00750017, 0x00740003, 0x00730045, 0x00760024, 0x00780033, 0x00760099, 0x00780043, 0x00750010 }; - uint32_t buffer[EAArrayCount(input)]; - radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - { - // Test values where an odd number of scatter operations will be done during sorting (which forces a copy operation to move values back to the input buffer). - uint32_t input[] = { 0x00000017, 0x00000003, 0x00000045, 0x00000024, 0x00000033, 0x00000099, 0x00000043, 0x00000010 }; - uint32_t buffer[EAArrayCount(input)]; - radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - { - // Test case for bug where the last histogram bucket was not being cleared to zero - uint32_t input[] = { 0xff00, 0xff }; - uint32_t buffer[EAArrayCount(input)]; - radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - } - - { - // Test different values for DigitBits - - { - uint32_t input[] = {2514513, 6278225, 2726217, 963245656, 35667326, 2625624562, 3562562562, 1556256252}; - uint32_t buffer[EAArrayCount(input)]; - radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>, 1>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - { - uint32_t input[] = { 2514513, 6278225, 2726217, 963245656, 35667326, 2625624562, 3562562562, 1556256252 }; - uint32_t buffer[EAArrayCount(input)]; - radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>, 3>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - { - uint32_t input[] = { 2514513, 6278225, 2726217, 963245656, 35667326, 2625624562, 3562562562, 1556256252 }; - uint32_t buffer[EAArrayCount(input)]; - radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>, 6>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - { - // Test a value for DigitBits that is more than half the size of the type. - uint16_t input[] = { 14513, 58225, 26217, 34656, 63326, 24562, 35562, 15652 }; - uint16_t buffer[EAArrayCount(input)]; - radix_sort<uint16_t*, identity_extract_radix_key<uint16_t>, 11>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - { - // Test a value for DigitBits that is the size of the type itself. - uint8_t input[] = { 113, 225, 217, 56, 26, 162, 62, 152 }; - uint8_t buffer[EAArrayCount(input)]; - radix_sort<uint8_t*, identity_extract_radix_key<uint8_t>, 8>(begin(input), end(input), buffer); - EATEST_VERIFY(is_sorted(begin(input), end(input))); - } - - } - - { - // void bucket_sort(ForwardIterator first, ForwardIterator last, ContainerArray& bucketArray, HashFunction hash) - - const size_t kElementRange = 32; - vector<int> intArray(1000); - - for(int i = 0; i < 1000; i++) - intArray[i] = rng() % kElementRange; - - vector< vector<int> > bucketArray(kElementRange); - bucket_sort(intArray.begin(), intArray.end(), bucketArray, eastl::hash_use_self<int>()); - EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end())); - } - - - { - // stable_sort general test - typedef eastl::less<int> IntCompare; - - int intArray[2] = { 0, 1 }; - - stable_sort(intArray, intArray + 2); - stable_sort(intArray, intArray + 2, IntCompare()); - stable_sort<int*>(intArray, intArray + 2); - stable_sort<int*, IntCompare>(intArray, intArray + 2, IntCompare()); - - MallocAllocator mallocAllocator; - - //stable_sort(intArray, intArray + 2, mallocAllocator); - stable_sort(intArray, intArray + 2, mallocAllocator, IntCompare()); - //stable_sort<int*, MallocAllocator>(intArray, intArray + 2, mallocAllocator); - stable_sort<int*, MallocAllocator, IntCompare>(intArray, intArray + 2, mallocAllocator, IntCompare()); - } - - { - // stable_sort special test - IntArrayArray intArrayArray(2); - IntArrayCompare compare; - - intArrayArray[0].push_back(0); - intArrayArray[1].push_back(1); - - stable_sort(intArrayArray.begin(), intArrayArray.end(), compare); - } - - - { - // Test to verify that Compare object references are preserved. - typedef deque<int> IntDeque; - typedef IntDeque::iterator IntDequeIterator; - - IntDeque intDeque, intDequeSaved; - StatefulCompare compare; - - // Set up intDequeSaved with random data. - for(int n = 0; n < 500; n++) - { - intDequeSaved.push_back(n); - - if(rng.RandLimit(10) == 0) - { - intDequeSaved.push_back(n); - - if(rng.RandLimit(5) == 0) - intDequeSaved.push_back(n); - } - } - - eastl::random_shuffle(intDequeSaved.begin(), intDequeSaved.end(), rng); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - bubble_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - shaker_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - insertion_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - selection_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - shell_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - comb_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - heap_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - merge_sort<IntDequeIterator, EASTLAllocatorType, StatefulCompare&>(intDeque.begin(), intDeque.end(), *get_default_allocator((EASTLAllocatorType*)NULL), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - intDeque = intDequeSaved; - quick_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - - StatefulCompare::Reset(); - vector<int> buffer(intDeque.size()/2); - intDeque = intDequeSaved; - tim_sort_buffer<IntDequeIterator, int, StatefulCompare&>(intDeque.begin(), intDeque.end(), buffer.data(), compare); - EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0)); - } - - { - // Test checking that deque sorting can compile. - deque<int> intDeque; - vector<int> intVector; - - stable_sort(intDeque.begin(), intDeque.end()); - stable_sort(intVector.begin(), intVector.end()); - } - - { - // Test checking that sorting containers having elements of a type without an operator< compiles correctly - - vector<TestNoLessOperator> noLessVector; - - stable_sort(noLessVector.begin(), noLessVector.end()); - bubble_sort(noLessVector.begin(), noLessVector.end()); - shaker_sort(noLessVector.begin(), noLessVector.end()); - insertion_sort(noLessVector.begin(), noLessVector.end()); - selection_sort(noLessVector.begin(), noLessVector.end()); - shell_sort(noLessVector.begin(), noLessVector.end()); - comb_sort(noLessVector.begin(), noLessVector.end()); - heap_sort(noLessVector.begin(), noLessVector.end()); - merge_sort(noLessVector.begin(), noLessVector.end(), *get_default_allocator(nullptr)); - quick_sort(noLessVector.begin(), noLessVector.end()); - - vector<TestNoLessOperator> buffer; - tim_sort_buffer(noLessVector.begin(), noLessVector.end(), buffer.data()); -} - - { - // Test sorting of a container of pointers to objects as opposed to a container of objects themselves. - vector<TestObject> toArray; - vector<TestObject*> topArray; - - for(eastl_size_t i = 0; i < 32; i++) - toArray.push_back(TestObject((int)rng.RandLimit(20))); - for(eastl_size_t i = 0; i < 32; i++) // This needs to be a second loop because the addresses might change in the first loop due to container resizing. - topArray.push_back(&toArray[i]); - - quick_sort(topArray.begin(), topArray.end(), TestObjectPtrCompare()); - EATEST_VERIFY(is_sorted(topArray.begin(), topArray.end(), TestObjectPtrCompare())); - } - - - { - // Test sorting of a container of array indexes to objects as opposed to a container of objects themselves. - - vector<TestObject> toArray; - vector<eastl_size_t> toiArray; - - for(eastl_size_t i = 0; i < 32; i++) - { - toArray.push_back(TestObject((int)rng.RandLimit(20))); - toiArray.push_back(i); - } - - quick_sort(toiArray.begin(), toiArray.end(), TestObjectIndexCompare(&toArray)); - EATEST_VERIFY(is_sorted(toiArray.begin(), toiArray.end(), TestObjectIndexCompare(&toArray))); - } - - - { - // Test of special floating point sort in the presence of NaNs. - vector<float> floatArray; - union FloatInt32{ float f; int32_t i; } fi; - - for(int i = 0; i < 1000; i++) - { - fi.i = (int32_t)rng.Rand(); - floatArray.push_back(fi.f); - } - - // Without SafeFloatCompare, the following quick_sort will crash, hang, or generate inconsistent results. - quick_sort(floatArray.begin(), floatArray.end(), SafeFloatCompare()); - EATEST_VERIFY(is_sorted(floatArray.begin(), floatArray.end(), SafeFloatCompare())); - } - - { - auto test_stable_sort = [&](auto testArray, size_t count) - { - auto isEven = [](auto val) { return (val % 2) == 0; }; - auto isOdd = [](auto val) { return (val % 2) != 0; }; - - for (size_t i = 0; i < count; i++) - testArray.push_back((uint16_t)rng.Rand()); - - vector<uint16_t> evenArray; - vector<uint16_t> oddArray; - - eastl::copy_if(testArray.begin(), testArray.end(), eastl::back_inserter(evenArray), isEven); - eastl::copy_if(testArray.begin(), testArray.end(), eastl::back_inserter(oddArray), isOdd); - - const auto boundary = eastl::stable_partition(testArray.begin(), testArray.end(), isEven); - - const auto evenCount = eastl::distance(testArray.begin(), boundary); - const auto oddCount = eastl::distance(boundary, testArray.end()); - - const auto evenExpectedCount = (ptrdiff_t)evenArray.size(); - const auto oddExpectedCount = (ptrdiff_t)oddArray.size(); - - EATEST_VERIFY(evenCount == evenExpectedCount); - EATEST_VERIFY(oddCount == oddExpectedCount); - EATEST_VERIFY(eastl::equal(testArray.begin(), boundary, evenArray.begin())); - EATEST_VERIFY(eastl::equal(boundary, testArray.end(), oddArray.begin())); - }; - - test_stable_sort(vector<uint16_t>(), 1000); // Test stable_partition - test_stable_sort(vector<uint16_t>(), 0); // Test stable_partition on empty container - test_stable_sort(vector<uint16_t>(), 1); // Test stable_partition on container of one element - test_stable_sort(vector<uint16_t>(), 2); // Test stable_partition on container of two element - test_stable_sort(list<uint16_t>(), 0); // Test stable_partition on bidirectional iterator (not random access) - } - - #if 0 // Disabled because it takes a long time and thus far seems to show no bug in quick_sort. - { - // Regression of Coverity report for Madden 2014 that quick_sort is reading beyond an array bounds within insertion_sort_simple. - // The Madden code was sorting the 11 players on the field for a team by some criteria. We write - vector<int> intArray(11); - for(eastl_size_t i = 0; i < intArray.size(); i++) - intArray[i] = i; - - do { - vector<int> intArrayCopy(intArray); - - // We need to verify that intArray[12] is never accessed. We could do that with a stomp allocator, - // which we don't currently have set up for the EASTL unit tests, or we could put a breakpoint in - // the debugger. Until we get a stomp allocator installed, do the breakpoint solution. - quick_sort(intArrayCopy.begin(), intArrayCopy.end()); - } while(next_permutation(intArray.begin(), intArray.end())); - } - #endif - - EATEST_VERIFY(TestObject::IsClear()); - TestObject::Reset(); - - return nErrorCount; -} - - - - - - - - - |