| 2174 | |
| 2175 | template <bool ignoreNullKeys> |
| 2176 | void HashTable<ignoreNullKeys>::eraseWithHashes( |
| 2177 | folly::Range<char**> rows, |
| 2178 | uint64_t* hashes) { |
| 2179 | auto numRows = rows.size(); |
| 2180 | if (hashMode_ == HashMode::kArray) { |
| 2181 | for (auto i = 0; i < numRows; ++i) { |
| 2182 | DCHECK(hashes[i] < capacity_); |
| 2183 | table_[hashes[i]] = nullptr; |
| 2184 | } |
| 2185 | } else { |
| 2186 | if (hashMode_ == HashMode::kNormalizedKey) { |
| 2187 | for (auto i = 0; i < numRows; ++i) { |
| 2188 | hashes[i] = mixNormalizedKey(hashes[i], sizeBits_); |
| 2189 | } |
| 2190 | } |
| 2191 | |
| 2192 | ProbeState state; |
| 2193 | for (auto i = 0; i < numRows; ++i) { |
| 2194 | state.preProbe(*this, hashes[i], i); |
| 2195 | |
| 2196 | state.firstProbe<ProbeState::Operation::kErase>(*this, 0); |
| 2197 | state.fullProbe<ProbeState::Operation::kErase>( |
| 2198 | *this, |
| 2199 | 0, |
| 2200 | [&](const char* group, int32_t row) { return rows[row] == group; }, |
| 2201 | [&](int32_t /*index*/, int32_t /*row*/) { return nullptr; }, |
| 2202 | numTombstones_, |
| 2203 | false); |
| 2204 | } |
| 2205 | } |
| 2206 | numDistinct_ -= numRows; |
| 2207 | if (!otherTables_.empty()) { |
| 2208 | raw_vector<char*> containerRows; |
| 2209 | containerRows.resize(rows.size()); |
| 2210 | for (auto& other : otherTables_) { |
| 2211 | const auto numContainerRows = |
| 2212 | other->rows()->findRows(rows, containerRows.data()); |
| 2213 | other->rows()->eraseRows( |
| 2214 | folly::Range(containerRows.data(), numContainerRows)); |
| 2215 | } |
| 2216 | const auto numContainerRows = rows_->findRows(rows, containerRows.data()); |
| 2217 | rows_->eraseRows(folly::Range(containerRows.data(), numContainerRows)); |
| 2218 | } else { |
| 2219 | rows_->eraseRows(rows); |
| 2220 | } |
| 2221 | } |
| 2222 | |
| 2223 | template <bool ignoreNullKeys> |
| 2224 | void HashTable<ignoreNullKeys>::checkConsistency() const { |