Replies: 1 comment 1 reply
-
|
Hi @robbiesri, thanks for the question! The first thing to say is that auto result = flux::zip(flux::ref(input_A), flux::ref(input_B), flux::ref(input_C))
.filter([](auto bundle){
auto [a, b, c] = bundle;
return PassTest(a);
})
.output_to(out_zip.begin());
const size_t copied_count = result.out - output.begin();That's an immediate improvement, but then I started thinking about how what other improvements we could make. I think what we'd really like to do is to flux::zip(flux::ref(input_A), flux::ref(input_B), flux::ref(input_C)))
.filter([](auto bundle) {
auto [a, b, c] = bundle;
return PassTest(a);
})
.for_each([](auto bundle) {
auto [a, b, c] = bundle;
output_A.push_back(a);
output_B.push_back(b);
output_C.push_back(c);
});If we wanted to, we could avoid having to manually use structured bindings by using flux::zip(flux::ref(input_A), flux::ref(input_B), flux::ref(input_C)))
.filter(flux::unpack([](auto a, auto, auto) {
return PassTest(a);
}))
.for_each(flux::unpack([](auto a, auto b, auto c) {
output_A.push_back(a);
output_B.push_back(b);
output_C.push_back(c);
}));This is probably as close to idiomatic as we can make it in terms of building up a data pipeline. If I were writing the code though, I would probably be tempted to go a little further, and "inline" the filter condition into the flux::zip(flux::ref(input_A), flux::ref(input_B), flux::ref(input_C)))
.for_each(flux::unpack([](auto a, auto b, auto c) {
if (PassTest(a)) {
output_A.push_back(a);
output_B.push_back(b);
output_C.push_back(c);
}
}));The reason for this is that I know that Flux has a special function for doing flux::zip_for_each([](auto a, auto b, auto c) {
if (PassTest(a)) {
output_A.push_back(a);
output_B.push_back(b);
output_C.push_back(c);
}, input_A, input_B, input_C);I think this is about as nice as I can make it. I tried it on Compiler Explorer and it ended up generating more assembly. I'm pretty sure this is because it needs to generate the code to handle expanding each of the three vectors, even though that code will never be hit because you're I hope this helps, and thanks for your interest in Flux! If you have any more questions please feel free to post them. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Thanks so much for creating this library. It's been fun for me to learn how to work with it, and compare it against raw for-loops +
ranges.I've been experimenting with some code where I'm iterating over a set of associated sequences, testing each bundle, and writing out the filtered sequence values. Speaking in adaptor + algorithmic terms, I want to zip the inputs, filter, and write to zipped outputs. I could also say zip +
copy_if.Codegen was tested against clang 20.10, with
-O3 -std=c++23.Here is a CompilerExplorer of my test setup: https://godbolt.org/z/9cnrG98T3
This is an anonymized version of my actual code, which doesn't actually use
vectors. Usingvectorbloats the code a bit, but the outputs are basically the same, as far as size differences.My raw indexed loop
Ranges version
This is my flux version. I originally had
output_tochained to.filter, but I couldn't figure out how to get the count of items that actually got thrufilter. Not a huge deal, but I suppose a little less ideal to look at. I also don't know if this is the idiomatic way you expected. I actually had a fairly difficult time writing this code, because I wrote this before I wrote therangesversion. I think if I had written therangesone first, I would have been able to write this one much quicker, because the structure is basically identical (which I'm sure you intended)Looking forward to hearing how I could have done this better!
Beta Was this translation helpful? Give feedback.
All reactions