Various hash table improvements.

This commit is contained in:
levlam 2022-02-19 11:34:43 +03:00
parent 4c3755cdce
commit 983cc2c45c
3 changed files with 37 additions and 29 deletions

View File

@ -93,7 +93,7 @@ struct MaskNeon {
auto eq_mask = vceqq_u8(input_mask, needle_mask); auto eq_mask = vceqq_u8(input_mask, needle_mask);
uint16x8_t MASK = vdupq_n_u16(0x180); uint16x8_t MASK = vdupq_n_u16(0x180);
uint16x8_t a_masked = vandq_u16(vreinterpretq_u16_u8(eq_mask), MASK); uint16x8_t a_masked = vandq_u16(vreinterpretq_u16_u8(eq_mask), MASK);
const int16_t __attribute__((aligned(16))) SHIFT_ARR[8] = {-7, -5, -3, -1, 1, 3, 5, 7}; const int16 __attribute__((aligned(16))) SHIFT_ARR[8] = {-7, -5, -3, -1, 1, 3, 5, 7};
int16x8_t SHIFT = vld1q_s16(SHIFT_ARR); int16x8_t SHIFT = vld1q_s16(SHIFT_ARR);
uint16x8_t a_shifted = vshlq_u16(a_masked, SHIFT); uint16x8_t a_shifted = vshlq_u16(a_masked, SHIFT);
return {vaddvq_u16(a_shifted) & ((1u << 14) - 1)}; return {vaddvq_u16(a_shifted) & ((1u << 14) - 1)};

View File

@ -51,11 +51,8 @@ struct MapNode {
new (&second) ValueT(std::move(value)); new (&second) ValueT(std::move(value));
DCHECK(!empty()); DCHECK(!empty());
} }
~MapNode() { MapNode(const MapNode &other) = delete;
if (!empty()) { MapNode &operator=(const MapNode &other) = delete;
second.~ValueT();
}
}
MapNode(MapNode &&other) noexcept { MapNode(MapNode &&other) noexcept {
*this = std::move(other); *this = std::move(other);
} }
@ -68,6 +65,11 @@ struct MapNode {
other.second.~ValueT(); other.second.~ValueT();
return *this; return *this;
} }
~MapNode() {
if (!empty()) {
second.~ValueT();
}
}
bool empty() const { bool empty() const {
return is_key_empty(key()); return is_key_empty(key());
@ -109,6 +111,8 @@ struct SetNode {
SetNode() = default; SetNode() = default;
explicit SetNode(KeyT key) : first(std::move(key)) { explicit SetNode(KeyT key) : first(std::move(key)) {
} }
SetNode(const SetNode &other) = delete;
SetNode &operator=(const SetNode &other) = delete;
SetNode(SetNode &&other) noexcept { SetNode(SetNode &&other) noexcept {
*this = std::move(other); *this = std::move(other);
} }
@ -119,6 +123,7 @@ struct SetNode {
other.first = KeyT{}; other.first = KeyT{};
return *this; return *this;
} }
~SetNode() = default;
bool empty() const { bool empty() const {
return is_key_empty(key()); return is_key_empty(key());
@ -126,7 +131,7 @@ struct SetNode {
void clear() { void clear() {
first = KeyT(); first = KeyT();
CHECK(empty()); DCHECK(empty());
} }
void emplace(KeyT key) { void emplace(KeyT key) {
@ -240,16 +245,17 @@ class FlatHashTable {
FlatHashTable(std::initializer_list<Node> nodes) { FlatHashTable(std::initializer_list<Node> nodes) {
reserve(nodes.size()); reserve(nodes.size());
for (auto &node : nodes) { for (auto &new_node : nodes) {
CHECK(!node.empty()); CHECK(!new_node.empty());
auto bucket = calc_bucket(node.first); auto bucket = calc_bucket(new_node.first);
while (true) { while (true) {
if (nodes_[bucket].key() == node.first) { auto &node = nodes_[bucket];
nodes_[bucket].second = node.second; if (node.key() == new_node.first) {
node.second = new_node.second;
break; break;
} }
if (nodes_[bucket].empty()) { if (node.empty()) {
nodes_[bucket].emplace(node.first, node.second); node.emplace(new_node.first, new_node.second);
used_nodes_++; used_nodes_++;
break; break;
} }
@ -289,10 +295,11 @@ class FlatHashTable {
} }
auto bucket = calc_bucket(key); auto bucket = calc_bucket(key);
while (true) { while (true) {
if (EqT()(nodes_[bucket].key(), key)) { auto &node = nodes_[bucket];
return Iterator{nodes_.begin() + bucket, this}; if (EqT()(node.key(), key)) {
return Iterator{&node, this};
} }
if (nodes_[bucket].empty()) { if (node.empty()) {
return end(); return end();
} }
next_bucket(bucket); next_bucket(bucket);
@ -346,13 +353,14 @@ class FlatHashTable {
CHECK(!is_key_empty(key)); CHECK(!is_key_empty(key));
auto bucket = calc_bucket(key); auto bucket = calc_bucket(key);
while (true) { while (true) {
if (EqT()(nodes_[bucket].key(), key)) { auto &node = nodes_[bucket];
return {Iterator{nodes_.begin() + bucket, this}, false}; if (EqT()(node.key(), key)) {
return {Iterator{&node, this}, false};
} }
if (nodes_[bucket].empty()) { if (node.empty()) {
nodes_[bucket].emplace(std::move(key), std::forward<ArgsT>(args)...); node.emplace(std::move(key), std::forward<ArgsT>(args)...);
used_nodes_++; used_nodes_++;
return {Iterator{nodes_.begin() + bucket, this}, true}; return {Iterator{&node, this}, true};
} }
next_bucket(bucket); next_bucket(bucket);
} }
@ -400,7 +408,7 @@ class FlatHashTable {
template <class F> template <class F>
void remove_if(F &&f) { void remove_if(F &&f) {
auto it = nodes_.begin(); auto it = begin().it_;
while (it != nodes_.end() && !it->empty()) { while (it != nodes_.end() && !it->empty()) {
++it; ++it;
} }
@ -473,15 +481,15 @@ class FlatHashTable {
fixed_vector<Node> old_nodes(new_size); fixed_vector<Node> old_nodes(new_size);
std::swap(old_nodes, nodes_); std::swap(old_nodes, nodes_);
for (auto &node : old_nodes) { for (auto &old_node : old_nodes) {
if (node.empty()) { if (old_node.empty()) {
continue; continue;
} }
size_t bucket = calc_bucket(node.key()); size_t bucket = calc_bucket(old_node.key());
while (!nodes_[bucket].empty()) { while (!nodes_[bucket].empty()) {
next_bucket(bucket); next_bucket(bucket);
} }
nodes_[bucket] = std::move(node); nodes_[bucket] = std::move(old_node);
} }
} }

View File

@ -525,8 +525,8 @@ static void BM_cache_miss(benchmark::State &state) {
} }
} }
static uint64_t equal_mask_slow(td::uint8 *bytes, td::uint8 needle) { static td::uint64 equal_mask_slow(td::uint8 *bytes, td::uint8 needle) {
uint64_t mask = 0; td::uint64 mask = 0;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
mask |= (bytes[i] == needle) << i; mask |= (bytes[i] == needle) << i;
} }