# @groups = groups1($s)
sub groups1 {
return map { substr $_[0], $-[$_], $+[$_] - $-[$_] } 1..$#-
}
####
# educated_foo
sub groups2 {
no strict 'refs'; return map { $$_ } 1..$#-
}
####
# demerphq
sub groups3 {
return eval '($'.join(',$',1..$#-).')'
}
####
s/iter demerphq @- and @- educated_foo
demerphq 6.65 -- -44% -50%
@- and @- 3.72 79% -- -10%
educated_foo 3.34 99% 11% --
####
#!/usr/bin/perl
# @groups = groups1($s)
sub groups1 {
return map { substr $_[0], $-[$_], $+[$_] - $-[$_] } 1..$#-
}
# educated_foo
sub groups2 {
no strict 'refs'; return map { $$_ } 1..$#-
}
# demerphq
sub groups3 {
return eval '($'.join(',$',1..$#-).')'
# return '($'.join(',$',1..$#-).')'
}
use constant MAX_GROUPS => 5; # use < 26 which corresponds to 'z'
use constant MAX_REPEAT => 20;
use constant ITERATIONS => 20000;
use constant RANDOM_SEED => 666;
# $re = random_re($n)
# a regex with $n groups qr/(a*)(b*)...(z*)/
# use $n >= 1 to avoid the subtleties of the empty regex qr//
sub random_re {
my $n = shift;
my $re = join '', map { "($_*)" } 'a' .. chr(ord('a')+$n-1);
return qr/$re/
}
# $text = random_text($n)
# a text which matches the random regex produced by random_re
sub random_text {
my $n = shift;
return join '', map { $_ x int(rand(MAX_REPEAT)) } 'a' .. chr(ord('a')+$n-1)
}
sub run_code {
my $sub = shift;
srand(RANDOM_SEED); # always the same seed - so that it is reproducible
for (1..ITERATIONS) {
$n = int(rand(MAX_GROUPS))+1;
$re = random_re($n);
$text = random_text($n);
# print "n: $n, re: $re, text: $text\n";
die "not ok: $text =~ /$re/" unless $text =~ /$re/; # assertion
@groups = $sub->($text);
# print "groups 1: @groups\n";
}
}
#run_code(\&groups2);
#exit;
use Benchmark qw(cmpthese :hireswallclock );
use constant MIN_RUNTIME => 30; # benchmark minimum time: ? CPU seconds
cmpthese(-MIN_RUNTIME(), {
'@- and @-' => sub { run_code(\&groups1) },
'educated_foo' => sub { run_code(\&groups2) },
'demerphq' => sub { run_code(\&groups3) },
});