sort

sort algorithms for any type of array
git clone https://noulin.net/git/sort.git
Log | Files | Refs | README | LICENSE

commit d4753e52dc50a892c6bcc1bf30e47d504e1f3166
parent da2c7d659930bdd5972109eec9d9d307876a3992
Author: Remy Noulin <loader2x@gmail.com>
Date:   Sat, 19 Jan 2019 21:40:44 +0100

add radix sort

main.c      | 714 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
package.yml |   6 +-
radixsort.h | 768 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sort.h      |   1 +
4 files changed, 1482 insertions(+), 7 deletions(-)

Diffstat:
Mmain.c | 714++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mpackage.yml | 6++++--
Aradixsort.h | 768+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msort.h | 1+
4 files changed, 1482 insertions(+), 7 deletions(-)

diff --git a/main.c b/main.c @@ -231,17 +231,677 @@ void flashSort_i32A(void *arr, size_t size, size_t elemSize, flashSortGetFt flas +//radix bsort +//#define RADIX_LEVEL 3 +#define RADIX_LEVEL 40 +internal inline void shellsort(u32 *arr, size_t size) { + u32 tmp; // tmp record + + rangeFrom(i, 3, size) { + tmp = arr[i]; + size_t j; + for(j = i ; j >= 3 && arr[j-3] > tmp; j-=3) { + arr[j] = arr[j-3]; + } + arr[j] = tmp; + } + + rangeFrom(i, 1, size) { + tmp = arr[i]; + size_t j; + for(j = i ; j >= 1 && arr[j-1] > tmp; j--) { + arr[j] = arr[j-1]; + } + arr[j] = tmp; + } +} + +void radixyOrig(u32 *arr, size_t size, size_t digit, size_t stackSize, size_t cutoff) { + #define stop 256 + u8 *a = (u8*) arr; + size_t counts[stop]; + size_t offsets[stop]; + size_t starts[stop]; + size_t ends[stop]; + size_t digt = sizeof(u32) - digit - 1; + + zeroBuf(counts, sizeof(counts)); + + // compute counts + range(x, size) { + u8 c = a[x * sizeof(u32) + digt]; + counts[c]++; + } + + // compute offsets + offsets[0] = 0; + starts[0] = 0; + rangeFrom(x, 1, stop) { + offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1]; + } + ends[stop-1] = size; + + + // loop on digit values + range(x, stop) { + // move records according to digit value + while(offsets[x] < ends[x]) { + u8 target = a[offsets[x] * sizeof(u32) + digt]; + if (target == x) { + // this record already placed in the correct bucket + offsets[x]++; + } + else { + size_t stackIdx = 0; + size_t stack[stackSize]; + stack[stackIdx++] = offsets[x]; + while(target != x && stackIdx < stackSize) { + stack[stackIdx] = offsets[target]++; + target = a[stack[stackIdx] * sizeof(u32) + digt]; + stackIdx++; + } + if (stackIdx != stackSize) { + // found an element to store a offsets[x] + offsets[x]++; + } + stackIdx--; + u32 tmp = arr[stack[stackIdx]]; + while(stackIdx) { + arr[stack[stackIdx]] = arr[stack[stackIdx-1]]; + stackIdx--; + } + arr[stack[0]] = tmp; + } + } + } + + // cutoff to shellsort + if (digit < cutoff) { + // loop on digit values to sort the buckets + range(x, stop) { + if (counts[x] > RADIX_LEVEL) { + radixyOrig(&arr[starts[x]], counts[x], digit+1, stackSize, cutoff); + } + else { + if (counts[x] < 2) continue; + shellsort(&arr[starts[x]], counts[x]); + } + } + } + else { + range(x, stop) { + if (counts[x] > 1) { + shellsort(&arr[starts[x]], counts[x]); + } + } + } + #undef stop +} + +void radixy(u32 *arr, size_t size, size_t digit, size_t stackSize, size_t cutoff); + +typ struct {u32 *arr; size_t size; size_t digit; size_t stackSize; size_t cutoff;} radixyArgst; + +typ struct {u32 *arr; size_t size;} shellsortArgst; + +void radixyThread(void *args) { + cast(radixyArgst*, p, args); + radixy(p->arr, p->size, p->digit, p->stackSize, p->cutoff); +} + +void shellsortThread(void *args) { + cast(shellsortArgst *, p, args); + shellsort(p->arr, p->size); +} + +// parallel radix sort for u32 array +void radixy(u32 *arr, size_t size, size_t digit, size_t stackSize, size_t cutoff) { + #define stop 256 + u8 *a = (u8*) arr; + size_t counts[stop]; + size_t offsets[stop]; + size_t starts[stop]; + size_t ends[stop]; + size_t digt = sizeof(u32) - digit - 1; + radixyArgst rdxArgs[stop]; + size_t rdxArgsIdx = 0; + + zeroBuf(counts, sizeof(counts)); + + // compute counts + range(x, size) { + u8 c = a[x * sizeof(u32) + digt]; + counts[c]++; + } + + // compute offsets + offsets[0] = 0; + starts[0] = 0; + rangeFrom(x, 1, stop) { + offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1]; + } + ends[stop-1] = size; + + + // loop on digit values + range(x, stop) { + // move records according to digit value + while(offsets[x] < ends[x]) { + u8 target = a[offsets[x] * sizeof(u32) + digt]; + if (target == x) { + // this record already placed in the correct bucket + offsets[x]++; + } + else { + size_t stackIdx = 0; + size_t stack[stackSize]; + stack[stackIdx++] = offsets[x]; + while(target != x && stackIdx < stackSize) { + stack[stackIdx] = offsets[target]++; + target = a[stack[stackIdx] * sizeof(u32) + digt]; + stackIdx++; + } + if (stackIdx != stackSize) { + // found an element to store a offsets[x] + offsets[x]++; + } + stackIdx--; + u32 tmp = arr[stack[stackIdx]]; + while(stackIdx) { + arr[stack[stackIdx]] = arr[stack[stackIdx-1]]; + stackIdx--; + } + arr[stack[0]] = tmp; + } + } + } + + // cutoff to shellsort + if (digit < cutoff) { + // loop on digit values to sort the buckets + range(x, stop) { + if (counts[x] > RADIX_LEVEL) { + if (!digit) { + rdxArgs[rdxArgsIdx] = (radixyArgst){.arr=&arr[starts[x]], .size=counts[x], .digit=digit+1, .stackSize=stackSize, .cutoff=cutoff}; + tpoolAdd(radixyThread, (void*)&rdxArgs[rdxArgsIdx]); + rdxArgsIdx++; + } + else + radixy(&arr[starts[x]], counts[x], digit+1, stackSize, cutoff); + } + else { + if (counts[x] < 2) continue; + /* ssArgs[ssArgsIdx] = (shellsortArgst){.arr=&arr[starts[x]], .size=counts[x]}; */ + /* tpoolAdd(shellsortThread, (void*)&ssArgs[ssArgsIdx]); */ + /* ssArgsIdx++; */ + shellsort(&arr[starts[x]], counts[x]); + } + } + } + else { + range(x, stop) { + if (counts[x] > 1) { + shellsort(&arr[starts[x]], counts[x]); + } + } + } + #undef stop + + if (!digit) { + tpoolWait; + } +} + +void radixyMacro(u32 *arr, size_t size, size_t digit, size_t stackSize, size_t cutoff) { + #define stop 256 + u32 *ar[sizeof(u32)]; + size_t sizes[sizeof(u32)]; + u8 *a[sizeof(u32)]; + size_t counts[sizeof(u32)][stop]; + size_t offsets[sizeof(u32)][stop]; + size_t starts[sizeof(u32)][stop]; + size_t ends[sizeof(u32)][stop]; + jmp_buf jumpBuffers[sizeof(u32)]; + + zeroBuf(counts, sizeof(counts)); + + ar[0] = arr; + sizes[0] = size; + + radixStart:; + a[0] = (u8*) ar[0]; + size_t digt = sizeof(u32) - digit - 1; + // compute counts + range(x, sizes[0]) { + u8 c = a[0][x * sizeof(u32) + digt]; + counts[0][c]++; + } + + // compute offsets + offsets[0][0] = 0; + starts[0][0] = 0; + rangeFrom(x, 1, stop) { + offsets[0][x] = starts[0][x] = ends[0][x-1] = offsets[0][x-1] + counts[0][x-1]; + } + ends[0][stop-1] = sizes[0]; + + + // loop on digit values + range(x, stop) { + // move records according to digit value + while(offsets[0][x] < ends[0][x]) { + u8 target = a[0][offsets[0][x] * sizeof(u32) + digt]; + if (target == x) { + // this record already placed in the correct bucket + offsets[0][x]++; + } + else { + size_t stackIdx = 0; + size_t stack[stackSize]; + stack[stackIdx++] = offsets[0][x]; + while(target != x && stackIdx < stackSize) { + stack[stackIdx] = offsets[0][target]++; + target = a[0][stack[stackIdx] * sizeof(u32) + digt]; + stackIdx++; + } + if (stackIdx != stackSize) { + // found an element to store a offsets[0][x] + offsets[0][x]++; + } + stackIdx--; + u32 tmp = ar[0][stack[stackIdx]]; + while(stackIdx) { + ar[0][stack[stackIdx]] = ar[0][stack[stackIdx-1]]; + stackIdx--; + } + ar[0][stack[0]] = tmp; + } + } + } + + // cutoff to shellsort + if (digit < cutoff) { + // loop on digit values to sort the buckets + range(x, stop) { + if (counts[0][x] > RADIX_LEVEL) { + radixy(&ar[0][starts[0][x]], counts[0][x], digit+1, stackSize, cutoff); + } + else { + if (counts[0][x] < 2) continue; + shellsort(&ar[0][starts[0][x]], counts[0][x]); + } + } + } + else { + range(x, stop) { + if (counts[0][x] > 1) { + shellsort(&ar[0][starts[0][x]], counts[0][x]); + } + } + } + #undef stop +} + + +// radixy from strings +internal inline void shellsortS(char **arr, size_t size) { + char *tmp; // tmp record + + rangeFrom(i, 3, size) { + tmp = arr[i]; + size_t j; + for(j = i ; j >= 3 && strcmp(arr[j-3],tmp) > 0; j-=3) { + arr[j] = arr[j-3]; + } + arr[j] = tmp; + } + + rangeFrom(i, 1, size) { + tmp = arr[i]; + size_t j; + for(j = i ; j >= 1 && strcmp(arr[j-1],tmp) > 0; j--) { + arr[j] = arr[j-1]; + } + arr[j] = tmp; + } +} + +/** + * radixyS doesn't accept empty strings + * it segfaults when there is an empty string in the array + */ +void radixySOrig(char **arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize, size_t cutoff) { + size_t counts[charStop+1]; + size_t offsets[charStop+1]; + size_t starts[charStop+1]; + size_t ends[charStop+1]; + size_t digt = digit; + + zeroBuf(counts, sizeof(counts)); + + // compute counts + range(x, size) { + u8 c = *(arr[x]+digt); + counts[c]++; + } + + // compute offsets + offsets[0] = 0; + starts[0] = 0; + offsets[charStart] = starts[charStart] = ends[0] = offsets[0] + counts[0]; + rangeFrom(x, charStart+1, charStop+1) { + offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1]; + } + ends[charStop] = size; + + // sort 0 end of string + // move records according to digit value + while(offsets[0] < ends[0]) { + u8 target = *(arr[offsets[0]] + digt); + if (target == 0) { + // this record already placed in the correct bucket + offsets[0]++; + } + else { + size_t stackIdx = 0; + size_t stack[stackSize]; + stack[stackIdx++] = offsets[0]; + while(target != 0 && stackIdx < stackSize) { + stack[stackIdx] = offsets[target]++; + target = *(arr[stack[stackIdx]] + digt); + stackIdx++; + } + if (stackIdx != stackSize) { + // found an element to store a offsets[0] + offsets[0]++; + } + stackIdx--; + char *tmp = arr[stack[stackIdx]]; + while(stackIdx) { + arr[stack[stackIdx]] = arr[stack[stackIdx-1]]; + stackIdx--; + } + arr[stack[0]] = tmp; + } + } + // loop on digit values + rangeFrom(x, charStart, charStop+1) { + // move records according to digit value + while(offsets[x] < ends[x]) { + u8 target = *(arr[offsets[x]] + digt); + if (target == x) { + // this record already placed in the correct bucket + offsets[x]++; + } + else { + size_t stackIdx = 0; + size_t stack[stackSize]; + stack[stackIdx++] = offsets[x]; + while(target != x && stackIdx < stackSize) { + stack[stackIdx] = offsets[target]++; + target = *(arr[stack[stackIdx]] + digt); + stackIdx++; + } + if (stackIdx != stackSize) { + // found an element to store a offsets[x] + offsets[x]++; + } + stackIdx--; + char *tmp = arr[stack[stackIdx]]; + while(stackIdx) { + arr[stack[stackIdx]] = arr[stack[stackIdx-1]]; + stackIdx--; + } + arr[stack[0]] = tmp; + } + } + } + + // cutoff to shellsort + if (digit < cutoff) { + // sort 0 end of string + if (counts[0] > RADIX_LEVEL) { + radixySOrig(&arr[starts[0]], counts[0], digit+1, charStart, charStop, stackSize, cutoff); + } + else { + if (counts[0] > 1) shellsortS(&arr[starts[0]], counts[0]); + } + // loop on digit values to sort the buckets + rangeFrom(x, charStart, charStop+1) { + if (counts[x] > RADIX_LEVEL) { + radixySOrig(&arr[starts[x]], counts[x], digit+1, charStart, charStop, stackSize, cutoff); + } + else { + if (counts[x] < 2) continue; + shellsortS(&arr[starts[x]], counts[x]); + } + } + } + else { + if (counts[0] > 1) { + shellsortS(&arr[starts[0]], counts[0]); + } + rangeFrom(x, charStart, charStop+1) { + if (counts[x] > 1) { + shellsortS(&arr[starts[x]], counts[x]); + } + } + } +} + +void radixyS(char **arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize, size_t cutoff); + +typ struct {char **arr; size_t size; size_t digit; u8 charStart; u16 charStop; size_t stackSize; size_t cutoff;} radixySArgst; + +void radixySThread(void *args) { + cast(radixySArgst*, p, args); + radixyS(p->arr, p->size, p->digit, p->charStart, p->charStop, p->stackSize, p->cutoff); +} + +// parallel radix sort for string (char*) arrays +void radixyS(char **arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize, size_t cutoff) { + size_t counts[charStop+1]; + size_t offsets[charStop+1]; + size_t starts[charStop+1]; + size_t ends[charStop+1]; + size_t digt = digit; + radixySArgst rdxArgs[charStop+1]; + size_t rdxArgsIdx = 0; + + zeroBuf(counts, sizeof(counts)); + + // compute counts + range(x, size) { + u8 c = *(arr[x]+digt); + counts[c]++; + } + + // compute offsets + offsets[0] = 0; + starts[0] = 0; + offsets[charStart] = starts[charStart] = ends[0] = offsets[0] + counts[0]; + rangeFrom(x, charStart+1, charStop+1) { + offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1]; + } + ends[charStop] = size; + + // sort 0 end of string + // move records according to digit value + while(offsets[0] < ends[0]) { + u8 target = *(arr[offsets[0]] + digt); + if (target == 0) { + // this record already placed in the correct bucket + offsets[0]++; + } + else { + size_t stackIdx = 0; + size_t stack[stackSize]; + stack[stackIdx++] = offsets[0]; + while(target != 0 && stackIdx < stackSize) { + stack[stackIdx] = offsets[target]++; + target = *(arr[stack[stackIdx]] + digt); + stackIdx++; + } + if (stackIdx != stackSize) { + // found an element to store a offsets[0] + offsets[0]++; + } + stackIdx--; + char *tmp = arr[stack[stackIdx]]; + while(stackIdx) { + arr[stack[stackIdx]] = arr[stack[stackIdx-1]]; + stackIdx--; + } + arr[stack[0]] = tmp; + } + } + // loop on digit values + rangeFrom(x, charStart, charStop+1) { + // move records according to digit value + while(offsets[x] < ends[x]) { + u8 target = *(arr[offsets[x]] + digt); + if (target == x) { + // this record already placed in the correct bucket + offsets[x]++; + } + else { + size_t stackIdx = 0; + size_t stack[stackSize]; + stack[stackIdx++] = offsets[x]; + while(target != x && stackIdx < stackSize) { + stack[stackIdx] = offsets[target]++; + target = *(arr[stack[stackIdx]] + digt); + stackIdx++; + } + if (stackIdx != stackSize) { + // found an element to store a offsets[x] + offsets[x]++; + } + stackIdx--; + char *tmp = arr[stack[stackIdx]]; + while(stackIdx) { + arr[stack[stackIdx]] = arr[stack[stackIdx-1]]; + stackIdx--; + } + arr[stack[0]] = tmp; + } + } + } + + // cutoff to shellsort + if (digit < cutoff) { + // sort 0 end of string + if (counts[0] > RADIX_LEVEL) { + if (!digit) { + rdxArgs[rdxArgsIdx] = (radixySArgst){.arr=&arr[starts[0]], .size=counts[0], .digit=digit+1, .charStart=charStart, .charStop=charStop, .stackSize=stackSize, .cutoff=cutoff}; + tpoolAdd(radixySThread, (void*)&rdxArgs[rdxArgsIdx]); + rdxArgsIdx++; + } + else + radixyS(&arr[starts[0]], counts[0], digit+1, charStart, charStop, stackSize, cutoff); + } + else { + if (counts[0] > 1) shellsortS(&arr[starts[0]], counts[0]); + } + // loop on digit values to sort the buckets + rangeFrom(x, charStart, charStop+1) { + if (counts[x] > RADIX_LEVEL) { + if (!digit) { + rdxArgs[rdxArgsIdx] = (radixySArgst){.arr=&arr[starts[x]], .size=counts[x], .digit=digit+1, .charStart=charStart, .charStop=charStop, .stackSize=stackSize, .cutoff=cutoff}; + tpoolAdd(radixySThread, (void*)&rdxArgs[rdxArgsIdx]); + rdxArgsIdx++; + } + else + radixyS(&arr[starts[x]], counts[x], digit+1, charStart, charStop, stackSize, cutoff); + } + else { + if (counts[x] < 2) continue; + shellsortS(&arr[starts[x]], counts[x]); + } + } + } + else { + if (counts[0] > 1) { + shellsortS(&arr[starts[0]], counts[0]); + } + rangeFrom(x, charStart, charStop+1) { + if (counts[x] > 1) { + shellsortS(&arr[starts[x]], counts[x]); + } + } + } + + if (!digit) { + tpoolWait; + } +} + + +// u32 array +#define radixsortAt(ptr) *(ptr) +radixyUintDef(/*scope*/,radi/*name*/,u32/*elemType*/,6/*stackSize*/,4/*cutoff*/,40/*RADIX_LEVEL*/); +#undef radixsortAt +//#define radi + + +// u64 array +typ struct {u64 a; int b;} rdxElemt; +#define radixsortAt(ptr) (ptr)->a +radixyUintThreadDef(/*scope*/,radi64/*name*/,rdxElemt/*elemType*/,6/*stackSize*/,4/*cutoff*/,40/*RADIX_LEVEL*/); +#undef radixsortAt + +// array with string keys +typ struct {char *a; int b;} skElemt; + +#define radixsortAt(ptr) (ptr)->a +radixyStringThreadDef(/*scope*/,radiS/*name*/,skElemt/*elemType*/,6/*stackSize*/,4/*cutoff*/, 40/*RADIX_LEVEL*/); +#undef radixsortAt + + +// end radix sort void trials(void) { typ struct {i32 a; int b;} elemt; //#define sz 600000 - #define sz 20 + #define sz 60 //goto rnd; + // radix sort struct array + rdxElemt radA[sz]; + skElemt radS[sz]; + + + + srandom(10); + range(i, ARRAY_SIZE(radA)) { + radA[i].a = (u64)random() << 27; + radA[i].b = i; + radS[i].a = randomS(random()%15+1); + radS[i].b = i; + /* printf("(%lu,%d) ", radA[i].a, radA[i].b); */ + printf("(%s,%d) ", radS[i].a, radS[i].b); + } + put;put; + + radi64(radA, sz); + //radiS(radS, sz); + if (!radiSSafe(radS, sz)) { + logE("Empty strings are not allowed"); + } + + //XSUCCESS; + + range(i, ARRAY_SIZE(radA)) { + /* printf("(%lu,%d) ", radA[i].a, radA[i].b); */ + printf("(%s,%d) ", radS[i].a, radS[i].b); + } + put; + XSUCCESS; + // -------------------------------- // float key array // @@ -374,6 +1034,9 @@ rnd:; u32 urnd[sz]; i64 rnd64[sz]; u64 urnd64[sz]; + char *list[sz+1]; + list[sz] = NULL; + char **lst = list; srandom(10); range(i, ARRAY_SIZE(rnd)) { @@ -381,14 +1044,22 @@ rnd:; //rnd[i] = absV((int)randomWordFromHW()) % (ARRAY_SIZE(rnd) *2); //rnd[i] = random() % (ARRAY_SIZE(rnd) *2); rnd[i] = (random() - 0x4fffffff) * 2; - urnd[i] = random() * 2; + //urnd[i] = (random() * 2); + urnd[i] = random(); + // string representing a number + /* sprintf((char*)&urnd[i], "%d", ARRAY_SIZE(rnd)-i-1); */ + /* sprintf((char*)&urnd[i], "%c", '0'+ARRAY_SIZE(rnd)-i-1); */ rnd64[i] = random() << 33 + random(); urnd64[i] = random() << 33 + random(); + /* list[i] = intToS(random()); */ + list[i] = randomS(random()%15+1); //printf("%d ", rnd[i]); //printf("%u ", urnd[i]); + //printf("%08x ", urnd[i]); //printf("%ld ", rnd64[i]); } + /* logVarG(lst); */ put;put stopwatchStart; @@ -403,11 +1074,19 @@ rnd:; //flashsortM(rnd, ARRAY_SIZE(rnd), 0.2 * ARRAY_SIZE(rnd)); //flashsortM(urnd, ARRAY_SIZE(urnd), 0.2 * ARRAY_SIZE(urnd)); //flashsortM(rnd64, ARRAY_SIZE(rnd64), 0.2 * ARRAY_SIZE(rnd64)); - flashsortM(urnd64, ARRAY_SIZE(urnd64), 0.2 * ARRAY_SIZE(urnd64)); + //flashsortM(urnd64, ARRAY_SIZE(urnd64), 0.2 * ARRAY_SIZE(urnd64)); //flashsort(rnd, ARRAY_SIZE(rnd)); //int *A = rnd; //flashsort(A, ARRAY_SIZE(rnd)); + //RadixSort(urnd, sz); + //radixSort(urnd, sz); + //radixy(urnd, sz, 0 /*digit*/, 6 /*stackSize*/, 4 /*cutoff*/); + radi(urnd, sz); + //radixyS(lst, sz, 0 /*digit*/, 44 /*start*/, 'z' /*stop*/, 5 /*stackSize*/, 4 /*cutoff*/); + //radixyStrTODO(urnd, sz, 0 /* digit */); + //sortG(&lst); + int cmp(const void *a, const void *b) { ret CMP(*(int*)a, *(int*)b); //ret ( *(int*)a - *(int*)b ); @@ -421,16 +1100,41 @@ rnd:; stopwatchLogUs; + // check + range(i, sz-1) { + if (urnd[i+1] < urnd[i]) { + logVarG(i); + logVarG(urnd[i]); + logVarG(urnd[i+1]); + logE("wrong order"); + /* XFAILURE; */ + } + } + + /* // check */ + /* range(i, sz-1) { */ + /* if (strcmp(lst[i+1], lst[i]) < 0) { */ + /* logVarG(i); */ + /* logVarG(lst[i]); */ + /* logVarG(lst[i+1]); */ + /* logE("wrong order"); */ + /* } */ + /* } */ //XSUCCESS; range(i, ARRAY_SIZE(rnd)) { /* printf("%d ", rnd[i]); */ - /* printf("%u ", urnd[i]); */ /* printf("%ld ", rnd64[i]); */ - printf("%lu ", urnd64[i]); + printf("%u ", urnd[i]); + /* printf("%08x ", urnd[i]); */ + /* printf("%s ", &urnd[i]); */ + /* printf("%lu ", urnd64[i]); */ } put; + /* logVarG(lst); */ + // TODO free lst strings + /* typeof(convertToUnsignedType(rnd[0])) a = 1; */ /* typeof(convertToUnsignedType(rnd[0])) b = -1; */ /* toUnsignedType((rnd[0])) a = 1; */ diff --git a/package.yml b/package.yml @@ -1,7 +1,7 @@ --- name: sort - version: 0.0.1 - description: "sorting algorithms for any type of array: flashsort" + version: 0.0.2 + description: "sorting algorithms for any type of array: radixsort, flashsort" bin: ./sort.h cflags: -O3 -std=gnu11 -fPIC -pipe #lflags: -lpcre @@ -10,6 +10,8 @@ url: git+https://github.com/RemyNoulin/sort.git keywords: - sorting + - radixsort + - flashsort - library author: Remy license: MIT diff --git a/radixsort.h b/radixsort.h @@ -0,0 +1,768 @@ +#pragma once + +/** + * type safe radix sort + * + * radix sort sorts keys that are either uint type or string type (char*) keys + * radix sort is faster than qsort from glibc and flashsort and takes less memory + * + * the radixyUintDef, radixyStringDef, radixyUintThreadDef, radixyStringThreadDef define the radix sort functions for arrays with the given element type: + * + * - shellsort##name or shellsortS##name - internal shell sort function + * - radixsort##name or radixsortS##name - function with all the parameters + * - name - function only with array and size parameters + * - nameSafe - like name and checks if there are empty strings + * + * the *ThreadDef macros defines threaded radix sort functions + * + * + * Example: + * + * // sorting array with string keys + * + * typ struct {char *a; int b;} skElemt; + * + * // define macro or function for access the key given an address to an element in the array + * #define radixsortAt(ptr) (ptr)->a + * + * // define a radixsort function with name 'radiS' and 'radiSSafe' sorting arrays with skElemt element type + * radixyStringDef(,radiS,skElemt,6,4, 40); + * #undef radixsortAt + * + * // the radiSSafe check if there are empty strings (NULL or "") in the keys + * // Empty strings are not allowed. + * + * // declare array + * skElemt radS[200]; + * + * // sort the array + * radiS(radS, sz); + * + * // or call safe function: + * if (!radiSSafe(radS, sz)) { + * logE("Empty strings are not allowed"); + * } + * + * + * + * // sorting a u32 array + * + * // define macro or function for access the key given an address to an element in the array + * #define radixsortAt(ptr) *(ptr) + * + * // define a radixsort function with name 'radi' sorting u32 arrays + * radixyUintDef(, radi , u32, 6, 4, 40); + * #undef radixsortAt + * + * // declare array + * u32 urnd[200]; + * + * // sort the array + * radi(urnd, 200); + * + * + * + * // sorting an array with struct elements + * + * // declare element type + * typ struct {u64 a; int b;} rdxElemt; + * + * // define macro or function to access the key given an address to an element in the array + * #define radixsortAt(ptr) (ptr)->a + * + * // define a radixsort function with name 'radi64' sorting arrays with elements of type rdxElemt and u64 keys + * radixyUintDef(, radi64 , rdxElemt, 6, 4, 40); + * #undef radixsortAt + * + * // declare array + * rdxElemt radA[200]; + * + * // sort the array + * radi64(radA, 200); + * + */ + +// define for internal use in radixyUint +#define radixyStop 256 + +/** + * radixyUintDef defines functions for sorting arrays of elemType + * the keys have to be unsigned int (any size) + * + * Functions: + * - shellsort##name - internal shell sort function + * - radixsort##name - function with all the parameters + * - name - function only with array and size parameters + * + * \param + * scope is static, internal or empty + * \param + * name function name for the sort function + * \param + * stackSizeP is the depth of the look-forward stack + * \param + * cutoffP is the digit cutoff for switching to shellsort + * \param + * radixLevel is minimun element count in a bucket for running radix sort, otherwise run shellsort + */ +#define radixyUintDef(scope, name, elemType, stackSizeP, cutoffP, radixLevel)\ +internal inline void shellsort##name(elemType *arr, size_t size) {\ + typeof(radixsortAt(&arr[0])) tmp; /* tmp key */\ + typeof(arr[0]) elem; /* tmp record */\ + \ + {rangeFrom(i, 3, size) {\ + tmp = radixsortAt(&arr[i]);\ + elem = arr[i];\ + size_t j;\ + for(j = i ; j >= 3 && radixsortAt(&arr[j-3]) > tmp; j-=3) {\ + arr[j] = arr[j-3];\ + }\ + arr[j] = elem;\ + }}\ + \ + {rangeFrom(i, 1, size) {\ + tmp = radixsortAt(&arr[i]);\ + elem = arr[i];\ + size_t j;\ + for(j = i ; j >= 1 && radixsortAt(&arr[j-1]) > tmp; j--) {\ + arr[j] = arr[j-1];\ + }\ + arr[j] = elem;\ + }}\ +}\ +\ +scope void radixsort##name(elemType *arr, size_t size, size_t digit, size_t stackSize, size_t cutoff) {\ + u8 *a;\ + size_t counts[radixyStop];\ + size_t offsets[radixyStop];\ + size_t starts[radixyStop];\ + size_t ends[radixyStop];\ + size_t digt = sizeof(radixsortAt(&arr[0])) - digit - 1;\ + \ + zeroBuf(counts, sizeof(counts));\ + \ + /* compute counts */\ + {range(x, size) {\ + a = (u8*)&radixsortAt(&arr[x]);\ + u8 c = a[digt];\ + counts[c]++;\ + }}\ + \ + /* compute offsets */\ + offsets[0] = 0;\ + starts[0] = 0;\ + {rangeFrom(x, 1, radixyStop) {\ + offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1];\ + }}\ + ends[radixyStop-1] = size;\ + \ + \ + /* loop on digit values */\ + {range(x, radixyStop) {\ + /* move records according to digit value */\ + while(offsets[x] < ends[x]) {\ + a = (u8*)&radixsortAt(&arr[offsets[x]]);\ + u8 target = a[digt];\ + if (target == x) {\ + /* this record already placed in the correct bucket */\ + offsets[x]++;\ + }\ + else {\ + size_t stackIdx = 0;\ + size_t stack[stackSize];\ + stack[stackIdx++] = offsets[x];\ + while(target != x && stackIdx < stackSize) {\ + stack[stackIdx] = offsets[target]++;\ + a = (u8*)&radixsortAt(&arr[stack[stackIdx]]);\ + target = a[digt];\ + stackIdx++;\ + }\ + if (stackIdx != stackSize) {\ + /* found an element to store a offsets[x] */\ + offsets[x]++;\ + }\ + stackIdx--;\ + var tmp = arr[stack[stackIdx]];\ + while(stackIdx) {\ + arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\ + stackIdx--;\ + }\ + arr[stack[0]] = tmp;\ + }\ + }\ + }}\ + \ + /* cutoff to shellsort */\ + if (digit < cutoff) {\ + /* loop on digit values to sort the buckets */\ + {range(x, radixyStop) {\ + if (counts[x] > radixLevel) {\ + radixsort##name(&arr[starts[x]], counts[x], digit+1, stackSize, cutoff);\ + }\ + else {\ + if (counts[x] < 2) continue;\ + shellsort##name(&arr[starts[x]], counts[x]);\ + }\ + }}\ + }\ + else {\ + {range(x, radixyStop) {\ + if (counts[x] > 1) {\ + shellsort##name(&arr[starts[x]], counts[x]);\ + }\ + }}\ + }\ +}\ +scope void name(elemType *arr, size_t size) {\ + radixsort##name(arr, size, 0, stackSizeP, cutoffP);\ +} + + +/** + * radixyUintThreadDef (like radixyUintDef) defines functions for sorting arrays of elemType + * the keys have to be unsigned int (any size) + * + * the defined functions by this macro are multithreaded using the threadpool in libsheepy + * + * Functions: + * - shellsort##name - internal shell sort function + * - radixsort##name - function with all the parameters + * - name - function only with array and size parameters + * + * \param + * scope is static, internal or empty + * \param + * name function name for the sort function + * \param + * stackSizeP is the depth of the look-forward stack + * \param + * cutoffP is the digit cutoff for switching to shellsort + * \param + * radixLevel is minimun element count in a bucket for running radix sort, otherwise run shellsort + */ +#define radixyUintThreadDef(scope, name, elemType, stackSizeP, cutoffP, radixLevel)\ +internal inline void shellsort##name(elemType *arr, size_t size) {\ + typeof(radixsortAt(&arr[0])) tmp; /* tmp key */\ + typeof(arr[0]) elem; /* tmp record */\ + \ + {rangeFrom(i, 3, size) {\ + tmp = radixsortAt(&arr[i]);\ + elem = arr[i];\ + size_t j;\ + for(j = i ; j >= 3 && radixsortAt(&arr[j-3]) > tmp; j-=3) {\ + arr[j] = arr[j-3];\ + }\ + arr[j] = elem;\ + }}\ + \ + {rangeFrom(i, 1, size) {\ + tmp = radixsortAt(&arr[i]);\ + elem = arr[i];\ + size_t j;\ + for(j = i ; j >= 1 && radixsortAt(&arr[j-1]) > tmp; j--) {\ + arr[j] = arr[j-1];\ + }\ + arr[j] = elem;\ + }}\ +}\ +\ +scope void radixsort##name(elemType *arr, size_t size, size_t digit, size_t stackSize, size_t cutoff);\ +\ +typ struct {elemType *arr; size_t size; size_t digit; size_t stackSize; size_t cutoff;} radixy##name##Argst;\ +\ +void radixsort##name##Thread(void *args) {\ + cast(radixy##name##Argst*, p, args);\ + radixsort##name(p->arr, p->size, p->digit, p->stackSize, p->cutoff);\ +}\ +\ +scope void radixsort##name(elemType *arr, size_t size, size_t digit, size_t stackSize, size_t cutoff) {\ + u8 *a;\ + size_t counts[radixyStop];\ + size_t offsets[radixyStop];\ + size_t starts[radixyStop];\ + size_t ends[radixyStop];\ + size_t digt = sizeof(radixsortAt(&arr[0])) - digit - 1;\ + radixy##name##Argst rdxArgs[radixyStop]; /* arguments for functions in the threadpool */\ + size_t rdxArgsIdx = 0;\ + \ + zeroBuf(counts, sizeof(counts));\ + \ + /* compute counts */\ + {range(x, size) {\ + a = (u8*)&radixsortAt(&arr[x]);\ + u8 c = a[digt];\ + counts[c]++;\ + }}\ + \ + /* compute offsets */\ + offsets[0] = 0;\ + starts[0] = 0;\ + {rangeFrom(x, 1, radixyStop) {\ + offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1];\ + }}\ + ends[radixyStop-1] = size;\ + \ + \ + /* loop on digit values */\ + {range(x, radixyStop) {\ + /* move records according to digit value */\ + while(offsets[x] < ends[x]) {\ + a = (u8*)&radixsortAt(&arr[offsets[x]]);\ + u8 target = a[digt];\ + if (target == x) {\ + /* this record already placed in the correct bucket */\ + offsets[x]++;\ + }\ + else {\ + size_t stackIdx = 0;\ + size_t stack[stackSize];\ + stack[stackIdx++] = offsets[x];\ + while(target != x && stackIdx < stackSize) {\ + stack[stackIdx] = offsets[target]++;\ + a = (u8*)&radixsortAt(&arr[stack[stackIdx]]);\ + target = a[digt];\ + stackIdx++;\ + }\ + if (stackIdx != stackSize) {\ + /* found an element to store a offsets[x] */\ + offsets[x]++;\ + }\ + stackIdx--;\ + var tmp = arr[stack[stackIdx]];\ + while(stackIdx) {\ + arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\ + stackIdx--;\ + }\ + arr[stack[0]] = tmp;\ + }\ + }\ + }}\ + \ + /* cutoff to shellsort */\ + if (digit < cutoff) {\ + /* loop on digit values to sort the buckets */\ + {range(x, radixyStop) {\ + if (counts[x] > radixLevel) {\ + if (!digit) {\ + rdxArgs[rdxArgsIdx] = (radixy##name##Argst){.arr=&arr[starts[x]], .size=counts[x], .digit=digit+1, .stackSize=stackSize, .cutoff=cutoff};\ + tpoolAdd(radixsort##name##Thread, (void*)&rdxArgs[rdxArgsIdx]);\ + rdxArgsIdx++;\ + }\ + else\ + radixsort##name(&arr[starts[x]], counts[x], digit+1, stackSize, cutoff);\ + }\ + else {\ + if (counts[x] < 2) continue;\ + shellsort##name(&arr[starts[x]], counts[x]);\ + }\ + }}\ + }\ + else {\ + {range(x, radixyStop) {\ + if (counts[x] > 1) {\ + shellsort##name(&arr[starts[x]], counts[x]);\ + }\ + }}\ + }\ + \ + if (!digit) {\ + tpoolWait;\ + }\ +}\ +scope void name(elemType *arr, size_t size) {\ + radixsort##name(arr, size, 0, stackSizeP, cutoffP);\ +} + + +/** + * radixyStringDef defines functions for sorting arrays of elemType + * the keys have to be strings (of type char*) and empty keys (NULL or "") are not allowed (segfaults) + * + * Functions: + * - shellsortS##name - internal shell sort function + * - radixsortS##name - function with all the parameters + * - name - function only with array and size parameters + * - nameSafe - like name and checks if there are empty strings + * + * \param + * scope is static, internal or empty + * \param + * name function name for the sort function + * \param + * stackSizeP is the depth of the look-forward stack + * \param + * cutoffP is the digit cutoff for switching to shellsort + * \param + * radixLevel is minimun element count in a bucket for running radix sort, otherwise run shellsort + */ +#define radixyStringDef(scope, name, elemType, stackSizeP, cutoffP, radixLevel)\ +internal inline void shellsortS##name(elemType *arr, size_t size) {\ + char *tmp; /* tmp key */\ + typeof(arr[0]) elem; /* tmp record */\ + \ + {rangeFrom(i, 3, size) {\ + tmp = radixsortAt(&arr[i]);\ + elem = arr[i];\ + size_t j;\ + for(j = i ; j >= 3 && strcmp(radixsortAt(&arr[j-3]),tmp) > 0; j-=3) {\ + arr[j] = arr[j-3];\ + }\ + arr[j] = elem;\ + }}\ + \ + {rangeFrom(i, 1, size) {\ + tmp = radixsortAt(&arr[i]);\ + elem = arr[i];\ + size_t j;\ + for(j = i ; j >= 1 && strcmp(radixsortAt(&arr[j-1]),tmp) > 0; j--) {\ + arr[j] = arr[j-1];\ + }\ + arr[j] = elem;\ + }}\ +}\ +\ +/** + * radixyS doesn't accept empty strings + * it segfaults when there is an empty string in the array + */\ +void radixsortS##name(elemType *arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize, size_t cutoff) {\ + size_t counts[charStop+1];\ + size_t offsets[charStop+1];\ + size_t starts[charStop+1];\ + size_t ends[charStop+1];\ + size_t digt = digit;\ + \ + zeroBuf(counts, sizeof(counts));\ + \ + /* compute counts */\ + {range(x, size) {\ + u8 c = *(radixsortAt(&arr[x])+digt);\ + counts[c]++;\ + }}\ + \ + /* compute offsets */\ + offsets[0] = 0;\ + starts[0] = 0;\ + offsets[charStart] = starts[charStart] = ends[0] = offsets[0] + counts[0];\ + rangeFrom(x, charStart+1, charStop+1) {\ + offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1];\ + }\ + ends[charStop] = size;\ + \ + /* sort 0 end of string */\ + /* move records according to digit value */\ + while(offsets[0] < ends[0]) {\ + u8 target = *(radixsortAt(&arr[offsets[0]]) + digt);\ + if (target == 0) {\ + /* this record already placed in the correct bucket */\ + offsets[0]++;\ + }\ + else {\ + size_t stackIdx = 0;\ + size_t stack[stackSize];\ + stack[stackIdx++] = offsets[0];\ + while(target != 0 && stackIdx < stackSize) {\ + stack[stackIdx] = offsets[target]++;\ + target = *(radixsortAt(&arr[stack[stackIdx]]) + digt);\ + stackIdx++;\ + }\ + if (stackIdx != stackSize) {\ + /* found an element to store a offsets[0] */\ + offsets[0]++;\ + }\ + stackIdx--;\ + var tmp = arr[stack[stackIdx]];\ + while(stackIdx) {\ + arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\ + stackIdx--;\ + }\ + arr[stack[0]] = tmp;\ + }\ + }\ + /* loop on digit values */\ + {rangeFrom(x, charStart, charStop+1) {\ + /* move records according to digit value */\ + while(offsets[x] < ends[x]) {\ + u8 target = *(radixsortAt(&arr[offsets[x]]) + digt);\ + if (target == x) {\ + /* this record already placed in the correct bucket */\ + offsets[x]++;\ + }\ + else {\ + size_t stackIdx = 0;\ + size_t stack[stackSize];\ + stack[stackIdx++] = offsets[x];\ + while(target != x && stackIdx < stackSize) {\ + stack[stackIdx] = offsets[target]++;\ + target = *(radixsortAt(&arr[stack[stackIdx]]) + digt);\ + stackIdx++;\ + }\ + if (stackIdx != stackSize) {\ + /* found an element to store a offsets[x] */\ + offsets[x]++;\ + }\ + stackIdx--;\ + var tmp = arr[stack[stackIdx]];\ + while(stackIdx) {\ + arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\ + stackIdx--;\ + }\ + arr[stack[0]] = tmp;\ + }\ + }\ + }}\ + \ + /* cutoff to shellsort */\ + if (digit < cutoff) {\ + /* sort 0 end of string */\ + if (counts[0] > radixLevel) {\ + radixsortS##name(&arr[starts[0]], counts[0], digit+1, charStart, charStop, stackSize, cutoff);\ + }\ + else {\ + if (counts[0] > 1) shellsortS##name(&arr[starts[0]], counts[0]);\ + }\ + /* loop on digit values to sort the buckets */\ + {rangeFrom(x, charStart, charStop+1) {\ + if (counts[x] > radixLevel) {\ + radixsortS##name(&arr[starts[x]], counts[x], digit+1, charStart, charStop, stackSize, cutoff);\ + }\ + else {\ + if (counts[x] < 2) continue;\ + shellsortS##name(&arr[starts[x]], counts[x]);\ + }\ + }}\ + }\ + else {\ + if (counts[0] > 1) {\ + shellsortS##name(&arr[starts[0]], counts[0]);\ + }\ + rangeFrom(x, charStart, charStop+1) {\ + if (counts[x] > 1) {\ + shellsortS##name(&arr[starts[x]], counts[x]);\ + }\ + }\ + }\ +}\ +scope void name(elemType *arr, size_t size) {\ + radixsortS##name(arr, size, 0, 32, 255, stackSizeP, cutoffP);\ +}\ +scope bool name##Safe(elemType *arr, size_t size) {\ + {range(i, size) {\ + if (isEmptyS(radixsortAt(&arr[i]))) ret false;\ + }}\ + radixsortS##name(arr, size, 0, 32, 255, stackSizeP, cutoffP);\ + ret true;\ +} + + + +/** + * radixyStringThreadDef (like radixyStringDef) defines functions for sorting arrays of elemType + * the keys have to be strings (of type char*) and empty keys (NULL or "") are not allowed (segfaults) + * + * the defined functions by this macro are multithreaded using the threadpool in libsheepy + * + * Functions: + * - shellsortS##name - internal shell sort function + * - radixsortS##name - function with all the parameters + * - name - function only with array and size parameters + * - nameSafe - like name and checks if there are empty strings + * + * \param + * scope is static, internal or empty + * \param + * name function name for the sort function + * \param + * stackSizeP is the depth of the look-forward stack + * \param + * cutoffP is the digit cutoff for switching to shellsort + * \param + * radixLevel is minimun element count in a bucket for running radix sort, otherwise run shellsort + */ +#define radixyStringThreadDef(scope, name, elemType, stackSizeP, cutoffP, radixLevel)\ +internal inline void shellsortS##name(elemType *arr, size_t size) {\ + char *tmp; /* tmp key */\ + typeof(arr[0]) elem; /* tmp record */\ + \ + {rangeFrom(i, 3, size) {\ + tmp = radixsortAt(&arr[i]);\ + elem = arr[i];\ + size_t j;\ + for(j = i ; j >= 3 && strcmp(radixsortAt(&arr[j-3]),tmp) > 0; j-=3) {\ + arr[j] = arr[j-3];\ + }\ + arr[j] = elem;\ + }}\ + \ + {rangeFrom(i, 1, size) {\ + tmp = radixsortAt(&arr[i]);\ + elem = arr[i];\ + size_t j;\ + for(j = i ; j >= 1 && strcmp(radixsortAt(&arr[j-1]),tmp) > 0; j--) {\ + arr[j] = arr[j-1];\ + }\ + arr[j] = elem;\ + }}\ +}\ +\ +void radixsortS##name(elemType *arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize, size_t cutoff);\ +\ +typ struct {elemType *arr; size_t size; size_t digit; u8 charStart; u16 charStop; size_t stackSize; size_t cutoff;} radixyS##name##Argst;\ +\ +void radixsortS##name##Thread(void *args) {\ + cast(radixyS##name##Argst*, p, args);\ + radixsortS##name(p->arr, p->size, p->digit, p->charStart, p->charStop, p->stackSize, p->cutoff);\ +}\ +\ +/** + * radixyS doesn't accept empty strings + * it segfaults when there is an empty string in the array + */\ +void radixsortS##name(elemType *arr, size_t size, size_t digit, u8 charStart, u16 charStop, size_t stackSize, size_t cutoff) {\ + size_t counts[charStop+1];\ + size_t offsets[charStop+1];\ + size_t starts[charStop+1];\ + size_t ends[charStop+1];\ + size_t digt = digit;\ + radixyS##name##Argst rdxArgs[charStop+1]; /* arguments for functions in the threadpool */\ + size_t rdxArgsIdx = 0;\ + \ + zeroBuf(counts, sizeof(counts));\ + \ + /* compute counts */\ + {range(x, size) {\ + u8 c = *(radixsortAt(&arr[x])+digt);\ + counts[c]++;\ + }}\ + \ + /* compute offsets */\ + offsets[0] = 0;\ + starts[0] = 0;\ + offsets[charStart] = starts[charStart] = ends[0] = offsets[0] + counts[0];\ + rangeFrom(x, charStart+1, charStop+1) {\ + offsets[x] = starts[x] = ends[x-1] = offsets[x-1] + counts[x-1];\ + }\ + ends[charStop] = size;\ + \ + /* sort 0 end of string */\ + /* move records according to digit value */\ + while(offsets[0] < ends[0]) {\ + u8 target = *(radixsortAt(&arr[offsets[0]]) + digt);\ + if (target == 0) {\ + /* this record already placed in the correct bucket */\ + offsets[0]++;\ + }\ + else {\ + size_t stackIdx = 0;\ + size_t stack[stackSize];\ + stack[stackIdx++] = offsets[0];\ + while(target != 0 && stackIdx < stackSize) {\ + stack[stackIdx] = offsets[target]++;\ + target = *(radixsortAt(&arr[stack[stackIdx]]) + digt);\ + stackIdx++;\ + }\ + if (stackIdx != stackSize) {\ + /* found an element to store a offsets[0] */\ + offsets[0]++;\ + }\ + stackIdx--;\ + var tmp = arr[stack[stackIdx]];\ + while(stackIdx) {\ + arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\ + stackIdx--;\ + }\ + arr[stack[0]] = tmp;\ + }\ + }\ + /* loop on digit values */\ + {rangeFrom(x, charStart, charStop+1) {\ + /* move records according to digit value */\ + while(offsets[x] < ends[x]) {\ + u8 target = *(radixsortAt(&arr[offsets[x]]) + digt);\ + if (target == x) {\ + /* this record already placed in the correct bucket */\ + offsets[x]++;\ + }\ + else {\ + size_t stackIdx = 0;\ + size_t stack[stackSize];\ + stack[stackIdx++] = offsets[x];\ + while(target != x && stackIdx < stackSize) {\ + stack[stackIdx] = offsets[target]++;\ + target = *(radixsortAt(&arr[stack[stackIdx]]) + digt);\ + stackIdx++;\ + }\ + if (stackIdx != stackSize) {\ + /* found an element to store a offsets[x] */\ + offsets[x]++;\ + }\ + stackIdx--;\ + var tmp = arr[stack[stackIdx]];\ + while(stackIdx) {\ + arr[stack[stackIdx]] = arr[stack[stackIdx-1]];\ + stackIdx--;\ + }\ + arr[stack[0]] = tmp;\ + }\ + }\ + }}\ + \ + /* cutoff to shellsort */\ + if (digit < cutoff) {\ + /* sort 0 end of string */\ + if (counts[0] > radixLevel) {\ + if (!digit) {\ + rdxArgs[rdxArgsIdx] = (radixyS##name##Argst){.arr=&arr[starts[0]], .size=counts[0], .digit=digit+1, .charStart=charStart, .charStop=charStop, .stackSize=stackSize, .cutoff=cutoff};\ + tpoolAdd(radixsortS##name##Thread, (void*)&rdxArgs[rdxArgsIdx]);\ + rdxArgsIdx++;\ + }\ + else\ + radixsortS##name(&arr[starts[0]], counts[0], digit+1, charStart, charStop, stackSize, cutoff);\ + }\ + else {\ + if (counts[0] > 1) shellsortS##name(&arr[starts[0]], counts[0]);\ + }\ + /* loop on digit values to sort the buckets */\ + {rangeFrom(x, charStart, charStop+1) {\ + if (counts[x] > radixLevel) {\ + if (!digit) {\ + rdxArgs[rdxArgsIdx] = (radixyS##name##Argst){.arr=&arr[starts[x]], .size=counts[x], .digit=digit+1, .charStart=charStart, .charStop=charStop, .stackSize=stackSize, .cutoff=cutoff};\ + tpoolAdd(radixsortS##name##Thread, (void*)&rdxArgs[rdxArgsIdx]);\ + rdxArgsIdx++;\ + }\ + else\ + radixsortS##name(&arr[starts[x]], counts[x], digit+1, charStart, charStop, stackSize, cutoff);\ + }\ + else {\ + if (counts[x] < 2) continue;\ + shellsortS##name(&arr[starts[x]], counts[x]);\ + }\ + }}\ + }\ + else {\ + if (counts[0] > 1) {\ + shellsortS##name(&arr[starts[0]], counts[0]);\ + }\ + rangeFrom(x, charStart, charStop+1) {\ + if (counts[x] > 1) {\ + shellsortS##name(&arr[starts[x]], counts[x]);\ + }\ + }\ + }\ + \ + if (!digit) {\ + tpoolWait;\ + }\ +}\ +scope void name(elemType *arr, size_t size) {\ + radixsortS##name(arr, size, 0, 32, 255, stackSizeP, cutoffP);\ +}\ +scope bool name##Safe(elemType *arr, size_t size) {\ + {range(i, size) {\ + if (isEmptyS(radixsortAt(&arr[i]))) ret false;\ + }}\ + radixsortS##name(arr, size, 0, 32, 255, stackSizeP, cutoffP);\ + ret true;\ +} + +// vim: set expandtab ts=2 sw=2: diff --git a/sort.h b/sort.h @@ -1,3 +1,4 @@ #pragma once #include "flashsort.h" +#include "radixsort.h"