AK: Store BinaryHeap key-value pairs together for efficient swaps

The 2 seperate key and value arrays are replaced with a single struct pair
array that allows for a 2x reduction in loads/stores during element swaps
in the common case of same-sized keys and values.
This commit is contained in:
Idan Horowitz 2021-03-13 23:28:30 +02:00 committed by Andreas Kling
parent 161b36bb09
commit 3c7aa56ae8

View file

@ -39,8 +39,10 @@ public:
{ {
VERIFY(size <= Capacity); VERIFY(size <= Capacity);
m_size = size; m_size = size;
__builtin_memcpy(m_keys, keys, size * sizeof(K)); for (size_t i = 0; i < size; i++) {
__builtin_memcpy(m_values, values, size * sizeof(V)); m_elements[i].key = keys[i];
m_elements[i].value = values[i];
}
for (ssize_t i = size / 2; i >= 0; i--) { for (ssize_t i = size / 2; i >= 0; i--) {
heapify_down(i); heapify_down(i);
@ -54,8 +56,8 @@ public:
{ {
VERIFY(m_size < Capacity); VERIFY(m_size < Capacity);
auto index = m_size++; auto index = m_size++;
m_keys[index] = key; m_elements[index].key = key;
m_values[index] = value; m_elements[index].value = value;
heapify_up(index); heapify_up(index);
} }
@ -63,22 +65,21 @@ public:
{ {
VERIFY(!is_empty()); VERIFY(!is_empty());
auto index = --m_size; auto index = --m_size;
swap(m_keys[0], m_keys[index]); swap(m_elements[0], m_elements[index]);
swap(m_values[0], m_values[index]);
heapify_down(0); heapify_down(0);
return m_values[index]; return m_elements[index].value;
} }
const V& peek_min() const const V& peek_min() const
{ {
VERIFY(!is_empty()); VERIFY(!is_empty());
return m_values[0]; return m_elements[0].value;
} }
const V& peek_min_key() const const K& peek_min_key() const
{ {
VERIFY(!is_empty()); VERIFY(!is_empty());
return m_keys[0]; return m_elements[0].key;
} }
void clear() void clear()
@ -94,13 +95,12 @@ private:
auto right_child = index * 2 + 2; auto right_child = index * 2 + 2;
auto min_child = left_child; auto min_child = left_child;
if (right_child < m_size && m_keys[right_child] < m_keys[min_child]) if (right_child < m_size && m_elements[right_child].key < m_elements[min_child].key)
min_child = right_child; min_child = right_child;
if (m_keys[index] <= m_keys[min_child]) if (m_elements[index].key <= m_elements[min_child].key)
break; break;
swap(m_keys[index], m_keys[min_child]); swap(m_elements[index], m_elements[min_child]);
swap(m_values[index], m_values[min_child]);
index = min_child; index = min_child;
} }
} }
@ -110,16 +110,17 @@ private:
while (index != 0) { while (index != 0) {
auto parent = (index - 1) / 2; auto parent = (index - 1) / 2;
if (m_keys[index] >= m_keys[parent]) if (m_elements[index].key >= m_elements[parent].key)
break; break;
swap(m_keys[index], m_keys[parent]); swap(m_elements[index], m_elements[parent]);
swap(m_values[index], m_values[parent]);
index = parent; index = parent;
} }
} }
K m_keys[Capacity]; struct {
V m_values[Capacity]; K key;
V value;
} m_elements[Capacity];
size_t m_size { 0 }; size_t m_size { 0 };
}; };