rurban/ctl

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