💾 Archived View for gmi.noulin.net › gitRepositories › sort › file › radixsort.h.gmi captured on 2024-07-09 at 02:46:08. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

🚧 View Differences

-=-=-=-=-=-=-

sort

Log

Files

Refs

README

LICENSE

radixsort.h (23557B)

     1 #pragma once
     2 
     3 /**
     4  * type safe radix sort
     5  *
     6  * radix sort sorts keys that are either uint type or string type (char*) keys
     7  * radix sort is faster than qsort from glibc and flashsort and takes less memory
     8  *
     9  * the radixyUintDef, radixyStringDef, radixyUintThreadDef, radixyStringThreadDef define the radix sort functions for arrays with the given element type:
    10  *
    11  * - shellsort##name or shellsortS##name - internal shell sort function
    12  * - radixsort##name or radixsortS##name - function with all the parameters
    13  * - name                                - function only with array and size parameters
    14  * - nameSafe                            - like name and checks if there are empty strings
    15  *
    16  * the *ThreadDef macros defines threaded radix sort functions
    17  *
    18  *
    19  * Example:
    20  *
    21  * // sorting array with string keys
    22  *
    23  * typ struct {char *a; int b;} skElemt;
    24  *
    25  * // define macro or function for access the key given an address to an element in the array
    26  * #define radixsortAt(ptr) (ptr)->a
    27  *
    28  * // define a radixsort function with name 'radiS' and 'radiSSafe' sorting arrays with skElemt element type
    29  * radixyStringDef(,radiS,skElemt,6,4, 40);
    30  * #undef radixsortAt
    31  *
    32  * // the radiSSafe check if there are empty strings (NULL or "") in the keys
    33  * // Empty strings are not allowed.
    34  *
    35  * // declare array
    36  * skElemt radS[200];
    37  *
    38  * // sort the array
    39  * radiS(radS, sz);
    40  *
    41  * // or call safe function:
    42  * if (!radiSSafe(radS, sz)) {
    43  *   logE("Empty strings are not allowed");
    44  * }
    45  *
    46  *
    47  *
    48  * // sorting a u32 array
    49  *
    50  * // define macro or function for access the key given an address to an element in the array
    51  * #define radixsortAt(ptr) *(ptr)
    52  *
    53  * // define a radixsort function with name 'radi' sorting u32 arrays
    54  * radixyUintDef(, radi , u32, 6, 4, 40);
    55  * #undef radixsortAt
    56  *
    57  * // declare array
    58  * u32 urnd[200];
    59  *
    60  * // sort the array
    61  * radi(urnd, 200);
    62  *
    63  *
    64  *
    65  * // sorting an array with struct elements
    66  *
    67  * // declare element type
    68  * typ struct {u64 a; int b;} rdxElemt;
    69  *
    70  * // define macro or function to access the key given an address to an element in the array
    71  * #define radixsortAt(ptr) (ptr)->a
    72  *
    73  * // define a radixsort function with name 'radi64' sorting arrays with elements of type rdxElemt and u64 keys
    74  * radixyUintDef(, radi64 , rdxElemt, 6, 4, 40);
    75  * #undef radixsortAt
    76  *
    77  * // declare array
    78  * rdxElemt radA[200];
    79  *
    80  * // sort the array
    81  * radi64(radA, 200);
    82  *
    83  */
    84 
    85 // define for internal use in radixyUint
    86 #define radixyStop 256
    87 
    88 /**
    89  * radixyUintDef defines functions for sorting arrays of elemType
    90  * the keys have to be unsigned int (any size)
    91  *
    92  * Functions:
    93  * - shellsort##name - internal shell sort function
    94  * - radixsort##name - function with all the parameters
    95  * - name            - function only with array and size parameters
    96  *
    97  * \param
    98  * scope is static, internal or empty
    99  * \param
   100  * name function name for the sort function
   101  * \param
   102  * stackSizeP is the depth of the look-forward stack
   103  * \param
   104  * cutoffP is the digit cutoff for switching to shellsort
   105  * \param
   106  * radixLevel is minimun element count in a bucket for running radix sort, otherwise run shellsort
   107  */
   108 #define radixyUintDef(scope, name, elemType, stackSizeP, cutoffP, radixLevel)\
   109 internal inline void shellsort##name(elemType *arr, size_t size) {\
   110   typeof(radixsortAt(&arr[0])) tmp; /* tmp key */\
   111   typeof(arr[0]) elem; /* tmp record */\
   112   \
   113   {rangeFrom(i, 3, size) {\
   114     tmp  = radixsortAt(&arr[i]);\
   115     elem = arr[i];\
   116     size_t j;\
   117     for(j = i ; j >= 3 && radixsortAt(&arr[j-3]) > tmp; j-=3) {\
   118       arr[j] = arr[j-3];\
   119     }\
   120     arr[j] = elem;\
   121   }}\
   122   \
   123   {rangeFrom(i, 1, size) {\
   124     tmp  = radixsortAt(&arr[i]);\
   125     elem = arr[i];\
   126     size_t j;\
   127     for(j = i ; j >= 1 && radixsortAt(&arr[j-1]) > tmp; j--) {\
   128       arr[j] = arr[j-1];\
   129     }\
   130     arr[j] = elem;\
   131   }}\
   132 }\
   133 \
   134 scope void radixsort##name(elemType *arr, size_t size, size_t digit, size_t stackSize,  size_t cutoff) {\
   135   u8 *a;\
   136   size_t counts[radixyStop];\
   137   size_t offsets[radixyStop];\
   138   size_t starts[radixyStop];\
   139   size_t ends[radixyStop];\
   140   size_t digt = sizeof(radixsortAt(&arr[0])) - digit - 1;\
   141   \
   142   pError0(zeroBuf(counts, sizeof(counts)));\
   143   \
   144   /* compute counts */\
   145   {range(x, size) {\
   146     a = (u8*)&radixsortAt(&arr[x]);\
   147     u8 c = a[digt];\
   148     counts[c]++;\
   149   }}\
   150   \
   151   /* compute offsets */\
   152   offsets[0] = 0;\
   153   starts[0]  = 0;\
   154   {rangeFrom(x, 1, radixyStop) {\
   155     offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1];\
   156   }}\
   157   ends[radixyStop-1] = size;\
   158   \
   159   \
   160   /* loop on digit values */\
   161   {range(x, radixyStop) {\
   162     /* move records according to digit value */\
   163     while(offsets[x] < ends[x]) {\
   164       a         = (u8*)&radixsortAt(&arr[offsets[x]]);\
   165       u8 target = a[digt];\
   166       if (target == x) {\
   167         /* this record already placed in the correct bucket */\
   168         offsets[x]++;\
   169       }\
   170       else {\
   171         size_t stackIdx = 0;\
   172         size_t stack[stackSize];\
   173         stack[stackIdx++] = offsets[x];\
   174         while(target != x && stackIdx < stackSize) {\
   175           stack[stackIdx] = offsets[target]++;\
   176           a               = (u8*)&radixsortAt(&arr[stack[stackIdx]]);\
   177           target          = a[digt];\
   178           stackIdx++;\
   179         }\
   180         if (stackIdx != stackSize) {\
   181           /* found an element to store a offsets[x] */\
   182           offsets[x]++;\
   183         }\
   184         stackIdx--;\
   185         var tmp = arr[stack[stackIdx]];\
   186         while(stackIdx) {\
   187           arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\
   188           stackIdx--;\
   189         }\
   190         arr[stack[0]] = tmp;\
   191       }\
   192     }\
   193   }}\
   194   \
   195   /* cutoff to shellsort */\
   196   if (digit < cutoff) {\
   197     /* loop on digit values to sort the buckets */\
   198     {range(x, radixyStop) {\
   199       if (counts[x] > radixLevel) {\
   200         radixsort##name(&arr[starts[x]], counts[x], digit+1, stackSize, cutoff);\
   201       }\
   202       else {\
   203         if (counts[x] < 2) continue;\
   204         shellsort##name(&arr[starts[x]], counts[x]);\
   205       }\
   206     }}\
   207   }\
   208   else {\
   209     {range(x, radixyStop) {\
   210       if (counts[x] > 1) {\
   211         shellsort##name(&arr[starts[x]], counts[x]);\
   212       }\
   213     }}\
   214   }\
   215 }\
   216 scope void name(elemType *arr, size_t size) {\
   217   radixsort##name(arr, size, 0, stackSizeP, cutoffP);\
   218 }
   219 
   220 
   221 /**
   222  * radixyUintThreadDef (like radixyUintDef) defines functions for sorting arrays of elemType
   223  * the keys have to be unsigned int (any size)
   224  *
   225  * the defined functions by this macro are multithreaded using the threadpool in libsheepy
   226  *
   227  * Functions:
   228  * - shellsort##name - internal shell sort function
   229  * - radixsort##name - function with all the parameters
   230  * - name            - function only with array and size parameters
   231  *
   232  * \param
   233  * scope is static, internal or empty
   234  * \param
   235  * name function name for the sort function
   236  * \param
   237  * stackSizeP is the depth of the look-forward stack
   238  * \param
   239  * cutoffP is the digit cutoff for switching to shellsort
   240  * \param
   241  * radixLevel is minimun element count in a bucket for running radix sort, otherwise run shellsort
   242  */
   243 #define radixyUintThreadDef(scope, name, elemType, stackSizeP, cutoffP, radixLevel)\
   244 internal inline void shellsort##name(elemType *arr, size_t size) {\
   245   typeof(radixsortAt(&arr[0])) tmp; /* tmp key */\
   246   typeof(arr[0]) elem; /* tmp record */\
   247   \
   248   {rangeFrom(i, 3, size) {\
   249     tmp  = radixsortAt(&arr[i]);\
   250     elem = arr[i];\
   251     size_t j;\
   252     for(j = i ; j >= 3 && radixsortAt(&arr[j-3]) > tmp; j-=3) {\
   253       arr[j] = arr[j-3];\
   254     }\
   255     arr[j] = elem;\
   256   }}\
   257   \
   258   {rangeFrom(i, 1, size) {\
   259     tmp  = radixsortAt(&arr[i]);\
   260     elem = arr[i];\
   261     size_t j;\
   262     for(j = i ; j >= 1 && radixsortAt(&arr[j-1]) > tmp; j--) {\
   263       arr[j] = arr[j-1];\
   264     }\
   265     arr[j] = elem;\
   266   }}\
   267 }\
   268 \
   269 scope void radixsort##name(elemType *arr, size_t size, size_t digit, size_t stackSize,  size_t cutoff);\
   270 \
   271 typ struct {elemType *arr; size_t size; size_t digit; size_t stackSize;  size_t cutoff;} radixy##name##Argst;\
   272 \
   273 void radixsort##name##Thread(void *args) {\
   274   cast(radixy##name##Argst*, p, args);\
   275   radixsort##name(p->arr, p->size, p->digit, p->stackSize, p->cutoff);\
   276 }\
   277 \
   278 scope void radixsort##name(elemType *arr, size_t size, size_t digit, size_t stackSize,  size_t cutoff) {\
   279   u8 *a;\
   280   size_t counts[radixyStop];\
   281   size_t offsets[radixyStop];\
   282   size_t starts[radixyStop];\
   283   size_t ends[radixyStop];\
   284   size_t digt = sizeof(radixsortAt(&arr[0])) - digit - 1;\
   285   radixy##name##Argst rdxArgs[radixyStop]; /* arguments for functions in the threadpool */\
   286   size_t rdxArgsIdx = 0;\
   287   \
   288   pError0(zeroBuf(counts, sizeof(counts)));\
   289   \
   290   /* compute counts */\
   291   {range(x, size) {\
   292     a = (u8*)&radixsortAt(&arr[x]);\
   293     u8 c = a[digt];\
   294     counts[c]++;\
   295   }}\
   296   \
   297   /* compute offsets */\
   298   offsets[0] = 0;\
   299   starts[0]  = 0;\
   300   {rangeFrom(x, 1, radixyStop) {\
   301     offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1];\
   302   }}\
   303   ends[radixyStop-1] = size;\
   304   \
   305   \
   306   /* loop on digit values */\
   307   {range(x, radixyStop) {\
   308     /* move records according to digit value */\
   309     while(offsets[x] < ends[x]) {\
   310       a         = (u8*)&radixsortAt(&arr[offsets[x]]);\
   311       u8 target = a[digt];\
   312       if (target == x) {\
   313         /* this record already placed in the correct bucket */\
   314         offsets[x]++;\
   315       }\
   316       else {\
   317         size_t stackIdx = 0;\
   318         size_t stack[stackSize];\
   319         stack[stackIdx++] = offsets[x];\
   320         while(target != x && stackIdx < stackSize) {\
   321           stack[stackIdx] = offsets[target]++;\
   322           a               = (u8*)&radixsortAt(&arr[stack[stackIdx]]);\
   323           target          = a[digt];\
   324           stackIdx++;\
   325         }\
   326         if (stackIdx != stackSize) {\
   327           /* found an element to store a offsets[x] */\
   328           offsets[x]++;\
   329         }\
   330         stackIdx--;\
   331         var tmp = arr[stack[stackIdx]];\
   332         while(stackIdx) {\
   333           arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\
   334           stackIdx--;\
   335         }\
   336         arr[stack[0]] = tmp;\
   337       }\
   338     }\
   339   }}\
   340   \
   341   /* cutoff to shellsort */\
   342   if (digit < cutoff) {\
   343     /* loop on digit values to sort the buckets */\
   344     {range(x, radixyStop) {\
   345       if (counts[x] > radixLevel) {\
   346         if (!digit) {\
   347           rdxArgs[rdxArgsIdx] = (radixy##name##Argst){.arr=&arr[starts[x]], .size=counts[x], .digit=digit+1, .stackSize=stackSize, .cutoff=cutoff};\
   348           tpoolAdd(radixsort##name##Thread, (void*)&rdxArgs[rdxArgsIdx]);\
   349           rdxArgsIdx++;\
   350         }\
   351         else\
   352           radixsort##name(&arr[starts[x]], counts[x], digit+1, stackSize, cutoff);\
   353       }\
   354       else {\
   355         if (counts[x] < 2) continue;\
   356         shellsort##name(&arr[starts[x]], counts[x]);\
   357       }\
   358     }}\
   359   }\
   360   else {\
   361     {range(x, radixyStop) {\
   362       if (counts[x] > 1) {\
   363         shellsort##name(&arr[starts[x]], counts[x]);\
   364       }\
   365     }}\
   366   }\
   367   \
   368   if (!digit) {\
   369     tpoolWait;\
   370   }\
   371 }\
   372 scope void name(elemType *arr, size_t size) {\
   373   radixsort##name(arr, size, 0, stackSizeP, cutoffP);\
   374 }
   375 
   376 
   377 /**
   378  * radixyStringDef defines functions for sorting arrays of elemType
   379  * the keys have to be strings (of type char*) and empty keys (NULL or "") are not allowed (segfaults)
   380  *
   381  * Functions:
   382  * - shellsortS##name - internal shell sort function
   383  * - radixsortS##name - function with all the parameters
   384  * - name             - function only with array and size parameters
   385  * - nameSafe         - like name and checks if there are empty strings
   386  *
   387  * \param
   388  * scope is static, internal or empty
   389  * \param
   390  * name function name for the sort function
   391  * \param
   392  * stackSizeP is the depth of the look-forward stack
   393  * \param
   394  * cutoffP is the digit cutoff for switching to shellsort
   395  * \param
   396  * radixLevel is minimun element count in a bucket for running radix sort, otherwise run shellsort
   397  */
   398 #define radixyStringDef(scope, name, elemType, stackSizeP, cutoffP, radixLevel)\
   399 internal inline void shellsortS##name(elemType *arr, size_t size) {\
   400   char *tmp; /* tmp key */\
   401   typeof(arr[0]) elem; /* tmp record */\
   402   \
   403   {rangeFrom(i, 3, size) {\
   404     tmp  = radixsortAt(&arr[i]);\
   405     elem = arr[i];\
   406     size_t j;\
   407     for(j = i ; j >= 3 && strcmp(radixsortAt(&arr[j-3]),tmp) > 0; j-=3) {\
   408       arr[j] = arr[j-3];\
   409     }\
   410     arr[j] = elem;\
   411   }}\
   412   \
   413   {rangeFrom(i, 1, size) {\
   414     tmp  = radixsortAt(&arr[i]);\
   415     elem = arr[i];\
   416     size_t j;\
   417     for(j = i ; j >= 1 && strcmp(radixsortAt(&arr[j-1]),tmp) > 0; j--) {\
   418       arr[j] = arr[j-1];\
   419     }\
   420     arr[j] = elem;\
   421   }}\
   422 }\
   423 \
   424 /**
   425  * radixyS doesn't accept empty strings
   426  * it segfaults when there is an empty string in the array
   427  */\
   428 void radixsortS##name(elemType *arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize,  size_t cutoff) {\
   429   size_t counts[charStop+1];\
   430   size_t offsets[charStop+1];\
   431   size_t starts[charStop+1];\
   432   size_t ends[charStop+1];\
   433   size_t digt       = digit;\
   434   \
   435   pError0(zeroBuf(counts, sizeof(counts)));\
   436   \
   437   /* compute counts */\
   438   {range(x, size) {\
   439     u8 c = *(radixsortAt(&arr[x])+digt);\
   440     counts[c]++;\
   441   }}\
   442   \
   443   /* compute offsets */\
   444   offsets[0] = 0;\
   445   starts[0]  = 0;\
   446   offsets[charStart] = starts[charStart] = ends[0] = offsets[0] + counts[0];\
   447   rangeFrom(x, charStart+1, charStop+1) {\
   448     offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1];\
   449   }\
   450   ends[charStop] = size;\
   451   \
   452   /* sort 0 end of string */\
   453   /* move records according to digit value */\
   454   while(offsets[0] < ends[0]) {\
   455     u8 target = *(radixsortAt(&arr[offsets[0]]) + digt);\
   456     if (target == 0) {\
   457       /* this record already placed in the correct bucket */\
   458       offsets[0]++;\
   459     }\
   460     else {\
   461       size_t stackIdx = 0;\
   462       size_t stack[stackSize];\
   463       stack[stackIdx++] = offsets[0];\
   464       while(target != 0 && stackIdx < stackSize) {\
   465         stack[stackIdx] = offsets[target]++;\
   466         target          = *(radixsortAt(&arr[stack[stackIdx]]) + digt);\
   467         stackIdx++;\
   468       }\
   469       if (stackIdx != stackSize) {\
   470         /* found an element to store a offsets[0] */\
   471         offsets[0]++;\
   472       }\
   473       stackIdx--;\
   474       var tmp = arr[stack[stackIdx]];\
   475       while(stackIdx) {\
   476         arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\
   477         stackIdx--;\
   478       }\
   479       arr[stack[0]] = tmp;\
   480     }\
   481   }\
   482   /* loop on digit values */\
   483   {rangeFrom(x, charStart, charStop+1) {\
   484     /* move records according to digit value */\
   485     while(offsets[x] < ends[x]) {\
   486       u8 target = *(radixsortAt(&arr[offsets[x]]) + digt);\
   487       if (target == x) {\
   488         /* this record already placed in the correct bucket */\
   489         offsets[x]++;\
   490       }\
   491       else {\
   492         size_t stackIdx = 0;\
   493         size_t stack[stackSize];\
   494         stack[stackIdx++] = offsets[x];\
   495         while(target != x && stackIdx < stackSize) {\
   496           stack[stackIdx] = offsets[target]++;\
   497           target          = *(radixsortAt(&arr[stack[stackIdx]]) + digt);\
   498           stackIdx++;\
   499         }\
   500         if (stackIdx != stackSize) {\
   501           /* found an element to store a offsets[x] */\
   502           offsets[x]++;\
   503         }\
   504         stackIdx--;\
   505         var tmp = arr[stack[stackIdx]];\
   506         while(stackIdx) {\
   507           arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\
   508           stackIdx--;\
   509         }\
   510         arr[stack[0]] = tmp;\
   511       }\
   512     }\
   513   }}\
   514   \
   515   /* cutoff to shellsort */\
   516   if (digit < cutoff) {\
   517     /* sort 0 end of string */\
   518     if (counts[0] > radixLevel) {\
   519       radixsortS##name(&arr[starts[0]], counts[0], digit+1, charStart, charStop, stackSize, cutoff);\
   520     }\
   521     else {\
   522       if (counts[0] > 1) shellsortS##name(&arr[starts[0]], counts[0]);\
   523     }\
   524     /* loop on digit values to sort the buckets */\
   525     {rangeFrom(x, charStart, charStop+1) {\
   526       if (counts[x] > radixLevel) {\
   527         radixsortS##name(&arr[starts[x]], counts[x], digit+1, charStart, charStop, stackSize, cutoff);\
   528       }\
   529       else {\
   530         if (counts[x] < 2) continue;\
   531         shellsortS##name(&arr[starts[x]], counts[x]);\
   532       }\
   533     }}\
   534   }\
   535   else {\
   536     if (counts[0] > 1) {\
   537       shellsortS##name(&arr[starts[0]], counts[0]);\
   538     }\
   539     rangeFrom(x, charStart, charStop+1) {\
   540       if (counts[x] > 1) {\
   541         shellsortS##name(&arr[starts[x]], counts[x]);\
   542       }\
   543     }\
   544   }\
   545 }\
   546 scope void name(elemType *arr, size_t size) {\
   547   radixsortS##name(arr, size, 0, 32, 255, stackSizeP, cutoffP);\
   548 }\
   549 scope bool name##Safe(elemType *arr, size_t size) {\
   550   {range(i, size) {\
   551     if (isEmptyS(radixsortAt(&arr[i]))) ret false;\
   552   }}\
   553   radixsortS##name(arr, size, 0, 32, 255, stackSizeP, cutoffP);\
   554   ret true;\
   555 }
   556 
   557 
   558 
   559 /**
   560  * radixyStringThreadDef (like radixyStringDef) defines functions for sorting arrays of elemType
   561  * the keys have to be strings (of type char*) and empty keys (NULL or "") are not allowed (segfaults)
   562  *
   563  * the defined functions by this macro are multithreaded using the threadpool in libsheepy
   564  *
   565  * Functions:
   566  * - shellsortS##name - internal shell sort function
   567  * - radixsortS##name - function with all the parameters
   568  * - name             - function only with array and size parameters
   569  * - nameSafe         - like name and checks if there are empty strings
   570  *
   571  * \param
   572  * scope is static, internal or empty
   573  * \param
   574  * name function name for the sort function
   575  * \param
   576  * stackSizeP is the depth of the look-forward stack
   577  * \param
   578  * cutoffP is the digit cutoff for switching to shellsort
   579  * \param
   580  * radixLevel is minimun element count in a bucket for running radix sort, otherwise run shellsort
   581  */
   582 #define radixyStringThreadDef(scope, name, elemType, stackSizeP, cutoffP, radixLevel)\
   583 internal inline void shellsortS##name(elemType *arr, size_t size) {\
   584   char *tmp; /* tmp key */\
   585   typeof(arr[0]) elem; /* tmp record */\
   586   \
   587   {rangeFrom(i, 3, size) {\
   588     tmp  = radixsortAt(&arr[i]);\
   589     elem = arr[i];\
   590     size_t j;\
   591     for(j = i ; j >= 3 && strcmp(radixsortAt(&arr[j-3]),tmp) > 0; j-=3) {\
   592       arr[j] = arr[j-3];\
   593     }\
   594     arr[j] = elem;\
   595   }}\
   596   \
   597   {rangeFrom(i, 1, size) {\
   598     tmp  = radixsortAt(&arr[i]);\
   599     elem = arr[i];\
   600     size_t j;\
   601     for(j = i ; j >= 1 && strcmp(radixsortAt(&arr[j-1]),tmp) > 0; j--) {\
   602       arr[j] = arr[j-1];\
   603     }\
   604     arr[j] = elem;\
   605   }}\
   606 }\
   607 \
   608 void radixsortS##name(elemType *arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize,  size_t cutoff);\
   609 \
   610 typ struct {elemType *arr; size_t size; size_t digit; u8 charStart; u16 charStop; size_t stackSize;  size_t cutoff;} radixyS##name##Argst;\
   611 \
   612 void radixsortS##name##Thread(void *args) {\
   613   cast(radixyS##name##Argst*, p, args);\
   614   radixsortS##name(p->arr, p->size, p->digit, p->charStart, p->charStop, p->stackSize, p->cutoff);\
   615 }\
   616 \
   617 /**
   618  * radixyS doesn't accept empty strings
   619  * it segfaults when there is an empty string in the array
   620  */\
   621 void radixsortS##name(elemType *arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize,  size_t cutoff) {\
   622   size_t counts[charStop+1];\
   623   size_t offsets[charStop+1];\
   624   size_t starts[charStop+1];\
   625   size_t ends[charStop+1];\
   626   size_t digt       = digit;\
   627   radixyS##name##Argst rdxArgs[charStop+1]; /* arguments for functions in the threadpool */\
   628   size_t rdxArgsIdx = 0;\
   629   \
   630   pError0(zeroBuf(counts, sizeof(counts)));\
   631   \
   632   /* compute counts */\
   633   {range(x, size) {\
   634     u8 c = *(radixsortAt(&arr[x])+digt);\
   635     counts[c]++;\
   636   }}\
   637   \
   638   /* compute offsets */\
   639   offsets[0] = 0;\
   640   starts[0]  = 0;\
   641   offsets[charStart] = starts[charStart] = ends[0] = offsets[0] + counts[0];\
   642   rangeFrom(x, charStart+1, charStop+1) {\
   643     offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1];\
   644   }\
   645   ends[charStop] = size;\
   646   \
   647   /* sort 0 end of string */\
   648   /* move records according to digit value */\
   649   while(offsets[0] < ends[0]) {\
   650     u8 target = *(radixsortAt(&arr[offsets[0]]) + digt);\
   651     if (target == 0) {\
   652       /* this record already placed in the correct bucket */\
   653       offsets[0]++;\
   654     }\
   655     else {\
   656       size_t stackIdx = 0;\
   657       size_t stack[stackSize];\
   658       stack[stackIdx++] = offsets[0];\
   659       while(target != 0 && stackIdx < stackSize) {\
   660         stack[stackIdx] = offsets[target]++;\
   661         target          = *(radixsortAt(&arr[stack[stackIdx]]) + digt);\
   662         stackIdx++;\
   663       }\
   664       if (stackIdx != stackSize) {\
   665         /* found an element to store a offsets[0] */\
   666         offsets[0]++;\
   667       }\
   668       stackIdx--;\
   669       var tmp = arr[stack[stackIdx]];\
   670       while(stackIdx) {\
   671         arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\
   672         stackIdx--;\
   673       }\
   674       arr[stack[0]] = tmp;\
   675     }\
   676   }\
   677   /* loop on digit values */\
   678   {rangeFrom(x, charStart, charStop+1) {\
   679     /* move records according to digit value */\
   680     while(offsets[x] < ends[x]) {\
   681       u8 target = *(radixsortAt(&arr[offsets[x]]) + digt);\
   682       if (target == x) {\
   683         /* this record already placed in the correct bucket */\
   684         offsets[x]++;\
   685       }\
   686       else {\
   687         size_t stackIdx = 0;\
   688         size_t stack[stackSize];\
   689         stack[stackIdx++] = offsets[x];\
   690         while(target != x && stackIdx < stackSize) {\
   691           stack[stackIdx] = offsets[target]++;\
   692           target          = *(radixsortAt(&arr[stack[stackIdx]]) + digt);\
   693           stackIdx++;\
   694         }\
   695         if (stackIdx != stackSize) {\
   696           /* found an element to store a offsets[x] */\
   697           offsets[x]++;\
   698         }\
   699         stackIdx--;\
   700         var tmp = arr[stack[stackIdx]];\
   701         while(stackIdx) {\
   702           arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\
   703           stackIdx--;\
   704         }\
   705         arr[stack[0]] = tmp;\
   706       }\
   707     }\
   708   }}\
   709   \
   710   /* cutoff to shellsort */\
   711   if (digit < cutoff) {\
   712     /* sort 0 end of string */\
   713     if (counts[0] > radixLevel) {\
   714       if (!digit) {\
   715         rdxArgs[rdxArgsIdx] = (radixyS##name##Argst){.arr=&arr[starts[0]], .size=counts[0], .digit=digit+1, .charStart=charStart, .charStop=charStop, .stackSize=stackSize, .cutoff=cutoff};\
   716         tpoolAdd(radixsortS##name##Thread, (void*)&rdxArgs[rdxArgsIdx]);\
   717         rdxArgsIdx++;\
   718       }\
   719       else\
   720         radixsortS##name(&arr[starts[0]], counts[0], digit+1, charStart, charStop, stackSize, cutoff);\
   721     }\
   722     else {\
   723       if (counts[0] > 1) shellsortS##name(&arr[starts[0]], counts[0]);\
   724     }\
   725     /* loop on digit values to sort the buckets */\
   726     {rangeFrom(x, charStart, charStop+1) {\
   727       if (counts[x] > radixLevel) {\
   728         if (!digit) {\
   729           rdxArgs[rdxArgsIdx] = (radixyS##name##Argst){.arr=&arr[starts[x]], .size=counts[x], .digit=digit+1, .charStart=charStart, .charStop=charStop, .stackSize=stackSize, .cutoff=cutoff};\
   730           tpoolAdd(radixsortS##name##Thread, (void*)&rdxArgs[rdxArgsIdx]);\
   731           rdxArgsIdx++;\
   732         }\
   733         else\
   734           radixsortS##name(&arr[starts[x]], counts[x], digit+1, charStart, charStop, stackSize, cutoff);\
   735       }\
   736       else {\
   737         if (counts[x] < 2) continue;\
   738         shellsortS##name(&arr[starts[x]], counts[x]);\
   739       }\
   740     }}\
   741   }\
   742   else {\
   743     if (counts[0] > 1) {\
   744       shellsortS##name(&arr[starts[0]], counts[0]);\
   745     }\
   746     rangeFrom(x, charStart, charStop+1) {\
   747       if (counts[x] > 1) {\
   748         shellsortS##name(&arr[starts[x]], counts[x]);\
   749       }\
   750     }\
   751   }\
   752   \
   753   if (!digit) {\
   754     tpoolWait;\
   755   }\
   756 }\
   757 scope void name(elemType *arr, size_t size) {\
   758   radixsortS##name(arr, size, 0, 32, 255, stackSizeP, cutoffP);\
   759 }\
   760 scope bool name##Safe(elemType *arr, size_t size) {\
   761   {range(i, size) {\
   762     if (isEmptyS(radixsortAt(&arr[i]))) ret false;\
   763   }}\
   764   radixsortS##name(arr, size, 0, 32, 255, stackSizeP, cutoffP);\
   765   ret true;\
   766 }
   767 
   768 // vim: set expandtab ts=2 sw=2: