Newton Dynamics  4.00
dSort.h
1 /* Copyright (c) <2003-2019> <Julio Jerez, Newton Game Dynamics>
2 *
3 * This software is provided 'as-is', without any express or implied
4 * warranty. In no event will the authors be held liable for any damages
5 * arising from the use of this software.
6 *
7 * Permission is granted to anyone to use this software for any purpose,
8 * including commercial applications, and to alter it and redistribute it
9 * freely, subject to the following restrictions:
10 *
11 * 1. The origin of this software must not be misrepresented; you must not
12 * claim that you wrote the original software. If you use this software
13 * in a product, an acknowledgment in the product documentation would be
14 * appreciated but is not required.
15 *
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 *
19 * 3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #ifndef __D_SORT_H__
23 #define __D_SORT_H__
24 
25 #include "dCoreStdafx.h"
26 #include "dHeap.h"
27 #include "dProfiler.h"
28 #include "dThreadPool.h"
29 
30 #define D_PARALLET_SORT_BATCH_SIZE 1024
31 
32 template <class T>
33 dInt32 dgBinarySearch(T const* array, dInt32 elements, const T& entry, dInt32(*compare) (const T* const A, const T* const B, void* const context), void* const context = nullptr)
34 {
35  dInt32 index0 = 0;
36  dInt32 index2 = elements - 1;
37 
38  while ((index2 - index0) > 4)
39  {
40  dInt32 index1 = (index0 + index2) >> 1;
41  dInt32 test = compare(&array[index1], &entry, context);
42  if (test < 0)
43  {
44  index0 = index1;
45  }
46  else
47  {
48  index2 = index1;
49  }
50  }
51 
52  index0 = (index0 > 0) ? index0 - 1 : 0;
53  index2 = ((index2 + 1) < elements) ? index2 + 1 : elements;
54  dInt32 index = index0 - 1;
55  for (dInt32 i = index0; i < index2; i++)
56  {
57  dInt32 test = compare(&array[i], &entry, context);
58  if (!test)
59  {
60  return i;
61  }
62  else if (test > 0)
63  {
64  break;
65  }
66  index = i;
67  }
68  return index;
69 }
70 
71 template <class T>
72 dInt32 dgBinarySearchIndirect(T** const array, dInt32 elements, const T& entry, dInt32(*compare) (const T* const A, const T* const B, void* const context), void* const context = nullptr)
73 {
74  dInt32 index0 = 0;
75  dInt32 index2 = elements - 1;
76 
77  while ((index2 - index0) > 4)
78  {
79  dInt32 index1 = (index0 + index2) >> 1;
80  dInt32 test = compare(array[index1], &entry, context);
81  if (test < 0)
82  {
83  index0 = index1;
84  }
85  else
86  {
87  index2 = index1;
88  }
89  }
90 
91  index0 = (index0 > 0) ? index0 - 1 : 0;
92  index2 = ((index2 + 1) < elements) ? index2 + 1 : elements;
93  dInt32 index = index0 - 1;
94  for (dInt32 i = index0; i < index2; i++)
95  {
96  dInt32 test = compare(array[i], &entry, context);
97  if (!test)
98  {
99  return i;
100  }
101  else if (test > 0)
102  {
103  break;
104  }
105  index = i;
106  }
107  return index;
108 }
109 
110 template <class T>
111 void dgRadixSort(T* const array, T* const tmpArray, dInt32 elements, dInt32 radixPass, dInt32(*getRadixKey) (const T* const A, void* const context), void* const context = nullptr)
112 {
113  dInt32 scanCount[256];
114  dInt32 histogram[256][4];
115 
116  dAssert(radixPass >= 1);
117  dAssert(radixPass <= 4);
118 
119  memset(histogram, 0, sizeof(histogram));
120  for (dInt32 i = 0; i < elements; i++)
121  {
122  dInt32 key = getRadixKey(&array[i], context);
123  for (dInt32 j = 0; j < radixPass; j++)
124  {
125  dInt32 radix = (key >> (j << 3)) & 0xff;
126  histogram[radix][j] = histogram[radix][j] + 1;
127  }
128  }
129 
130  for (dInt32 radix = 0; radix < radixPass; radix += 2)
131  {
132  scanCount[0] = 0;
133  for (dInt32 i = 1; i < 256; i++)
134  {
135  scanCount[i] = scanCount[i - 1] + histogram[i - 1][radix];
136  }
137  dInt32 radixShift = radix << 3;
138  for (dInt32 i = 0; i < elements; i++)
139  {
140  dInt32 key = (getRadixKey(&array[i], context) >> radixShift) & 0xff;
141  dInt32 index = scanCount[key];
142  tmpArray[index] = array[i];
143  scanCount[key] = index + 1;
144  }
145 
146  if ((radix + 1) < radixPass)
147  {
148  scanCount[0] = 0;
149  for (dInt32 i = 1; i < 256; i++) {
150  scanCount[i] = scanCount[i - 1] + histogram[i - 1][radix + 1];
151  }
152 
153  dInt32 radixShift = (radix + 1) << 3;
154  for (dInt32 i = 0; i < elements; i++)
155  {
156  dInt32 key = (getRadixKey(&array[i], context) >> radixShift) & 0xff;
157  dInt32 index = scanCount[key];
158  array[index] = tmpArray[i];
159  scanCount[key] = index + 1;
160  }
161  }
162  else
163  {
164  memcpy(array, tmpArray, elements * sizeof(T));
165  }
166  }
167 
168  #ifdef _DEBUG
169  for (dInt32 i = 0; i < (elements - 1); i++)
170  {
171  dAssert(getRadixKey(&array[i], context) <= getRadixKey(&array[i + 1], context));
172  }
173  #endif
174 }
175 
176 template <class T>
177 void dSort(T* const array, dInt32 elements, dInt32(*compare) (const T* const A, const T* const B, void* const context), void* const context = nullptr)
178 {
179  const dInt32 batchSize = 8;
180  dInt32 stack[1024][2];
181 
182  stack[0][0] = 0;
183  stack[0][1] = elements - 1;
184  dInt32 stackIndex = 1;
185  while (stackIndex)
186  {
187  stackIndex--;
188  dInt32 lo = stack[stackIndex][0];
189  dInt32 hi = stack[stackIndex][1];
190  if ((hi - lo) > batchSize)
191  {
192  dInt32 mid = (lo + hi) >> 1;
193  if (compare(&array[lo], &array[mid], context) > 0)
194  {
195  dSwap(array[lo], array[mid]);
196  }
197  if (compare(&array[mid], &array[hi], context) > 0)
198  {
199  dSwap(array[mid], array[hi]);
200  }
201  if (compare(&array[lo], &array[mid], context) > 0)
202  {
203  dSwap(array[lo], array[mid]);
204  }
205  dInt32 i = lo + 1;
206  dInt32 j = hi - 1;
207  T pivot(array[mid]);
208  do
209  {
210  while (compare(&array[i], &pivot, context) < 0) i++;
211  while (compare(&array[j], &pivot, context) > 0) j--;
212 
213  if (i <= j)
214  {
215  dSwap(array[i], array[j]);
216  i++;
217  j--;
218  }
219  } while (i <= j);
220 
221  if (i < hi)
222  {
223  stack[stackIndex][0] = i;
224  stack[stackIndex][1] = hi;
225  stackIndex++;
226  }
227  if (lo < j)
228  {
229  stack[stackIndex][0] = lo;
230  stack[stackIndex][1] = j;
231  stackIndex++;
232  }
233  dAssert(stackIndex < dInt32(sizeof(stack) / (2 * sizeof(stack[0][0]))));
234  }
235  }
236 
237  dInt32 stride = batchSize + 1;
238  if (elements < stride)
239  {
240  stride = elements;
241  }
242  for (dInt32 i = 1; i < stride; i++)
243  {
244  if (compare(&array[0], &array[i], context) > 0)
245  {
246  dSwap(array[0], array[i]);
247  }
248  }
249 
250  for (dInt32 i = 1; i < elements; i++)
251  {
252  dInt32 j = i;
253  T tmp(array[i]);
254  for (; compare(&array[j - 1], &tmp, context) > 0; j--)
255  {
256  dAssert(j > 0);
257  array[j] = array[j - 1];
258  }
259  array[j] = tmp;
260  }
261 
262  #ifdef _DEBUG
263  for (dInt32 i = 0; i < (elements - 1); i++)
264  {
265  dAssert(compare(&array[i], &array[i + 1], context) <= 0);
266  }
267  #endif
268 }
269 
270 template <class T>
271 void dSortIndirect(T** const array, dInt32 elements, dInt32(*compare) (const T* const A, const T* const B, void* const context), void* const context = nullptr)
272 {
273  D_TRACKTIME();
274  const dInt32 batchSize = 8;
275  dInt32 stack[1024][2];
276 
277  stack[0][0] = 0;
278  stack[0][1] = elements - 1;
279  dInt32 stackIndex = 1;
280  while (stackIndex)
281  {
282  stackIndex--;
283  dInt32 lo = stack[stackIndex][0];
284  dInt32 hi = stack[stackIndex][1];
285  if ((hi - lo) > batchSize)
286  {
287  dInt32 mid = (lo + hi) >> 1;
288  if (compare(array[lo], array[mid], context) > 0)
289  {
290  dSwap(array[lo], array[mid]);
291  }
292  if (compare(array[mid], array[hi], context) > 0)
293  {
294  dSwap(array[mid], array[hi]);
295  }
296  if (compare(array[lo], array[mid], context) > 0)
297  {
298  dSwap(array[lo], array[mid]);
299  }
300  dInt32 i = lo + 1;
301  dInt32 j = hi - 1;
302  T* val(array[mid]);
303  do
304  {
305  while (compare(array[i], val, context) < 0) i++;
306  while (compare(array[j], val, context) > 0) j--;
307 
308  if (i <= j)
309  {
310  dSwap(array[i], array[j]);
311  i++;
312  j--;
313  }
314  } while (i <= j);
315 
316  if (i < hi)
317  {
318  stack[stackIndex][0] = i;
319  stack[stackIndex][1] = hi;
320  stackIndex++;
321  }
322  if (lo < j)
323  {
324  stack[stackIndex][0] = lo;
325  stack[stackIndex][1] = j;
326  stackIndex++;
327  }
328  dAssert(stackIndex < dInt32(sizeof(stack) / (2 * sizeof(stack[0][0]))));
329  }
330  }
331 
332  dInt32 stride = batchSize + 1;
333  if (elements < stride)
334  {
335  stride = elements;
336  }
337  for (dInt32 i = 1; i < stride; i++)
338  {
339  if (compare(array[0], array[i], context) > 0)
340  {
341  dSwap(array[0], array[i]);
342  }
343  }
344 
345  for (dInt32 i = 1; i < elements; i++)
346  {
347  dInt32 j = i;
348  T* tmp(array[i]);
349  for (; compare(array[j - 1], tmp, context) > 0; j--)
350  {
351  dAssert(j > 0);
352  array[j] = array[j - 1];
353  }
354  array[j] = tmp;
355  }
356 
357  #ifdef _DEBUG
358  for (dInt32 i = 0; i < (elements - 1); i++)
359  {
360  dAssert(compare(array[i], array[i + 1], context) <= 0);
361  }
362  #endif
363 }
364 
365 #endif