# This file implements the following set operators: # (&) intersection (ASCII) # ∩ intersection proto sub infix:<(&)>(|) is pure {*} multi sub infix:<(&)>() { set() } multi sub infix:<(&)>(QuantHash:D $a) { $a } # Set/Bag/Mix multi sub infix:<(&)>(Setty:D $a, Setty:D $b) { nqp::if( (my $araw := $a.RAW-HASH) && nqp::elems($araw) && (my $braw := $b.RAW-HASH) && nqp::elems($braw), nqp::stmts( # both have elems nqp::if( nqp::islt_i(nqp::elems($araw),nqp::elems($braw)), nqp::stmts( # a smallest, iterate over it (my $iter := nqp::iterator($araw)), (my $base := $braw) ), nqp::stmts( # b smallest, iterate over that ($iter := nqp::iterator($braw)), ($base := $araw) ) ), (my $elems := nqp::create(Rakudo::Internals::IterationSet)), nqp::while( $iter, nqp::if( # bind if in both nqp::existskey($base,nqp::iterkey_s(nqp::shift($iter))), nqp::bindkey($elems,nqp::iterkey_s($iter),nqp::iterval($iter)) ) ), nqp::create($a.WHAT).SET-SELF($elems) ), nqp::if( # one/neither has elems nqp::istype($a,Set), nqp::if(nqp::eqaddr($a.WHAT,Set), set(), nqp::create($a.WHAT)), nqp::create(SetHash) ) ) } multi sub infix:<(&)>(Setty:D $a, Baggy:D $b) { Rakudo::QuantHash.INTERSECT-BAGGIES($a.Baggy, $b, Bag) } multi sub infix:<(&)>(Baggy:D $a, Setty:D $b) { Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b.Bag, Bag) } multi sub infix:<(&)>(Setty:D $a, Mixy:D $b) { Rakudo::QuantHash.INTERSECT-BAGGIES($a.Mixy, $b, Mix) } multi sub infix:<(&)>(Mixy:D $a, Setty:D $b) { Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b.Mix, Mix) } multi sub infix:<(&)>(Baggy:D $a, Baggy:D $b) { Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b, Bag) } multi sub infix:<(&)>(Mixy:D $a, Baggy:D $b) { Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b, Mix) } multi sub infix:<(&)>(Baggy:D $a, Mixy:D $b) { Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b, Mix) } multi sub infix:<(&)>(Mixy:D $a, Mixy:D $b) { Rakudo::QuantHash.INTERSECT-BAGGIES($a, $b, Mix) } multi sub infix:<(&)>(Baggy:D $a, Any:D $b) { nqp::istype((my $bbag := $b.Bag),Bag) ?? Rakudo::QuantHash.INTERSECT-BAGGIES($a, $bbag, Bag) !! $bbag.throw } multi sub infix:<(&)>(Any:D $a, Baggy:D $b) { $b.Bag (&) $a } multi sub infix:<(&)>(Mixy:D $a, Any:D $b) { nqp::istype((my $bmix := $b.Mix),Mix) ?? Rakudo::QuantHash.INTERSECT-BAGGIES($a, $bmix, Mix) !! $bmix.throw } multi sub infix:<(&)>(Any:D $a, Mixy:D $b) { $b.Mix (&) $a } multi sub infix:<(&)>(Map:D \a, Map:D \b) { nqp::if( nqp::istype(a,Hash::Object) || nqp::istype(b,Hash::Object), (a.Set (&) b.Set), # either is object hash, coerce! nqp::if( # both ordinary Str hashes nqp::elems( my \araw := nqp::getattr(nqp::decont(a),Map,'$!storage') ) && nqp::elems( my \braw := nqp::getattr(nqp::decont(b),Map,'$!storage') ), nqp::stmts( # both are initialized nqp::if( nqp::islt_i(nqp::elems(araw),nqp::elems(braw)), nqp::stmts( # a smallest, iterate over it (my $iter := nqp::iterator(araw)), (my $base := braw) ), nqp::stmts( # b smallest, iterate over that ($iter := nqp::iterator(braw)), ($base := araw) ) ), (my $elems := nqp::create(Rakudo::Internals::IterationSet)), nqp::while( $iter, nqp::if( # create if in both nqp::existskey( $base, nqp::iterkey_s(nqp::shift($iter)) ), nqp::bindkey( $elems,nqp::iterkey_s($iter).WHICH,nqp::iterkey_s($iter)) ) ), nqp::create(Set).SET-SELF($elems) ), set() # one/neither has elems ) ) } multi sub infix:<(&)>(Any $, Failure:D $b) { $b.throw } multi sub infix:<(&)>(Failure:D $a, Any $) { $a.throw } # Note that we cannot create a Setty:D,Any candidate because that will result # in an ambiguous dispatch, so we need to hack a check for Setty in here. multi sub infix:<(&)>(Any \a, Any \b) { nqp::isconcrete(a) ?? nqp::istype(a,Mixy) ?? a (&) b.Mix !! nqp::istype(a,Baggy) ?? a (&) b.Bag !! nqp::istype(a,Setty) ?? a (&) b.Set !! nqp::isconcrete(b) ?? nqp::istype(b,Mixy) ?? a.Mix (&) b !! nqp::istype(b,Baggy) ?? a.Bag (&) b !! a.Set (&) b.Set !! a (&) b.Set !! a.Set (&) b } multi sub infix:<(&)>(+@p) { # also Any my $iterator := @p.iterator; nqp::if( nqp::eqaddr((my $result := $iterator.pull-one),IterationEnd), set(), # nothing to process nqp::if( nqp::eqaddr((my $pulled := $iterator.pull-one),IterationEnd), $result.Set, # only 1 elem to process nqp::stmts( nqp::repeat_until( nqp::eqaddr(($pulled := $iterator.pull-one),IterationEnd), ($result := $result (&) $pulled) ), $result ) ) ) } # U+2229 INTERSECTION my constant &infix:<∩> := &infix:<(&)>; # vim: expandtab shiftwidth=4