Deque rotate on current node
François Dumont
frs.dumont@gmail.com
Tue Jun 30 20:33:47 GMT 2020
Hi
Any feedback regarding this patch ?
François
On 17/01/20 6:27 pm, François Dumont wrote:
> On 1/17/20 11:01 AM, Jonathan Wakely wrote:
>> On 20/05/19 07:39 +0200, François Dumont wrote:
>>> Hi
>>>
>>> std::deque is supposed to be like a double-queue that you can
>>> attack from front and back. But currrently its implementation makes
>>> it behave differently when starting from a fresh deque. If push_back
>>> then all goes well, it is copy/move to the current internal 'node'.
>>> If push_front then a new 'node' is created and on next pop_back the
>>> initial node will be deallocated without having ever be used.
>>>
>>> This patch changes this behavior. As long as deque is empty we can
>>> play with its state to make it push_back- or push_front-ready. It
>>> will also benefit to the usage of deque in the std::stack.
>>>
>>> More generally it could really improve scenario in which deque is
>>> used as queue of elements exchanged between different threads. As
>>> you need to make sure that consumers are faster than producers then
>>> your deque should remain empty most of the time and so this proposed
>>> patch should avoid nodes to be allocated/deallocated all the time.
>>
>> This benefits the case where you always push at the same end. But with
>> your patch if I do push_front then push_back,
>> we still allocate a second node even though the first one is nearly
>> empty.
>>
>> Would it be better to point into the middle of the node, not right at
>> the end or right at the beginning?
>
> That's purely empirical but I tend to think that when you need
> push_back only you go with std::vector or std::deque, when you need
> push_front only you go with std::deque and when you need both you go
> with std::list. At least std::stack and std::queue are following this
> axiom per default.
>
> The tradeoff you are describing is not worst than current situation
> where you will eventually deallocate a node that you haven't used at all.
>
> Are you proposing to just init in the middle or also to always reset
> when empty in the middle ? If we also reset in the middle those doing
> always push_back or push_front will live with half a node unreachable.
>
> We could just init in the middle however. It would be a different
> patch as this one is focus on just recycling the last empty node.
>
> I consider adding a flag keeping the info that the deque is
> push_back|push_front|both-oriented updated based on its usage but I
> doubt it would worth it. Moreover it would introduce an abi breakage.
>
>>
>>> * include/bits/deque.tcc (deque<>::_M_push_back_aux):
>>> Rotate on current node if deque is empty.
>>> (deue<>::_M_push_front_aux): Likewise.
>>>
>>> Tested under Linux x86_64, ok to commit ?
>>>
>>> François
>>>
>>
>>> diff --git a/libstdc++-v3/include/bits/deque.tcc
>>> b/libstdc++-v3/include/bits/deque.tcc
>>> index 2053afe1d69..245e3e712d8 100644
>>> --- a/libstdc++-v3/include/bits/deque.tcc
>>> +++ b/libstdc++-v3/include/bits/deque.tcc
>>> @@ -507,6 +507,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>> _M_push_back_aux(const value_type& __t)
>>> #endif
>>> {
>>> + if (empty())
>>> + {
>>> + // Move iterators to point to the current node begin.
>>> + this->_M_impl._M_start._M_cur =
>>> this->_M_impl._M_start._M_first;
>>> + this->_M_impl._M_finish._M_cur =
>>> this->_M_impl._M_finish._M_first;
>>> +#if __cplusplus >= 201103L
>>> + emplace_back(std::forward<_Args>(__args)...);
>>> +#else
>>> + push_back(__t);
>>> +#endif
>>> + return;
>>> + }
>>> +
>>> if (size() == max_size())
>>> __throw_length_error(
>>> __N("cannot create std::deque larger than max_size()"));
>>> @@ -546,6 +559,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>> _M_push_front_aux(const value_type& __t)
>>> #endif
>>> {
>>> + if (empty())
>>> + {
>>> + // Move iterators to point to the current node end.
>>> + this->_M_impl._M_finish._M_cur =
>>> this->_M_impl._M_finish._M_last - 1;
>>> + this->_M_impl._M_start._M_cur =
>>> this->_M_impl._M_start._M_last - 1;
>>> +#if __cplusplus >= 201103L
>>> + emplace_front(std::forward<_Args>(__args)...);
>>> +#else
>>> + push_front(__t);
>>> +#endif
>>> + return;
>>> + }
>>> +
>>> if (size() == max_size())
>>> __throw_length_error(
>>> __N("cannot create std::deque larger than max_size()"));
>>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: deque_reuse_node.patch
Type: text/x-patch
Size: 1422 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20200630/4413b19d/attachment.bin>
More information about the Libstdc++
mailing list