Skip to content

Add iterable concept#238

Draft
tcbrindle wants to merge 66 commits intomainfrom
devel
Draft

Add iterable concept#238
tcbrindle wants to merge 66 commits intomainfrom
devel

Conversation

@tcbrindle
Copy link
Owner

No description provided.

@tcbrindle tcbrindle marked this pull request as draft May 16, 2025 16:50
@codecov
Copy link

codecov bot commented May 20, 2025

Codecov Report

❌ Patch coverage is 98.14634% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.85%. Comparing base (e8936e5) to head (c4a5513).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
include/flux/adaptor/chunk.hpp 92.85% 3 Missing ⚠️
include/flux/adaptor/take_while.hpp 78.57% 3 Missing ⚠️
test/test_utils.hpp 87.50% 1 Missing and 2 partials ⚠️
include/flux/adaptor/chain.hpp 94.11% 2 Missing ⚠️
include/flux/factory/generator.hpp 92.00% 2 Missing ⚠️
include/flux/adaptor/flatten_with.hpp 97.36% 1 Missing ⚠️
include/flux/adaptor/scan_first.hpp 94.73% 1 Missing ⚠️
include/flux/algorithm/to.hpp 94.11% 1 Missing ⚠️
include/flux/algorithm/zip_algorithms.hpp 94.44% 1 Missing ⚠️
test/test_generator.cpp 75.00% 0 Missing and 1 partial ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #238      +/-   ##
==========================================
- Coverage   97.74%   96.85%   -0.90%     
==========================================
  Files         146      148       +2     
  Lines        5149     5147       -2     
  Branches      244      301      +57     
==========================================
- Hits         5033     4985      -48     
- Misses         80      127      +47     
+ Partials       36       35       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Injected class name causes chaos!

This was a weird on to track down.
This adds `iterable` conformance to `generator` and removes `sequence`
Previously, if the user specified a non-reference `T` in `generator<T>`, we changed the actual element type to `const T&`, the reason being that it was possible to call `read_at()` multiple times so we couldn't safely yield an rvalue (reference).

Under the new model, we can only read each value once, so it's safe to actually give the user what they ask for -- well, almost. Instead of yielding a prvalue we actually use an xvalue to save a move.
...but no longer sequences.

Also, remove the `from_istreambuf()` function -- pass an lvalue istreambuf to `iterate()` instead.
...rather than plain old `element_t` and `value_t` in inline_sequence_base.

Asking for one of the sequence typedefs with a non-sequence (i.e. just an iterable) can result in hard errors, which is really really annoying.
...which apparently turned up lots of other bugs
STL iterators are required to be at least movable. Since iteration contexts are typically non-copyable and non-movable, we cannot store one inside a valid iterator. This means that in order to use plain iterables with STL algorithms we need to use the `as_range` adaptor, which can hold the iter_ctx and hand out movable iterators which hold a pointer back to it.

However, range-for loops have considerably weaker requirements than the standard library concepts. So to enable iterables to be directly used with range-for loops, this commit adds "pseudoiterators" which meet the bare minimum requirements that the range-for needs. These pseudoiterators won't work with standard library algorithms, and in fact we deliberately don't add extra typedefs and things just to try to emphasise that they're not real iterators.
Instead, use flux::ref(), flux::mut_ref() or flux::from().

Under the new model, all ranges are at least iterable. Sized, random-access ranges will also become collections. However, the new collection requirements will mean that we will no longer be able to treat non-RA ranges as collections (even if we were willing to do so unsafely).
Whereas the translation to iterables has simplified most adaptors, these seem a bit tricky to move to the new API, as they require comparing the same element multiple times (and therefore internal caching).

For now we'll just require their bases to be multipass sequences.
Use std::span instead (begrudgingly)
For an incrementable type, iota(i) gives an infinite iterable, and iota(i, j) gives an iterable that will iterate until i == j.

If the type is additionally decrementable, then iota(i, j) will additionally be reverse iterable. If the type is additionally advanceable, then iota(i, j) will also be sized.

If the type is strongly ordered (with op<=>) then it is a multipass sequence (and in future, a collection), plus bidir if decrementable and RA if advancable.

Finally, for a type which is `std::is_arithmetic_v<T>`, iota(a) is equivalent to `iota(a, numeric_limits<T>::max())` -- that is, we treat it as a bounded collection rather than an infinite iterable.
This is an interesting one, because we're actually removing functionality -- infinite repeat was previously random-access, but we can't do that when we move to collections.

It does raise the question of whether impls should be able to override (certain? all?) algorithms -- because now `repeat(x).take(n)` is iterable-only, whereas we want it to work the same as `repeat(x, n)`, i.e. be random-access. Also, repeat(x).drop(n) could be a no-op, and stride() and reverse() and...
It's causing odd linker errors relating to flux::detail::unreachable, not really sure what the problem is
Apparently consistency errors with code inlining lambdas is a known problem
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant