# This file implements the following set operators: # (+) baggy addition (ASCII) # ⊎ baggy addition proto sub infix:<(+)>(|) is pure {*} multi sub infix:<(+)>() { bag() } multi sub infix:<(+)>(Bag:D $a) { $a } multi sub infix:<(+)>(Mix:D $a) { $a } multi sub infix:<(+)>(MixHash:D $a) { $a.Mix } multi sub infix:<(+)>(Setty:D $a, QuantHash:D $b) { nqp::if( (my \araw := $a.RAW-HASH) && nqp::elems(araw), nqp::if( # elems on left (my \braw := $b.RAW-HASH) && nqp::elems(braw), nqp::stmts( # elems on both sides (my \elems := Rakudo::QuantHash.SET-BAGGIFY(araw)), nqp::create( nqp::if( nqp::istype($b,Mixy),$a.WHAT.Mixy,$a.WHAT.Baggy) ).SET-SELF( nqp::if( nqp::istype($b,Mixy), Rakudo::QuantHash.ADD-MIX-TO-MIX(elems, braw), nqp::if( nqp::istype($b,Baggy), Rakudo::QuantHash.ADD-BAG-TO-BAG(elems, braw), Rakudo::QuantHash.ADD-SET-TO-BAG(elems, braw) ) ) ) ), nqp::if(nqp::istype($b,Mixy),$a.Mixy,$a.Baggy) # no elems on right ), nqp::if( # no elems left/either nqp::istype($a,Set), nqp::if(nqp::istype($b,Mixy),$b.Mix, $b.Bag), nqp::if(nqp::istype($b,Mixy),$b.MixHash,$b.BagHash) ) ) } multi sub infix:<(+)>(Setty:D $a, Map:D \b) { nqp::if( (my \araw := $a.RAW-HASH) && nqp::elems(araw), nqp::if( # elems on left nqp::elems(nqp::getattr(nqp::decont(b),Map,'$!storage')), nqp::create( nqp::if(nqp::istype($a,Set),Bag,BagHash) ).SET-SELF( # elems on both sides Rakudo::QuantHash.ADD-MAP-TO-BAG( Rakudo::QuantHash.SET-BAGGIFY(araw), b ) ), $a.Baggy # no elems on right ), nqp::if(nqp::istype($a,Set),b.Bag,b.BagHash ) # no elems left/either ) } multi sub infix:<(+)>(Mixy:D $a, QuantHash:D $b) { nqp::if( (my \araw := $a.RAW-HASH) && nqp::elems(araw), nqp::if( # elems on left (my \braw := $b.RAW-HASH) && nqp::elems(braw), nqp::stmts( # elems on both sides (my \elems := Rakudo::QuantHash.BAGGY-CLONE(araw)), nqp::create($a.WHAT).SET-SELF( nqp::if( nqp::istype($b,Baggy), Rakudo::QuantHash.ADD-MIX-TO-MIX(elems, braw), Rakudo::QuantHash.ADD-SET-TO-MIX(elems, braw) ) ) ), $a # no elems on right ), nqp::if(nqp::istype($a,Mix),$b.Mix,$b.MixHash ) # no elems left/either ) } multi sub infix:<(+)>(Baggy:D $a, QuantHash:D $b) { nqp::if( (my \araw := $a.RAW-HASH) && nqp::elems(araw), nqp::if( # elems on left (my \braw := $b.RAW-HASH) && nqp::elems(braw), nqp::stmts( # elems on both sides (my \elems := Rakudo::QuantHash.BAGGY-CLONE(araw)), nqp::create( nqp::if( nqp::istype($b,Mixy), nqp::if(nqp::istype($a,Bag),Mix,MixHash), nqp::if(nqp::istype($a,Bag),$a.WHAT,BagHash) ) ).SET-SELF( nqp::if( nqp::istype($b,Mixy), Rakudo::QuantHash.ADD-MIX-TO-MIX(elems, braw), nqp::if( nqp::istype($b,Baggy), Rakudo::QuantHash.ADD-BAG-TO-BAG(elems, braw), Rakudo::QuantHash.ADD-SET-TO-BAG(elems, braw) ) ) ) ), nqp::if(nqp::istype($b,Mixy),$a.Mixy,$a) # no elems on right ), nqp::if( # no elems left/either nqp::istype($a,Mix) || nqp::istype($a,Bag), nqp::if( nqp::istype($b,Mixy),$b.Mix, $b.Bag), nqp::if( nqp::istype($b,Mixy),$b.MixHash,$b.BagHash) ) ) } multi sub infix:<(+)>(Map:D \a, Map:D \b) { nqp::if( nqp::elems(nqp::getattr(nqp::decont(a),Map,'$!storage')), nqp::if( # elems on left nqp::elems(nqp::getattr(nqp::decont(b),Map,'$!storage')), nqp::create(Bag).SET-SELF( # elems on both sides Rakudo::QuantHash.ADD-MAP-TO-BAG( Rakudo::QuantHash.COERCE-MAP-TO-BAG(a), b ) ), a.Bag # no elems on right ), b.Bag # no elems left/either ) } multi sub infix:<(+)>(Iterable:D \a, Iterable:D \b) { nqp::create(Bag).SET-SELF( Rakudo::QuantHash.ADD-PAIRS-TO-BAG( Rakudo::QuantHash.ADD-PAIRS-TO-BAG( nqp::create(Rakudo::Internals::IterationSet), a.iterator, Mu ), b.iterator, Mu ) ) } multi sub infix:<(+)>(Any, Failure:D $b) { $b.throw } multi sub infix:<(+)>(Failure:D $a, Any) { $a.throw } multi sub infix:<(+)>(Any \a, Any \b) { nqp::if( nqp::istype(a,QuantHash) && nqp::isconcrete(a), nqp::if( nqp::istype(a,Mixy) || nqp::istype(b,Mixy), infix:<(+)>(a.Mixy, b.Mix(:view)), # :view is implementation-detail infix:<(+)>(a.Baggy, b.Bag(:view)) # :view is implementation-detail ), nqp::if( nqp::istype(a,Mixy) || nqp::istype(b,Mixy), infix:<(+)>(a.Mix, b.Mix(:view)), # :view is implementation-detail infix:<(+)>(a.Bag, b.Bag(:view)) # :view is implementation-detail ) ) } multi sub infix:<(+)>(+@p) { # also Any my $iterator := @p.iterator; nqp::if( nqp::eqaddr((my $result := $iterator.pull-one),IterationEnd), bag(), # nothing to process nqp::if( nqp::eqaddr((my $pulled := $iterator.pull-one),IterationEnd), $result.Bag, # only 1 elem to process nqp::stmts( nqp::repeat_until( nqp::eqaddr(($pulled := $iterator.pull-one),IterationEnd), ($result := $result (+) $pulled) ), $result ) ) ) } # U+228E MULTISET UNION my constant &infix:<⊎> := &infix:<(+)>; # vim: expandtab shiftwidth=4