/* * 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/interface/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