| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| // When the platform supports STL, the functions are implemented using a |
| // templated spreadsort algorithm (http://sourceforge.net/projects/spreadsort/), |
| // part of the Boost C++ library collection. Otherwise, the C standard library's |
| // qsort() will be used. |
| |
| #include "sort.h" |
| |
| #include <cassert> |
| #include <cstring> // memcpy |
| #include <new> // nothrow new |
| |
| #ifdef NO_STL |
| #include <cstdlib> // qsort |
| #else |
| #include <algorithm> // std::sort |
| #include <vector> |
| #include "spreadsort.hpp" // TODO (ajm) upgrade to spreadsortv2. |
| #endif |
| |
| #ifdef NO_STL |
| #define COMPARE_DEREFERENCED(XT, YT) \ |
| do \ |
| { \ |
| if ((XT) > (YT)) \ |
| { \ |
| return 1; \ |
| } \ |
| else if ((XT) < (YT)) \ |
| { \ |
| return -1; \ |
| } \ |
| \ |
| return 0; \ |
| } \ |
| while(0) |
| |
| #define COMPARE_FOR_QSORT(X, Y, TYPE) \ |
| do \ |
| { \ |
| TYPE xT = static_cast<TYPE>(*static_cast<const TYPE*>(X)); \ |
| TYPE yT = static_cast<TYPE>(*static_cast<const TYPE*>(Y)); \ |
| COMPARE_DEREFERENCED(xT, yT); \ |
| } \ |
| while(0) |
| |
| #define COMPARE_KEY_FOR_QSORT(SORT_KEY_X, SORT_KEY_Y, TYPE) \ |
| do \ |
| { \ |
| TYPE xT = static_cast<TYPE>(*static_cast<TYPE*> \ |
| (static_cast<const SortKey*>(SORT_KEY_X)->key)); \ |
| TYPE yT = static_cast<TYPE>(*static_cast<TYPE*> \ |
| (static_cast<const SortKey*>(SORT_KEY_Y)->key)); \ |
| COMPARE_DEREFERENCED(xT, yT); \ |
| } \ |
| while(0) |
| |
| #define KEY_QSORT(SORT_KEY, KEY, NUM_OF_ELEMENTS, KEY_TYPE, COMPARE_FUNC) \ |
| do \ |
| { \ |
| KEY_TYPE* keyT = (KEY_TYPE*)(key); \ |
| for (WebRtc_UWord32 i = 0; i < (NUM_OF_ELEMENTS); i++) \ |
| { \ |
| ptrSortKey[i].key = &keyT[i]; \ |
| ptrSortKey[i].index = i; \ |
| } \ |
| \ |
| qsort((SORT_KEY), (NUM_OF_ELEMENTS), sizeof(SortKey), (COMPARE_FUNC));\ |
| } \ |
| while(0) |
| #endif |
| |
| namespace webrtc |
| { |
| #ifdef NO_STL |
| struct SortKey |
| { |
| void* key; |
| WebRtc_UWord32 index; |
| }; |
| #else |
| template<typename KeyType> |
| struct SortKey |
| { |
| KeyType key; |
| WebRtc_UWord32 index; |
| }; |
| #endif |
| |
| namespace // Unnamed namespace provides internal linkage. |
| { |
| #ifdef NO_STL |
| int CompareWord8(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, WebRtc_Word8); |
| } |
| |
| int CompareUWord8(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, WebRtc_UWord8); |
| } |
| |
| int CompareWord16(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, WebRtc_Word16); |
| } |
| |
| int CompareUWord16(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, WebRtc_UWord16); |
| } |
| |
| int CompareWord32(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, WebRtc_Word32); |
| } |
| |
| int CompareUWord32(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, WebRtc_UWord32); |
| } |
| |
| int CompareWord64(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, WebRtc_Word64); |
| } |
| |
| int CompareUWord64(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, WebRtc_UWord64); |
| } |
| |
| int CompareFloat32(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, float); |
| } |
| |
| int CompareFloat64(const void* x, const void* y) |
| { |
| COMPARE_FOR_QSORT(x, y, double); |
| } |
| |
| int CompareKeyWord8(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_Word8); |
| } |
| |
| int CompareKeyUWord8(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_UWord8); |
| } |
| |
| int CompareKeyWord16(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_Word16); |
| } |
| |
| int CompareKeyUWord16(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_UWord16); |
| } |
| |
| int CompareKeyWord32(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_Word32); |
| } |
| |
| int CompareKeyUWord32(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_UWord32); |
| } |
| |
| int CompareKeyWord64(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_Word64); |
| } |
| |
| int CompareKeyUWord64(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_UWord64); |
| } |
| |
| int CompareKeyFloat32(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, float); |
| } |
| |
| int CompareKeyFloat64(const void* sortKeyX, const void* sortKeyY) |
| { |
| COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, double); |
| } |
| #else |
| template <typename KeyType> |
| struct KeyLessThan |
| { |
| bool operator()(const SortKey<KeyType>& sortKeyX, |
| const SortKey<KeyType>& sortKeyY) const |
| { |
| return sortKeyX.key < sortKeyY.key; |
| } |
| }; |
| |
| template <typename KeyType> |
| struct KeyRightShift |
| { |
| KeyType operator()(const SortKey<KeyType>& sortKey, |
| const unsigned offset) const |
| { |
| return sortKey.key >> offset; |
| } |
| }; |
| |
| template <typename DataType> |
| inline void IntegerSort(void* data, WebRtc_UWord32 numOfElements) |
| { |
| DataType* dataT = static_cast<DataType*>(data); |
| boost::integer_sort(dataT, dataT + numOfElements); |
| } |
| |
| template <typename DataType, typename IntegerType> |
| inline void FloatSort(void* data, WebRtc_UWord32 numOfElements) |
| { |
| DataType* dataT = static_cast<DataType*>(data); |
| IntegerType cVal = 0; |
| boost::float_sort_cast(dataT, dataT + numOfElements, cVal); |
| } |
| |
| template <typename DataType> |
| inline void StdSort(void* data, WebRtc_UWord32 numOfElements) |
| { |
| DataType* dataT = static_cast<DataType*>(data); |
| std::sort(dataT, dataT + numOfElements); |
| } |
| |
| template<typename KeyType> |
| inline WebRtc_Word32 SetupKeySort(void* key, |
| SortKey<KeyType>*& ptrSortKey, |
| WebRtc_UWord32 numOfElements) |
| { |
| ptrSortKey = new(std::nothrow) SortKey<KeyType>[numOfElements]; |
| if (ptrSortKey == NULL) |
| { |
| return -1; |
| } |
| |
| KeyType* keyT = static_cast<KeyType*>(key); |
| for (WebRtc_UWord32 i = 0; i < numOfElements; i++) |
| { |
| ptrSortKey[i].key = keyT[i]; |
| ptrSortKey[i].index = i; |
| } |
| |
| return 0; |
| } |
| |
| template<typename KeyType> |
| inline WebRtc_Word32 TeardownKeySort(void* data, |
| SortKey<KeyType>* ptrSortKey, |
| WebRtc_UWord32 numOfElements, WebRtc_UWord32 sizeOfElement) |
| { |
| WebRtc_UWord8* ptrData = static_cast<WebRtc_UWord8*>(data); |
| WebRtc_UWord8* ptrDataSorted = new(std::nothrow) WebRtc_UWord8 |
| [numOfElements * sizeOfElement]; |
| if (ptrDataSorted == NULL) |
| { |
| return -1; |
| } |
| |
| for (WebRtc_UWord32 i = 0; i < numOfElements; i++) |
| { |
| memcpy(ptrDataSorted + i * sizeOfElement, ptrData + |
| ptrSortKey[i].index * sizeOfElement, sizeOfElement); |
| } |
| memcpy(ptrData, ptrDataSorted, numOfElements * sizeOfElement); |
| delete[] ptrSortKey; |
| delete[] ptrDataSorted; |
| return 0; |
| } |
| |
| template<typename KeyType> |
| inline WebRtc_Word32 IntegerKeySort(void* data, void* key, |
| WebRtc_UWord32 numOfElements, |
| WebRtc_UWord32 sizeOfElement) |
| { |
| SortKey<KeyType>* ptrSortKey; |
| if (SetupKeySort<KeyType>(key, ptrSortKey, numOfElements) != 0) |
| { |
| return -1; |
| } |
| |
| boost::integer_sort(ptrSortKey, ptrSortKey + numOfElements, |
| KeyRightShift<KeyType>(), KeyLessThan<KeyType>()); |
| |
| if (TeardownKeySort<KeyType>(data, ptrSortKey, numOfElements, |
| sizeOfElement) != 0) |
| { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| template<typename KeyType> |
| inline WebRtc_Word32 StdKeySort(void* data, void* key, |
| WebRtc_UWord32 numOfElements, |
| WebRtc_UWord32 sizeOfElement) |
| { |
| SortKey<KeyType>* ptrSortKey; |
| if (SetupKeySort<KeyType>(key, ptrSortKey, numOfElements) != 0) |
| { |
| return -1; |
| } |
| |
| std::sort(ptrSortKey, ptrSortKey + numOfElements, |
| KeyLessThan<KeyType>()); |
| |
| if (TeardownKeySort<KeyType>(data, ptrSortKey, numOfElements, |
| sizeOfElement) != 0) |
| { |
| return -1; |
| } |
| |
| return 0; |
| } |
| #endif |
| } |
| |
| WebRtc_Word32 Sort(void* data, WebRtc_UWord32 numOfElements, Type type) |
| { |
| if (data == NULL) |
| { |
| return -1; |
| } |
| |
| #ifdef NO_STL |
| switch (type) |
| { |
| case TYPE_Word8: |
| qsort(data, numOfElements, sizeof(WebRtc_Word8), CompareWord8); |
| break; |
| case TYPE_UWord8: |
| qsort(data, numOfElements, sizeof(WebRtc_UWord8), CompareUWord8); |
| break; |
| case TYPE_Word16: |
| qsort(data, numOfElements, sizeof(WebRtc_Word16), CompareWord16); |
| break; |
| case TYPE_UWord16: |
| qsort(data, numOfElements, sizeof(WebRtc_UWord16), CompareUWord16); |
| break; |
| case TYPE_Word32: |
| qsort(data, numOfElements, sizeof(WebRtc_Word32), CompareWord32); |
| break; |
| case TYPE_UWord32: |
| qsort(data, numOfElements, sizeof(WebRtc_UWord32), CompareUWord32); |
| break; |
| case TYPE_Word64: |
| qsort(data, numOfElements, sizeof(WebRtc_Word64), CompareWord64); |
| break; |
| case TYPE_UWord64: |
| qsort(data, numOfElements, sizeof(WebRtc_UWord64), CompareUWord64); |
| break; |
| case TYPE_Float32: |
| qsort(data, numOfElements, sizeof(float), CompareFloat32); |
| break; |
| case TYPE_Float64: |
| qsort(data, numOfElements, sizeof(double), CompareFloat64); |
| break; |
| default: |
| return -1; |
| } |
| #else |
| // Fall back to std::sort for 64-bit types and floats due to compiler |
| // warnings and VS 2003 build crashes respectively with spreadsort. |
| switch (type) |
| { |
| case TYPE_Word8: |
| IntegerSort<WebRtc_Word8>(data, numOfElements); |
| break; |
| case TYPE_UWord8: |
| IntegerSort<WebRtc_UWord8>(data, numOfElements); |
| break; |
| case TYPE_Word16: |
| IntegerSort<WebRtc_Word16>(data, numOfElements); |
| break; |
| case TYPE_UWord16: |
| IntegerSort<WebRtc_UWord16>(data, numOfElements); |
| break; |
| case TYPE_Word32: |
| IntegerSort<WebRtc_Word32>(data, numOfElements); |
| break; |
| case TYPE_UWord32: |
| IntegerSort<WebRtc_UWord32>(data, numOfElements); |
| break; |
| case TYPE_Word64: |
| StdSort<WebRtc_Word64>(data, numOfElements); |
| break; |
| case TYPE_UWord64: |
| StdSort<WebRtc_UWord64>(data, numOfElements); |
| break; |
| case TYPE_Float32: |
| StdSort<float>(data, numOfElements); |
| break; |
| case TYPE_Float64: |
| StdSort<double>(data, numOfElements); |
| break; |
| default: |
| return -1; |
| } |
| #endif |
| return 0; |
| } |
| |
| WebRtc_Word32 KeySort(void* data, void* key, WebRtc_UWord32 numOfElements, |
| WebRtc_UWord32 sizeOfElement, Type keyType) |
| { |
| if (data == NULL) |
| { |
| return -1; |
| } |
| |
| if (key == NULL) |
| { |
| return -1; |
| } |
| |
| if ((WebRtc_UWord64)numOfElements * sizeOfElement > 0xffffffff) |
| { |
| return -1; |
| } |
| |
| #ifdef NO_STL |
| SortKey* ptrSortKey = new(std::nothrow) SortKey[numOfElements]; |
| if (ptrSortKey == NULL) |
| { |
| return -1; |
| } |
| |
| switch (keyType) |
| { |
| case TYPE_Word8: |
| KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_Word8, |
| CompareKeyWord8); |
| break; |
| case TYPE_UWord8: |
| KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_UWord8, |
| CompareKeyUWord8); |
| break; |
| case TYPE_Word16: |
| KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_Word16, |
| CompareKeyWord16); |
| break; |
| case TYPE_UWord16: |
| KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_UWord16, |
| CompareKeyUWord16); |
| break; |
| case TYPE_Word32: |
| KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_Word32, |
| CompareKeyWord32); |
| break; |
| case TYPE_UWord32: |
| KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_UWord32, |
| CompareKeyUWord32); |
| break; |
| case TYPE_Word64: |
| KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_Word64, |
| CompareKeyWord64); |
| break; |
| case TYPE_UWord64: |
| KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_UWord64, |
| CompareKeyUWord64); |
| break; |
| case TYPE_Float32: |
| KEY_QSORT(ptrSortKey, key, numOfElements, float, |
| CompareKeyFloat32); |
| break; |
| case TYPE_Float64: |
| KEY_QSORT(ptrSortKey, key, numOfElements, double, |
| CompareKeyFloat64); |
| break; |
| default: |
| return -1; |
| } |
| |
| // Shuffle into sorted position based on index map. |
| WebRtc_UWord8* ptrData = static_cast<WebRtc_UWord8*>(data); |
| WebRtc_UWord8* ptrDataSorted = new(std::nothrow) WebRtc_UWord8 |
| [numOfElements * sizeOfElement]; |
| if (ptrDataSorted == NULL) |
| { |
| return -1; |
| } |
| |
| for (WebRtc_UWord32 i = 0; i < numOfElements; i++) |
| { |
| memcpy(ptrDataSorted + i * sizeOfElement, ptrData + |
| ptrSortKey[i].index * sizeOfElement, sizeOfElement); |
| } |
| memcpy(ptrData, ptrDataSorted, numOfElements * sizeOfElement); |
| |
| delete[] ptrSortKey; |
| delete[] ptrDataSorted; |
| |
| return 0; |
| #else |
| // Fall back to std::sort for 64-bit types and floats due to compiler |
| // warnings and errors respectively with spreadsort. |
| switch (keyType) |
| { |
| case TYPE_Word8: |
| return IntegerKeySort<WebRtc_Word8>(data, key, numOfElements, |
| sizeOfElement); |
| case TYPE_UWord8: |
| return IntegerKeySort<WebRtc_UWord8>(data, key, numOfElements, |
| sizeOfElement); |
| case TYPE_Word16: |
| return IntegerKeySort<WebRtc_Word16>(data, key, numOfElements, |
| sizeOfElement); |
| case TYPE_UWord16: |
| return IntegerKeySort<WebRtc_UWord16>(data, key, numOfElements, |
| sizeOfElement); |
| case TYPE_Word32: |
| return IntegerKeySort<WebRtc_Word32>(data, key, numOfElements, |
| sizeOfElement); |
| case TYPE_UWord32: |
| return IntegerKeySort<WebRtc_UWord32>(data, key, numOfElements, |
| sizeOfElement); |
| case TYPE_Word64: |
| return StdKeySort<WebRtc_Word64>(data, key, numOfElements, |
| sizeOfElement); |
| case TYPE_UWord64: |
| return StdKeySort<WebRtc_UWord64>(data, key, numOfElements, |
| sizeOfElement); |
| case TYPE_Float32: |
| return StdKeySort<float>(data, key, numOfElements, sizeOfElement); |
| case TYPE_Float64: |
| return StdKeySort<double>(data, key, numOfElements, sizeOfElement); |
| default: |
| return -1; |
| } |
| #endif |
| } |
| } // namespace webrtc |