0

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?

Grimkin
  • 107
  • 5

2 Answers2

2

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();
Ranoiaetep
  • 5,872
  • 1
  • 14
  • 39
  • @Grimkin I'm not that familiar with range-v3, but I assume it should work with both. – Ranoiaetep Dec 06 '22 at 10:40
  • 1
    I now tried it now and it works in both. My mistake was to trust Intellisense in MSVC which showed an error and I didn't try to compile it. Thanks for the help – Grimkin Dec 06 '22 at 10:47
0

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