diff options
Diffstat (limited to 'include/EASTL/sort.h')
-rw-r--r-- | include/EASTL/sort.h | 2022 |
1 files changed, 0 insertions, 2022 deletions
diff --git a/include/EASTL/sort.h b/include/EASTL/sort.h deleted file mode 100644 index fb1c6e5..0000000 --- a/include/EASTL/sort.h +++ /dev/null @@ -1,2022 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////// -// This file implements sorting algorithms. Some of these are equivalent to -// std C++ sorting algorithms, while others don't have equivalents in the -// C++ standard. We implement the following sorting algorithms: -// is_sorted -- -// sort -- Unstable. The implementation of this is mapped to quick_sort by default. -// quick_sort -- Unstable. This is actually an intro-sort (quick sort with switch to insertion sort). -// tim_sort -- Stable. -// tim_sort_buffer -- Stable. -// partial_sort -- Unstable. -// insertion_sort -- Stable. -// shell_sort -- Unstable. -// heap_sort -- Unstable. -// stable_sort -- Stable. The implementation of this is simply mapped to merge_sort. -// merge -- -// merge_sort -- Stable. -// merge_sort_buffer -- Stable. -// nth_element -- Unstable. -// radix_sort -- Stable. Important and useful sort for integral data, and faster than all others for this. -// comb_sort -- Unstable. Possibly the best combination of small code size but fast sort. -// bubble_sort -- Stable. Useful in practice for sorting tiny sets of data (<= 10 elements). -// selection_sort* -- Unstable. -// shaker_sort* -- Stable. -// bucket_sort* -- Stable. -// -// * Found in sort_extra.h. -// -// Additional sorting and related algorithms we may want to implement: -// partial_sort_copy This would be like the std STL version. -// paritition This would be like the std STL version. This is not categorized as a sort routine by the language standard. -// stable_partition This would be like the std STL version. -// counting_sort Maybe we don't want to implement this. -// -////////////////////////////////////////////////////////////////////////////// - - -#ifndef EASTL_SORT_H -#define EASTL_SORT_H - - -#include <EASTL/internal/config.h> -#include <EASTL/internal/move_help.h> -#include <EASTL/iterator.h> -#include <EASTL/memory.h> -#include <EASTL/algorithm.h> -#include <EASTL/functional.h> -#include <EASTL/heap.h> -#include <EASTL/allocator.h> -#include <EASTL/memory.h> - - -#if defined(EA_PRAGMA_ONCE_SUPPORTED) - #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. -#endif - - -// EASTL_PLATFORM_PREFERRED_ALIGNMENT -// -// Allows for slightly faster buffers in some cases. -// -#if !defined(EASTL_PLATFORM_PREFERRED_ALIGNMENT) - #if defined(EA_PROCESSOR_ARM) - #define EASTL_PLATFORM_PREFERRED_ALIGNMENT 8 - #else - #define EASTL_PLATFORM_PREFERRED_ALIGNMENT 16 - #endif -#endif - - -namespace eastl -{ - - /// is_sorted - /// - /// Returns true if the range [first, last) is sorted. - /// An empty range is considered to be sorted. - /// To test if a range is reverse-sorted, use 'greater' as the comparison - /// instead of 'less'. - /// - /// Example usage: - /// vector<int> intArray; - /// bool bIsSorted = is_sorted(intArray.begin(), intArray.end()); - /// bool bIsReverseSorted = is_sorted(intArray.begin(), intArray.end(), greater<int>()); - /// - template <typename ForwardIterator, typename StrictWeakOrdering> - bool is_sorted(ForwardIterator first, ForwardIterator last, StrictWeakOrdering compare) - { - if(first != last) - { - ForwardIterator current = first; - - for(++current; current != last; first = current, ++current) - { - if(compare(*current, *first)) - { - EASTL_VALIDATE_COMPARE(!compare(*first, *current)); // Validate that the compare function is sane. - return false; - } - } - } - return true; - } - - template <typename ForwardIterator> - inline bool is_sorted(ForwardIterator first, ForwardIterator last) - { - typedef eastl::less<typename eastl::iterator_traits<ForwardIterator>::value_type> Less; - - return eastl::is_sorted<ForwardIterator, Less>(first, last, Less()); - } - - - - /// is_sorted_until - /// - /// Returns an iterator to the first element in the range [first,last) which does not follow an ascending order. - /// The range between first and the iterator returned is sorted. - /// If the entire range is sorted, the function returns last. - /// The elements are compared using operator< for the first version, and comp for the second. - /// - /// Example usage: - /// vector<int> intArray; - /// vector<int>::iterator unsorted_element = is_sorted_until(eastl::end(intArray), eastl::end(intArray)); - /// vector<int>::iterator unsorted_element_with_user_compare = is_sorted_until(eastl::end(intArray), eastl::end(intArray), eastl::less<int>()); - /// - template<typename ForwardIterator> - ForwardIterator is_sorted_until(ForwardIterator first, ForwardIterator last) - { - if(first != last) - { - ForwardIterator next = first; - - while(++next != last) - { - if(*next < *first) - return next; - - first = next; - } - } - - return last; - } - - template<typename ForwardIterator, typename Compare> - ForwardIterator is_sorted_until(ForwardIterator first, ForwardIterator last, Compare compare) - { - if(first != last) - { - ForwardIterator next = first; - - while(++next != last) - { - if(compare(*next, *first)) - return next; - - first = next; - } - } - - return last; - } - - - - /// merge - /// - /// This function merges two sorted input sorted ranges into a result sorted range. - /// This merge is stable in that no element from the first range will be changed - /// in order relative to other elements from the first range. - /// - template <typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare> - OutputIterator merge(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare compare) - { - while((first1 != last1) && (first2 != last2)) - { - if(compare(*first2, *first1)) - { - EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. - *result = *first2; - ++first2; - } - else - { - *result = *first1; - ++first1; - } - ++result; - } - - // Check which list is empty and explicitly copy remaining items from the other list. - // For performance reasons, only a single copy operation is invoked to avoid the potential overhead - // introduced by chaining two copy operations together. Even if a copy is of zero size there can - // be overhead from calling memmove with a zero size copy. - if (first1 == last1) - { - return eastl::copy(first2, last2, result); - } - else - { - return eastl::copy(first1, last1, result); - } - } - - template <typename InputIterator1, typename InputIterator2, typename OutputIterator> - inline OutputIterator merge(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) - { - typedef eastl::less<typename eastl::iterator_traits<InputIterator1>::value_type> Less; - - return eastl::merge<InputIterator1, InputIterator2, OutputIterator, Less> - (first1, last1, first2, last2, result, Less()); - } - - - ////////////////////////////////////////////////////////////////////////////// - /// insertion_sort - /// - /// insertion_sort is an O(n^2) stable sorting algorithm that starts at the - /// (k + 1) element and assumes the first (k) elements are sorted. - /// Then copy_backwards from (k + 1) to the begining any elements where the - /// (k + 1) element is less than [0, k] elements. The position of k when - /// (k + 1) element is not less than k is the sorted position of the (k + 1) element. - /// - /// Example With Intermediate Steps: - /// (k + 1) == 2 : [3, 2, 1] -> [3, 3, 1] -> [2, 3, 1] - /// (k + 1) == 1 : [2, 3, 1] -> [2, 3, 3] -> [2, 2, 3] -> [1, 2, 3] - /// : [1, 2, 3] - template <typename BidirectionalIterator, typename StrictWeakOrdering> - void insertion_sort(BidirectionalIterator first, BidirectionalIterator last, StrictWeakOrdering compare) - { - typedef typename eastl::iterator_traits<BidirectionalIterator>::value_type value_type; - - if (first != last) - { - BidirectionalIterator i = first; - - for (++i; i != last; ++i) - { - value_type insertValue(eastl::move(*i)); - BidirectionalIterator insertPosition = i; - - for (BidirectionalIterator movePosition = i; movePosition != first && compare(insertValue, *(--movePosition)); --insertPosition) - { - EASTL_VALIDATE_COMPARE(!compare(*movePosition, insertValue)); - *insertPosition = eastl::move(*movePosition); - } - - *insertPosition = eastl::move(insertValue); - } - } - } // insertion_sort - - - template <typename BidirectionalIterator> - void insertion_sort(BidirectionalIterator first, BidirectionalIterator last) - { - typedef eastl::less<typename eastl::iterator_traits<BidirectionalIterator>::value_type> Less; - - insertion_sort<BidirectionalIterator>(first, last, Less()); - - } // insertion_sort - - - /// shell_sort - /// - /// Implements the ShellSort algorithm. This algorithm is a serious algorithm for larger - /// data sets, as reported by Sedgewick in his discussions on QuickSort. Note that shell_sort - /// requires a random access iterator, which usually means an array (eg. vector, deque). - /// ShellSort has good performance with presorted sequences. - /// The term "shell" derives from the name of the inventor, David Shell. - /// - /// To consider: Allow the user to specify the "h-sequence" array. - /// - template <typename RandomAccessIterator, typename StrictWeakOrdering> - void shell_sort(RandomAccessIterator first, RandomAccessIterator last, StrictWeakOrdering compare) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type; - - // We use the Knuth 'h' sequence below, as it is easy to calculate at runtime. - // However, possibly we are better off using a different sequence based on a table. - // One such sequence which averages slightly better than Knuth is: - // 1, 5, 19, 41, 109, 209, 505, 929, 2161, 3905, 8929, 16001, 36289, - // 64769, 146305, 260609, 587521, 1045505, 2354689, 4188161, 9427969, 16764929 - - if(first != last) - { - RandomAccessIterator iCurrent, iBack, iSorted, iInsertFirst; - difference_type nSize = last - first; - difference_type nSpace = 1; // nSpace is the 'h' value of the ShellSort algorithm. - - while(nSpace < nSize) - nSpace = (nSpace * 3) + 1; // This is the Knuth 'h' sequence: 1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720, 797161, 2391484, 7174453, 21523360, 64570081, 193710244, - - for(nSpace = (nSpace - 1) / 3; nSpace >= 1; nSpace = (nSpace - 1) / 3) // Integer division is less than ideal. - { - for(difference_type i = 0; i < nSpace; i++) - { - iInsertFirst = first + i; - - for(iSorted = iInsertFirst + nSpace; iSorted < last; iSorted += nSpace) - { - iBack = iCurrent = iSorted; - - for(; (iCurrent != iInsertFirst) && compare(*iCurrent, *(iBack -= nSpace)); iCurrent = iBack) - { - EASTL_VALIDATE_COMPARE(!compare(*iBack, *iCurrent)); // Validate that the compare function is sane. - eastl::iter_swap(iCurrent, iBack); - } - } - } - } - } - } // shell_sort - - template <typename RandomAccessIterator> - inline void shell_sort(RandomAccessIterator first, RandomAccessIterator last) - { - typedef eastl::less<typename eastl::iterator_traits<RandomAccessIterator>::value_type> Less; - - eastl::shell_sort<RandomAccessIterator, Less>(first, last, Less()); - } - - - - /// heap_sort - /// - /// Implements the HeapSort algorithm. - /// Note that heap_sort requires a random access iterator, which usually means - /// an array (eg. vector, deque). - /// - template <typename RandomAccessIterator, typename StrictWeakOrdering> - void heap_sort(RandomAccessIterator first, RandomAccessIterator last, StrictWeakOrdering compare) - { - // We simply call our heap algorithms to do the work for us. - eastl::make_heap<RandomAccessIterator, StrictWeakOrdering>(first, last, compare); - eastl::sort_heap<RandomAccessIterator, StrictWeakOrdering>(first, last, compare); - } - - template <typename RandomAccessIterator> - inline void heap_sort(RandomAccessIterator first, RandomAccessIterator last) - { - typedef eastl::less<typename eastl::iterator_traits<RandomAccessIterator>::value_type> Less; - - eastl::heap_sort<RandomAccessIterator, Less>(first, last, Less()); - } - - - - namespace Internal - { - // Sorts a range whose initial (start - first) entries are already sorted. - // This function is a useful helper to the tim_sort function. - // This is the same as insertion_sort except that it has a start parameter which indicates - // where the start of the unsorted data is. - template <typename BidirectionalIterator, typename StrictWeakOrdering> - void insertion_sort_already_started(BidirectionalIterator first, BidirectionalIterator last, BidirectionalIterator start, StrictWeakOrdering compare) - { - typedef typename eastl::iterator_traits<BidirectionalIterator>::value_type value_type; - - if (first != last) // if the range is non-empty... - { - BidirectionalIterator iCurrent, iNext, iSorted = start - 1; - - for (++iSorted; iSorted != last; ++iSorted) - { - const value_type temp(*iSorted); - - iNext = iCurrent = iSorted; - - for (--iCurrent; (iNext != first) && compare(temp, *iCurrent); --iNext, --iCurrent) - { - EASTL_VALIDATE_COMPARE(!compare(*iCurrent, temp)); // Validate that the compare function is sane. - *iNext = *iCurrent; - } - - *iNext = temp; - } - } - } - } - - - - /// merge_sort_buffer - /// - /// Implements the MergeSort algorithm with a user-supplied buffer. - /// The input buffer must be able to hold a number of items equal to 'last - first'. - /// Note that merge_sort_buffer requires a random access iterator, which usually means - /// an array (eg. vector, deque). - /// - /// The algorithm used for merge sort is not the standard merge sort. It has been modified - /// to improve performance for data that is already partially sorted. In fact, if data - /// is completely sorted, then performance is O(n), but even data with partially sorted - /// regions can benefit from the modifications. - /// - /// 'InsertionSortLimit' specifies a size limit for which the algorithm will use insertion sort. - /// Due to the overhead of merge sort, it is often faster to use insertion sort once the size of a region - /// is fairly small. However, insertion sort is not as efficient (in terms of assignments orcomparisons) - /// so choosing a value that is too large will reduce performance. Generally a value of 16 to 32 is reasonable, - /// but the best choose will depend on the data being sorted. - template <typename RandomAccessIterator, typename T, typename StrictWeakOrdering, typename difference_type, int InsertionSortLimit> - class MergeSorter - { - public: - static void sort(RandomAccessIterator first, RandomAccessIterator last, T* pBuffer, StrictWeakOrdering compare) - { - if (sort_impl(first, last, pBuffer, difference_type(0), compare) == RL_Buffer) - { - const difference_type nCount = last - first; - eastl::copy<T*, RandomAccessIterator>(pBuffer, pBuffer + nCount, first); - } - EASTL_DEV_ASSERT((eastl::is_sorted<RandomAccessIterator, StrictWeakOrdering>(first, last, compare))); - } - - private: - static_assert(InsertionSortLimit > 1, "Sequences of length 1 are already sorted. Use a larger value for InsertionSortLimit"); - - enum ResultLocation - { - RL_SourceRange, // i.e. result is in the range defined by [first, last) - RL_Buffer, // i.e. result is in pBuffer - }; - - // sort_impl - // - // This sort routine sorts the data in [first, last) and places the result in pBuffer or in the original range of the input. The actual - // location of the data is indicated by the enum returned. - // - // lastSortedEnd is used to specify a that data in the range [first, first + lastSortedEnd] is already sorted. This information is used - // to avoid unnecessary merge sorting of already sorted data. lastSortedEnd is a hint, and can be an under estimate of the sorted elements - // (i.e. it is legal to pass 0). - static ResultLocation sort_impl(RandomAccessIterator first, RandomAccessIterator last, T* pBuffer, difference_type lastSortedEnd, StrictWeakOrdering compare) - { - const difference_type nCount = last - first; - - if (lastSortedEnd < 1) - { - lastSortedEnd = eastl::is_sorted_until<RandomAccessIterator, StrictWeakOrdering>(first, last, compare) - first; - } - - // Sort the region unless lastSortedEnd indicates it is already sorted. - if (lastSortedEnd < nCount) - { - // If the size is less than or equal to InsertionSortLimit use insertion sort instead of recursing further. - if (nCount <= InsertionSortLimit) - { - eastl::Internal::insertion_sort_already_started<RandomAccessIterator, StrictWeakOrdering>(first, last, first + lastSortedEnd, compare); - return RL_SourceRange; - } - else - { - const difference_type nMid = nCount / 2; - - ResultLocation firstHalfLocation = RL_SourceRange; - // Don't sort the first half if it is already sorted. - if (lastSortedEnd < nMid) - { - firstHalfLocation = sort_impl(first, first + nMid, pBuffer, lastSortedEnd, compare); - } - - ResultLocation secondHalfLocation = sort_impl(first + nMid, last, pBuffer + nMid, lastSortedEnd - nMid, compare); - - return merge_halves(first, last, nMid, pBuffer, firstHalfLocation, secondHalfLocation, compare); - } - } - else - { - EASTL_DEV_ASSERT((eastl::is_sorted<RandomAccessIterator, StrictWeakOrdering>(first, last, compare))); - return RL_SourceRange; - } - } - - // merge_halves - // - // Merge two sorted regions of elements. - // The inputs to this method effectively define two large buffers. The variables 'firstHalfLocation' and 'secondHalfLocation' define where the data to be - // merged is located within the two buffers. It is entirely possible that the two areas to be merged could be entirely located in either of the larger buffers. - // Upon returning the merged results will be in one of the two buffers (indicated by the return result). - static ResultLocation merge_halves(RandomAccessIterator first, RandomAccessIterator last, difference_type nMid, T* pBuffer, ResultLocation firstHalfLocation, ResultLocation secondHalfLocation, StrictWeakOrdering compare) - { - const difference_type nCount = last - first; - if (firstHalfLocation == RL_SourceRange) - { - if (secondHalfLocation == RL_SourceRange) - { - eastl::merge<RandomAccessIterator, RandomAccessIterator, T*, StrictWeakOrdering>(first, first + nMid, first + nMid, last, pBuffer, compare); - EASTL_DEV_ASSERT((eastl::is_sorted<T*, StrictWeakOrdering>(pBuffer, pBuffer + nCount, compare))); - return RL_Buffer; - } - else - { - eastl::copy(first, first + nMid, pBuffer); - eastl::merge<T*, T*, RandomAccessIterator, StrictWeakOrdering>(pBuffer, pBuffer + nMid, pBuffer + nMid, pBuffer + nCount, first, compare); - EASTL_DEV_ASSERT((eastl::is_sorted<RandomAccessIterator, StrictWeakOrdering>(first, last, compare))); - return RL_SourceRange; - } - } - else - { - if (secondHalfLocation == RL_SourceRange) - { - eastl::copy(first + nMid, last, pBuffer + nMid); - eastl::merge<T*, T*, RandomAccessIterator, StrictWeakOrdering>(pBuffer, pBuffer + nMid, pBuffer + nMid, pBuffer + nCount, first, compare); - EASTL_DEV_ASSERT((eastl::is_sorted<RandomAccessIterator, StrictWeakOrdering>(first, last, compare))); - return RL_SourceRange; - } - else - { - eastl::merge<T*, T*, RandomAccessIterator, StrictWeakOrdering>(pBuffer, pBuffer + nMid, pBuffer + nMid, pBuffer + nCount, first, compare); - EASTL_DEV_ASSERT((eastl::is_sorted<RandomAccessIterator, StrictWeakOrdering>(first, last, compare))); - return RL_SourceRange; - } - } - } - - }; - - - template <typename RandomAccessIterator, typename T, typename StrictWeakOrdering> - void merge_sort_buffer(RandomAccessIterator first, RandomAccessIterator last, T* pBuffer, StrictWeakOrdering compare) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type; - MergeSorter<RandomAccessIterator, T, StrictWeakOrdering, difference_type, 16>::sort(first, last, pBuffer, compare); - } - - template <typename RandomAccessIterator, typename T> - inline void merge_sort_buffer(RandomAccessIterator first, RandomAccessIterator last, T* pBuffer) - { - typedef eastl::less<typename eastl::iterator_traits<RandomAccessIterator>::value_type> Less; - - eastl::merge_sort_buffer<RandomAccessIterator, T, Less>(first, last, pBuffer, Less()); - } - - - - /// merge_sort - /// - /// Implements the MergeSort algorithm. - /// This algorithm allocates memory via the user-supplied allocator. Use merge_sort_buffer - /// function if you want a version which doesn't allocate memory. - /// Note that merge_sort requires a random access iterator, which usually means - /// an array (eg. vector, deque). - /// - template <typename RandomAccessIterator, typename Allocator, typename StrictWeakOrdering> - void merge_sort(RandomAccessIterator first, RandomAccessIterator last, Allocator& allocator, StrictWeakOrdering compare) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type; - typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type; - - const difference_type nCount = last - first; - - if(nCount > 1) - { - // We need to allocate an array of nCount value_type objects as a temporary buffer. - value_type* const pBuffer = (value_type*)allocate_memory(allocator, nCount * sizeof(value_type), EASTL_ALIGN_OF(value_type), 0); - eastl::uninitialized_fill(pBuffer, pBuffer + nCount, value_type()); - - eastl::merge_sort_buffer<RandomAccessIterator, value_type, StrictWeakOrdering> - (first, last, pBuffer, compare); - - eastl::destruct(pBuffer, pBuffer + nCount); - EASTLFree(allocator, pBuffer, nCount * sizeof(value_type)); - } - } - - template <typename RandomAccessIterator, typename Allocator> - inline void merge_sort(RandomAccessIterator first, RandomAccessIterator last, Allocator& allocator) - { - typedef eastl::less<typename eastl::iterator_traits<RandomAccessIterator>::value_type> Less; - - eastl::merge_sort<RandomAccessIterator, Allocator, Less>(first, last, allocator, Less()); - } - - - - /// partition - /// - /// Implements the partition algorithm. - /// Rearranges the elements in the range [first, last), in such a way that all the elements - /// for which pred returns true precede all those for which it returns false. The iterator - /// returned points to the first element of the second group. - /// The relative ordering within each group is not necessarily the same as before the call. - /// See function stable_partition for a function with a similar behavior and stability in - /// the ordering. - /// - /// To do: Implement a version that uses a faster BidirectionalIterator algorithm for the - /// case that the iterator range is a bidirectional iterator instead of just an - /// input iterator (one direction). - /// - template<typename InputIterator, typename Predicate> - InputIterator partition(InputIterator begin, InputIterator end, Predicate predicate) - { - if(begin != end) - { - while(predicate(*begin)) - { - if(++begin == end) - return begin; - } - - InputIterator middle = begin; - - while(++middle != end) - { - if(predicate(*middle)) - { - eastl::swap(*begin, *middle); - ++begin; - } - } - } - - return begin; - } - - /// stable_partition - /// - /// Performs the same function as @p partition() with the additional - /// guarantee that the relative ordering of elements in each group is - /// preserved. - template <typename ForwardIterator, typename Predicate> - ForwardIterator stable_partition(ForwardIterator first, ForwardIterator last, Predicate pred) - { - first = eastl::find_if_not(first, last, pred); - - if (first == last) - return first; - - typedef typename iterator_traits<ForwardIterator>::value_type value_type; - - const auto requested_size = eastl::distance(first, last); - - auto allocator = *get_default_allocator(0); - value_type* const buffer = - (value_type*)allocate_memory(allocator, requested_size * sizeof(value_type), EASTL_ALIGN_OF(value_type), 0); - eastl::uninitialized_fill(buffer, buffer + requested_size, value_type()); - - ForwardIterator result1 = first; - value_type* result2 = buffer; - - *result2 = eastl::move(*first); - ++result2; - ++first; - for (; first != last; ++first) - { - if (pred(*first)) - { - *result1 = eastl::move(*first); - ++result1; - } - else - { - *result2 = eastl::move(*first); - ++result2; - } - } - - eastl::copy(buffer, result2, result1); - - eastl::destruct(buffer, buffer + requested_size); - EASTLFree(allocator, buffer, requested_size * sizeof(value_type)); - - return result1; - } - - ///////////////////////////////////////////////////////////////////// - // quick_sort - // - // We do the "introspection sort" variant of quick sort which is now - // well-known and understood. You can read about this algorithm in - // many articles on quick sort, but briefly what it does is a median- - // of-three quick sort whereby the recursion depth is limited to a - // some value (after which it gives up on quick sort and switches to - // a heap sort) and whereby after a certain amount of sorting the - // algorithm stops doing quick-sort and finishes the sorting via - // a simple insertion sort. - ///////////////////////////////////////////////////////////////////// - - #if (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) - static const int kQuickSortLimit = 28; // For sorts of random arrays over 100 items, 28 - 32 have been found to be good numbers on x86. - #else - static const int kQuickSortLimit = 16; // It seems that on other processors lower limits are more beneficial, as they result in fewer compares. - #endif - - namespace Internal - { - template <typename Size> - inline Size Log2(Size n) - { - int i; - for(i = 0; n; ++i) - n >>= 1; - return i - 1; - } - - // To do: Investigate the speed of this bit-trick version of Log2. - // It may work better on some platforms but not others. - // - // union FloatUnion { - // float f; - // uint32_t i; - // }; - // - // inline uint32_t Log2(uint32_t x) - // { - // const FloatInt32Union u = { x }; - // return (u.i >> 23) - 127; - // } - } - - template <typename RandomAccessIterator, typename T> - inline RandomAccessIterator get_partition_impl(RandomAccessIterator first, RandomAccessIterator last, T&& pivotValue) - { - using PureT = decay_t<T>; - - for(; ; ++first) - { - while(eastl::less<PureT>()(*first, pivotValue)) - { - EASTL_VALIDATE_COMPARE(!eastl::less<PureT>()(pivotValue, *first)); // Validate that the compare function is sane. - ++first; - } - --last; - - while(eastl::less<PureT>()(pivotValue, *last)) - { - EASTL_VALIDATE_COMPARE(!eastl::less<PureT>()(*last, pivotValue)); // Validate that the compare function is sane. - --last; - } - - if(first >= last) // Random access iterators allow operator >= - return first; - - eastl::iter_swap(first, last); - } - } - - /// get_partition - /// - /// This function takes const T& instead of T because T may have special alignment - /// requirements and some compilers (e.g. VC++) are don't respect alignment requirements - /// for function arguments. - /// - template <typename RandomAccessIterator, typename T> - inline RandomAccessIterator get_partition(RandomAccessIterator first, RandomAccessIterator last, const T& pivotValue) - { - const T pivotCopy(pivotValue); // Need to make a temporary because the sequence below is mutating. - return get_partition_impl<RandomAccessIterator, const T&>(first, last, pivotCopy); - } - - template <typename RandomAccessIterator, typename T> - inline RandomAccessIterator get_partition(RandomAccessIterator first, RandomAccessIterator last, T&& pivotValue) - { - // Note: unlike the copy-constructible variant of get_partition... we can't create a temporary const move-constructible object - return get_partition_impl<RandomAccessIterator, T&&>(first, last, eastl::move(pivotValue)); - } - - template <typename RandomAccessIterator, typename T, typename Compare> - inline RandomAccessIterator get_partition_impl(RandomAccessIterator first, RandomAccessIterator last, T&& pivotValue, Compare compare) - { - for(; ; ++first) - { - while(compare(*first, pivotValue)) - { - EASTL_VALIDATE_COMPARE(!compare(pivotValue, *first)); // Validate that the compare function is sane. - ++first; - } - --last; - - while(compare(pivotValue, *last)) - { - EASTL_VALIDATE_COMPARE(!compare(*last, pivotValue)); // Validate that the compare function is sane. - --last; - } - - if(first >= last) // Random access iterators allow operator >= - return first; - - eastl::iter_swap(first, last); - } - } - - template <typename RandomAccessIterator, typename T, typename Compare> - inline RandomAccessIterator get_partition(RandomAccessIterator first, RandomAccessIterator last, const T& pivotValue, Compare compare) - { - const T pivotCopy(pivotValue); // Need to make a temporary because the sequence below is mutating. - return get_partition_impl<RandomAccessIterator, const T&, Compare>(first, last, pivotCopy, compare); - } - - template <typename RandomAccessIterator, typename T, typename Compare> - inline RandomAccessIterator get_partition(RandomAccessIterator first, RandomAccessIterator last, T&& pivotValue, Compare compare) - { - // Note: unlike the copy-constructible variant of get_partition... we can't create a temporary const move-constructible object - return get_partition_impl<RandomAccessIterator, T&&, Compare>(first, last, eastl::forward<T>(pivotValue), compare); - } - - - namespace Internal - { - // This function is used by quick_sort and is not intended to be used by itself. - // This is because the implementation below makes an assumption about the input - // data that quick_sort satisfies but arbitrary data may not. - // There is a standalone insertion_sort function. - template <typename RandomAccessIterator> - inline void insertion_sort_simple(RandomAccessIterator first, RandomAccessIterator last) - { - for(RandomAccessIterator current = first; current != last; ++current) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type; - - RandomAccessIterator end(current), prev(current); - value_type value(eastl::forward<value_type>(*current)); - - for(--prev; eastl::less<value_type>()(value, *prev); --end, --prev) // We skip checking for (prev >= first) because quick_sort (our caller) makes this unnecessary. - { - EASTL_VALIDATE_COMPARE(!eastl::less<value_type>()(*prev, value)); // Validate that the compare function is sane. - *end = eastl::forward<value_type>(*prev); - } - - *end = eastl::forward<value_type>(value); - } - } - - - // This function is used by quick_sort and is not intended to be used by itself. - // This is because the implementation below makes an assumption about the input - // data that quick_sort satisfies but arbitrary data may not. - // There is a standalone insertion_sort function. - template <typename RandomAccessIterator, typename Compare> - inline void insertion_sort_simple(RandomAccessIterator first, RandomAccessIterator last, Compare compare) - { - for(RandomAccessIterator current = first; current != last; ++current) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type; - - RandomAccessIterator end(current), prev(current); - value_type value(eastl::forward<value_type>(*current)); - - for(--prev; compare(value, *prev); --end, --prev) // We skip checking for (prev >= first) because quick_sort (our caller) makes this unnecessary. - { - EASTL_VALIDATE_COMPARE(!compare(*prev, value)); // Validate that the compare function is sane. - *end = eastl::forward<value_type>(*prev); - } - - *end = eastl::forward<value_type>(value); - } - } - } // namespace Internal - - - template <typename RandomAccessIterator> - inline void partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type; - typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type; - - eastl::make_heap<RandomAccessIterator>(first, middle); - - for(RandomAccessIterator i = middle; i < last; ++i) - { - if(eastl::less<value_type>()(*i, *first)) - { - EASTL_VALIDATE_COMPARE(!eastl::less<value_type>()(*first, *i)); // Validate that the compare function is sane. - value_type temp(eastl::forward<value_type>(*i)); - *i = eastl::forward<value_type>(*first); - eastl::adjust_heap<RandomAccessIterator, difference_type, value_type> - (first, difference_type(0), difference_type(middle - first), difference_type(0), eastl::forward<value_type>(temp)); - } - } - - eastl::sort_heap<RandomAccessIterator>(first, middle); - } - - - template <typename RandomAccessIterator, typename Compare> - inline void partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare compare) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type; - typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type; - - eastl::make_heap<RandomAccessIterator, Compare>(first, middle, compare); - - for(RandomAccessIterator i = middle; i < last; ++i) - { - if(compare(*i, *first)) - { - EASTL_VALIDATE_COMPARE(!compare(*first, *i)); // Validate that the compare function is sane. - value_type temp(eastl::forward<value_type>(*i)); - *i = eastl::forward<value_type>(*first); - eastl::adjust_heap<RandomAccessIterator, difference_type, value_type, Compare> - (first, difference_type(0), difference_type(middle - first), difference_type(0), eastl::forward<value_type>(temp), compare); - } - } - - eastl::sort_heap<RandomAccessIterator, Compare>(first, middle, compare); - } - - - template<typename RandomAccessIterator> - inline void nth_element(RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last) - { - typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; - - while((last - first) > 5) - { - const value_type midValue(eastl::median<value_type>(*first, *(first + (last - first) / 2), *(last - 1))); - const RandomAccessIterator midPos(eastl::get_partition<RandomAccessIterator, value_type>(first, last, midValue)); - - if(midPos <= nth) - first = midPos; - else - last = midPos; - } - - eastl::insertion_sort<RandomAccessIterator>(first, last); - } - - - template<typename RandomAccessIterator, typename Compare> - inline void nth_element(RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last, Compare compare) - { - typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; - - while((last - first) > 5) - { - const value_type midValue(eastl::median<value_type, Compare>(*first, *(first + (last - first) / 2), *(last - 1), compare)); - const RandomAccessIterator midPos(eastl::get_partition<RandomAccessIterator, value_type, Compare>(first, last, midValue, compare)); - - if(midPos <= nth) - first = midPos; - else - last = midPos; - } - - eastl::insertion_sort<RandomAccessIterator, Compare>(first, last, compare); - } - - - namespace Internal - { - EA_DISABLE_VC_WARNING(4702) // unreachable code - template <typename RandomAccessIterator, typename Size, typename PivotValueType> - inline void quick_sort_impl_helper(RandomAccessIterator first, RandomAccessIterator last, Size kRecursionCount) - { - typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; - - while(((last - first) > kQuickSortLimit) && (kRecursionCount > 0)) - { - const RandomAccessIterator position(eastl::get_partition<RandomAccessIterator, value_type>(first, last, - eastl::forward<PivotValueType>(eastl::median<value_type>(eastl::forward<value_type>(*first), eastl::forward<value_type>(*(first + (last - first) / 2)), eastl::forward<value_type>(*(last - 1)))))); - - eastl::Internal::quick_sort_impl_helper<RandomAccessIterator, Size, PivotValueType>(position, last, --kRecursionCount); - last = position; - } - - if(kRecursionCount == 0) - eastl::partial_sort<RandomAccessIterator>(first, last, last); - } - - template <typename RandomAccessIterator, typename Size, typename Compare, typename PivotValueType> - inline void quick_sort_impl_helper(RandomAccessIterator first, RandomAccessIterator last, Size kRecursionCount, Compare compare) - { - typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; - - while(((last - first) > kQuickSortLimit) && (kRecursionCount > 0)) - { - const RandomAccessIterator position(eastl::get_partition<RandomAccessIterator, value_type, Compare>(first, last, - eastl::forward<PivotValueType>(eastl::median<value_type, Compare>(eastl::forward<value_type>(*first), eastl::forward<value_type>(*(first + (last - first) / 2)), eastl::forward<value_type>(*(last - 1)), compare)), compare)); - - eastl::Internal::quick_sort_impl_helper<RandomAccessIterator, Size, Compare, PivotValueType>(position, last, --kRecursionCount, compare); - last = position; - } - - if(kRecursionCount == 0) - eastl::partial_sort<RandomAccessIterator, Compare>(first, last, last, compare); - } - EA_RESTORE_VC_WARNING() - - template <typename RandomAccessIterator, typename Size> - inline void quick_sort_impl(RandomAccessIterator first, RandomAccessIterator last, Size kRecursionCount, - typename eastl::enable_if<eastl::is_copy_constructible<typename iterator_traits<RandomAccessIterator>::value_type>::value>::type* = 0) - { - typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; - - // copy constructors require const value_type - quick_sort_impl_helper<RandomAccessIterator, Size, const value_type>(first, last, kRecursionCount); - } - - template <typename RandomAccessIterator, typename Size> - inline void quick_sort_impl(RandomAccessIterator first, RandomAccessIterator last, Size kRecursionCount, - typename eastl::enable_if<eastl::is_move_constructible<typename iterator_traits<RandomAccessIterator>::value_type>::value - && !eastl::is_copy_constructible<typename iterator_traits<RandomAccessIterator>::value_type>::value>::type* = 0) - { - typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; - - // move constructors require non-const value_type - quick_sort_impl_helper<RandomAccessIterator, Size, value_type>(first, last, kRecursionCount); - } - - template <typename RandomAccessIterator, typename Size, typename Compare> - inline void quick_sort_impl(RandomAccessIterator first, RandomAccessIterator last, Size kRecursionCount, Compare compare, - typename eastl::enable_if<eastl::is_copy_constructible<typename iterator_traits<RandomAccessIterator>::value_type>::value>::type* = 0) - { - typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; - - // copy constructors require const value_type - quick_sort_impl_helper<RandomAccessIterator, Size, Compare, const value_type>(first, last, kRecursionCount, compare); - } - - template <typename RandomAccessIterator, typename Size, typename Compare> - inline void quick_sort_impl(RandomAccessIterator first, RandomAccessIterator last, Size kRecursionCount, Compare compare, - typename eastl::enable_if<eastl::is_move_constructible<typename iterator_traits<RandomAccessIterator>::value_type>::value - && !eastl::is_copy_constructible<typename iterator_traits<RandomAccessIterator>::value_type>::value>::type* = 0) - { - typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; - - // move constructors require non-const value_type - quick_sort_impl_helper<RandomAccessIterator, Size, Compare, value_type>(first, last, kRecursionCount, compare); - } - } - - - /// quick_sort - /// - /// This is an unstable sort. - /// quick_sort sorts the elements in [first, last) into ascending order, - /// meaning that if i and j are any two valid iterators in [first, last) - /// such that i precedes j, then *j is not less than *i. quick_sort is not - /// guaranteed to be stable. That is, suppose that *i and *j are equivalent: - /// neither one is less than the other. It is not guaranteed that the - /// relative order of these two elements will be preserved by sort. - /// - /// We implement the "introspective" variation of quick-sort. This is - /// considered to be the best general-purpose variant, as it avoids - /// worst-case behaviour and optimizes the final sorting stage by - /// switching to an insertion sort. - /// - template <typename RandomAccessIterator> - void quick_sort(RandomAccessIterator first, RandomAccessIterator last) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type; - - if(first != last) - { - eastl::Internal::quick_sort_impl<RandomAccessIterator, difference_type>(first, last, 2 * Internal::Log2(last - first)); - - if((last - first) > (difference_type)kQuickSortLimit) - { - eastl::insertion_sort<RandomAccessIterator>(first, first + kQuickSortLimit); - eastl::Internal::insertion_sort_simple<RandomAccessIterator>(first + kQuickSortLimit, last); - } - else - eastl::insertion_sort<RandomAccessIterator>(first, last); - } - } - - - template <typename RandomAccessIterator, typename Compare> - void quick_sort(RandomAccessIterator first, RandomAccessIterator last, Compare compare) - { - typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type; - - if(first != last) - { - eastl::Internal::quick_sort_impl<RandomAccessIterator, difference_type, Compare>(first, last, 2 * Internal::Log2(last - first), compare); - - if((last - first) > (difference_type)kQuickSortLimit) - { - eastl::insertion_sort<RandomAccessIterator, Compare>(first, first + kQuickSortLimit, compare); - eastl::Internal::insertion_sort_simple<RandomAccessIterator, Compare>(first + kQuickSortLimit, last, compare); - } - else - eastl::insertion_sort<RandomAccessIterator, Compare>(first, last, compare); - } - } - - - - - namespace Internal - { - // Portions of the tim_sort code were originally written by Christopher Swenson. - // https://github.com/swenson/sort - // All code in this repository, unless otherwise specified, is hereby licensed under the - // MIT Public License: Copyright (c) 2010 Christopher Swenson - - const intptr_t kTimSortStackSize = 64; // Question: What's the upper-limit size requirement for this? - - struct tim_sort_run - { - intptr_t start; - intptr_t length; - }; - - - // EASTL_COUNT_LEADING_ZEROES - // - // Count leading zeroes in an integer. - // - #ifndef EASTL_COUNT_LEADING_ZEROES - #if defined(__GNUC__) - #if (EA_PLATFORM_PTR_SIZE == 8) - #define EASTL_COUNT_LEADING_ZEROES __builtin_clzll - #else - #define EASTL_COUNT_LEADING_ZEROES __builtin_clz - #endif - #endif - - #ifndef EASTL_COUNT_LEADING_ZEROES - static inline int eastl_count_leading_zeroes(uint64_t x) - { - if(x) - { - int n = 0; - if(x & UINT64_C(0xFFFFFFFF00000000)) { n += 32; x >>= 32; } - if(x & 0xFFFF0000) { n += 16; x >>= 16; } - if(x & 0xFFFFFF00) { n += 8; x >>= 8; } - if(x & 0xFFFFFFF0) { n += 4; x >>= 4; } - if(x & 0xFFFFFFFC) { n += 2; x >>= 2; } - if(x & 0xFFFFFFFE) { n += 1; } - return 63 - n; - } - return 64; - } - - static inline int eastl_count_leading_zeroes(uint32_t x) - { - if(x) - { - int n = 0; - if(x <= 0x0000FFFF) { n += 16; x <<= 16; } - if(x <= 0x00FFFFFF) { n += 8; x <<= 8; } - if(x <= 0x0FFFFFFF) { n += 4; x <<= 4; } - if(x <= 0x3FFFFFFF) { n += 2; x <<= 2; } - if(x <= 0x7FFFFFFF) { n += 1; } - return n; - } - return 32; - } - - #define EASTL_COUNT_LEADING_ZEROES eastl_count_leading_zeroes - #endif - #endif - - - // reverse_elements - // - // Reverses the range [first + start, first + start + size) - // To consider: Use void eastl::reverse(BidirectionalIterator first, BidirectionalIterator last); - // - template <typename RandomAccessIterator> - void reverse_elements(RandomAccessIterator first, intptr_t start, intptr_t end) - { - while(start < end) - { - eastl::swap(*(first + start), *(first + end)); - ++start; - --end; - } - } - - - // tim_sort_count_run - // - // Finds the length of a run which is already sorted (either up or down). - // If the run is in reverse order, this function puts it in regular order. - // - template <typename RandomAccessIterator, typename StrictWeakOrdering> - intptr_t tim_sort_count_run(const RandomAccessIterator first, const intptr_t start, const intptr_t size, StrictWeakOrdering compare) - { - if((size - start) > 1) // If there is anything in the set... - { - intptr_t curr = (start + 2); - - if(!compare(*(first + start + 1), *(first + start))) // If (first[start + 1] >= first[start]) (If the run is increasing) ... - { - for(;; ++curr) - { - if(curr >= (size - 1)) // If we are at the end of the data... this run is done. - break; - - if(compare(*(first + curr), *(first + curr - 1))) // If this item is not in order... this run is done. - break; - } - } - else // Else it is decreasing. - { - for(;; ++curr) - { - if(curr >= (size - 1)) // If we are at the end of the data... this run is done. - break; - - if(!compare(*(first + curr), *(first + curr - 1))) // If this item is not in order... this run is done. - break; // Note that we intentionally compare against <= 0 and not just < 0. This is because - } // The reverse_elements call below could reverse two equal elements and break our stability requirement. - - reverse_elements(first, start, curr - 1); - } - - return (curr - start); - } - - // Else we have just one item in the set. - return 1; - } - - - // Input Return - // -------------- - // 64 32 - // 65 33 - // 66 33 - // 67 34 - // 68 34 - // ... - // 125 63 - // 126 63 - // 127 64 - // 128 32 - // 129 33 - // 130 33 - // 131 33 - // 132 33 - // 133 34 - // 134 34 - // 135 34 - // 136 34 - // 137 35 - // ... - // - // This function will return a value that is always in the range of [32, 64]. - // - static inline intptr_t timsort_compute_minrun(intptr_t size) - { - const int32_t top_bit = (int32_t)((sizeof(intptr_t) * 8) - EASTL_COUNT_LEADING_ZEROES((uintptr_t)size)); - const int32_t shift = (top_bit > 6) ? (top_bit - 6) : 0; - const intptr_t mask = (intptr_t(1) << shift) - 1; - intptr_t minrun = (intptr_t)(size >> shift); - - if(mask & size) - ++minrun; - - return minrun; - } - - - template <typename RandomAccessIterator, typename T, typename StrictWeakOrdering> - void tim_sort_merge(RandomAccessIterator first, const tim_sort_run* run_stack, const intptr_t stack_curr, - T* pBuffer, StrictWeakOrdering compare) - { - const intptr_t A = run_stack[stack_curr - 2].length; - const intptr_t B = run_stack[stack_curr - 1].length; - const intptr_t curr = run_stack[stack_curr - 2].start; - - EASTL_DEV_ASSERT((A < 10000000) && (B < 10000000) && (curr < 10000000)); // Sanity check. - - if(A < B) // If the first run is shorter than the second run... merge left. - { - // Copy to another location so we have room in the main array to put the sorted items. - eastl::copy(first + curr, first + curr + A, pBuffer); - - #if EASTL_DEV_DEBUG - typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type; - - for(intptr_t i = 0; i < A; i++) - *(first + curr + i) = value_type(); - #endif - - intptr_t i = 0; - intptr_t j = curr + A; - - for(intptr_t k = curr; k < curr + A + B; k++) - { - if((i < A) && (j < (curr + A + B))) - { - if(!compare(*(first + j), *(pBuffer + i))) // If (first[j] >= pBuffer[i])... - *(first + k) = *(pBuffer + i++); - else - *(first + k) = *(first + j++); - } - else if(i < A) - *(first + k) = *(pBuffer + i++); - else - *(first + k) = *(first + j++); - } - } - else // Else the second run is equal or shorter... merge right. - { - eastl::copy(first + curr + A, first + curr + A + B, pBuffer); - - intptr_t i = B - 1; - intptr_t j = curr + A - 1; - - for(intptr_t k = curr + A + B - 1; k >= curr; k--) - { - if((i >= 0) && (j >= curr)) - { - if(compare(*(pBuffer + i), *(first + j))) // If (pBuffer[i] < first[j]) ... - *(first + k) = *(first + j--); - else - *(first + k) = *(pBuffer + i--); - } - else if(i >= 0) - *(first + k) = *(pBuffer + i--); - else - *(first + k) = *(first + j--); - } - } - } - - - // See the timsort.txt file for an explanation of this function. - // - // ------------------------------------------------------------------------ - // What turned out to be a good compromise maintains two invariants on the - // stack entries, where A, B and C are the lengths of the three righmost - // not-yet merged slices: - // 1. A > B+C - // 2. B > C - // ------------------------------------------------------------------------ - // - static inline bool timsort_check_invariant(tim_sort_run* run_stack, const intptr_t stack_curr) - { - // To do: Optimize this for the most common type of values. - if(stack_curr > 2) - { - const intptr_t A = run_stack[stack_curr - 3].length; - const intptr_t B = run_stack[stack_curr - 2].length; - const intptr_t C = run_stack[stack_curr - 1].length; - - EASTL_DEV_ASSERT((A < 10000000) && (B < 10000000) && (C < 10000000)); // Sanity check. - - if((A <= (B + C)) || (B <= C)) - return true; // Merge the right-most runs. - } - else if(stack_curr == 2) - { - const intptr_t A = run_stack[stack_curr - 2].length; - const intptr_t B = run_stack[stack_curr - 1].length; - - EASTL_DEV_ASSERT((A < 10000000) && (B < 10000000)); // Sanity check. - - if(A <= B) - return true; // Merge the right-most runs. - } - - return false; // Don't merge the right-most runs. - } - - - template <typename RandomAccessIterator, typename T, typename StrictWeakOrdering> - intptr_t tim_sort_collapse(RandomAccessIterator first, tim_sort_run* run_stack, intptr_t stack_curr, - T* pBuffer, const intptr_t size, StrictWeakOrdering compare) - { - // If the run_stack only has one thing on it, we are done with the collapse. - while(stack_curr > 1) - { - // If this is the last merge, just do it. - if((stack_curr == 2) && ((run_stack[0].length + run_stack[1].length) == size)) - { - tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare); - run_stack[0].length += run_stack[1].length; - stack_curr--; - - #if EASTL_DEV_DEBUG - memset(&run_stack[stack_curr], 0, sizeof(run_stack[stack_curr])); - #endif - - break; - } - // Check if the invariant is off for a run_stack of 2 elements. - else if((stack_curr == 2) && (run_stack[0].length <= run_stack[1].length)) - { - tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare); - run_stack[0].length += run_stack[1].length; - stack_curr--; - - #if EASTL_DEV_DEBUG - memset(&run_stack[stack_curr], 0, sizeof(run_stack[stack_curr])); - #endif - - break; - } - else if (stack_curr == 2) - break; - - const intptr_t A = run_stack[stack_curr - 3].length; - const intptr_t B = run_stack[stack_curr - 2].length; - const intptr_t C = run_stack[stack_curr - 1].length; - - if(A <= (B + C)) // Check first invariant. - { - if(A < C) - { - tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr - 1, pBuffer, compare); - - stack_curr--; - run_stack[stack_curr - 2].length += run_stack[stack_curr - 1].length; // Merge A and B. - run_stack[stack_curr - 1] = run_stack[stack_curr]; - - #if EASTL_DEV_DEBUG - EASTL_DEV_ASSERT((run_stack[stack_curr - 2].start + run_stack[stack_curr - 2].length) <= size); - EASTL_DEV_ASSERT((run_stack[stack_curr - 1].start + run_stack[stack_curr - 1].length) <= size); - memset(&run_stack[stack_curr], 0, sizeof(run_stack[stack_curr])); - #endif - } - else - { - tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare); // Merge B and C. - - stack_curr--; - run_stack[stack_curr - 1].length += run_stack[stack_curr].length; - - #if EASTL_DEV_DEBUG - EASTL_DEV_ASSERT((run_stack[stack_curr - 1].start + run_stack[stack_curr - 1].length) <= size); - memset(&run_stack[stack_curr], 0, sizeof(run_stack[stack_curr])); - #endif - } - } - else if(B <= C) // Check second invariant - { - tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare); - - stack_curr--; - run_stack[stack_curr - 1].length += run_stack[stack_curr].length; // Merge B and C. - - #if EASTL_DEV_DEBUG - EASTL_DEV_ASSERT((run_stack[stack_curr - 1].start + run_stack[stack_curr - 1].length) <= size); - memset(&run_stack[stack_curr], 0, sizeof(run_stack[stack_curr])); - #endif - } - else - break; - } - - return stack_curr; - } - - - // tim_sort_add_run - // - // Return true if the sort is done. - // - template <typename RandomAccessIterator, typename T, typename StrictWeakOrdering> - bool tim_sort_add_run(tim_sort_run* run_stack, RandomAccessIterator first, T* pBuffer, const intptr_t size, const intptr_t minrun, - intptr_t& len, intptr_t& run, intptr_t& curr, intptr_t& stack_curr, StrictWeakOrdering compare) - { - len = tim_sort_count_run<RandomAccessIterator, StrictWeakOrdering>(first, curr, size, compare); // This will count the length of the run and reverse the run if it is backwards. - run = minrun; - - if(run < minrun) // Always make runs be of minrun length (we'll sort the additional data as needed below) - run = minrun; - - if(run > (size - curr)) // But if there isn't minrun data remaining, just sort what's remaining. - run = (size - curr); - - if(run > len) // If there is any additional data we want to sort to bring up the run length to minrun. - { - insertion_sort_already_started<RandomAccessIterator, StrictWeakOrdering>(first + curr, first + curr + run, first + curr + len, compare); - len = run; - } - - // At this point, run will be equal to minrun or will go to the end of our data. - // Add this run to our stack of runs. - EASTL_DEV_ASSERT(stack_curr < kTimSortStackSize); - EASTL_DEV_ASSERT((curr >= 0) && (curr < size) && ((curr + len) <= size)); - - run_stack[stack_curr].start = curr; - run_stack[stack_curr].length = len; - stack_curr++; - - // Move to the beginning of the next run in the data. - curr += len; - - if(curr == size) // If we have hit the end of the data... - { - while(stack_curr > 1) // If there is any more than one run... (else all the data is sorted) - { - tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare); - - run_stack[stack_curr - 2].length += run_stack[stack_curr - 1].length; - stack_curr--; - - #if EASTL_DEV_DEBUG - EASTL_DEV_ASSERT((run_stack[stack_curr - 1].start + run_stack[stack_curr - 1].length) <= size); - memset(&run_stack[stack_curr], 0, sizeof(run_stack[stack_curr])); - #endif - } - - return true; // We are done with sorting. - } - - return false; - } - - } // namespace Internal - - - // tim_sort_buffer - // - /// This is a stable sort. - // Implements the tim-sort sorting algorithm with a user-provided scratch buffer. - // http://en.wikipedia.org/wiki/Timsort - // This sort is the fastest sort when sort stability (maintaining order of equal values) is required and - // data sets are non-trivial (size >= 15). It's also the fastest sort (e.g. faster than quick_sort) for - // the case that at at least half your data is already sorted. Otherwise, eastl::quick_sort is about 10% - // faster than tim_sort_buffer but is not a stable sort. There are some reports that tim_sort outperforms - // quick_sort but most of these aren't taking into account that optimal quick_sort implementations use - // a hybrid approach called "introsort" (http://en.wikipedia.org/wiki/Introsort) which improves quick_sort - // considerably in practice. - // - // Strengths: - // - Fastest stable sort for most sizes of data. - // - Fastest sort for containers of data already mostly sorted. - // - Simpler to understand than quick_sort. - // - // Weaknesses: - // - User must provide a scratch buffer, otherwise the buffer is dynamically allocated during runtime. - // - Not as fast as quick_sort for the general case of randomized data. - // - Requires a RandomAccessIterator; thus must be on an array container type and not a list container type. - // - Uses a lot of code to implement; thus it's not great when there is little room for more code. - // - // The pBuffer parameter must hold at least ((last-first)/2) elements (i.e. half the elements of the container). - // This minimum size is a worst-case size requirement, but handles all possible cases. pBuffer is just a scratch - // buffer and is not needed after the return of this function, and doesn't need to be seeded with any particular - // values upon entering this function. - // - // Example usage: - // int intArray[64]; - // int buffer[32]; - // ... - // tim_sort_buffer(intArray, intArray + 64, buffer); - // - template <typename RandomAccessIterator, typename T, typename StrictWeakOrdering> - void tim_sort_buffer(RandomAccessIterator first, RandomAccessIterator last, T* pBuffer, StrictWeakOrdering compare) - { - using namespace Internal; - - // To consider: Convert the implementation to use first/last instead of first/size. - const intptr_t size = (intptr_t)(last - first); - - if(size < 64) - insertion_sort_already_started(first, first + size, first + 1, compare); - else - { - tim_sort_run run_stack[kTimSortStackSize]; - intptr_t stack_curr = 0; - intptr_t len, run; - intptr_t curr = 0; - const intptr_t minrun = timsort_compute_minrun(size); - - #if EASTL_DEV_DEBUG - memset(run_stack, 0, sizeof(run_stack)); - #endif - - if(tim_sort_add_run<RandomAccessIterator, T, StrictWeakOrdering>(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare)) - return; - if(tim_sort_add_run<RandomAccessIterator, T, StrictWeakOrdering>(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare)) - return; - if(tim_sort_add_run<RandomAccessIterator, T, StrictWeakOrdering>(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare)) - return; - - for(;;) - { - if(timsort_check_invariant(run_stack, stack_curr)) - stack_curr = tim_sort_collapse<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, size, compare); - else - { - if(tim_sort_add_run<RandomAccessIterator, T, StrictWeakOrdering>(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare)) - break; - } - } - } - } - - - template <typename RandomAccessIterator, typename T> - inline void tim_sort_buffer(RandomAccessIterator first, RandomAccessIterator last, T* pBuffer) - { - typedef eastl::less<T> Less; - - eastl::tim_sort_buffer<RandomAccessIterator, T, Less>(first, last, pBuffer, Less()); - } - - - - - /// radix_sort - /// - /// Implements a classic LSD (least significant digit) radix sort. - /// See http://en.wikipedia.org/wiki/Radix_sort. - /// This sort requires that the sorted data be of a type that has a member - /// radix_type typedef and an mKey member of that type. The type must be - /// an integral type. This limits what can be sorted, but radix_sort is - /// very fast -- typically faster than any other sort. - /// For example: - /// struct Sortable { - /// typedef int radix_type; - /// radix_type mKey; - /// // User data goes here, or the user can inherit from Sortable. - /// }; - /// or, more generally: - /// template <typname Integer> - /// struct Sortable { - /// typedef Integer radix_type; - /// Integer mKey; - /// }; - /// - /// Example usage: - /// struct Element { - /// typedef uint16_t radix_type; - /// uint16_t mKey; - /// uint16_t mUserData; - /// }; - /// - /// Element elementArray[100]; - /// Element buffer[100]; - /// - /// radix_sort<Element*, extract_radix_key<Element> >(elementArray, elementArray + 100, buffer); - /// - /// To consider: A static linked-list implementation may be faster than the version here. - - namespace Internal - { - /// extract_radix_key - /// - /// Default radix sort integer value reader. It expects the sorted elements - /// to have an integer member of type radix_type and of name "mKey". - /// - template <typename Node> - struct extract_radix_key - { - typedef typename Node::radix_type radix_type; - - const radix_type operator()(const Node& x) const - { return x.mKey; } - }; - - // The radix_sort implementation uses two optimizations that are not part of a typical radix sort implementation. - // 1. Computing a histogram (i.e. finding the number of elements per bucket) for the next pass is done in parallel with the loop that "scatters" - // elements in the current pass. The advantage is that it avoids the memory traffic / cache pressure of reading keys in a separate operation. - // Note: It would also be possible to compute all histograms in a single pass. However, that would increase the amount of stack space used and - // also increase cache pressure slightly. However, it could still be faster under some situations. - // 2. If all elements are mapped to a single bucket, then there is no need to perform a scatter operation. Instead the elements are left in place - // and only copied if they need to be copied to the final output buffer. - template <typename RandomAccessIterator, typename ExtractKey, int DigitBits, typename IntegerType> - void radix_sort_impl(RandomAccessIterator first, - RandomAccessIterator last, - RandomAccessIterator buffer, - ExtractKey extractKey, - IntegerType) - { - RandomAccessIterator srcFirst = first; - EA_CONSTEXPR_OR_CONST size_t numBuckets = 1 << DigitBits; - EA_CONSTEXPR_OR_CONST IntegerType bucketMask = numBuckets - 1; - - // The alignment of this variable isn't required; it merely allows the code below to be faster on some platforms. - uint32_t EA_PREFIX_ALIGN(EASTL_PLATFORM_PREFERRED_ALIGNMENT) bucketSize[numBuckets]; - uint32_t EA_PREFIX_ALIGN(EASTL_PLATFORM_PREFERRED_ALIGNMENT) bucketPosition[numBuckets]; - - RandomAccessIterator temp; - uint32_t i; - - bool doSeparateHistogramCalculation = true; - uint32_t j; - for (j = 0; j < (8 * sizeof(IntegerType)); j += DigitBits) - { - if (doSeparateHistogramCalculation) - { - memset(bucketSize, 0, sizeof(bucketSize)); - // Calculate histogram for the first scatter operation - for (temp = srcFirst; temp != last; ++temp) - ++bucketSize[(extractKey(*temp) >> j) & bucketMask]; - } - - // If a single bucket contains all of the elements, then don't bother redistributing all elements to the - // same bucket. - if (bucketSize[((extractKey(*srcFirst) >> j) & bucketMask)] == uint32_t(last - srcFirst)) - { - // Set flag to ensure histogram is computed for next digit position. - doSeparateHistogramCalculation = true; - } - else - { - // The histogram is either not needed or it will be calculated in parallel with the scatter operation below for better cache efficiency. - doSeparateHistogramCalculation = false; - - // If this is the last digit position, then don't calculate a histogram - if (j == (8 * sizeof(IntegerType) - DigitBits)) - { - bucketPosition[0] = 0; - for (i = 0; i < numBuckets - 1; i++) - { - bucketPosition[i + 1] = bucketPosition[i] + bucketSize[i]; - } - - for (temp = srcFirst; temp != last; ++temp) - { - IntegerType key = extractKey(*temp); - const size_t digit = (key >> j) & bucketMask; - buffer[bucketPosition[digit]++] = *temp; - } - } - // Compute the histogram while performing the scatter operation - else - { - bucketPosition[0] = 0; - for (i = 0; i < numBuckets - 1; i++) - { - bucketPosition[i + 1] = bucketPosition[i] + bucketSize[i]; - bucketSize[i] = 0; // Clear the bucket for the next pass - } - bucketSize[numBuckets - 1] = 0; - - uint32_t jNext = j + DigitBits; - for (temp = srcFirst; temp != last; ++temp) - { - IntegerType key = extractKey(*temp); - const size_t digit = (key >> j) & bucketMask; - buffer[bucketPosition[digit]++] = *temp; - - // Update histogram for the next scatter operation - ++bucketSize[(extractKey(*temp) >> jNext) & bucketMask]; - } - } - - last = buffer + (last - srcFirst); - temp = srcFirst; - srcFirst = buffer; - buffer = temp; - } - } - - if (srcFirst != first) - { - // Copy values back into the expected buffer - for (temp = srcFirst; temp != last; ++temp) - *buffer++ = *temp; - } - } - } // namespace Internal - - template <typename RandomAccessIterator, typename ExtractKey, int DigitBits = 8> - void radix_sort(RandomAccessIterator first, RandomAccessIterator last, RandomAccessIterator buffer) - { - static_assert(DigitBits > 0, "DigitBits must be > 0"); - static_assert(DigitBits <= (sizeof(typename ExtractKey::radix_type) * 8), "DigitBits must be <= the size of the key (in bits)"); - eastl::Internal::radix_sort_impl<RandomAccessIterator, ExtractKey, DigitBits>(first, last, buffer, ExtractKey(), typename ExtractKey::radix_type()); - } - - - - /// comb_sort - /// - /// This is an unstable sort. - /// Implements the CombSort algorithm; in particular, implements the CombSort11 variation - /// of the CombSort algorithm, based on the reference to '11' in the implementation. - /// - /// To consider: Use a comb sort table instead of the '((nSpace * 10) + 3) / 13' expression. - /// Ideal tables can be found on the Internet by looking up "comb sort table". - /// - template <typename ForwardIterator, typename StrictWeakOrdering> - void comb_sort(ForwardIterator first, ForwardIterator last, StrictWeakOrdering compare) - { - typedef typename eastl::iterator_traits<ForwardIterator>::difference_type difference_type; - - ForwardIterator iCurrent, iNext; - difference_type length = eastl::distance(first, last); - difference_type nSpace = length; - - for(bool bSwapped = false; (nSpace > 1) || bSwapped; ) - { - nSpace = ((nSpace * 10) + 3) / 13; // Integer division is less than ideal. - - if((nSpace == 9) || (nSpace == 10)) - nSpace = 11; - - iCurrent = iNext = first; - eastl::advance(iNext, nSpace); - - for(bSwapped = false; iNext != last; iCurrent++, iNext++) - { - if(compare(*iNext, *iCurrent)) - { - EASTL_VALIDATE_COMPARE(!compare(*iCurrent, *iNext)); // Validate that the compare function is sane. - eastl::iter_swap(iCurrent, iNext); - bSwapped = true; - } - } - } - } // comb_sort - - template <typename ForwardIterator> - inline void comb_sort(ForwardIterator first, ForwardIterator last) - { - typedef eastl::less<typename eastl::iterator_traits<ForwardIterator>::value_type> Less; - - eastl::comb_sort<ForwardIterator, Less>(first, last, Less()); - } - - - - - /// bubble_sort - /// - /// This is a stable sort. - /// Implements the BubbleSort algorithm. This algorithm is only useful for - /// small range sizes, such as 10 or less items. You may be better off using - /// insertion_sort for cases where bubble_sort works. - /// - namespace Internal - { - template <typename ForwardIterator, typename StrictWeakOrdering> - void bubble_sort_impl(ForwardIterator first, ForwardIterator last, StrictWeakOrdering compare, EASTL_ITC_NS::forward_iterator_tag) - { - ForwardIterator iCurrent, iNext; - - while(first != last) - { - iNext = iCurrent = first; - - for(++iNext; iNext != last; iCurrent = iNext, ++iNext) - { - if(compare(*iNext, *iCurrent)) - { - EASTL_VALIDATE_COMPARE(!compare(*iCurrent, *iNext)); // Validate that the compare function is sane. - eastl::iter_swap(iCurrent, iNext); - } - } - last = iCurrent; - } - } - - template <typename BidirectionalIterator, typename StrictWeakOrdering> - void bubble_sort_impl(BidirectionalIterator first, BidirectionalIterator last, StrictWeakOrdering compare, EASTL_ITC_NS::bidirectional_iterator_tag) - { - if(first != last) - { - BidirectionalIterator iCurrent, iNext, iLastModified; - - last--; - - while(first != last) - { - iLastModified = iNext = iCurrent = first; - - for(++iNext; iCurrent != last; iCurrent = iNext, ++iNext) - { - if(compare(*iNext, *iCurrent)) - { - EASTL_VALIDATE_COMPARE(!compare(*iCurrent, *iNext)); // Validate that the compare function is sane. - iLastModified = iCurrent; - eastl::iter_swap(iCurrent, iNext); - } - } - - last = iLastModified; - } - } - } - } // namespace Internal - - template <typename ForwardIterator, typename StrictWeakOrdering> - inline void bubble_sort(ForwardIterator first, ForwardIterator last, StrictWeakOrdering compare) - { - typedef typename eastl::iterator_traits<ForwardIterator>::iterator_category IC; - - eastl::Internal::bubble_sort_impl<ForwardIterator, StrictWeakOrdering>(first, last, compare, IC()); - } - - template <typename ForwardIterator> - inline void bubble_sort(ForwardIterator first, ForwardIterator last) - { - typedef eastl::less<typename eastl::iterator_traits<ForwardIterator>::value_type> Less; - typedef typename eastl::iterator_traits<ForwardIterator>::iterator_category IC; - - eastl::Internal::bubble_sort_impl<ForwardIterator, Less>(first, last, Less(), IC()); - } - - - - /// sort - /// - /// We use quick_sort by default. See quick_sort for details. - /// - /// EASTL_DEFAULT_SORT_FUNCTION - /// If a default sort function is specified then call it, otherwise use EASTL's default quick_sort. - /// EASTL_DEFAULT_SORT_FUNCTION must be namespace-qualified and include any necessary template - /// parameters (e.g. eastl::comb_sort instead of just comb_sort), and it must be visible to this code. - /// The EASTL_DEFAULT_SORT_FUNCTION must be provided in two versions: - /// template <typename RandomAccessIterator> - /// void EASTL_DEFAULT_SORT_FUNCTION(RandomAccessIterator first, RandomAccessIterator last); - /// - /// template <typename RandomAccessIterator, typename Compare> - /// void EASTL_DEFAULT_SORT_FUNCTION(RandomAccessIterator first, RandomAccessIterator last, Compare compare) - /// - template <typename RandomAccessIterator> - inline void sort(RandomAccessIterator first, RandomAccessIterator last) - { - #if defined(EASTL_DEFAULT_SORT_FUNCTION) - EASTL_DEFAULT_SORT_FUNCTION(first, last); - #else - eastl::quick_sort<RandomAccessIterator>(first, last); - #endif - } - - template <typename RandomAccessIterator, typename Compare> - inline void sort(RandomAccessIterator first, RandomAccessIterator last, Compare compare) - { - #if defined(EASTL_DEFAULT_SORT_FUNCTION) - EASTL_DEFAULT_SORT_FUNCTION(first, last, compare); - #else - eastl::quick_sort<RandomAccessIterator, Compare>(first, last, compare); - #endif - } - - - - /// stable_sort - /// - /// We use merge_sort by default. See merge_sort for details. - /// Beware that the used merge_sort -- and thus stable_sort -- allocates - /// memory during execution. Try using merge_sort_buffer if you want - /// to avoid memory allocation. - /// - /// EASTL_DEFAULT_STABLE_SORT_FUNCTION - /// If a default sort function is specified then call it, otherwise use EASTL's default merge_sort. - /// EASTL_DEFAULT_STABLE_SORT_FUNCTION must be namespace-qualified and include any necessary template - /// parameters (e.g. eastl::tim_sort instead of just tim_sort), and it must be visible to this code. - /// The EASTL_DEFAULT_STABLE_SORT_FUNCTION must be provided in three versions, though the third - /// allocation implementation may choose to ignore the allocator parameter: - /// template <typename RandomAccessIterator, typename StrictWeakOrdering> - /// void EASTL_DEFAULT_STABLE_SORT_FUNCTION(RandomAccessIterator first, RandomAccessIterator last, StrictWeakOrdering compare); - /// - /// template <typename RandomAccessIterator> - /// void EASTL_DEFAULT_STABLE_SORT_FUNCTION(RandomAccessIterator first, RandomAccessIterator last); - /// - /// template <typename RandomAccessIterator, typename Allocator, typename StrictWeakOrdering> - /// void EASTL_DEFAULT_STABLE_SORT_FUNCTION(RandomAccessIterator first, RandomAccessIterator last, Allocator& allocator, StrictWeakOrdering compare); - /// - template <typename RandomAccessIterator, typename StrictWeakOrdering> - void stable_sort(RandomAccessIterator first, RandomAccessIterator last, StrictWeakOrdering compare) - { - #if defined(EASTL_DEFAULT_STABLE_SORT_FUNCTION) - EASTL_DEFAULT_STABLE_SORT_FUNCTION(first, last, *get_default_allocator(0), compare); - #else - eastl::merge_sort<RandomAccessIterator, EASTLAllocatorType, StrictWeakOrdering> - (first, last, *get_default_allocator(0), compare); - #endif - } - - template <typename RandomAccessIterator> - void stable_sort(RandomAccessIterator first, RandomAccessIterator last) - { - #if defined(EASTL_DEFAULT_STABLE_SORT_FUNCTION) - EASTL_DEFAULT_STABLE_SORT_FUNCTION(first, last, *get_default_allocator(0)); - #else - eastl::merge_sort<RandomAccessIterator, EASTLAllocatorType> - (first, last, *get_default_allocator(0)); - #endif - } - - template <typename RandomAccessIterator, typename Allocator, typename StrictWeakOrdering> - void stable_sort(RandomAccessIterator first, RandomAccessIterator last, Allocator& allocator, StrictWeakOrdering compare) - { - #if defined(EASTL_DEFAULT_STABLE_SORT_FUNCTION) - EASTL_DEFAULT_STABLE_SORT_FUNCTION(first, last, allocator, compare); - #else - eastl::merge_sort<RandomAccessIterator, Allocator, StrictWeakOrdering>(first, last, allocator, compare); - #endif - } - - // This is not defined because it would cause compiler errors due to conflicts with a version above. - //template <typename RandomAccessIterator, typename Allocator> - //void stable_sort(RandomAccessIterator first, RandomAccessIterator last, Allocator& allocator) - //{ - // #if defined(EASTL_DEFAULT_STABLE_SORT_FUNCTION) - // EASTL_DEFAULT_STABLE_SORT_FUNCTION<RandomAccessIterator, Allocator>(first, last, allocator); - // #else - // eastl::merge_sort<RandomAccessIterator, Allocator>(first, last, allocator); - // #endif - //} - - - - - /* - // Something to consider adding: An eastl sort which uses qsort underneath. - // The primary purpose of this is to have an eastl interface for sorting which - // results in very little code generation, since all instances map to the - // C qsort function. - - template <typename T> - int small_footprint_sort_func(const void* a, const void* b) - { - if(*(const T*)a < *(const T*)b) - return -1; - if(*(const T*)a > *(const T*)b) - return +1; - return 0; - } - - template <typename ContiguousIterator> - void small_footprint_sort(ContiguousIterator first, ContiguousIterator last) - { - typedef typename eastl::iterator_traits<ContiguousIterator>::value_type value_type; - - qsort(first, (size_t)eastl::distance(first, last), sizeof(value_type), small_footprint_sort_func<value_type>); - } - */ - -} // namespace eastl - - -#endif // Header include guard - - - |