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