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