bl_generator.h (22415B)
1 #include <stdio.h> 2 #include <stdint.h> 3 #include <string.h> 4 5 #include <atomic> 6 #include <algorithm> 7 #include <cmath> 8 #include <map> 9 #include <mutex> 10 #include <random> 11 #include <string> 12 #include <thread> 13 #include <utility> 14 #include <vector> 15 16 // This is a stupid hash function finder that maps uint32_t inputs into a set of predefined consecutive IDs. 17 // 18 // Why stupid? Because it's a brute force approach and totally anti computer science - there is no theory behind 19 // this except for trying to find a constant that when multiplied with input generates the least number of 20 // collisions. 21 namespace StupidHash { 22 23 // Utility Functions 24 // ================= 25 26 static uint32_t alignUpToPowerOf2(uint32_t n) { 27 n -= 1; 28 29 n |= n >> 1; 30 n |= n >> 2; 31 n |= n >> 4; 32 n |= n >> 8; 33 n |= n >> 16; 34 35 return n + 1; 36 } 37 38 static uint32_t count_trailing_bits(uint32_t n) { 39 for (uint32_t i = 0; i < 32; i++) 40 if (n & (1u << i)) 41 return i; 42 return 32; 43 } 44 45 static size_t replace_in_string(std::string& str, const std::string& pattern, const std::string& replacement) { 46 size_t pos = 0; 47 size_t count = 0; 48 49 for (;;) { 50 pos = str.find(pattern, pos); 51 if (pos == std::string::npos) 52 return count; 53 str.replace(pos, pattern.length(), replacement); 54 pos += replacement.length(); 55 count++; 56 } 57 } 58 59 static inline uint32_t mul64Op1(uint32_t value, uint32_t adder, uint64_t multiplier, uint32_t shift) noexcept { 60 return uint32_t(((value + adder) * multiplier) >> shift); 61 } 62 63 static inline uint32_t mulOp1(uint32_t value, uint32_t multiplier, uint32_t shift) noexcept { 64 return (value * multiplier) >> shift; 65 } 66 67 static inline uint32_t mulOp2(uint32_t value, uint32_t multiplier, uint32_t shift) noexcept { 68 return ((value * multiplier + (13u << shift)) >> shift); 69 } 70 71 // [Pseudo] Random Number Generator 72 // ================================ 73 74 // A pseudo random number generator based on a paper by Sebastiano Vigna: 75 // http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf 76 class Random { 77 public: 78 // Constants suggested as `23/18/5`. 79 enum Steps : uint32_t { 80 kStep1_SHL = 23, 81 kStep2_SHR = 18, 82 kStep3_SHR = 5 83 }; 84 85 inline explicit Random(uint64_t seed = 0) noexcept { reset(seed); } 86 inline Random(const Random& other) noexcept = default; 87 88 inline void reset(uint64_t seed = 0) noexcept { 89 // The number is arbitrary, it means nothing. 90 constexpr uint64_t kZeroSeed = 0x1F0A2BE71D163FA0u; 91 92 // Generate the state data by using splitmix64. 93 for (uint32_t i = 0; i < 2; i++) { 94 seed += 0x9E3779B97F4A7C15u; 95 uint64_t x = seed; 96 x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9u; 97 x = (x ^ (x >> 27)) * 0x94D049BB133111EBu; 98 x = (x ^ (x >> 31)); 99 _state[i] = x != 0 ? x : kZeroSeed; 100 } 101 } 102 103 inline uint32_t next_uint32() noexcept { 104 return uint32_t(next_uint64() >> 32); 105 } 106 107 inline uint64_t next_uint64() noexcept { 108 uint64_t x = _state[0]; 109 uint64_t y = _state[1]; 110 111 x ^= x << kStep1_SHL; 112 y ^= y >> kStep3_SHR; 113 x ^= x >> kStep2_SHR; 114 x ^= y; 115 116 _state[0] = y; 117 _state[1] = x; 118 return x + y; 119 } 120 121 uint64_t _state[2]; 122 }; 123 124 // Bit Array 125 // ========= 126 127 class BitArray { 128 std::vector<size_t> _bits; 129 enum : size_t { kBitWordSize = sizeof(size_t) * 8u }; 130 131 public: 132 inline void resize(size_t size) { 133 size_t size_in_words = (size + kBitWordSize - 1) / kBitWordSize; 134 _bits.resize(size_in_words); 135 clear(); 136 } 137 138 inline void clear() { 139 std::fill(_bits.begin(), _bits.end(), size_t(0)); 140 } 141 142 inline bool has_bit(size_t bit_index) const { 143 size_t word_index = bit_index / kBitWordSize; 144 size_t mask = size_t(1) << (bit_index % kBitWordSize); 145 return (_bits[word_index] & mask) != 0; 146 } 147 148 inline void set_bit(size_t bit_index) { 149 size_t word_index = bit_index / kBitWordSize; 150 size_t mask = size_t(1) << (bit_index % kBitWordSize); 151 _bits[word_index] |= mask; 152 } 153 }; 154 155 // Hash Function 156 // ============= 157 158 class HashFunction { 159 public: 160 struct Param { 161 bool used; 162 uint32_t multiplier; 163 uint32_t shift; 164 std::vector<uint32_t> table; 165 }; 166 167 Param params[2]; 168 std::vector<std::pair<uint32_t, uint32_t>> remaining; 169 170 std::string body(const std::string& prototype, const std::string& input_value, const std::string& check_id_before, const std::string& check_id_after) const { 171 // Single hash table. 172 const char function_template_1[] = 173 "{\n" 174 " static const $TABLE_TYPE_A$ hash_table[$TABLE_SIZE_A$] = {\n" 175 "$TABLE_VALUES_A$\n" 176 " };\n" 177 "\n" 178 " uint32_t h1 = ($INPUT_VALUE$ * $HASH_MULTIPLIER_A$u) >> $HASH_SHIFT_A$u;\n" 179 " uint32_t i1 = hash_table[h1];\n" 180 " uint32_t index = 0xFFFFFFFFu;\n" 181 "\n" 182 " if ($CHECK_ID_BEFORE$i1$CHECK_ID_AFTER$ == $INPUT_VALUE$)\n" 183 " index = i1;\n" 184 "$REMAINING_CHECKS$" 185 "\n" 186 " return index;\n" 187 "}\n"; 188 189 // Single hash table, two hash functions. 190 const char function_template_2[] = 191 "{\n" 192 " static const $TABLE_TYPE_A$ hash_table[$TABLE_SIZE_A$] = {\n" 193 "$TABLE_VALUES_A$\n" 194 " };\n" 195 "\n" 196 " uint32_t h1 = ($INPUT_VALUE$ * $HASH_MULTIPLIER_A$u) >> $HASH_SHIFT_A$u;\n" 197 " uint32_t h2 = ($INPUT_VALUE$ * $HASH_MULTIPLIER_B$u) >> $HASH_SHIFT_B$u;\n" 198 "\n" 199 " uint32_t i1 = hash_table[h1];\n" 200 " uint32_t i2 = hash_table[h2];\n" 201 "\n" 202 " uint32_t index = 0xFFFFFFFFu;\n" 203 "\n" 204 " if ($CHECK_ID_BEFORE$i1$CHECK_ID_AFTER$ == $INPUT_VALUE$)\n" 205 " index = i1;\n" 206 "\n" 207 " if ($CHECK_ID_BEFORE$i2$CHECK_ID_AFTER$ == $INPUT_VALUE$)\n" 208 " index = i2;\n" 209 "$REMAINING_CHECKS$" 210 "\n" 211 " return index;\n" 212 "}\n"; 213 214 // Two hash tables, two hash functions. 215 const char function_template_3[] = 216 "{\n" 217 " static const $TABLE_TYPE_A$ hashTable1[$TABLE_SIZE_A$] = {\n" 218 "$TABLE_VALUES_A$\n" 219 " };\n" 220 "\n" 221 " static const $TABLE_TYPE_B$ hashTable2[$TABLE_SIZE_B$] = {\n" 222 "$TABLE_VALUES_B$\n" 223 " };\n" 224 "\n" 225 " uint32_t h1 = ($INPUT_VALUE$ * $HASH_MULTIPLIER_A$u) >> $HASH_SHIFT_A$u;\n" 226 " uint32_t h2 = ($INPUT_VALUE$ * $HASH_MULTIPLIER_B$u) >> $HASH_SHIFT_B$u;\n" 227 "\n" 228 " uint32_t i1 = hashTable1[h1];\n" 229 " uint32_t i2 = hashTable2[h2];\n" 230 "\n" 231 " uint32_t index = 0xFFFFFFFFu;\n" 232 "\n" 233 " if ($CHECK_ID_BEFORE$i1$CHECK_ID_AFTER$ == $INPUT_VALUE$)\n" 234 " index = i1;\n" 235 "\n" 236 " if ($CHECK_ID_BEFORE$i2$CHECK_ID_AFTER$ == $INPUT_VALUE$)\n" 237 " index = i2;\n" 238 "$REMAINING_CHECKS$" 239 "\n" 240 " return index;\n" 241 "}\n"; 242 243 std::string body; 244 245 auto format_table = [](const std::vector<uint32_t>& t) { 246 std::string s(" "); 247 for (size_t i = 0; i < t.size(); i++) { 248 if (i != 0) { 249 if ((i % 24) == 0) 250 s.append(",\n "); 251 else 252 s.append(", "); 253 } 254 s.append(std::to_string(t[i] != 0xFFFFFFFFu ? t[i] : uint32_t(0u))); 255 } 256 return s; 257 }; 258 259 auto value_type_of_table = [](const std::vector<uint32_t>& t) { 260 uint32_t greatest = 0; 261 for (size_t i = 0; i < t.size(); i++) { 262 if (t[i] == 0xFFFFFFFFu) 263 continue; 264 greatest = std::max(greatest, t[i]); 265 } 266 267 if (greatest > 65535u) 268 return "uint32_t"; 269 else if (greatest > 255u) 270 return "uint16_t"; 271 else 272 return "uint8_t"; 273 }; 274 275 uint32_t bitMask0 = (1u << (32u - params[0].shift)) - 1u; 276 uint32_t bitMask1 = (1u << (32u - params[1].shift)) - 1u; 277 278 if (params[1].used) 279 body = params[1].table.size() == 0 ? function_template_2 : function_template_3; 280 else 281 body = function_template_1; 282 283 std::string remaining_checks; 284 if (!remaining.empty()) { 285 for (auto p : remaining) { 286 std::string condition("\n" 287 " if ($INPUT_VALUE$ == $KEY$)\n" 288 " index = $KEY_VALUE$;\n"); 289 replace_in_string(condition, std::string("$INPUT_VALUE$"), input_value); 290 replace_in_string(condition, std::string("$KEY$"), std::to_string(p.first)); 291 replace_in_string(condition, std::string("$KEY_VALUE$"), std::to_string(p.second)); 292 remaining_checks += condition; 293 } 294 } 295 296 replace_in_string(body, std::string("$INPUT_VALUE$"), input_value); 297 replace_in_string(body, std::string("$CHECK_ID_BEFORE$"), check_id_before); 298 replace_in_string(body, std::string("$CHECK_ID_AFTER$"), check_id_after); 299 300 replace_in_string(body, std::string("$HASH_MULTIPLIER_A$"), std::to_string(params[0].multiplier)); 301 replace_in_string(body, std::string("$HASH_MULTIPLIER_B$"), std::to_string(params[1].multiplier)); 302 replace_in_string(body, std::string("$HASH_SHIFT_A$"), std::to_string(params[0].shift)); 303 replace_in_string(body, std::string("$HASH_SHIFT_B$"), std::to_string(params[1].shift)); 304 replace_in_string(body, std::string("$HASH_MASK_A$"), std::to_string(bitMask0)); 305 replace_in_string(body, std::string("$HASH_MASK_B$"), std::to_string(bitMask1)); 306 replace_in_string(body, std::string("$TABLE_TYPE_A$"), value_type_of_table(params[0].table)); 307 replace_in_string(body, std::string("$TABLE_TYPE_B$"), value_type_of_table(params[1].table)); 308 replace_in_string(body, std::string("$TABLE_SIZE_A$"), std::to_string(params[0].table.size())); 309 replace_in_string(body, std::string("$TABLE_SIZE_B$"), std::to_string(params[1].table.size())); 310 replace_in_string(body, std::string("$TABLE_VALUES_A$"), format_table(params[0].table)); 311 replace_in_string(body, std::string("$TABLE_VALUES_B$"), format_table(params[1].table)); 312 replace_in_string(body, std::string("$REMAINING_CHECKS$"), remaining_checks); 313 body = std::string(prototype) + " " + body; 314 315 return body; 316 } 317 }; 318 319 template<typename Lambda> 320 static void run_async(Lambda&& fn, size_t thread_count) { 321 std::vector<std::thread> threads; 322 323 for (size_t thread_id = 0; thread_id < thread_count; thread_id++) 324 threads.push_back(std::thread(fn)); 325 326 for (std::thread& thread : threads) 327 thread.join(); 328 } 329 330 // Hash Function Finder 331 // -------------------- 332 333 class Finder { 334 public: 335 const uint32_t* _values {}; 336 uint32_t _size {}; 337 HashFunction _hf {}; 338 339 Finder(const uint32_t* values, uint32_t size) { 340 _values = values; 341 _size = size; 342 } 343 /* 344 void try_another(uint32_t bucketCount1) { 345 BitArray occupied1; 346 BitArray occupied2; 347 348 std::vector<uint32_t> hits; 349 350 occupied1.resize(bucketCount1); 351 occupied2.resize(bucketCount1); 352 hits.resize(bucketCount1); 353 354 const uint32_t* values = _values; 355 uint32_t size = _size; 356 uint32_t localBestCollisions1 = 0xFFFFFFFFu; 357 uint32_t localBestCollisions2 = 0xFFFFFFFFu; 358 uint32_t best_score = 0xFFFFFFFFu; 359 360 uint32_t shift1 = 64 - count_trailing_bits(bucketCount1); 361 Random r; 362 363 uint64_t m1_base = r.next_uint64(); 364 uint32_t attempt = 0; 365 366 for (;;) { 367 uint64_t bestM1 = m1_base; 368 369 uint64_t pattern1; 370 uint64_t pattern2; 371 372 if (attempt == 0) { 373 pattern1 = 0x1; 374 pattern2 = 0x1; 375 } 376 else if (attempt % 16 == 0) { 377 pattern1 = r.next_uint64() & 0x00FF00FF00FF00FF; 378 pattern2 = r.next_uint64() & 0xFF00FF00FF00FF00; 379 } 380 else { 381 pattern1 = r.next_uint64() & 0xF; 382 pattern2 = r.next_uint64() & 0xF000000000000000; 383 } 384 385 for (uint32_t a = 0; a < 100; a++) { 386 for (uint32_t bit1 = 0; bit1 < 64; bit1++) { 387 for (uint32_t bit2 = 0; bit2 < 64; bit2++) { 388 uint64_t m1 = m1_base ^ (uint64_t(pattern1) << bit1) 389 ^ (uint64_t(pattern2) >> bit2); 390 uint32_t collisions = 0; 391 uint32_t moreThan2Collisions = 0; 392 393 occupied1.clear(); 394 occupied2.clear(); 395 uint32_t score = uint32_t(_size); 396 397 for (size_t i = 0; i < size; i++) { 398 uint32_t index = mul64Op1(values[i], 0, m1, shift1); 399 if (occupied1.has_bit(index)) { 400 collisions++; 401 moreThan2Collisions += occupied2.has_bit(index); 402 occupied2.set_bit(index); 403 if (hits[index] > 1) 404 score += 1000; 405 else 406 score += 1; 407 hits[index]++; 408 } 409 else { 410 occupied1.set_bit(index); 411 hits[index] = 1; 412 score--; 413 } 414 } 415 416 if (score < best_score) { 417 localBestCollisions1 = collisions; 418 419 if (score < best_score) 420 best_score = score; 421 422 bestM1 = m1; 423 attempt = 0; 424 425 _hf.params[0].used = true; 426 _hf.params[0].multiplier = m1; 427 _hf.params[0].shift = shift1; 428 429 // best_collisions = collisions; 430 printf(" Found (mul=0x%08llX) (collisions=%u) %s\n", (unsigned long long)bestM1, collisions, moreThan2Collisions ? "" : "(max 2 collisions per bucket)"); 431 432 if (collisions == 0) { 433 return; 434 } 435 } 436 } 437 } 438 } 439 440 if (m1_base == bestM1) { 441 // m1_base += r.next_uint64(); 442 if (++attempt > 10000000) { 443 printf("Maximum attempts reached\n"); 444 return; 445 } 446 } 447 else { 448 m1_base = bestM1; 449 } 450 } 451 } 452 */ 453 bool find_hash_function(uint32_t bucketCount1) { 454 constexpr uint32_t thread_count = 30; 455 constexpr uint32_t mStep = 0x00100000u; 456 457 uint32_t mGlobal = 0; 458 uint32_t mMaxGlobal = 0x7FFFFFFFu; 459 460 uint32_t best_collisions = 0xFFFFFFFFu; 461 uint32_t bucketCount2 = 0; 462 std::mutex mutex; 463 464 auto stop_workers = [&]() { mGlobal = 0xFFFFFFFFu; }; 465 466 auto next_multiplier_base = [&]() -> uint32_t { 467 std::lock_guard<std::mutex> guard(mutex); 468 if (mGlobal == 0xFFFFFFFFu) 469 return 0xFFFFFFFFu; 470 471 uint32_t m1_base = mGlobal; 472 mGlobal += mStep; 473 if (mGlobal >= mMaxGlobal) 474 mGlobal = 0xFFFFFFFFu; 475 476 return m1_base; 477 }; 478 479 auto reset_multiplier = [&](uint32_t bucket_count, bool guess_max_global = false) { 480 mGlobal = 0; 481 uint32_t t = count_trailing_bits(bucket_count); 482 if (t <= 5 || !guess_max_global) 483 mMaxGlobal = 0x7FFFFFFFu; 484 else 485 mMaxGlobal = 0xFFFFFFFFu >> (t - 5); 486 }; 487 488 printf("Finder::find_hash_function() - Trying to find a first hash function for %u values [%u buckets]\n", _size, bucketCount1); 489 best_collisions = 0xFFFFFFFFu; 490 reset_multiplier(bucketCount1, true); 491 492 uint32_t shift1 = 32 - count_trailing_bits(bucketCount1); 493 494 run_async([&]() { 495 BitArray occupied1; 496 BitArray occupied2; 497 498 occupied1.resize(bucketCount1); 499 occupied2.resize(bucketCount1); 500 501 const uint32_t* values = _values; 502 uint32_t size = _size; 503 uint32_t localBestCollisions1 = 0xFFFFFFFFu; 504 uint32_t localBestCollisions2 = 0xFFFFFFFFu; 505 506 for (;;) { 507 uint32_t m1_base = next_multiplier_base(); 508 if (m1_base == 0xFFFFFFFFu) 509 return; 510 511 for (uint32_t m1_index = 0; m1_index < mStep; m1_index++) { 512 uint32_t m1 = m1_base + m1_index; 513 uint32_t collisions = 0; 514 uint32_t moreThan2Collisions = 0; 515 516 occupied1.clear(); 517 occupied2.clear(); 518 519 for (size_t i = 0; i < size; i++) { 520 uint32_t index = mulOp1(values[i], m1, shift1); 521 if (occupied1.has_bit(index)) { 522 collisions++; 523 moreThan2Collisions += occupied2.has_bit(index); 524 occupied2.set_bit(index); 525 } 526 occupied1.set_bit(index); 527 } 528 529 if (collisions < localBestCollisions2 && moreThan2Collisions == 0) { 530 std::lock_guard<std::mutex> guard(mutex); 531 localBestCollisions2 = collisions; 532 printf(" Found 0x%08X (collisions=%u) - no third collision\n", m1, collisions); 533 } 534 535 if (collisions < localBestCollisions1) { 536 std::lock_guard<std::mutex> guard(mutex); 537 localBestCollisions1 = best_collisions; 538 539 if (collisions < best_collisions) { 540 _hf.params[0].used = true; 541 _hf.params[0].multiplier = m1; 542 _hf.params[0].shift = shift1; 543 544 best_collisions = collisions; 545 printf(" Found 0x%08X (collisions=%u)\n", m1, collisions); 546 547 if (collisions == 0) 548 stop_workers(); 549 } 550 } 551 } 552 } 553 }, thread_count); 554 555 printf("Finder::find_hash_function() - Found a hash function with %u collision(s)\n", best_collisions); 556 std::vector<std::pair<uint32_t, uint32_t>> remaining_pairs; 557 std::vector<uint32_t> remaining_values; 558 559 BitArray occupied1; 560 occupied1.resize(bucketCount1); 561 562 { 563 for (uint32_t i = 0; i < _size; i++) { 564 uint32_t index = (_values[i] * _hf.params[0].multiplier) >> _hf.params[0].shift; 565 if (occupied1.has_bit(index)) { 566 remaining_pairs.push_back(std::pair<uint32_t, uint32_t>(_values[i], i)); 567 remaining_values.push_back(_values[i]); 568 } 569 else { 570 occupied1.set_bit(index); 571 } 572 } 573 } 574 575 // Try to find another hash function that would use the same table. 576 bool m2_found = false; 577 bool m2_same_bucket_table = false; 578 579 // Don't create a secondary hash table for 1 value. 580 if (remaining_values.size() == 1) { 581 _hf.remaining = std::move(remaining_pairs); 582 m2_found = true; 583 } 584 585 if (!m2_found && best_collisions > 0) { 586 printf("Finder::find_hash_function() - Trying to find a second hash function using the same bucket list [%u buckets]\n", bucketCount1); 587 588 reset_multiplier(bucketCount1); 589 run_async([&]() { 590 const uint32_t* values_data = remaining_values.data(); 591 size_t values_count = remaining_values.size(); 592 593 BitArray occupied; 594 occupied.resize(bucketCount1); 595 596 for (;;) { 597 uint32_t m2_base = next_multiplier_base(); 598 if (m2_base == 0xFFFFFFFFu) 599 return; 600 601 for (uint32_t m2_index = 0; m2_index < mStep; m2_index++) { 602 bool found = true; 603 uint32_t m2 = m2_base + m2_index; 604 occupied.clear(); 605 606 for (size_t i = 0; i < values_count; i++) { 607 uint32_t index = mulOp2(values_data[i], m2, shift1); 608 if (occupied1.has_bit(index) || occupied.has_bit(index)) { 609 found = false; 610 break; 611 } 612 occupied.set_bit(index); 613 } 614 615 if (found) { 616 std::lock_guard<std::mutex> guard(mutex); 617 if (!m2_found) { 618 printf("FOUND\n"); 619 m2_found = true; 620 m2_same_bucket_table = true; 621 stop_workers(); 622 623 _hf.params[1].used = true; 624 _hf.params[1].multiplier = m2; 625 _hf.params[1].shift = shift1; 626 break; 627 } 628 } 629 } 630 } 631 }, thread_count); 632 } 633 634 // Reset the global multiplier - we want to start from zero again, to find the second hash function M. 635 if (!m2_found && best_collisions > 0) { 636 bucketCount2 = alignUpToPowerOf2(best_collisions); 637 for (;;) { 638 printf("Finder::find_hash_function() - Trying to find a second hash function [%u buckets]\n", bucketCount2); 639 640 reset_multiplier(bucketCount2); 641 uint32_t shift2 = 32 - count_trailing_bits(bucketCount2); 642 643 run_async([&]() { 644 const uint32_t* values_data = remaining_values.data(); 645 size_t values_count = remaining_values.size(); 646 647 BitArray occupied; 648 occupied.resize(bucketCount2); 649 650 for (;;) { 651 uint32_t m2_base = next_multiplier_base(); 652 if (m2_base == 0xFFFFFFFFu) 653 return; 654 655 for (uint32_t m2_index = 0; m2_index < mStep; m2_index++) { 656 bool found = true; 657 uint32_t m2 = m2_base + m2_index; 658 occupied.clear(); 659 660 for (size_t i = 0; i < values_count; i++) { 661 uint32_t index = mulOp2(values_data[i], m2, shift2); 662 if (occupied.has_bit(index)) { 663 found = false; 664 break; 665 } 666 occupied.set_bit(index); 667 } 668 669 if (found) { 670 std::lock_guard<std::mutex> guard(mutex); 671 if (!m2_found) { 672 m2_found = true; 673 stop_workers(); 674 675 _hf.params[1].used = true; 676 _hf.params[1].multiplier = m2; 677 _hf.params[1].shift = shift2; 678 break; 679 } 680 } 681 } 682 } 683 }, thread_count); 684 685 if (m2_found) 686 break; 687 bucketCount2 *= 2u; 688 } 689 } 690 691 // Build tables. 692 { 693 BitArray occupied; 694 std::vector<uint32_t> remaining_indexes; 695 696 occupied.resize(bucketCount1); 697 _hf.params[0].table.resize(bucketCount1, uint32_t(0xFFFFFFFFu)); 698 _hf.params[1].table.resize(bucketCount2, uint32_t(0xFFFFFFFFu)); 699 700 { 701 std::vector<uint32_t>& table = _hf.params[0].table; 702 for (uint32_t i = 0; i < _size; i++) { 703 uint32_t index1 = (_values[i] * _hf.params[0].multiplier) >> _hf.params[0].shift; 704 if (!occupied.has_bit(index1)) { 705 table[index1] = i; 706 occupied.set_bit(index1); 707 } 708 else { 709 remaining_indexes.push_back(i); 710 } 711 } 712 } 713 714 if (m2_same_bucket_table || bucketCount2) { 715 std::vector<uint32_t>& table = m2_same_bucket_table ? _hf.params[0].table : _hf.params[1].table; 716 for (uint32_t i : remaining_indexes) { 717 uint32_t index2 = (_values[i] * _hf.params[1].multiplier) >> _hf.params[1].shift; 718 if (table[index2] == 0xFFFFFFFFu) 719 table[index2] = i; 720 } 721 } 722 } 723 724 return best_collisions != 0xFFFFFFFFu; 725 } 726 727 bool find_solution() { 728 uint32_t bucket_count = alignUpToPowerOf2(_size); 729 for (;;) { 730 if (find_hash_function(bucket_count)) 731 return true; 732 733 bucket_count <<= 1; 734 if (bucket_count > _size * 8) 735 return false; 736 } 737 } 738 }; 739 740 } // {StupidHash}