mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-22 16:07:30 +00:00
488 lines
15 KiB
C++
488 lines
15 KiB
C++
|
/*
|
||
|
* 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
|