Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 // When the platform supports STL, the functions are implemented using a
     12 // templated spreadsort algorithm (http://sourceforge.net/projects/spreadsort/),
     13 // part of the Boost C++ library collection. Otherwise, the C standard library's
     14 // qsort() will be used.
     15 
     16 #include "webrtc/system_wrappers/include/sort.h"
     17 
     18 #include <assert.h>
     19 #include <string.h>  // memcpy
     20 
     21 #include <new>      // nothrow new
     22 
     23 #ifdef NO_STL
     24 #include <stdlib.h>      // qsort
     25 #else
     26 #include <algorithm>    // std::sort
     27 #include <vector>
     28 
     29 // TODO(ajm) upgrade to spreadsort v2.
     30 #include "webrtc/system_wrappers/source/spreadsortlib/spreadsort.hpp"
     31 #endif
     32 
     33 #ifdef NO_STL
     34 #define COMPARE_DEREFERENCED(XT, YT)      \
     35   do {                                    \
     36     if ((XT) > (YT)) {                    \
     37       return 1;                           \
     38     }                                     \
     39     else if ((XT) < (YT)) {               \
     40       return -1;                          \
     41     }                                     \
     42     return 0;                             \
     43   } while(0)
     44 
     45 #define COMPARE_FOR_QSORT(X, Y, TYPE)                           \
     46   do {                                                          \
     47     TYPE xT = static_cast<TYPE>(*static_cast<const TYPE*>(X));  \
     48     TYPE yT = static_cast<TYPE>(*static_cast<const TYPE*>(Y));  \
     49     COMPARE_DEREFERENCED(xT, yT);                               \
     50   } while(0)
     51 
     52 #define COMPARE_KEY_FOR_QSORT(SORT_KEY_X, SORT_KEY_Y, TYPE)                   \
     53   do {                                                                        \
     54     TYPE xT = static_cast<TYPE>(                                              \
     55         *static_cast<TYPE*>(static_cast<const SortKey*>(SORT_KEY_X)->key_));  \
     56     TYPE yT = static_cast<TYPE>(                                              \
     57         *static_cast<TYPE*>(static_cast<const SortKey*>(SORT_KEY_Y)->key_));  \
     58     COMPARE_DEREFERENCED(xT, yT);                                             \
     59   } while(0)
     60 
     61 #define KEY_QSORT(SORT_KEY, KEY, NUM_OF_ELEMENTS, KEY_TYPE, COMPARE_FUNC)     \
     62   do {                                                                        \
     63     KEY_TYPE* key_type = (KEY_TYPE*)(key);                                    \
     64     for (uint32_t i = 0; i < (NUM_OF_ELEMENTS); ++i) {                  \
     65       ptr_sort_key[i].key_ = &key_type[i];                                    \
     66       ptr_sort_key[i].index_ = i;                                             \
     67     }                                                                         \
     68     qsort((SORT_KEY), (NUM_OF_ELEMENTS), sizeof(SortKey), (COMPARE_FUNC));    \
     69   } while(0)
     70 #endif
     71 
     72 namespace webrtc {
     73 
     74 #ifdef NO_STL
     75 struct SortKey {
     76   void* key_;
     77   uint32_t index_;
     78 };
     79 #else
     80 template<typename KeyType>
     81 struct SortKey {
     82   KeyType key_;
     83   uint32_t index_;
     84 };
     85 #endif
     86 
     87 namespace {  // Unnamed namespace provides internal linkage.
     88 
     89 #ifdef NO_STL
     90 int CompareWord8(const void* x, const void* y) {
     91   COMPARE_FOR_QSORT(x, y, int8_t);
     92 }
     93 
     94 int CompareUWord8(const void* x, const void* y) {
     95   COMPARE_FOR_QSORT(x, y, uint8_t);
     96 }
     97 
     98 int CompareWord16(const void* x, const void* y) {
     99   COMPARE_FOR_QSORT(x, y, int16_t);
    100 }
    101 
    102 int CompareUWord16(const void* x, const void* y) {
    103   COMPARE_FOR_QSORT(x, y, uint16_t);
    104 }
    105 
    106 int CompareWord32(const void* x, const void* y) {
    107   COMPARE_FOR_QSORT(x, y, int32_t);
    108 }
    109 
    110 int CompareUWord32(const void* x, const void* y) {
    111   COMPARE_FOR_QSORT(x, y, uint32_t);
    112 }
    113 
    114 int CompareWord64(const void* x, const void* y) {
    115   COMPARE_FOR_QSORT(x, y, int64_t);
    116 }
    117 
    118 int CompareUWord64(const void* x, const void* y) {
    119   COMPARE_FOR_QSORT(x, y, uint64_t);
    120 }
    121 
    122 int CompareFloat32(const void* x, const void* y) {
    123   COMPARE_FOR_QSORT(x, y, float);
    124 }
    125 
    126 int CompareFloat64(const void* x, const void* y) {
    127   COMPARE_FOR_QSORT(x, y, double);
    128 }
    129 
    130 int CompareKeyWord8(const void* sort_key_x, const void* sort_key_y) {
    131   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int8_t);
    132 }
    133 
    134 int CompareKeyUWord8(const void* sort_key_x, const void* sort_key_y) {
    135   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint8_t);
    136 }
    137 
    138 int CompareKeyWord16(const void* sort_key_x, const void* sort_key_y) {
    139   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int16_t);
    140 }
    141 
    142 int CompareKeyUWord16(const void* sort_key_x, const void* sort_key_y) {
    143   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint16_t);
    144 }
    145 
    146 int CompareKeyWord32(const void* sort_key_x, const void* sort_key_y) {
    147   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int32_t);
    148 }
    149 
    150 int CompareKeyUWord32(const void* sort_key_x, const void* sort_key_y) {
    151   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint32_t);
    152 }
    153 
    154 int CompareKeyWord64(const void* sort_key_x, const void* sort_key_y) {
    155   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int64_t);
    156 }
    157 
    158 int CompareKeyUWord64(const void* sort_key_x, const void* sort_key_y) {
    159   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint64_t);
    160 }
    161 
    162 int CompareKeyFloat32(const void* sort_key_x, const void* sort_key_y) {
    163   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, float);
    164 }
    165 
    166 int CompareKeyFloat64(const void* sort_key_x, const void* sort_key_y) {
    167   COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, double);
    168 }
    169 #else
    170 template <typename KeyType>
    171 struct KeyLessThan {
    172   bool operator()(const SortKey<KeyType>& sort_key_x,
    173                   const SortKey<KeyType>& sort_key_y) const {
    174     return sort_key_x.key_ < sort_key_y.key_;
    175   }
    176 };
    177 
    178 template <typename KeyType>
    179 struct KeyRightShift {
    180   KeyType operator()(const SortKey<KeyType>& sort_key,
    181                      const unsigned offset) const {
    182     return sort_key.key_ >> offset;
    183   }
    184 };
    185 
    186 template <typename DataType>
    187 inline void IntegerSort(void* data, uint32_t num_of_elements) {
    188   DataType* data_type = static_cast<DataType*>(data);
    189   boost::integer_sort(data_type, data_type + num_of_elements);
    190 }
    191 
    192 template <typename DataType, typename IntegerType>
    193 inline void FloatSort(void* data, uint32_t num_of_elements) {
    194   DataType* data_type = static_cast<DataType*>(data);
    195   IntegerType c_val = 0;
    196   boost::float_sort_cast(data_type, data_type + num_of_elements, c_val);
    197 }
    198 
    199 template <typename DataType>
    200 inline void StdSort(void* data, uint32_t num_of_elements) {
    201   DataType* data_type = static_cast<DataType*>(data);
    202   std::sort(data_type, data_type + num_of_elements);
    203 }
    204 
    205 template<typename KeyType>
    206 inline int32_t SetupKeySort(void* key,
    207                             SortKey<KeyType>*& ptr_sort_key,
    208                             uint32_t num_of_elements) {
    209   ptr_sort_key = new(std::nothrow) SortKey<KeyType>[num_of_elements];
    210   if (ptr_sort_key == NULL) {
    211     return -1;
    212   }
    213 
    214   KeyType* key_type = static_cast<KeyType*>(key);
    215   for (uint32_t i = 0; i < num_of_elements; i++) {
    216     ptr_sort_key[i].key_ = key_type[i];
    217     ptr_sort_key[i].index_ = i;
    218   }
    219 
    220   return 0;
    221 }
    222 
    223 template<typename KeyType>
    224 inline int32_t TeardownKeySort(void* data,
    225                                SortKey<KeyType>* ptr_sort_key,
    226                                uint32_t num_of_elements,
    227                                uint32_t size_of_element) {
    228   uint8_t* ptr_data = static_cast<uint8_t*>(data);
    229   uint8_t* ptr_data_sorted =
    230       new(std::nothrow) uint8_t[num_of_elements * size_of_element];
    231   if (ptr_data_sorted == NULL) {
    232     return -1;
    233   }
    234 
    235   for (uint32_t i = 0; i < num_of_elements; i++) {
    236     memcpy(ptr_data_sorted + i * size_of_element, ptr_data +
    237            ptr_sort_key[i].index_ * size_of_element, size_of_element);
    238   }
    239   memcpy(ptr_data, ptr_data_sorted, num_of_elements * size_of_element);
    240   delete[] ptr_sort_key;
    241   delete[] ptr_data_sorted;
    242   return 0;
    243 }
    244 
    245 template<typename KeyType>
    246 inline int32_t IntegerKeySort(void* data, void* key,
    247                               uint32_t num_of_elements,
    248                               uint32_t size_of_element) {
    249   SortKey<KeyType>* ptr_sort_key;
    250   if (SetupKeySort<KeyType>(key, ptr_sort_key, num_of_elements) != 0) {
    251     return -1;
    252   }
    253 
    254   boost::integer_sort(ptr_sort_key, ptr_sort_key + num_of_elements,
    255                       KeyRightShift<KeyType>(), KeyLessThan<KeyType>());
    256 
    257   if (TeardownKeySort<KeyType>(data, ptr_sort_key, num_of_elements,
    258                                size_of_element) != 0) {
    259     return -1;
    260   }
    261 
    262   return 0;
    263 }
    264 
    265 template<typename KeyType>
    266 inline int32_t StdKeySort(void* data, void* key,
    267                           uint32_t num_of_elements,
    268                           uint32_t size_of_element) {
    269   SortKey<KeyType>* ptr_sort_key;
    270   if (SetupKeySort<KeyType>(key, ptr_sort_key, num_of_elements) != 0) {
    271     return -1;
    272   }
    273 
    274   std::sort(ptr_sort_key, ptr_sort_key + num_of_elements,
    275             KeyLessThan<KeyType>());
    276 
    277   if (TeardownKeySort<KeyType>(data, ptr_sort_key, num_of_elements,
    278                                size_of_element) != 0) {
    279     return -1;
    280   }
    281 
    282   return 0;
    283 }
    284 #endif
    285 }
    286 
    287 int32_t Sort(void* data, uint32_t num_of_elements, Type type) {
    288   if (data == NULL) {
    289     return -1;
    290   }
    291 
    292 #ifdef NO_STL
    293   switch (type) {
    294     case TYPE_Word8:
    295       qsort(data, num_of_elements, sizeof(int8_t), CompareWord8);
    296       break;
    297     case TYPE_UWord8:
    298       qsort(data, num_of_elements, sizeof(uint8_t), CompareUWord8);
    299       break;
    300     case TYPE_Word16:
    301       qsort(data, num_of_elements, sizeof(int16_t), CompareWord16);
    302       break;
    303     case TYPE_UWord16:
    304       qsort(data, num_of_elements, sizeof(uint16_t), CompareUWord16);
    305       break;
    306     case TYPE_Word32:
    307       qsort(data, num_of_elements, sizeof(int32_t), CompareWord32);
    308       break;
    309     case TYPE_UWord32:
    310       qsort(data, num_of_elements, sizeof(uint32_t), CompareUWord32);
    311       break;
    312     case TYPE_Word64:
    313       qsort(data, num_of_elements, sizeof(int64_t), CompareWord64);
    314       break;
    315     case TYPE_UWord64:
    316       qsort(data, num_of_elements, sizeof(uint64_t), CompareUWord64);
    317       break;
    318     case TYPE_Float32:
    319       qsort(data, num_of_elements, sizeof(float), CompareFloat32);
    320       break;
    321     case TYPE_Float64:
    322       qsort(data, num_of_elements, sizeof(double), CompareFloat64);
    323       break;
    324     default:
    325       return -1;
    326   }
    327 #else
    328   // Fall back to std::sort for 64-bit types and floats due to compiler
    329   // warnings and VS 2003 build crashes respectively with spreadsort.
    330   switch (type) {
    331     case TYPE_Word8:
    332       IntegerSort<int8_t>(data, num_of_elements);
    333       break;
    334     case TYPE_UWord8:
    335       IntegerSort<uint8_t>(data, num_of_elements);
    336       break;
    337     case TYPE_Word16:
    338       IntegerSort<int16_t>(data, num_of_elements);
    339       break;
    340     case TYPE_UWord16:
    341       IntegerSort<uint16_t>(data, num_of_elements);
    342       break;
    343     case TYPE_Word32:
    344       IntegerSort<int32_t>(data, num_of_elements);
    345       break;
    346     case TYPE_UWord32:
    347       IntegerSort<uint32_t>(data, num_of_elements);
    348       break;
    349     case TYPE_Word64:
    350       StdSort<int64_t>(data, num_of_elements);
    351       break;
    352     case TYPE_UWord64:
    353       StdSort<uint64_t>(data, num_of_elements);
    354       break;
    355     case TYPE_Float32:
    356       StdSort<float>(data, num_of_elements);
    357       break;
    358     case TYPE_Float64:
    359       StdSort<double>(data, num_of_elements);
    360       break;
    361   }
    362 #endif
    363   return 0;
    364 }
    365 
    366 int32_t KeySort(void* data, void* key, uint32_t num_of_elements,
    367                 uint32_t size_of_element, Type key_type) {
    368   if (data == NULL) {
    369     return -1;
    370   }
    371 
    372   if (key == NULL) {
    373     return -1;
    374   }
    375 
    376   if ((uint64_t)num_of_elements * size_of_element > 0xffffffff) {
    377     return -1;
    378   }
    379 
    380 #ifdef NO_STL
    381   SortKey* ptr_sort_key = new(std::nothrow) SortKey[num_of_elements];
    382   if (ptr_sort_key == NULL) {
    383     return -1;
    384   }
    385 
    386   switch (key_type) {
    387     case TYPE_Word8:
    388       KEY_QSORT(ptr_sort_key, key, num_of_elements, int8_t,
    389                 CompareKeyWord8);
    390       break;
    391     case TYPE_UWord8:
    392       KEY_QSORT(ptr_sort_key, key, num_of_elements, uint8_t,
    393                 CompareKeyUWord8);
    394       break;
    395     case TYPE_Word16:
    396       KEY_QSORT(ptr_sort_key, key, num_of_elements, int16_t,
    397                 CompareKeyWord16);
    398       break;
    399     case TYPE_UWord16:
    400       KEY_QSORT(ptr_sort_key, key, num_of_elements, uint16_t,
    401                 CompareKeyUWord16);
    402       break;
    403     case TYPE_Word32:
    404       KEY_QSORT(ptr_sort_key, key, num_of_elements, int32_t,
    405                 CompareKeyWord32);
    406       break;
    407     case TYPE_UWord32:
    408       KEY_QSORT(ptr_sort_key, key, num_of_elements, uint32_t,
    409                 CompareKeyUWord32);
    410       break;
    411     case TYPE_Word64:
    412       KEY_QSORT(ptr_sort_key, key, num_of_elements, int64_t,
    413                 CompareKeyWord64);
    414       break;
    415     case TYPE_UWord64:
    416       KEY_QSORT(ptr_sort_key, key, num_of_elements, uint64_t,
    417                 CompareKeyUWord64);
    418       break;
    419     case TYPE_Float32:
    420       KEY_QSORT(ptr_sort_key, key, num_of_elements, float,
    421                 CompareKeyFloat32);
    422       break;
    423     case TYPE_Float64:
    424       KEY_QSORT(ptr_sort_key, key, num_of_elements, double,
    425                 CompareKeyFloat64);
    426       break;
    427     default:
    428       return -1;
    429   }
    430 
    431   // Shuffle into sorted position based on index map.
    432   uint8_t* ptr_data = static_cast<uint8_t*>(data);
    433   uint8_t* ptr_data_sorted =
    434       new(std::nothrow) uint8_t[num_of_elements * size_of_element];
    435   if (ptr_data_sorted == NULL) {
    436     return -1;
    437   }
    438 
    439   for (uint32_t i = 0; i < num_of_elements; i++) {
    440     memcpy(ptr_data_sorted + i * size_of_element, ptr_data +
    441            ptr_sort_key[i].index_ * size_of_element, size_of_element);
    442   }
    443   memcpy(ptr_data, ptr_data_sorted, num_of_elements * size_of_element);
    444 
    445   delete[] ptr_sort_key;
    446   delete[] ptr_data_sorted;
    447 
    448   return 0;
    449 #else
    450   // Fall back to std::sort for 64-bit types and floats due to compiler
    451   // warnings and errors respectively with spreadsort.
    452   switch (key_type) {
    453     case TYPE_Word8:
    454       return IntegerKeySort<int8_t>(data, key, num_of_elements,
    455                                     size_of_element);
    456     case TYPE_UWord8:
    457       return IntegerKeySort<uint8_t>(data, key, num_of_elements,
    458                                      size_of_element);
    459     case TYPE_Word16:
    460       return IntegerKeySort<int16_t>(data, key, num_of_elements,
    461                                      size_of_element);
    462     case TYPE_UWord16:
    463       return IntegerKeySort<uint16_t>(data, key, num_of_elements,
    464                                       size_of_element);
    465     case TYPE_Word32:
    466       return IntegerKeySort<int32_t>(data, key, num_of_elements,
    467                                      size_of_element);
    468     case TYPE_UWord32:
    469       return IntegerKeySort<uint32_t>(data, key, num_of_elements,
    470                                       size_of_element);
    471     case TYPE_Word64:
    472       return StdKeySort<int64_t>(data, key, num_of_elements,
    473                                  size_of_element);
    474     case TYPE_UWord64:
    475       return StdKeySort<uint64_t>(data, key, num_of_elements,
    476                                   size_of_element);
    477     case TYPE_Float32:
    478       return StdKeySort<float>(data, key, num_of_elements, size_of_element);
    479     case TYPE_Float64:
    480       return StdKeySort<double>(data, key, num_of_elements, size_of_element);
    481   }
    482   assert(false);
    483   return -1;
    484 #endif
    485 }
    486 
    487 }  // namespace webrtc
    488