Given str
is a string
auto str = std::string{};
getline(std::cin, str);
I notice when we have a view::filter
exist on a lazy range, there will be many redundant sentinel checks even with -O3. CE godbolt.org/g/B3ZGbm
for (auto sv : str | ranges::view::delimit('#')
// (1) pointer check and delimit check here
| ranges::view::filter(onlyalpha)
// (2) pointer check and delimit check here also!
| ranges::view::transform(to_ints) ) {
std::cout << sv;
// (3) pointer check and delimit check here too!
}
However, if I try to embed that filter into transform like this
auto to_ints_with_filter = [](unsigned char ch){
if (std::isalpha(ch)) {
auto index = (ch - 1) & 0b0001'1111;
static constexpr auto table =
std::array<char,27> {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
};
return std::string_view(&table[index],1);
}
else
return std::string_view();
};
The redundant sentinel checks all are gone. CE godbolt.org/g/4sMYhM
for (auto sv : str | ranges::view::delimit('#')
| ranges::view::transform(to_ints_with_filter ) ) {
std::cout << sv;
}
Why can't the optimizer get rid of those redundant checks when view::filter
is present?
Is this considered a literally minuscule overhead of view::filter
?
Update
Change bad std::string_view(nullptr)
to std::string_view()
as Casey instructed in the comment.
After add -DNDEBUG
as Casey instructed in the comment. The end of loop checkings are now gone. There are still the extra checkings before entering the transform. CE godbolt.org/g/YWUPaK
for (auto sv : str | ranges::view::delimit('#')
// (1) pointer check and delimit check here
| ranges::view::filter(onlyalpha)
// (2) pointer check and delimit check here also
| ranges::view::transform(to_ints) ) {
std::cout << sv;
}
With -DNDEBUG
, it yields a lot better but there seems one more redundant lingering still.
Update 2
I try adding another transform. It seems there is only set of redundant checks at right after the view::filter
itself. CE godbolt.org/g/sSt8qb
for (auto sv : str | ranges::view::delimit('#')
// (1) pointer check and delimit check here
| ranges::view::filter(onlyalpha)
// (2) pointer check and delimit check here also
| ranges::view::transform(to_ints)
| ranges::view::transform(to_ints2) ) {
std::cout << sv;
}