Skip to content

Commit

Permalink
Make .unique(:with) about 4x faster
Browse files Browse the repository at this point in the history
- based on a 100 elem array with unique elements (aka worst case)
- don't use gather / take, create proper iterator
- don't use .first, but loop over low level list directly
  • Loading branch information
lizmat committed Jul 24, 2017
1 parent a636fa8 commit 47d9bd9
Showing 1 changed file with 38 additions and 8 deletions.
46 changes: 38 additions & 8 deletions src/core/Any-iterable-methods.pm
Expand Up @@ -1588,15 +1588,45 @@ Did you mean to add a stub (\{...\}) or did you mean to .classify?"
multi method unique( :&with! ) {
nextwith() if &with === &[===]; # use optimized version

my @seen; # should be Mu, but doesn't work in settings :-(
my Mu $target;
gather self.map: {
$target := $_;
if first( { with($target,$_) }, @seen ) =:= Nil {
@seen.push($target);
take $_;
Seq.new(class :: does Iterator {
has Mu $!iter;
has &!with;
has $!seen;
method !SET-SELF(\list, &!with) {
$!iter = list.iterator;
$!seen := nqp::list;
self
}
}
method new(\list, &with) { nqp::create(self)!SET-SELF(list, &with) }
method pull-one() {
nqp::stmts(
(my &with := &!with), # lexicals are faster than attributes
(my $seen := $!seen),
nqp::until(
nqp::eqaddr((my $needle := $!iter.pull-one),IterationEnd),
nqp::stmts(
(my int $i = -1),
(my int $elems = nqp::elems($!seen)),
nqp::while(
nqp::islt_i(($i = nqp::add_i($i,1)),$elems)
&& nqp::isfalse(with($needle,nqp::atpos($seen,$i))),
nqp::null
),
nqp::if(
nqp::iseq_i($i,$elems),
nqp::stmts(
nqp::push($!seen,$needle),
(return $needle)
)
)
)
),
IterationEnd
)
}
method is-lazy() { $!iter.is-lazy }
method sink-all(--> IterationEnd) { $!iter.sink-all }
}.new(self, &with))
}

proto method repeated(|) is nodal {*}
Expand Down

0 comments on commit 47d9bd9

Please sign in to comment.