Skip to content
Permalink
Browse files

Make metaops with assigning ops between 1.3x and 1.7x as fast

If the left hand side of a meta op is a mutable structure, and we know
that the op does an assignment, we don't have to build any result structure
as the result is the same as the left hand side then.  This allows for quite
some savings.
  • Loading branch information...
lizmat committed Nov 15, 2018
1 parent 21434dd commit 234e298bf708976b1ddf788c4dcd1e6bb80347b9
Showing with 66 additions and 38 deletions.
  1. +66 −38 src/core/Hyper.pm6
@@ -48,13 +48,19 @@ class Hyper {
multi method infix(Associative:D \left, \right --> Associative:D) {
return self!pair-mu(left,right) if nqp::istype(left,Pair);

my @keys is List = left.keys;
my \result := nqp::create(left.WHAT).STORE(
@keys,
self.infix(left{@keys},right),
:INITIALIZE
);
nqp::iscont(left) ?? result.item !! result;
if $!assigns {
self.infix(left.values,right);
left
}
else {
my @keys is List = left.keys;
my \result := nqp::create(left.WHAT).STORE(
@keys,
self.infix(left{@keys},right),
:INITIALIZE
);
nqp::iscont(left) ?? result.item !! result;
}
}

# ... >>op<< %y
@@ -89,23 +95,35 @@ class Hyper {
or $left-elems > 1 and $!dwim-right
or $left-elems == 0 and $!dwim-left || $!dwim-right;

my \values := nqp::create(IterationBuffer);
my \iterator := left.iterator;

nqp::until(
nqp::eqaddr((my \value := iterator.pull-one),IterationEnd),
nqp::push(values, self.infix(value,right))
);

my \result := nqp::eqaddr(left.WHAT,List)
|| nqp::eqaddr(left.WHAT,Slip)
?? nqp::p6bindattrinvres(nqp::create(left),List,'$!reified',values)
!! nqp::can(left,"STORE")
?? left.WHAT.new(nqp::p6bindattrinvres(
nqp::create(List),List,'$!reified',values
))
!! nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',values);
nqp::iscont(left) ?? result.item !! result
if $!assigns {
nqp::until(
nqp::eqaddr((my \value := iterator.pull-one),IterationEnd),
self.infix(value,right)
);
left
}
else {
my \values := nqp::create(IterationBuffer);
nqp::until(
nqp::eqaddr((my \value := iterator.pull-one),IterationEnd),
nqp::push(values, self.infix(value,right))
);

my \result := nqp::eqaddr(left.WHAT,List)
|| nqp::eqaddr(left.WHAT,Slip)
?? nqp::p6bindattrinvres(
nqp::create(left),List,'$!reified',values
)
!! nqp::can(left,"STORE")
?? left.WHAT.new(nqp::p6bindattrinvres(
nqp::create(List),List,'$!reified',values
))
!! nqp::p6bindattrinvres(
nqp::create(List),List,'$!reified',values
);
nqp::iscont(left) ?? result.item !! result
}
}

# x >>op<< [y]
@@ -310,7 +328,7 @@ class Hyper {
)
)
);

result
}

@@ -331,13 +349,18 @@ class Hyper {
my @keys is List =
nqp::p6bindattrinvres(nqp::create(Map),Map,'$!storage',$keys).keys;

# run with the left/right values
my \result := nqp::create(left.WHAT).STORE(
@keys,
(quietly self.infix(left{@keys}, right{@keys})),
:INITIALIZE
);
nqp::iscont(left) ?? result.item !! result;
if $!assigns {
quietly self.infix(left{@keys}, right{@keys});
left
}
else {
my \result := nqp::create(left.WHAT).STORE(
@keys,
(quietly self.infix(left{@keys}, right{@keys})),
:INITIALIZE
);
nqp::iscont(left) ?? result.item !! result;
}
}

# handle object hashes / QuantHashes
@@ -357,13 +380,18 @@ class Hyper {
my @keys is List =
nqp::p6bindattrinvres(nqp::create(Map),Map,'$!storage',$keys).values;

# run with the left/right values
my \result := nqp::create(left.WHAT).STORE(
@keys,
(quietly self.infix(left{@keys}, right{@keys})),
:INITIALIZE
);
nqp::iscont(left) ?? result.item !! result;
if $!assigns {
quietly self.infix(left{@keys}, right{@keys});
left
}
else {
my \result := nqp::create(left.WHAT).STORE(
@keys,
(quietly self.infix(left{@keys}, right{@keys})),
:INITIALIZE
);
nqp::iscont(left) ?? result.item !! result;
}
}

# error when left side of non-DWIM exhausted

0 comments on commit 234e298

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