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