diff options
Diffstat (limited to 'src/system_wrappers/source/sort.cc')
-rw-r--r-- | src/system_wrappers/source/sort.cc | 551 |
1 files changed, 551 insertions, 0 deletions
diff --git a/src/system_wrappers/source/sort.cc b/src/system_wrappers/source/sort.cc new file mode 100644 index 0000000000..f44b644978 --- /dev/null +++ b/src/system_wrappers/source/sort.cc @@ -0,0 +1,551 @@ +/* + * 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 |