Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Make s/// up to 25% faster (for many changes)
- abstract optimized .subst case into private method APPLY-MATCHES
- optimize APPLY-MATCHES further by avoiding repeat checks where possible
- make both .subst and .subst-mutate use this private method
  • Loading branch information
lizmat committed Feb 20, 2015
1 parent 59b16d5 commit e6b992f
Showing 1 changed file with 62 additions and 33 deletions.
95 changes: 62 additions & 33 deletions src/core/Str.pm
Expand Up @@ -628,33 +628,26 @@ my class Str does Stringy { # declared in BOOTSTRAP
my $global = %options<g> || %options<global>;
my $caller_dollar_slash := nqp::getlexcaller('$/');
my $SET_DOLLAR_SLASH = $SET_CALLER_DOLLAR_SLASH || nqp::istype($matcher, Regex);
my @matches = self.match($matcher, |%options);

try $caller_dollar_slash = $/ if $SET_DOLLAR_SLASH;
my @matches = self.match($matcher, |%options);

return Nil unless @matches;
return Nil if @matches == 1 && !@matches[0];

my $prev = 0;
my $result = '';
for @matches -> $m {
try $caller_dollar_slash = $m if $SET_DOLLAR_SLASH;
$result ~= substr(self,$prev, $m.from - $prev);

my $real_replacement = ~(nqp::istype($replacement,Callable)
?? ($replacement.count == 0 ?? $replacement() !! $replacement($m))
!! $replacement);
$real_replacement = $real_replacement.samecase(~$m) if $samecase;
$real_replacement = $real_replacement.samespace(~$m) if $samespace;
$result ~= $real_replacement;
$prev = $m.to;
if !@matches || (@matches == 1 && !@matches[0]) {
Nil;
}
else {
$self = $self!APPLY-MATCHES(
@matches,
$replacement,
$caller_dollar_slash,
$SET_DOLLAR_SLASH,
$samecase,
$samespace,
);
$global ?? (@matches,).list !! @matches[0];
}
my $last = @matches[@matches-1];
$result ~= substr(self,$last.to);
$self = $result;
$global ?? (@matches,).list !! @matches[0];
}


multi method subst(Str:D: Str \from, Str \to, :$global!, *%adverbs) {
if $global {
TRANSPOSE(self,from,to);
Expand All @@ -674,27 +667,63 @@ my class Str does Stringy { # declared in BOOTSTRAP
# nothing to do
try $caller_dollar_slash = $/ if $SET_DOLLAR_SLASH;
my @matches = self.match($matcher, |%options);
return self if !@matches || (@matches == 1 && !@matches[0]);

!@matches || (@matches == 1 && !@matches[0])
?? self
!! self!APPLY-MATCHES(
@matches,
$replacement,
$caller_dollar_slash,
$SET_DOLLAR_SLASH,
$samecase,
$samespace,
);
}

method !APPLY-MATCHES(\matches,$replacement,\cds,\SDS,\case,\space) {
my \callable := nqp::istype($replacement,Callable);

my int $prev;
my str $str = nqp::unbox_s(self);
my Mu $result := nqp::list_s();
try cds = $/ if SDS;

# need to do something special
if $SET_DOLLAR_SLASH || $samecase || $samespace || nqp::istype($replacement,Callable) {
if SDS || case || space || callable {
my \noargs := callable ?? $replacement.count == 0 !! False;
my \case-or-space := case || space;
my \case-and-space := case && space;

for @matches -> $m {
try $caller_dollar_slash = $m if $SET_DOLLAR_SLASH;
for matches -> $m {
try cds = $m if SDS;
nqp::push_s(
$result,nqp::substr($str,$prev,nqp::unbox_i($m.from) - $prev)
);

my $real_replacement = ~(nqp::istype($replacement,Callable)
?? ($replacement.count == 0 ?? $replacement() !! $replacement($m))
!! $replacement);
$real_replacement = $real_replacement.samecase(~$m) if $samecase;
$real_replacement = $real_replacement.samespace(~$m) if $samespace;
nqp::push_s($result,nqp::unbox_s($real_replacement));
if case-or-space {
my $it := ~(callable
?? (noargs ?? $replacement() !! $replacement($m))
!! $replacement
);
if case-and-space {
my $mstr := $m.Str;
nqp::push_s($result,nqp::unbox_s(
$it.samecase($mstr).samespace($mstr)
) );
}
elsif case {
nqp::push_s($result,nqp::unbox_s($it.samecase(~$m)));
}
else { # space
nqp::push_s($result,nqp::unbox_s($it.samespace(~$m)));
}
}
else {
nqp::push_s($result,nqp::unbox_s( ~(callable
?? (noargs ?? $replacement() !! $replacement($m))
!! $replacement
) ) );
}
$prev = nqp::unbox_i($m.to);
}
nqp::push_s($result,nqp::substr($str,$prev));
Expand All @@ -703,7 +732,7 @@ my class Str does Stringy { # declared in BOOTSTRAP

# simple string replacement
else {
for @matches -> $m {
for matches -> $m {
nqp::push_s(
$result,nqp::substr($str,$prev,nqp::unbox_i($m.from) - $prev)
);
Expand Down

0 comments on commit e6b992f

Please sign in to comment.