| /* |
| * Copyright (c) 2012 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 "webrtc/system_wrappers/include/sort.h" |
| |
| #include <assert.h> |
| #include <string.h> // memcpy |
| |
| #include <new> // nothrow new |
| |
| #ifdef NO_STL |
| #include <stdlib.h> // qsort |
| #else |
| #include <algorithm> // std::sort |
| #include <vector> |
| |
| // TODO(ajm) upgrade to spreadsort v2. |
| #include "webrtc/system_wrappers/source/spreadsortlib/spreadsort.hpp" |
| #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* key_type = (KEY_TYPE*)(key); \ |
| for (uint32_t i = 0; i < (NUM_OF_ELEMENTS); ++i) { \ |
| ptr_sort_key[i].key_ = &key_type[i]; \ |
| ptr_sort_key[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_; |
| uint32_t index_; |
| }; |
| #else |
| template<typename KeyType> |
| struct SortKey { |
| KeyType key_; |
| uint32_t index_; |
| }; |
| #endif |
| |
| namespace { // Unnamed namespace provides internal linkage. |
| |
| #ifdef NO_STL |
| int CompareWord8(const void* x, const void* y) { |
| COMPARE_FOR_QSORT(x, y, int8_t); |
| } |
| |
| int CompareUWord8(const void* x, const void* y) { |
| COMPARE_FOR_QSORT(x, y, uint8_t); |
| } |
| |
| int CompareWord16(const void* x, const void* y) { |
| COMPARE_FOR_QSORT(x, y, int16_t); |
| } |
| |
| int CompareUWord16(const void* x, const void* y) { |
| COMPARE_FOR_QSORT(x, y, uint16_t); |
| } |
| |
| int CompareWord32(const void* x, const void* y) { |
| COMPARE_FOR_QSORT(x, y, int32_t); |
| } |
| |
| int CompareUWord32(const void* x, const void* y) { |
| COMPARE_FOR_QSORT(x, y, uint32_t); |
| } |
| |
| int CompareWord64(const void* x, const void* y) { |
| COMPARE_FOR_QSORT(x, y, int64_t); |
| } |
| |
| int CompareUWord64(const void* x, const void* y) { |
| COMPARE_FOR_QSORT(x, y, uint64_t); |
| } |
| |
| 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* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int8_t); |
| } |
| |
| int CompareKeyUWord8(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint8_t); |
| } |
| |
| int CompareKeyWord16(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int16_t); |
| } |
| |
| int CompareKeyUWord16(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint16_t); |
| } |
| |
| int CompareKeyWord32(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int32_t); |
| } |
| |
| int CompareKeyUWord32(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint32_t); |
| } |
| |
| int CompareKeyWord64(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int64_t); |
| } |
| |
| int CompareKeyUWord64(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint64_t); |
| } |
| |
| int CompareKeyFloat32(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, float); |
| } |
| |
| int CompareKeyFloat64(const void* sort_key_x, const void* sort_key_y) { |
| COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, double); |
| } |
| #else |
| template <typename KeyType> |
| struct KeyLessThan { |
| bool operator()(const SortKey<KeyType>& sort_key_x, |
| const SortKey<KeyType>& sort_key_y) const { |
| return sort_key_x.key_ < sort_key_y.key_; |
| } |
| }; |
| |
| template <typename KeyType> |
| struct KeyRightShift { |
| KeyType operator()(const SortKey<KeyType>& sort_key, |
| const unsigned offset) const { |
| return sort_key.key_ >> offset; |
| } |
| }; |
| |
| template <typename DataType> |
| inline void IntegerSort(void* data, uint32_t num_of_elements) { |
| DataType* data_type = static_cast<DataType*>(data); |
| boost::integer_sort(data_type, data_type + num_of_elements); |
| } |
| |
| template <typename DataType, typename IntegerType> |
| inline void FloatSort(void* data, uint32_t num_of_elements) { |
| DataType* data_type = static_cast<DataType*>(data); |
| IntegerType c_val = 0; |
| boost::float_sort_cast(data_type, data_type + num_of_elements, c_val); |
| } |
| |
| template <typename DataType> |
| inline void StdSort(void* data, uint32_t num_of_elements) { |
| DataType* data_type = static_cast<DataType*>(data); |
| std::sort(data_type, data_type + num_of_elements); |
| } |
| |
| template<typename KeyType> |
| inline int32_t SetupKeySort(void* key, |
| SortKey<KeyType>*& ptr_sort_key, |
| uint32_t num_of_elements) { |
| ptr_sort_key = new(std::nothrow) SortKey<KeyType>[num_of_elements]; |
| if (ptr_sort_key == NULL) { |
| return -1; |
| } |
| |
| KeyType* key_type = static_cast<KeyType*>(key); |
| for (uint32_t i = 0; i < num_of_elements; i++) { |
| ptr_sort_key[i].key_ = key_type[i]; |
| ptr_sort_key[i].index_ = i; |
| } |
| |
| return 0; |
| } |
| |
| template<typename KeyType> |
| inline int32_t TeardownKeySort(void* data, |
| SortKey<KeyType>* ptr_sort_key, |
| uint32_t num_of_elements, |
| uint32_t size_of_element) { |
| uint8_t* ptr_data = static_cast<uint8_t*>(data); |
| uint8_t* ptr_data_sorted = |
| new(std::nothrow) uint8_t[num_of_elements * size_of_element]; |
| if (ptr_data_sorted == NULL) { |
| return -1; |
| } |
| |
| for (uint32_t i = 0; i < num_of_elements; i++) { |
| memcpy(ptr_data_sorted + i * size_of_element, ptr_data + |
| ptr_sort_key[i].index_ * size_of_element, size_of_element); |
| } |
| memcpy(ptr_data, ptr_data_sorted, num_of_elements * size_of_element); |
| delete[] ptr_sort_key; |
| delete[] ptr_data_sorted; |
| return 0; |
| } |
| |
| template<typename KeyType> |
| inline int32_t IntegerKeySort(void* data, void* key, |
| uint32_t num_of_elements, |
| uint32_t size_of_element) { |
| SortKey<KeyType>* ptr_sort_key; |
| if (SetupKeySort<KeyType>(key, ptr_sort_key, num_of_elements) != 0) { |
| return -1; |
| } |
| |
| boost::integer_sort(ptr_sort_key, ptr_sort_key + num_of_elements, |
| KeyRightShift<KeyType>(), KeyLessThan<KeyType>()); |
| |
| if (TeardownKeySort<KeyType>(data, ptr_sort_key, num_of_elements, |
| size_of_element) != 0) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| template<typename KeyType> |
| inline int32_t StdKeySort(void* data, void* key, |
| uint32_t num_of_elements, |
| uint32_t size_of_element) { |
| SortKey<KeyType>* ptr_sort_key; |
| if (SetupKeySort<KeyType>(key, ptr_sort_key, num_of_elements) != 0) { |
| return -1; |
| } |
| |
| std::sort(ptr_sort_key, ptr_sort_key + num_of_elements, |
| KeyLessThan<KeyType>()); |
| |
| if (TeardownKeySort<KeyType>(data, ptr_sort_key, num_of_elements, |
| size_of_element) != 0) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| #endif |
| } |
| |
| int32_t Sort(void* data, uint32_t num_of_elements, Type type) { |
| if (data == NULL) { |
| return -1; |
| } |
| |
| #ifdef NO_STL |
| switch (type) { |
| case TYPE_Word8: |
| qsort(data, num_of_elements, sizeof(int8_t), CompareWord8); |
| break; |
| case TYPE_UWord8: |
| qsort(data, num_of_elements, sizeof(uint8_t), CompareUWord8); |
| break; |
| case TYPE_Word16: |
| qsort(data, num_of_elements, sizeof(int16_t), CompareWord16); |
| break; |
| case TYPE_UWord16: |
| qsort(data, num_of_elements, sizeof(uint16_t), CompareUWord16); |
| break; |
| case TYPE_Word32: |
| qsort(data, num_of_elements, sizeof(int32_t), CompareWord32); |
| break; |
| case TYPE_UWord32: |
| qsort(data, num_of_elements, sizeof(uint32_t), CompareUWord32); |
| break; |
| case TYPE_Word64: |
| qsort(data, num_of_elements, sizeof(int64_t), CompareWord64); |
| break; |
| case TYPE_UWord64: |
| qsort(data, num_of_elements, sizeof(uint64_t), CompareUWord64); |
| break; |
| case TYPE_Float32: |
| qsort(data, num_of_elements, sizeof(float), CompareFloat32); |
| break; |
| case TYPE_Float64: |
| qsort(data, num_of_elements, 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<int8_t>(data, num_of_elements); |
| break; |
| case TYPE_UWord8: |
| IntegerSort<uint8_t>(data, num_of_elements); |
| break; |
| case TYPE_Word16: |
| IntegerSort<int16_t>(data, num_of_elements); |
| break; |
| case TYPE_UWord16: |
| IntegerSort<uint16_t>(data, num_of_elements); |
| break; |
| case TYPE_Word32: |
| IntegerSort<int32_t>(data, num_of_elements); |
| break; |
| case TYPE_UWord32: |
| IntegerSort<uint32_t>(data, num_of_elements); |
| break; |
| case TYPE_Word64: |
| StdSort<int64_t>(data, num_of_elements); |
| break; |
| case TYPE_UWord64: |
| StdSort<uint64_t>(data, num_of_elements); |
| break; |
| case TYPE_Float32: |
| StdSort<float>(data, num_of_elements); |
| break; |
| case TYPE_Float64: |
| StdSort<double>(data, num_of_elements); |
| break; |
| } |
| #endif |
| return 0; |
| } |
| |
| int32_t KeySort(void* data, void* key, uint32_t num_of_elements, |
| uint32_t size_of_element, Type key_type) { |
| if (data == NULL) { |
| return -1; |
| } |
| |
| if (key == NULL) { |
| return -1; |
| } |
| |
| if ((uint64_t)num_of_elements * size_of_element > 0xffffffff) { |
| return -1; |
| } |
| |
| #ifdef NO_STL |
| SortKey* ptr_sort_key = new(std::nothrow) SortKey[num_of_elements]; |
| if (ptr_sort_key == NULL) { |
| return -1; |
| } |
| |
| switch (key_type) { |
| case TYPE_Word8: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, int8_t, |
| CompareKeyWord8); |
| break; |
| case TYPE_UWord8: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, uint8_t, |
| CompareKeyUWord8); |
| break; |
| case TYPE_Word16: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, int16_t, |
| CompareKeyWord16); |
| break; |
| case TYPE_UWord16: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, uint16_t, |
| CompareKeyUWord16); |
| break; |
| case TYPE_Word32: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, int32_t, |
| CompareKeyWord32); |
| break; |
| case TYPE_UWord32: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, uint32_t, |
| CompareKeyUWord32); |
| break; |
| case TYPE_Word64: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, int64_t, |
| CompareKeyWord64); |
| break; |
| case TYPE_UWord64: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, uint64_t, |
| CompareKeyUWord64); |
| break; |
| case TYPE_Float32: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, float, |
| CompareKeyFloat32); |
| break; |
| case TYPE_Float64: |
| KEY_QSORT(ptr_sort_key, key, num_of_elements, double, |
| CompareKeyFloat64); |
| break; |
| default: |
| return -1; |
| } |
| |
| // Shuffle into sorted position based on index map. |
| uint8_t* ptr_data = static_cast<uint8_t*>(data); |
| uint8_t* ptr_data_sorted = |
| new(std::nothrow) uint8_t[num_of_elements * size_of_element]; |
| if (ptr_data_sorted == NULL) { |
| return -1; |
| } |
| |
| for (uint32_t i = 0; i < num_of_elements; i++) { |
| memcpy(ptr_data_sorted + i * size_of_element, ptr_data + |
| ptr_sort_key[i].index_ * size_of_element, size_of_element); |
| } |
| memcpy(ptr_data, ptr_data_sorted, num_of_elements * size_of_element); |
| |
| delete[] ptr_sort_key; |
| delete[] ptr_data_sorted; |
| |
| return 0; |
| #else |
| // Fall back to std::sort for 64-bit types and floats due to compiler |
| // warnings and errors respectively with spreadsort. |
| switch (key_type) { |
| case TYPE_Word8: |
| return IntegerKeySort<int8_t>(data, key, num_of_elements, |
| size_of_element); |
| case TYPE_UWord8: |
| return IntegerKeySort<uint8_t>(data, key, num_of_elements, |
| size_of_element); |
| case TYPE_Word16: |
| return IntegerKeySort<int16_t>(data, key, num_of_elements, |
| size_of_element); |
| case TYPE_UWord16: |
| return IntegerKeySort<uint16_t>(data, key, num_of_elements, |
| size_of_element); |
| case TYPE_Word32: |
| return IntegerKeySort<int32_t>(data, key, num_of_elements, |
| size_of_element); |
| case TYPE_UWord32: |
| return IntegerKeySort<uint32_t>(data, key, num_of_elements, |
| size_of_element); |
| case TYPE_Word64: |
| return StdKeySort<int64_t>(data, key, num_of_elements, |
| size_of_element); |
| case TYPE_UWord64: |
| return StdKeySort<uint64_t>(data, key, num_of_elements, |
| size_of_element); |
| case TYPE_Float32: |
| return StdKeySort<float>(data, key, num_of_elements, size_of_element); |
| case TYPE_Float64: |
| return StdKeySort<double>(data, key, num_of_elements, size_of_element); |
| } |
| assert(false); |
| return -1; |
| #endif |
| } |
| |
| } // namespace webrtc |