Potential efficiency improvement to std::make_heap and std::pop_heap functions.
Vamsi Krishna Reddy Satti
vamsi3@outlook.com
Sat Jul 25 05:52:55 GMT 2020
Hello!
I was having a look over the implementation of std::make_heap and std::pop_heap in "include/bits/stl_heap.h" on the latest source. I suspect that the implementation is inefficient and possibly does some unnecessary operations.
Most of my concern comes from the __adjust_heap function which is used in common by above two functions. From my understanding, __adjust_heap just needs to perform the textbook shift-down or heapify-down operation for correctness of std::make_heap and std::pop_heap functions.
template<typename _RandomAccessIterator, typename _Distance,
typename _Tp, typename _Compare>
_GLIBCXX20_CONSTEXPR
void
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
_Distance __len, _Tp __value, _Compare __comp)
{
const _Distance __topIndex = __holeIndex;
_Distance __secondChild = __holeIndex;
while (__secondChild < (__len - 1) / 2)
{
__secondChild = 2 * (__secondChild + 1);
if (__comp(__first + __secondChild,
__first + (__secondChild - 1)))
__secondChild--;
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
__holeIndex = __secondChild;
}
if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
{
__secondChild = 2 * (__secondChild + 1);
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
+ (__secondChild - 1)));
__holeIndex = __secondChild - 1;
}
__decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp)))
__cmp(_GLIBCXX_MOVE(__comp));
std::__push_heap(__first, __holeIndex, __topIndex,
_GLIBCXX_MOVE(__value), __cmp);
}
But the __adjust_heap function right now takes the __holeIndex all the way down to a leaf unconditionally. And then calls the __push_heap function which performs the textbook shift-up or heapify-up operation.
I believe that instead, we should add checks to compare (using __comp) the value at index __secondChild and __value to determine if we should stop proceeding further. In that way, a call to push_heap at the end is also not required and instead we just assign __value to the iterator at index __secondChild in the container.
P.S. Sorry if this is not the right place to ask this question. Please let me know if I'm mistaken, since I wanted to clarify before filing the improvement as a bug.
More information about the Libstdc++
mailing list