VTK-m  2.0
KXSort.h
Go to the documentation of this file.
1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 
11 /* The MIT License
12  Copyright (c) 2016 Dinghua Li <voutcn@gmail.com>
13 
14  Permission is hereby granted, free of charge, to any person obtaining
15  a copy of this software and associated documentation files (the
16  "Software"), to deal in the Software without restriction, including
17  without limitation the rights to use, copy, modify, merge, publish,
18  distribute, sublicense, and/or sell copies of the Software, and to
19  permit persons to whom the Software is furnished to do so, subject to
20  the following conditions:
21 
22  The above copyright notice and this permission notice shall be
23  included in all copies or substantial portions of the Software.
24 
25  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  SOFTWARE.
33 */
34 
35 #ifndef KXSORT_H__
36 #define KXSORT_H__
37 
38 #include <algorithm>
39 #include <iterator>
40 
41 namespace kx
42 {
43 
44 static constexpr int kRadixBits = 8;
45 static constexpr size_t kInsertSortThreshold = 64;
46 static constexpr int kRadixMask = (1 << kRadixBits) - 1;
47 static constexpr int kRadixBin = 1 << kRadixBits;
48 
49 //================= HELPING FUNCTIONS ====================
50 
51 template <class T>
52 struct RadixTraitsUnsigned
53 {
54  static constexpr int nBytes = sizeof(T);
55  int kth_byte(const T& x, int k) { return (x >> (kRadixBits * k)) & kRadixMask; }
56  bool compare(const T& x, const T& y) { return x < y; }
57 };
58 
59 template <class T>
60 struct RadixTraitsSigned
61 {
62  static constexpr int nBytes = sizeof(T);
63  static const T kMSB = T(0x80) << ((sizeof(T) - 1) * 8);
64  int kth_byte(const T& x, int k) { return ((x ^ kMSB) >> (kRadixBits * k)) & kRadixMask; }
65  bool compare(const T& x, const T& y) { return x < y; }
66 };
67 
68 template <class RandomIt, class ValueType, class RadixTraits>
69 inline void insert_sort_core_(RandomIt s, RandomIt e, RadixTraits radix_traits)
70 {
71  for (RandomIt i = s + 1; i < e; ++i)
72  {
73  if (radix_traits.compare(*i, *(i - 1)))
74  {
75  RandomIt j;
76  ValueType tmp = *i;
77  *i = *(i - 1);
78  for (j = i - 1; j > s && radix_traits.compare(tmp, *(j - 1)); --j)
79  {
80  *j = *(j - 1);
81  }
82  *j = tmp;
83  }
84  }
85 }
86 
87 template <class RandomIt, class ValueType, class RadixTraits, int kWhichByte>
88 inline void radix_sort_core_(RandomIt s, RandomIt e, RadixTraits radix_traits)
89 {
90  RandomIt last_[kRadixBin + 1];
91  RandomIt* last = last_ + 1;
92  size_t count[kRadixBin] = { 0 };
93 
94  for (RandomIt i = s; i < e; ++i)
95  {
96  ++count[radix_traits.kth_byte(*i, kWhichByte)];
97  }
98 
99  last_[0] = last_[1] = s;
100 
101  for (int i = 1; i < kRadixBin; ++i)
102  {
103  last[i] = last[i - 1] + count[i - 1];
104  }
105 
106  for (int i = 0; i < kRadixBin; ++i)
107  {
108  RandomIt end = last[i - 1] + count[i];
109  if (end == e)
110  {
111  last[i] = e;
112  break;
113  }
114  while (last[i] != end)
115  {
116  ValueType swapper = *last[i];
117  int tag = radix_traits.kth_byte(swapper, kWhichByte);
118  if (tag != i)
119  {
120  do
121  {
122  std::swap(swapper, *last[tag]++);
123  } while ((tag = radix_traits.kth_byte(swapper, kWhichByte)) != i);
124  *last[i] = swapper;
125  }
126  ++last[i];
127  }
128  }
129 
130  if (kWhichByte > 0)
131  {
132  for (int i = 0; i < kRadixBin; ++i)
133  {
134  if (count[i] > kInsertSortThreshold)
135  {
136  radix_sort_core_<RandomIt, ValueType, RadixTraits, (kWhichByte > 0 ? (kWhichByte - 1) : 0)>(
137  last[i - 1], last[i], radix_traits);
138  }
139  else if (count[i] > 1)
140  {
141  insert_sort_core_<RandomIt, ValueType, RadixTraits>(last[i - 1], last[i], radix_traits);
142  }
143  }
144  }
145 }
146 
147 template <class RandomIt, class ValueType, class RadixTraits>
148 inline void radix_sort_entry_(RandomIt s, RandomIt e, ValueType*, RadixTraits radix_traits)
149 {
150  if (e - s <= (int)kInsertSortThreshold)
151  insert_sort_core_<RandomIt, ValueType, RadixTraits>(s, e, radix_traits);
152  else
153  radix_sort_core_<RandomIt, ValueType, RadixTraits, RadixTraits::nBytes - 1>(s, e, radix_traits);
154 }
155 
156 template <class RandomIt, class ValueType>
157 inline void radix_sort_entry_(RandomIt s, RandomIt e, ValueType*)
158 {
159  if (ValueType(-1) > ValueType(0))
160  {
161  radix_sort_entry_(s, e, (ValueType*)(0), RadixTraitsUnsigned<ValueType>());
162  }
163  else
164  {
165  radix_sort_entry_(s, e, (ValueType*)(0), RadixTraitsSigned<ValueType>());
166  }
167 }
168 
169 //================= INTERFACES ====================
170 
171 template <class RandomIt, class RadixTraits>
172 inline void radix_sort(RandomIt s, RandomIt e, RadixTraits radix_traits)
173 {
174  typename std::iterator_traits<RandomIt>::value_type* dummy(0);
175  radix_sort_entry_(s, e, dummy, radix_traits);
176 }
177 
178 template <class RandomIt>
179 inline void radix_sort(RandomIt s, RandomIt e)
180 {
181  typename std::iterator_traits<RandomIt>::value_type* dummy(0);
182  radix_sort_entry_(s, e, dummy);
183 }
184 }
185 
186 #endif