#include "rsort.h"
#include <string.h>
static unsigned char readLevel(const sha256_midstate* a, size_t i) {
return ((const unsigned char*)(a->s))[i];
}
static bool freq(size_t* result, const sha256_midstate * const * a, size_t len, size_t j) {
memset(result, 0, CHAR_COUNT * sizeof(size_t));
if (0 == len) return true;
for (size_t i = 0; i < len - 1; ++i) {
result[readLevel(a[i],j)]++;
}
return len == ++result[readLevel(a[len-1],j)];
}
static void cumulative(size_t* restrict result, const size_t* restrict sizes) {
size_t accumulator = 0;
for (size_t i = 0; i < CHAR_COUNT; ++i) {
accumulator += sizes[i];
result[i] = accumulator;
}
}
static size_t bucketStart(const size_t* ends, size_t i) {
return i ? ends[i-1] : 0;
}
static void swap(const sha256_midstate** a, const sha256_midstate** b) {
const sha256_midstate* tmp = *a;
*a = *b;
*b = tmp;
}
const sha256_midstate* rsort(size_t* scratch, const sha256_midstate** a, size_t len, size_t level) {
if (len < 2) return NULL;
if (0 == level) return a[0];
simplicity_assert(level <= sizeof((*a)->s));
size_t* bucketEnds = scratch;
{
size_t* bucketSize = scratch + CHAR_COUNT;
while (freq(bucketSize, a, len, level - 1)) {
level--;
if (0 == level) return a[0];
};
cumulative(bucketEnds, bucketSize);
simplicity_assert(len == bucketEnds[UCHAR_MAX]);
for (size_t i = 0; i < CHAR_COUNT; ++i) {
size_t start = bucketStart(bucketEnds, i);
while (bucketSize[i]) {
size_t bucket = readLevel(a[start], level - 1);
simplicity_assert(bucketSize[bucket]);
bucketSize[bucket]--;
swap(a + start, a + bucketStart(bucketEnds, bucket) + bucketSize[bucket]);
}
}
}
for (size_t i = 0; i < CHAR_COUNT; ++i) {
size_t start = bucketStart(bucketEnds, i);
const sha256_midstate* rec = rsort(scratch + CHAR_COUNT, a + start, bucketEnds[i] - start, level - 1);
if (rec) return rec;
}
return NULL;
}