#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use constant MIN => 2;
use Benchmark qw/:all :hireswallclock/;
my $str='aabcdabcabcecdecd';
sub blazar {
local $_=shift;
my $l=length;
my %count;
for my $off (0..$l-1) {
for my $len (MIN .. $l-$off) {
my $s=substr $_, $off, $len;
$count{ $s } ||= ()= /$s/g;
}
$count{$_} == 1 and
delete $count{$_} for keys %count;
}
\%count;
}
sub oha {
my $s=shift;
my %saw;
while($s =~ /(..+)(?=.*?\1)/g) {
for my $x (0..length $1) {
@saw{ map {substr $1, $x, $_} $x+2..length $1 } = ();
}
}
$saw{$_} =()= $s =~ /\Q$_/g for keys %saw;
\%saw;
}
{
my %count;
sub count1 {
my( $string) = @_;
my $length = length( $string );
if ($length < MIN) {
$count{$_} == 1 and delete $count{$_} for keys %count;
return \%count;
}
for my $l (MIN..$length) {
my $s = substr( $string, 0, $l );
$count{ $s } += 1;
}
count1( substr( $string, 1 ) );
}
sub kramba {
count1 shift;
for (keys %count) {
delete $count{$_} unless
$count{$_} >= 2 and length($_) >= MIN;
}
\%count;
}
}
sub ikegami {
my $str = shift;
local our %counts;
$str =~ /
(.{2,}) # or (.+)
(?(?{ !$counts{$1} })(?=.*\1))
(?{ ++$counts{$1} })
(?!)
/x;
\%counts;
}
cmpthese 10_000 => {
blazar => sub { blazar $str },
oha => sub { oha $str },
kramba => sub { kramba $str },
ikegami => sub { ikegami $str },
};
__END__
####
Rate blazar kramba ikegami oha
blazar 405/s -- -77% -89% -89%
kramba 1788/s 341% -- -52% -52%
ikegami 3743/s 823% 109% -- -0%
oha 3743/s 823% 109% 0% --
##
##
sub lodin {
my $str = shift;
local our %count;
$str =~ /
(.{2,})
(?(?{ $count{$1} })
(?!)
)
.*
\1
(?{ ($count{$1} ||= 1)++ })
(?!)
/x;
\%count;
}
##
##
sub kramba {
my %count;
my $count;
$count = sub {
my( $string) = @_;
my $length = length( $string );
if ($length < MIN) {
$count{$_} == 1 and delete $count{$_} for keys %count;
return \%count;
}
for my $l (MIN..$length) {
my $s = substr( $string, 0, $l );
$count{ $s } += 1;
}
$count->( substr( $string, 1 ) );
};
$count->(shift);
for (keys %count) {
delete $count{$_} unless
$count{$_} >= 2 and length($_) >= MIN;
}
\%count;
}
##
##
Rate blazar kramba oha ikegami lodin
blazar 577/s -- -72% -90% -91% -91%
kramba 2045/s 254% -- -66% -67% -69%
oha 6039/s 946% 195% -- -2% -9%
ikegami 6154/s 966% 201% 2% -- -8%
lodin 6667/s 1055% 226% 10% 8% --