SURFEX v8.1
General documentation of Surfex
countingsort.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <limits.h>
4 #include <signal.h>
5 #include "intercept_alloc.h"
6 #include "raise.h"
7 
8 /* ec_countingsort_() : Fortran-callable counting-sort */
9 
10 /*
11  by Sami Saarinen, ECMWF, 01/11/2007 : 1st working version
12 
13  Algorithm derived from C++ implementation in Wikipedia
14  However, the index[]'ed version added by ourselves.
15 */
16 
17 /*
18  Methods:
19 
20  0 : Unsigned 32-bit ints
21  1 : Signed 32-bit ints
22  2 : 64-bit doubles (IEEE) : signbit + 11-bit exp + 52-bits mantissa
23  3 : 32-bit floats (IEEE) : signbit + 8-bit exp + 23-bits mantissa
24  4 : Signed 64-bit ints
25  5 : Unsigned 64-bit ints
26 
27 */
28 
29 #define SORT_UINT 0
30 
31 #define SORT_INT 1
32 
33 #define SORT_R64 2
34 
35 #define SORT_R32 3
36 
37 #define SORT_I64 4
38 
39 #define SORT_U64 5
40 
41 typedef unsigned long long int Uint64;
42 typedef long long int Sint64;
43 typedef unsigned int Uint32;
44 typedef int Sint32;
45 
46 typedef long long int ll_t;
47 typedef unsigned long long int u_ll_t;
48 
49 #define ALLOC(x,size) \
50  { ll_t bytes = (ll_t)sizeof(*x) * (size); \
51  bytes = (bytes < 1) ? 1 : bytes; \
52  x = THEmalloc(bytes); \
53  if (!x) { fprintf(stderr, \
54  "malloc() of %s (%lld bytes) failed in file=%s, line=%d\n", \
55  #x, bytes, __FILE__, __LINE__); RAISE(SIGABRT); } }
56 
57 #define CALLOC(x,size) \
58  { ll_t sz = (ll_t)(size); \
59  sz = (sz < 1) ? 1 : sz; \
60  x = THEcalloc(sz, sizeof(*x)); \
61  if (!x) { ll_t bytes = (ll_t)sizeof(*x) * (sz); \
62  fprintf(stderr, \
63  "calloc() of %s (%lld bytes) failed in file=%s, line=%d\n", \
64  #x, bytes, __FILE__, __LINE__); RAISE(SIGABRT); } }
65 
66 #define FREE(x) if (x) { THEfree(x); x = NULL; }
67 
68 #ifdef DEBUG
69 #define AZZERT(cond) if (cond) ABOR1("Azzertion failed: "#cond)
70 #else
71 #define AZZERT(cond)
72 #endif
73 
74 /* Applicable for 32-bits only */
75 
76 #define SIGNBIT32 0x80000000u
77 #define MASKALL32 0xFFFFFFFFu
78 
79 #define CVMGM32(a,b,c) ( ((c) & SIGNBIT32) ? (a) : (b) )
80 
81 static const int Npasses32 = 2; /* i.e. 2 x 16-bit passes == 32-bits */
82 
83 /* Applicable for 64-bits only */
84 
85 #define SIGNBIT64 0x8000000000000000ull
86 #define MASKALL64 0xFFFFFFFFFFFFFFFFull
87 
88 #define CVMGM64(a,b,c) ( ((c) & SIGNBIT64) ? (a) : (b) )
89 
90 static const int Npasses64 = 4; /* i.e. 4 x 16-bit passes == 64-bits */
91 
92 /* CountingSort */
93 
94 #define MASKALL16 0xFFFF
95 
96 #define NCOUNT (MASKALL16+1)
97 
98 typedef struct {
99  int *sorted;
100  int counts[NCOUNT];
101 } cs_shared_t;
102 
103 #define FOR(i,s,e) for (i = s; i < e; ++i)
104 
105 #define SHIFTMASK(a,shift) ((int)(((a) >> shift) & mask))
106 
107 #define CntSort(T,NB,shift,idummy) \
108 static void \
109 CSortSM##shift##NB(const T A[], const int n, int local_index[], \
110  const T idummy, cs_shared_t *cs, const int irev) \
111 { /* Note: A[] is a contiguous, stride=1, local data -- a shade copy of the original "void *Data"-array */ \
112  const T mask = MASKALL16; \
113  int i, tmp, nr, min = MASKALL16, max = min; \
114  FOR(i,0,n) { \
115  tmp = SHIFTMASK(A[i],shift); if (tmp < min) min = tmp; else if (tmp > max) max = tmp; \
116  } \
117  nr = max - min + 1; \
118  AZZERT(nr <= 0 || nr > NCOUNT); \
119  if (nr > 1) { /* i.e. max > min */ \
120  /* nr == 1 would have meant that all values were equal --> skip */ \
121  int j, icnt; \
122  int *counts = cs->counts; \
123  memset(counts, 0, nr * sizeof(*counts)); \
124  if (irev) { /* Reverse, descending order */ \
125  FOR(i,0,n) { tmp = max - SHIFTMASK(A[i],shift); AZZERT(tmp < 0 || tmp >= NCOUNT); ++counts[ tmp ]; } \
126  } \
127  else { /* Ascending order */ \
128  FOR(i,0,n) { tmp = SHIFTMASK(A[i],shift) - min; AZZERT(tmp < 0 || tmp >= NCOUNT); ++counts[ tmp ]; } \
129  } \
130  /* Cascade counts to get cumulative counts */ \
131  FOR(j,1,nr) counts[j] += counts[j-1]; \
132  { \
133  int *sorted = cs->sorted; \
134  if (!sorted) { ALLOC(sorted, n); cs->sorted = sorted; } \
135  if (irev) { /* Reverse, descending order */ \
136  for (i = n-1; i >= 0; --i) { \
137  j = local_index[i]; \
138  tmp = max - SHIFTMASK(A[j],shift); AZZERT(tmp < 0 || tmp >= NCOUNT); \
139  icnt = --counts[ tmp ]; AZZERT(icnt < 0 || icnt >= n); \
140  sorted[icnt] = j; \
141  } \
142  } \
143  else { /* Ascending order */ \
144  for (i = n-1; i >= 0; --i) { \
145  j = local_index[i]; \
146  tmp = SHIFTMASK(A[j],shift) - min; AZZERT(tmp < 0 || tmp >= NCOUNT); \
147  icnt = --counts[ tmp ]; AZZERT(icnt < 0 || icnt >= n); \
148  sorted[icnt] = j; \
149  } \
150  } \
151  memcpy(local_index, sorted, n * sizeof(int)); \
152  } \
153  } /* if (nr > 1) */ \
154 }
155 
156 #define Helpers(T,NB) \
157 static T * \
158 signmask##NB(const T Data[], int n, int inc, const int *index, int index_adj) \
159 { \
160  T *A = NULL; \
161  int i; \
162  ALLOC(A, n); \
163  if (index && index_adj == 0) { \
164  if (inc == 1) { \
165  FOR(i,0,n) { \
166  int j = index[i]; \
167  T mask = CVMGM##NB(MASKALL##NB, SIGNBIT##NB, Data[j]); \
168  A[i] = Data[j] ^ mask; \
169  } \
170  } else { \
171  FOR(i,0,n) { \
172  int j = index[i]*inc; \
173  T mask = CVMGM##NB(MASKALL##NB, SIGNBIT##NB, Data[j]); \
174  A[i] = Data[j] ^ mask; \
175  } \
176  } \
177  } \
178  else if (index) { \
179  if (inc == 1) { \
180  FOR(i,0,n) { \
181  int j = (index[i] - index_adj); \
182  T mask = CVMGM##NB(MASKALL##NB, SIGNBIT##NB, Data[j]); \
183  A[i] = Data[j] ^ mask; \
184  } \
185  } else { \
186  FOR(i,0,n) { \
187  int j = (index[i] - index_adj)*inc; \
188  T mask = CVMGM##NB(MASKALL##NB, SIGNBIT##NB, Data[j]); \
189  A[i] = Data[j] ^ mask; \
190  } \
191  } \
192  } else { \
193  if (inc == 1) { \
194  FOR(i,0,n) { \
195  T mask = CVMGM##NB(MASKALL##NB, SIGNBIT##NB, Data[i]); \
196  A[i] = Data[i] ^ mask; \
197  } \
198  } else { \
199  FOR(i,0,n) { \
200  int j = i*inc; \
201  T mask = CVMGM##NB(MASKALL##NB, SIGNBIT##NB, Data[j]); \
202  A[i] = Data[j] ^ mask; \
203  } \
204  } \
205  } \
206  return A; \
207 } \
208 static T * \
209 justcopy##NB(const T Data[], int n, int inc, const int *index, int index_adj) \
210 { \
211  T *A = NULL; \
212  int i; \
213  ALLOC(A, n); \
214  if (index && index_adj == 0) { \
215  if (inc == 1) { \
216  FOR(i,0,n) A[i] = Data[index[i]]; \
217  } else { \
218  FOR(i,0,n) A[i] = Data[index[i]*inc]; \
219  } \
220  } \
221  else if (index) { \
222  if (inc == 1) { \
223  FOR(i,0,n) A[i] = Data[(index[i]-index_adj)]; \
224  } else { \
225  FOR(i,0,n) A[i] = Data[(index[i]-index_adj)*inc]; \
226  } \
227  } \
228  else { \
229  if (inc == 1) { \
230  memcpy(A, Data, n * sizeof(T)); \
231  } else { \
232  FOR(i,0,n) A[i] = Data[i*inc]; \
233  } \
234  } \
235  return A; \
236 } \
237 static void \
238 sorted##NB(T Data[], int n, int inc, const int local_index[], T work[]) \
239 { \
240  int i; \
241  if (inc == 1) { \
242  FOR(i,0,n) work[i] = Data[local_index[i]]; \
243  memcpy(Data, work, n * sizeof(T)); \
244  } \
245  else { \
246  FOR(i,0,n) work[i] = Data[local_index[i]*inc]; \
247  FOR(i,0,n) Data[i * inc] = work[i]; \
248  } \
249 }
250 
251 
252 static int *
254 {
255  int *local_index = NULL;
256  int i;
257  ALLOC(local_index, n);
258  FOR(i,0,n) local_index[i] = i;
259  return local_index;
260 }
261 
262 static void
263 Local2GlobalIndex(int n, const int local_index[], int index[], void *work)
264 {
265  int i;
266  int *tmpidx = work;
267  FOR(i,0,n) {
268  int lc = local_index[i];
269  AZZERT(lc < 0 || lc >= n);
270  tmpidx[i] = index[lc];
271  }
272  memcpy(index, tmpidx, n * sizeof(*index));
273 }
274 
275 
276 CntSort(Uint32,32,0,idummy)
277 CntSort(Uint32,32,shift,shift)
278 Helpers(Uint32,32)
279 
280 
281 CntSort(Uint64,64,0,idummy)
282 CntSort(Uint64,64,shift,shift)
283 Helpers(Uint64,64)
284 
285 
286 #define DoSort(T,copyfun,NB) { \
287  int j; \
288  int Npasses = Npasses##NB; \
289  int *local_index = NULL; \
290  T *data = Data; \
291  T *dada = copyfun(&data[addr], n, inc, index, index ? index_adj : 0); \
292  T shift = 0; \
293  cs_shared_t cs; \
294  cs.sorted = NULL; \
295  local_index = CreateIndex(n); \
296  CSortSM0##NB(dada, n, local_index, shift, &cs, irev); \
297  for (j=1; j<Npasses; j++) { \
298  shift += 16; \
299  CSortSMshift##NB(dada, n, local_index, shift, &cs, irev); \
300  } \
301  if (index) { \
302  Local2GlobalIndex(n, local_index, index, dada); \
303  } \
304  else { /* No index[] supplied */ \
305  sorted##NB(&data[addr], n, inc, local_index, dada); \
306  } \
307  FREE(local_index); \
308  FREE(cs.sorted); \
309  FREE(dada); \
310  rc = n; \
311 }
312 
313 void
314 ec_countingsort_(const int *Mode,
315  const int *N,
316  const int *Inc,
317  const int *Start_addr,
318  void *Data,
319  int *index,
320  const int *Nindex,
321  const int *Index_adj,
322  const int *Reverse,
323  int *retc)
324 {
325  int mode = *Mode;
326  int method = mode%10;
327  int n = *N;
328  int rc = n;
329  int inc = *Inc;
330  int addr = (*Start_addr) - 1; /* Fortran to C */
331  int nidx = *Nindex; /* Must be >= n or otherwise the index[] is disregarded */
332  int index_adj = *Index_adj;
333  int irev = *Reverse;
334 
335  if (n <= 0) goto finish;
336 
337  if (nidx < n) index = NULL;
338 
339  switch (method) {
340  case SORT_UINT:
341  DoSort(Uint32,justcopy32,32);
342  break;
343  case SORT_INT:
344  DoSort(Uint32,signmask32,32);
345  break;
346  case SORT_R64:
347  DoSort(Uint64,signmask64,64);
348  break;
349  case SORT_R32:
350  DoSort(Uint32,signmask32,32);
351  break;
352  case SORT_I64:
353  DoSort(Uint64,signmask64,64);
354  break;
355  case SORT_U64:
356  DoSort(Uint64,justcopy64,64);
357  break;
358  default:
359  rc = -1;
360  break;
361  }
362 
363  finish:
364  *retc = rc;
365 }
366 
CntSort(CntSort(Uint32, CntSort(32, CntSort(0, idummy)
Definition: countingsort.c:276
ERROR in method
Definition: ecsort_shared.h:90
static const int Npasses32
Definition: countingsort.c:81
static void Local2GlobalIndex(int n, const int local_index[], int index[], void *work)
Definition: countingsort.c:263
long long int Sint64
Definition: countingsort.c:42
unsigned long long int Uint64
Definition: countingsort.c:41
void ec_countingsort_(const int *Mode, const int *N, const int *Inc, const int *Start_addr, void *Data, int *index, const int *Nindex, const int *Index_adj, const int *Reverse, int *retc)
Definition: countingsort.c:314
integer(kind=kindofint) nidx
int Sint32
Definition: countingsort.c:44
ERROR in n
Definition: ecsort_shared.h:90
unsigned long long int u_ll_t
Definition: countingsort.c:47
unsigned int Uint32
Definition: countingsort.c:43
static int * CreateIndex(int n)
Definition: countingsort.c:253
static const int Npasses64
Definition: countingsort.c:90
ERROR in index
Definition: ecsort_shared.h:90
long long int ll_t
Definition: countingsort.c:46