Various hash table improvements.
This commit is contained in:
parent
4c3755cdce
commit
983cc2c45c
@ -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)};
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user