# This file implements the following set operators: # (<=) is a subset of (ASCII) # ⊆ is a subset of # ⊈ is NOT a subset of # (>=) is a superset of (ASCII) # ⊇ is a superset of # ⊉ is NOT a superset of proto sub infix:<<(<=)>>($, $, *% --> Bool:D) is pure {*} multi sub infix:<<(<=)>>(Setty:D $a, Setty:D $b --> Bool:D) { nqp::unless( nqp::eqaddr($a,$b), nqp::if( (my \araw := $a.RAW-HASH) && nqp::elems(araw), nqp::if( # number of elems in B *always* >= A (my \braw := $b.RAW-HASH) && nqp::isle_i(nqp::elems(araw),nqp::elems(braw)) && (my \iter := nqp::iterator(araw)), nqp::while( # number of elems in B >= A iter, nqp::unless( nqp::existskey(braw,nqp::iterkey_s(nqp::shift(iter))), return False # elem in A doesn't exist in B ) ), return False # number of elems in B smaller than A ) ) ); True } multi sub infix:<<(<=)>>(Setty:D $a, Mixy:D $b --> Bool:D) { $a.Mix (<=) $b } multi sub infix:<<(<=)>>(Setty:D $a, Baggy:D $b --> Bool:D) { $a.Bag (<=) $b } multi sub infix:<<(<=)>>(Setty:D $a, Any \b --> Bool:D) { $a (<=) b.Set } multi sub infix:<<(<=)>>(Mixy:D $a, Mixy:D $b --> Bool:D) { Rakudo::QuantHash.MIX-IS-SUBSET($a, $b) } multi sub infix:<<(<=)>>(Mixy:D $a, Baggy:D $b --> Bool:D) { Rakudo::QuantHash.MIX-IS-SUBSET($a, $b) } multi sub infix:<<(<=)>>(Mixy:D $a, Setty:D $b --> Bool:D) { $a (<=) $b.Mix } multi sub infix:<<(<=)>>(Mixy:D $a, Any \b --> Bool:D) { $a (<=) b.Mix } multi sub infix:<<(<=)>>(Baggy:D $a, Mixy:D $b --> Bool:D) { Rakudo::QuantHash.MIX-IS-SUBSET($a, $b) } multi sub infix:<<(<=)>>(Baggy:D $a, Baggy:D $b --> Bool:D) { nqp::unless( nqp::eqaddr($a,$b), nqp::if( (my \araw := $a.RAW-HASH) && nqp::elems(araw), nqp::if( # number of elems in B *always* >= A (my \braw := $b.RAW-HASH) && nqp::isle_i(nqp::elems(araw),nqp::elems(braw)) && (my \iter := nqp::iterator(araw)), nqp::while( # number of elems in B >= A iter, nqp::unless( nqp::getattr(nqp::iterval(nqp::shift(iter)),Pair,'$!value') <= # value in A should be less or equal than B nqp::getattr( nqp::ifnull( nqp::atkey(braw,nqp::iterkey_s(iter)), BEGIN # provide virtual value 0 nqp::p6bindattrinvres(nqp::create(Pair),Pair,'$!value',0) ), Pair, '$!value' ), return False ) ), return False # number of elems in B smaller than A ) ) ); True } multi sub infix:<<(<=)>>(Baggy:D $a, Setty:D $b --> Bool:D) { $a (<=) $b.Bag } multi sub infix:<<(<=)>>(Baggy:D $a, Any \b --> Bool:D) { $a (<=) b.Bag } multi sub infix:<<(<=)>>(Map:D \a, Map:D \b --> Bool:D) { nqp::if( nqp::eqaddr(nqp::decont(a),nqp::decont(b)), True, # B is alias of A nqp::if( # A and B are different nqp::elems(my \araw := nqp::getattr(nqp::decont(a),Map,'$!storage')), nqp::if( # something in A nqp::istype(a,Hash::Object) || nqp::istype(b,Hash::Object), (a.Set (<=) b.Set), # either is objectHash, so coerce nqp::if( # both are normal Maps (my \iter := nqp::iterator(araw)) && nqp::elems( my \braw := nqp::getattr(nqp::decont(b),Map,'$!storage') ), nqp::stmts( # something to check for in B nqp::while( iter, nqp::if( nqp::iterval(nqp::shift(iter)), nqp::unless( # valid in A nqp::atkey(braw,nqp::iterkey_s(iter)), return False # valid elem in A isn't valid elem in B ) ) ), True # all valids in A occur as valids in B ), nqp::stmts( # nothing to check for in B nqp::while( iter, nqp::if( nqp::iterval(nqp::shift(iter)), return False # valid in elem in A (and none in B) ) ), True # no valid elems in A ) ) ), True # nothing in A ) ) } multi sub infix:<<(<=)>>(Iterable:D \a, Map:D \b --> Bool:D) { my \iterator := a.iterator; my \braw := nqp::getattr(nqp::decont(b),Map,'$!storage'); if nqp::istype(b,Hash::Object) { nqp::until( nqp::eqaddr((my \object := iterator.pull-one),IterationEnd), nqp::unless( nqp::existskey(braw,my str $key = object.WHICH) && nqp::istrue( nqp::getattr(nqp::atkey(braw,$key),Pair,'$!value') ), (return False) ) ); } else { nqp::until( nqp::eqaddr((my \string := iterator.pull-one),IterationEnd), nqp::unless( nqp::existskey(braw,my str $key = string.Str) && nqp::istrue(nqp::atkey(braw,$key)), (return False) ) ); } True } multi sub infix:<<(<=)>>(Any \a, Mixy:D $b --> Bool:D) { a.Mix (<=) $b } multi sub infix:<<(<=)>>(Any \a, Baggy:D $b --> Bool:D) { a.Bag (<=) $b } multi sub infix:<<(<=)>>(Any \a, Setty:D $b --> Bool:D) { a.Set (<=) $b } multi sub infix:<<(<=)>>(Failure:D $a, Any $) { $a.throw } multi sub infix:<<(<=)>>(Any $, Failure:D $b) { $b.throw } multi sub infix:<<(<=)>>(Any \a, Any \b --> Bool:D) { a.Set (<=) b.Set } # U+2286 SUBSET OF OR EQUAL TO my constant &infix:<⊆> := &infix:<<(<=)>>; # U+2288 NEITHER A SUBSET OF NOR EQUAL TO proto sub infix:<⊈>($, $, *%) is pure {*} multi sub infix:<⊈>(\a, \b --> Bool:D) { not a (<=) b } proto sub infix:<<(>=)>>($, $, *%) is pure {*} multi sub infix:<<(>=)>>(\a, \b --> Bool:D) { b (<=) a } # U+2287 SUPERSET OF OR EQUAL TO proto sub infix:<⊇>($, $, *%) is pure {*} multi sub infix:<⊇>(\a, \b --> Bool:D) { b (<=) a } # U+2289 NEITHER A SUPERSET OF NOR EQUAL TO proto sub infix:<⊉>($, $, *%) is pure {*} multi sub infix:<⊉>(\a, \b --> Bool:D) { not b (<=) a } # vim: expandtab shiftwidth=4