| 205 | } |
| 206 | |
| 207 | void rehash(int hashPos) { |
| 208 | // function needs to possibly reorder elements by a different hash value |
| 209 | // chances are very high we are already ordered correctly as we use 16 |
| 210 | // bits of the hash and one level is uses 6 bits, so the new values |
| 211 | // are guaranteed to be ordered correctly by their 10 most significant |
| 212 | // bits if increasing the hash position by 1 and only if the 10 bits of |
| 213 | // the hash had a collision the new 6 bits might break a tie differently. |
| 214 | // It is, however, important to maintain the exact ordering as otherwise |
| 215 | // elements may not be found. |
| 216 | occupation = 0; |
| 217 | for (int i = 0; i < size; ++i) { |
| 218 | hashes[i] = get_hash_chunks16(compute_hash(entries[i].key()), hashPos); |
| 219 | occupation.set(get_first_chunk16(hashes[i])); |
| 220 | } |
| 221 | |
| 222 | int i = 0; |
| 223 | while (i < size) { |
| 224 | uint8_t hashChunk = get_first_chunk16(hashes[i]); |
| 225 | int pos = occupation.num_set_until(hashChunk) - 1; |
| 226 | |
| 227 | // if the position is after i the element definitely comes later, so we |
| 228 | // swap it to that position and proceed without increasing i until |
| 229 | // eventually an element appears that comes at position i or before |
| 230 | if (pos > i) { |
| 231 | std::swap(hashes[pos], hashes[i]); |
| 232 | std::swap(entries[pos], entries[i]); |
| 233 | continue; |
| 234 | } |
| 235 | |
| 236 | // the position is before or at i, now check where the exact location |
| 237 | // should be for the ordering by hash so that the invariant is that all |
| 238 | // elements up to i are properly sorted. Essentially insertion sort but |
| 239 | // with the modification of having a high chance to guess the correct |
| 240 | // position already using the occupation flags. |
| 241 | while (pos < i && hashes[pos] >= hashes[i]) ++pos; |
| 242 | |
| 243 | // if the final position is before i we need to move elements to |
| 244 | // make space at that position, otherwise nothing needs to be done but |
| 245 | // incrementing i increasing the sorted range by 1. |
| 246 | if (pos < i) { |
| 247 | uint64_t hash = hashes[i]; |
| 248 | auto entry = std::move(entries[i]); |
| 249 | move_backward(pos, i); |
| 250 | hashes[pos] = hash; |
| 251 | entries[pos] = std::move(entry); |
| 252 | } |
| 253 | ++i; |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | void move_backward(const int& first, const int& last) { |
| 258 | // move elements backwards |
no test coverage detected