Home > OS >  Using range::find on a view
Using range::find on a view

Time:12-06

I'd like to rangify the following code, which checks for the first occurance of a sequence of unique characters:

bool hasOnlyUniqueElements( auto& data ) {
    std::unordered_set<char> set;

    for( auto& value : data )
        set.emplace( value );

    return set.size() == data.size();
}

int64_t getStartPacketMarker( const std::string& data, int64_t markerSize ) {
    for( int64_t i = 0; i < data.size() - markerSize; i   )
    {
        std::string_view packet( data.begin()   i, data.begin()   i   markerSize );
        if( hasOnlyUniqueElements( packet ) )
            return i   markerSize;
    }
    return -1;
}

I came up with the following, that uses ranges but is only marginally better:

int64_t getStartPacketMarker( const std::string& data, int64_t markerSize ) {
    int64_t idx = 0;
    for( auto packet :  data | ranges::views::sliding( markerSize ) ) {
        if( hasOnlyUniqueElements( packet ) )
            return idx   markerSize;
        idx  ;
    }

    return -1;
}

This should be a simple find operation, but I couldn't make it work and couldn't find any examples on find being used on views. Is it possible to use find on views?

CodePudding user response:

Yes, you can use find on views. However, in your case, you should use find_if since you are checking against a predicate function:

auto view = data | std::views::slide(markerSize);
auto it = std::ranges::find_if(
              view, somePredicate
          );
return it == view.end() ? -1 : it - view.begin();

However, since your predicate function has an auto-deduced parameter, you can't get the function pointer of it directly, and you would need to wrap it in a lambda instead:

auto view = data | std::views::slide(markerSize);
auto it = std::ranges::find_if(
              view, [](const auto& v) { return hasOnlyUniqueElements(v); }
          );
return it == view.end() ? -1 : it - view.begin();

CodePudding user response:

Besides using std::ranges::find_if on the range you could skip the ´for´ loop that builds the set in hasOnlyUniqueElements using std::unique:

auto set = data;
std::unique(std::sort(set));
  • Related