Attempts to (partially) sort an array of pointers to 'sha256_midstate's in place in memcmp order. * If NULL == hasDuplicates then sorting is always run to completion. * Otherwise, if NULL != hasDuplicates and if duplicate entries are found, the sorting is aborted and * *hasDuplicates is set to one of pointers of a duplicate entry. * If NULL != hasDuplicates and no duplicate entries are found,
| 122 | * uint32_t stack[(CHAR_COUNT - 1)*(sizeof(*a)->s) + 1]; |
| 123 | */ |
| 124 | static void rsort_ex(const sha256_midstate** a, uint_fast32_t len, const sha256_midstate** hasDuplicates, uint32_t* stack) { |
| 125 | unsigned int depth = 0; |
| 126 | size_t bucketCount[sizeof((*a)->s) + 1]; |
| 127 | size_t totalBucketCount = 1; |
| 128 | |
| 129 | static_assert(sizeof((*a)->s) <= UINT_MAX, "UINT_MAX too small to hold depth."); |
| 130 | stack[0]=0; |
| 131 | bucketCount[depth] = 1; |
| 132 | |
| 133 | /* This implementation contains a 'stack' of 'totalBucketCount' many subarrays (called buckets) |
| 134 | that have been partially sorted up to various prefix length. |
| 135 | |
| 136 | The buckets are disjoint and cover the entire array from 0 up to len. |
| 137 | As sorting proceeds, the end of the array will be sorted first. |
| 138 | We will decrease len as we go as we find out that items at the end of the array are in their proper, sorted position. |
| 139 | |
| 140 | The 'i'th bucket is the subarray a[stack[i]:stack[i+1]), |
| 141 | except for the last bucket which is the subarray a[stack[totalBucketCount-1]:len). |
| 142 | |
| 143 | The depth to which various buckets are sorted increases the further down the stack you go. |
| 144 | The 'bucketCount' stores how many buckets are sorted to various depths. |
| 145 | |
| 146 | * for all i <= depth, the subarray a[sum(j < i, bucketCount[i]):end) have their first i characters sorted. |
| 147 | * for all i <= depth, the (sum(j < i, bucketCount[i]))th and later buckets have all the first i characters of their entries identical. |
| 148 | |
| 149 | So all buckets are sorted up to a prefix length of 0 many characters. |
| 150 | Then, if 1 <= depth, all bucket except for the first bucketCount[0]-many buckets are sorted by their 1 character prefix |
| 151 | And then, if 2 <= depth, all bucket except for the first (bucketCount[0] + bucket[1])-many buckets are sorted by their 2 character prefix |
| 152 | And so on. |
| 153 | |
| 154 | It is always the case that 'totalBucketCount = sum(i <= depth, bucketCount[i])', |
| 155 | and thus the last bucket in the stack is located at stack[totalBucketCount-1]. |
| 156 | 'totalBucketCount' and 'bucketCount' items are always increased and decreased in tandum. |
| 157 | |
| 158 | The loop is initialized with a 'totalBucketCount' of 1 and this one bucket contains the whole array a[0:len). |
| 159 | 'depth' is initialized to 0, and all the entries are trivialy sorted by the first 0-many characters. |
| 160 | |
| 161 | As we go through the loop, the last bucket is "popped" off the stack and processed, which can go one of two ways. |
| 162 | |
| 163 | If the last bucket is size 2 or greater, we proceed to sort it by its 'depth' character and partition the bucket into 256 sub-buckets |
| 164 | which are then pushed onto the stack (notice this causes a net increase of the stack size by 255 items, because one was popped off). |
| 165 | |
| 166 | If ever the depth is beyond the size of the data being sorted, |
| 167 | we can immediately halt as we have found 2 or more item that are identical. |
| 168 | |
| 169 | Note: there is an added optimization where by if there is only one non-empty bucket found when attempting to sort, |
| 170 | i.e. it happens that every bucket item already has identical 'depth' characters, |
| 171 | we skip the subdivision and move onto the next depth immediately. |
| 172 | (This is equivalent to pushing the one non-empty bucket onto the stack and immediately popping it back off.) |
| 173 | |
| 174 | If the last bucket is of size 0 or 1, it must be already be sorted. |
| 175 | Since this bucket is at the end of the array we decrease 'len'. |
| 176 | */ |
| 177 | while(totalBucketCount) { |
| 178 | /* Find the correct "depth" of the last bucket. */ |
| 179 | while(0 == bucketCount[depth]) { |
| 180 | simplicity_assert(depth); |
| 181 | depth--; |
no test coverage detected