This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [libstdc++/61347] std::distance(list.first(),list.end()) in O(1)
- From: Jonathan Wakely <jwakely at redhat dot com>
- To: Marc Glisse <marc dot glisse at inria dot fr>
- Cc: libstdc++ at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Mon, 13 Apr 2015 16:10:57 +0100
- Subject: Re: [libstdc++/61347] std::distance(list.first(),list.end()) in O(1)
- Authentication-results: sourceware.org; auth=none
- References: <alpine dot DEB dot 2 dot 11 dot 1504131033550 dot 13447 at stedding dot saclay dot inria dot fr> <20150413134025 dot GI9755 at redhat dot com> <alpine dot DEB dot 2 dot 11 dot 1504131549210 dot 13447 at stedding dot saclay dot inria dot fr>
On 13/04/15 16:14 +0200, Marc Glisse wrote:
On Mon, 13 Apr 2015, Jonathan Wakely wrote:
On 13/04/15 13:42 +0200, Marc Glisse wrote:
this patch makes std::distance(list.first(),list.end()) a constant
time operation when optimizing, with no penalty for other calls.
We could do the test always (no __builtin_constant_p) but then it
will add a small runtime penalty for other calls, someone else can
take responsibility for that.
I like the way you've done it. No penalty for other calls is great
and IMHO it's OK that the optimisation only happens when optimising.
(Does it work even at -Og?)
No, the testcase currently passes with -O1 but not -Og.
OK, we can live with that.
Sadly, that node is going to look even stranger when I finish adding
support for C++11 allocators, as the type of node becomes dependent on
the allocator's pointer, which makes _List_node<size_t> much more
complicated :-(
But then I assume _List_node_base is the part really getting more
complicated, so without looking too closely it seems almost
orthogonal.
In order to avoid making any changes to std::list<T, std::allocator<T>>
I'm adding an entire parallel hierarchy of a new node base type
(parameterized on the allocator's void_pointer type), a new node type
and new iterators (parameterized on the pointer type), which will only
be used when !is_pointer<Alloc::pointer>. So it will just mean adding
two new overloads for the two new iterator types.
Not a big deal, as long as I remember to do it :-)
This should still be a qualified call to std::__distance, otherwise the
compiler might end up instantiating things to figure out if there are
any associated namespaces, e.g. for vector<unique_ptr<T>>::iterator we
don't want to know T's base classes and rheir associated namespaces.
Then the approach will not work. C++ overload resolution will not
consider the later __distance declarations in stl_list.h if the call
is qualified (I didn't change it gratuitously).
Ahhh, yes, of course.
A forward declaration
of list iterators and those __distance overloads in
bits/stl_iterator_base_funcs.h is not very appealing but may work (or
it may cause issues, I don't know). Otherwise, I guess we are back to
creating a new file bits/list_iterator.h, which <list> includes if
<iterator> has already been included and vice versa, and which
provides overloads for distance directly.
I don't have a preference, but I think the forward declarations should
work without problems. <list> includes bits/stl_iterator_base_funcs.h
so if the forward declarations didn't match the definitions for some
reason we'd know right away.