简体   繁体   中英

Using range::find on a view

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?

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();

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));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM