Skip to content
Permalink
Browse files

Make Map/Hash.sort about 11x faster

- instead of first generating a list of Pairs and sort on .key
- create native str array of keys and sort that
- then create Pairs on a new iterator on the native str array of keys
- this delays the creation of Pairs until they're really needed
- the removes the need unpack each pair to be able to sort
- prevents unneeded Pairs from being created, e.g. %h.sort.head(100)
- keep old logic for object hashes for now
  • Loading branch information...
lizmat committed Jan 7, 2019
1 parent 307ae38 commit 8ae4310e9da2c79b2a43b301040cc77193beceb3
Showing with 65 additions and 6 deletions.
  1. +11 −0 src/core/Hash.pm6
  2. +54 −6 src/core/Map.pm6
@@ -618,6 +618,17 @@ my class Hash { # declared in BOOTSTRAP
)
}

multi method sort(::?CLASS:D: --> Seq:D) {
Seq.new(
Rakudo::Iterator.ReifiedList(
Rakudo::Sorting.MERGESORT-REIFIED-LIST-AS(
self.IterationBuffer.List,
{ nqp::getattr(nqp::decont($^a),Pair,'$!key') }
)
)
)
}

my class Keys does Rakudo::Iterator::Mappy {
method pull-one() {
nqp::if(
@@ -126,14 +126,62 @@ my class Map does Iterable does Associative { # declared in BOOTSTRAP
)
}

# Produce a native str array with all the keys
method !keys-as-str() {
my $keys := nqp::list_s;
nqp::if(
($!storage && my \iter := nqp::iterator($!storage)),
nqp::while(
iter,
nqp::push_s($keys,nqp::iterkey_s(nqp::shift(iter)))
),
);
$keys
}

# Iterator over a native string array holding the keys and producing
# Pairs.
my class Iterate-keys does Iterator {
has $!map;
has $!iter;
method new(Mu \map, Mu \keys) {
nqp::p6bindattrinvres(
nqp::p6bindattrinvres(
nqp::create(self),
self,
'$!map',nqp::getattr(map,Map,'$!storage')
),
self,
'$!iter',
nqp::iterator(keys)
)
}
method pull-one() {
nqp::if(
$!iter,
nqp::stmts(
(my \key := nqp::shift($!iter)),
Pair.new(key,nqp::atkey($!map,key))
),
IterationEnd
)
}
method push-all($target --> IterationEnd) {
my \map := $!map;
my \iter := $!iter;
nqp::while(
iter,
nqp::stmts(
(my \key := nqp::shift(iter)),
$target.push(Pair.new(key,nqp::atkey(map,key)))
)
)
}
}

multi method sort(Map:D: --> Seq:D) {
Seq.new(
Rakudo::Iterator.ReifiedList(
Rakudo::Sorting.MERGESORT-REIFIED-LIST-AS(
self.IterationBuffer.List,
{ nqp::getattr(nqp::decont($^a),Pair,'$!key') }
)
)
Iterate-keys.new(self,Rakudo::Sorting.MERGESORT-str(self!keys-as-str))
)
}

0 comments on commit 8ae4310

Please sign in to comment.
You can’t perform that action at this time.