Skip to content

Commit

Permalink
Make (1,2,3,4,1,2).QuantHash>>-- work
Browse files Browse the repository at this point in the history
Spotted in #5057 .

The above basically runs QuantHash.new(1,2,3,4,1,2).deepmap(&postfix:<-->)

The problem was caused by there being an Associative candidate
for deepmap, and QuantHashes being Associative.  Since .deepmap is
supposed to *return* an object of the *same* type, this effectively
means a new object needs to be created.  In the case of the code in
the issue, essentially:

    $ raku -e 'my $a=‘abcdeabc’.comb.BagHash»--; $a.keys.sort.say'

there would be a BagHash object created, but then the deepmap logic
for Associatives would do some magic that would do the wrong thing
for QuantHashes (and possibly for Hash and Map as well, but that
requires further investigation).  The result was that the order in
which updates where being done, got confused, and the new BagHash
object got mutilated.

This commit adds specific Setty, Baggy and Mixy candidates for
deepmap, that actually uses information about the internal structure
of the QuantHashes to allow a fast creation of the new, updated
object.  This allows >>-- to even work on immutable QuantHashes (as
we create a new immutable object under the hood).  So this now works:

    $ raku -e 'say ‘abcdeabc’.comb.Bag»--'
    Bag(a b c)
  • Loading branch information
lizmat committed Sep 13, 2022
1 parent 7342d9d commit 63d03eb
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/core.c/Baggy.pm6
Expand Up @@ -54,6 +54,24 @@ my role Baggy does QuantHash {
)
}

# https://github.com/rakudo/rakudo/issues/5057
multi method deepmap(Baggy:D: &mapper) {
my $type := self.WHAT;
my $elems := nqp::clone($!elems);
my $iter := nqp::iterator($elems);

while $iter {
my $pair := nqp::iterval(nqp::shift($iter));
my $value = nqp::getattr($pair,Pair,'$!value');
mapper($value);
$value > 0
?? nqp::bindattr($pair,Pair,'$!value',nqp::decont($value))
!! nqp::deletekey($elems,nqp::iterkey_s($iter))
}

nqp::p6bindattrinvres(nqp::create($type),$type,'$!elems',$elems)
}

#--- object creation methods

# helper method to create Bag from iterator, check for laziness
Expand Down
18 changes: 18 additions & 0 deletions src/core.c/Mixy.pm6
Expand Up @@ -5,6 +5,24 @@ my role Mixy does Baggy {
multi method hash(Mixy:D: --> Hash:D) { self!HASHIFY(Real) }
multi method Hash(Mixy:D: --> Hash:D) { self!HASHIFY(Any) }

# https://github.com/rakudo/rakudo/issues/5057
multi method deepmap(Mixy:D: &mapper) {
my $type := self.WHAT;
my $elems := nqp::clone(nqp::getattr(self,self.WHAT,'$!elems'));
my $iter := nqp::iterator($elems);

while $iter {
my $pair := nqp::iterval(nqp::shift($iter));
my $value = nqp::getattr($pair,Pair,'$!value');
mapper($value);
$value
?? nqp::bindattr($pair,Pair,'$!value',nqp::decont($value))
!! nqp::deletekey($elems,nqp::iterkey_s($iter))
}

nqp::p6bindattrinvres(nqp::create($type),$type,'$!elems',$elems)
}

multi method kxxv(Mixy:D:) {
".kxxv is not supported on a {self.^name}".Failure
}
Expand Down
15 changes: 15 additions & 0 deletions src/core.c/Setty.pm6
Expand Up @@ -47,6 +47,21 @@ my role Setty does QuantHash {
)
}

# https://github.com/rakudo/rakudo/issues/5057
multi method deepmap(Setty:D: &mapper) {
my $type := self.WHAT;
my $elems := nqp::clone(nqp::getattr(self,self.WHAT,'$!elems'));
my $iter := nqp::iterator($elems);

while $iter {
nqp::shift($iter);
mapper(my $value = 1);
nqp::deletekey($elems,nqp::iterkey_s($iter)) unless $value;
}

nqp::p6bindattrinvres(nqp::create($type),$type,'$!elems',$elems)
}

method default(--> False) { }

multi method keys(Setty:D:) {
Expand Down

0 comments on commit 63d03eb

Please sign in to comment.