Redesign iters
rurban opened this issue · 2 comments
Keep our I
API for _it
Add another abstract IT
type, which is the return type of begin(), end().
Abstract IT (T* value, B* node or size_t index) and foreach_range.
We have three major kinds of iterators:
- returning
B*
nodes (list, set, uset) - returning
T*
valuerefs directly (arrays). - returning
size_t
index directly (deque).
Algorithms dont take I*
iters, but IT
elems, like for list B* first, B* last (i.e. IT first, IT last).
Iters (I) are useless and tricky to compute by the users, he only cares about the nodes, (or T* or size_t index for deque), which is the type returned. With I* first, I* last
, only I iter
would be really needed, as I* first
contains the end info already.
But then we need A* self
again, not just I* first, I* last
.
It's the same in the STL, there they have special Iterator types, with those underlying. Not really matching our I* helper type.
See the https://github.com/rurban/ctl/commits/iters branch
The 2nd idea is to slim down the expensive it.step computation.
We currently set 3 fields, node, next and ref, the STL only needs node.
Only next is needed to check for end. No need for ref, done, next, begin, container and such.
See the perf images.
foreach: => for (IT it = new iter, IT end = A->end(); it->next != end; it++)
it.ref can be a macro. node is the iter value, but next can be computed by ++ (from B*, T* or size_t)
For uset (hashes) we need to improve iter run-time performance. Link the buckets together. Not only the chain, but also the main entries, so we don't need two states, only next
. Get rid of the bucket_index
state. This costs a bit on insert.
Also, there needs to be a advance
method, and see the existing iter
method to convert IT
to I*
, i.e. to create I* objects. This is also needed for random access iters. (eg needed for pctl, parallel container algos)
Another new idea is to embed the it->container
field in I*
,
I*
being just a struct of IT + container.
Publicly passed around is just IT, so that we can increment it. (B*->next, T*++, size_t++)
The container is just added on construction, or when it's missing.
And only to omit self from the range algos.
Merged