3

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;
}
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
sandthorn
  • 2,770
  • 1
  • 15
  • 59
  • 3
    `std::string_view(nullptr)` has undefined behavior: you want `std::string_view()`. – Casey Mar 22 '18 at 15:05
  • 2
    If you're going to analyze the assembly, you likely want to compile with `-DNDEBUG` to turn off debugging checks in range-v3. – Casey Mar 22 '18 at 15:06
  • @Casey Thank you for your kind instructions. I fixed it and added some updates. `-DNDEBUG` helps a lot but there are still extra checkings before enter the transform. – sandthorn Mar 22 '18 at 17:07

0 Answers0