my role Mixy does Baggy { method of() { Real } 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::getattr(self,self.WHAT,'$!elems'); my $clone := nqp::clone($elems); my $iter := nqp::iterator($elems); while $iter { my str $key = nqp::iterkey_s(nqp::shift($iter)); my $pair := nqp::iterval($iter); my $value = nqp::getattr($pair,Pair,'$!value'); # must be Scalar $value := nqp::decont($value) if nqp::istype($type,Mix); # update clone my $returned := nqp::decont(mapper($value).Int); $returned ?? nqp::bindkey( $clone, $key, nqp::p6bindattrinvres( nqp::clone($pair),Pair,'$!value',$returned ) ) !! nqp::deletekey($clone,$key); $value ?? nqp::bindattr($pair,Pair,'$!value',nqp::decont($value)) !! nqp::deletekey($elems,$key) } nqp::p6bindattrinvres(nqp::create($type),$type,'$!elems',$clone) } multi method kxxv(Mixy:D:) { ".kxxv is not supported on a {self.^name}".Failure } multi method grab(Mixy:D: $count?) { ".grab is not supported on a {self.^name}".Failure } multi method pick(Mixy:D: $count?) { ".pick is not supported on a {self.^name}, maybe use .roll instead?".Failure } multi method roll(Mixy:D:) { (my \raw := self.RAW-HASH) && (my \total := self!total-positive) ?? nqp::getattr( nqp::iterval(Rakudo::QuantHash.MIX-ROLL(raw,total)),Pair,'$!key' ) !! Nil } multi method roll(Mixy:D: Whatever) { Seq.new( (my \raw := self.RAW-HASH) && (my \total := self!total-positive) ?? Rakudo::Iterator.Callable( { nqp::getattr( nqp::iterval(Rakudo::QuantHash.MIX-ROLL(raw,total)), Pair, '$!key' ) }, True ) !! Rakudo::Iterator.Empty ) } multi method roll(Mixy:D: Callable:D $calculate) { (my $total := self!total-positive) ?? self.roll($calculate($total)) !! Seq.new(Rakudo::Iterator.Empty) } multi method roll(Mixy:D: $count) { $count == Inf ?? self.roll(*) # let Whatever handle it !! Seq.new( # something else as count (my $todo = $count.Int) < 1 # also handles NaN ?? Rakudo::Iterator.Empty # nothing to do !! (my \raw := self.RAW-HASH) && (my \total := self!total-positive) && ++$todo ?? Rakudo::Iterator.Callable( { # need to do a number of times --$todo ?? nqp::getattr( nqp::iterval( Rakudo::QuantHash.MIX-ROLL(raw,total) ), Pair, '$!key' ) !! IterationEnd } ) !! Rakudo::Iterator.Empty # nothing to roll for ) } #--- object creation methods method new-from-pairs(Mixy:_: *@pairs --> Mixy:D) { (my \iterator := @pairs.iterator).is-lazy ?? self.fail-iterator-cannot-be-lazy('coerce') !! nqp::create(self).SET-SELF( Rakudo::QuantHash.ADD-PAIRS-TO-MIX( nqp::create(Rakudo::Internals::IterationSet), iterator, self.keyof ) ) } #--- coercion methods sub SETIFY(\mixy, \type) { nqp::if( (my \raw := mixy.RAW-HASH) && nqp::elems(raw), nqp::stmts( (my \elems := nqp::clone(raw)), (my \iter := nqp::iterator(elems)), nqp::while( iter, nqp::if( nqp::getattr(nqp::iterval(nqp::shift(iter)),Pair,'$!value') < 0, nqp::deletekey(elems,nqp::iterkey_s(iter)), nqp::bindkey( elems, nqp::iterkey_s(iter), nqp::getattr(nqp::iterval(iter),Pair,'$!key') ) ) ), nqp::create(type).SET-SELF(elems) ), nqp::if( nqp::eqaddr(type,Set), set(), nqp::create(type) ) ) } multi method Set(Mixy:D:) { SETIFY(self,Set) } multi method SetHash(Mixy:D:) { SETIFY(self,SetHash) } sub BAGGIFY(\mixy, \type) { nqp::if( (my \raw := mixy.RAW-HASH) && nqp::elems(raw), nqp::stmts( # something to coerce (my \elems := nqp::clone(raw)), (my \iter := nqp::iterator(elems)), nqp::while( iter, nqp::if( (my \value := nqp::getattr( nqp::iterval(nqp::shift(iter)),Pair,'$!value' ).Int) > 0, # .Int also deconts nqp::bindkey( # ok to keep value.Int elems, nqp::iterkey_s(iter), nqp::p6bindattrinvres( nqp::iterval(iter),Pair,'$!value',value) ), nqp::deletekey(elems,nqp::iterkey_s(iter)) ) ), nqp::create(type).SET-SELF(elems), ), nqp::if( # nothing to coerce nqp::istype(type,Bag), bag(), nqp::create(BagHash) ) ) } multi method Bag(Baggy:D:) { BAGGIFY(self, Bag) } multi method BagHash(Baggy:D:) { BAGGIFY(self, BagHash) } } # vim: expandtab shiftwidth=4