| 1509 | |
| 1510 | template <bool ignoreNullKeys> |
| 1511 | void HashTable<ignoreNullKeys>::enableRangeWhereCan( |
| 1512 | const std::vector<uint64_t>& rangeSizes, |
| 1513 | const std::vector<uint64_t>& distinctSizes, |
| 1514 | std::vector<bool>& useRange) { |
| 1515 | // Sort non-range keys by the cardinality increase going from distinct to |
| 1516 | // range. |
| 1517 | std::vector<size_t> indices(rangeSizes.size()); |
| 1518 | std::vector<uint64_t> rangeMultipliers( |
| 1519 | rangeSizes.size(), std::numeric_limits<uint64_t>::max()); |
| 1520 | for (auto i = 0; i < rangeSizes.size(); i++) { |
| 1521 | indices[i] = i; |
| 1522 | if (!useRange[i]) { |
| 1523 | rangeMultipliers[i] = rangeSizes[i] / distinctSizes[i]; |
| 1524 | } |
| 1525 | } |
| 1526 | |
| 1527 | boost::sort::pdqsort(indices.begin(), indices.end(), [&](auto i, auto j) { |
| 1528 | return rangeMultipliers[i] < rangeMultipliers[j]; |
| 1529 | }); |
| 1530 | |
| 1531 | auto calculateNewMultiplier = [&]() { |
| 1532 | uint64_t multiplier = 1; |
| 1533 | for (auto i = 0; i < rangeSizes.size(); ++i) { |
| 1534 | // NOLINT |
| 1535 | multiplier = |
| 1536 | safeMul(multiplier, useRange[i] ? rangeSizes[i] : distinctSizes[i]); |
| 1537 | } |
| 1538 | return multiplier; |
| 1539 | }; |
| 1540 | |
| 1541 | // Switch distinct to range if the cardinality increase does not overflow |
| 1542 | // 64 bits. |
| 1543 | for (auto i = 0; i < rangeSizes.size(); ++i) { |
| 1544 | if (!useRange[indices[i]]) { |
| 1545 | useRange[indices[i]] = true; |
| 1546 | auto newProduct = calculateNewMultiplier(); |
| 1547 | if (newProduct == VectorHasher::kRangeTooLarge) { |
| 1548 | useRange[indices[i]] = false; |
| 1549 | return; |
| 1550 | } |
| 1551 | } |
| 1552 | } |
| 1553 | } |
| 1554 | |
| 1555 | template <bool ignoreNullKeys> |
| 1556 | uint64_t HashTable<ignoreNullKeys>::setHasherMode( |