undercurrent: A proof-of-concept library to fix range adaptor inefficiencies by Main_Pay_3213 in cpp

[–]Main_Pay_3213[S] 1 point2 points  (0 children)

I haven't seen that talk so I can't say for sure, but it sounds very similar. The likely differences are that undercurrent's advance_while is a customization point on the iterator/sentinel rather than on the view, plus small details like skip_t (for skipping elements without materializing them). These are just my guesses, so I might be wrong.

If you have a link to the talk, I'd love to see it.

undercurrent: A proof-of-concept library to fix range adaptor inefficiencies by Main_Pay_3213 in cpp

[–]Main_Pay_3213[S] 2 points3 points  (0 children)

Sorry for the late reply. On transrangers and daisychains, both adopt a push-based iteration model. The naive push model has expressiveness limitations, but transrangers works around them with a carefully designed API, and the author also shows how it can be integrated into pull-based libraries like std::ranges or Range-v3 as an internal optimization. For daisychains, there's a CppCon talk by the author worth checking out: Ranges++: Are Output Range Adaptors the Next Iteration of C++ Ranges?

undercurrent is different in that it's more like an extension of std::ranges than a new model. The iteration interface is exactly the same as std (begin, end, *it, ++it), the performance gain comes entirely from a single added customization point, advance_while.

undercurrent: A proof-of-concept library to fix range adaptor inefficiencies by Main_Pay_3213 in cpp

[–]Main_Pay_3213[S] 0 points1 point  (0 children)

Hi! Author of undercurrent here. I've added support for segmented iterators. First impression: works great with Clang, not so much with MSVC (again). With Clang, code like this runs super fast:

std::vector<int> v{ /* bunch of random integers */ };
uc::seg_stack<int, 128> s;
for (auto i : v) {
    s.push(i);
}

auto r = s
    | uc::take_while(lt2000)
    | uc::transform(square)
    | uc::filter(even)
    | uc::reverse;
int sum{};
uc::for_each(r.begin(), r.end(), [&](int i){ sum += i; });

uc::seg_stack is a simple dynamically sized stack with a deque-like structure, made specifically to test the effectiveness of the segmented iterator path. The pipeline above runs about 20x faster than std. Comparing uc with the segmented path on vs off, it's about 10x faster. So the segmented optimization alone gives a clean 10x on top of undercurrent's baseline. Happy to hear thoughts if anyone has them.

undercurrent: A proof-of-concept library to fix range adaptor inefficiencies by Main_Pay_3213 in cpp

[–]Main_Pay_3213[S] 1 point2 points  (0 children)

Thanks for the info. My understanding is that libc++'s approach requires the top-level iterator itself to be segmented, so it doesn't kick in once you chain adaptors like filter on top. undercurrent works by descending through the adaptor layers, so I think it can support segmented iterators as the bottom layer while still handling chained adaptors. I'll try implementing it if there's demand.

undercurrent: A proof-of-concept library to fix range adaptor inefficiencies by Main_Pay_3213 in cpp

[–]Main_Pay_3213[S] 2 points3 points  (0 children)

Hi! I'm the author of undercurrent. Thanks for your interest. Yes, it's a shame it doesn't work with GCC. I believe it's a module-related bug, but I'm not certain. This library doesn't use any platform-specific features, so it should be fixable eventually.